Merge ethereum/poc-9 into accounts-integration
Conflicts: cmd/utils/cmd.go cmd/utils/flags.go core/manager.go eth/backend.go rpc/http/server.go xeth/xeth.go
This commit is contained in:
@ -6,14 +6,15 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/pow/ezp"
|
||||
)
|
||||
|
||||
func proc() (*BlockProcessor, *ChainManager) {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
var mux event.TypeMux
|
||||
|
||||
chainMan := NewChainManager(db, &mux)
|
||||
return NewBlockProcessor(db, nil, chainMan, &mux), chainMan
|
||||
chainMan := NewChainManager(db, db, &mux)
|
||||
return NewBlockProcessor(db, ezp.New(), nil, chainMan, &mux), chainMan
|
||||
}
|
||||
|
||||
func TestNumber(t *testing.T) {
|
||||
@ -21,13 +22,13 @@ func TestNumber(t *testing.T) {
|
||||
block1 := chain.NewBlock(nil)
|
||||
block1.Header().Number = big.NewInt(3)
|
||||
|
||||
err := bp.ValidateBlock(block1, chain.Genesis())
|
||||
err := bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
||||
if err != BlockNumberErr {
|
||||
t.Errorf("expected block number error")
|
||||
}
|
||||
|
||||
block1 = chain.NewBlock(nil)
|
||||
err = bp.ValidateBlock(block1, chain.Genesis())
|
||||
err = bp.ValidateHeader(block1.Header(), chain.Genesis().Header())
|
||||
if err == BlockNumberErr {
|
||||
t.Errorf("didn't expect block number error")
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Da
|
||||
// Create a new chain manager starting from given block
|
||||
// Effectively a fork factory
|
||||
func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager {
|
||||
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
|
||||
bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux}
|
||||
if block == nil {
|
||||
bc.Reset()
|
||||
} else {
|
||||
|
@ -19,11 +19,6 @@ var (
|
||||
jsonlogger = logger.NewJsonLogger()
|
||||
)
|
||||
|
||||
type ChainEvent struct {
|
||||
Block *types.Block
|
||||
Td *big.Int
|
||||
}
|
||||
|
||||
type StateQuery interface {
|
||||
GetAccount(addr []byte) *state.StateObject
|
||||
}
|
||||
@ -66,7 +61,6 @@ func CalcGasLimit(parent, block *types.Block) *big.Int {
|
||||
}
|
||||
|
||||
// ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024
|
||||
|
||||
previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit())
|
||||
current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.GasUsed()), big.NewRat(6, 5))
|
||||
curInt := new(big.Int).Div(current.Num(), current.Denom())
|
||||
@ -81,7 +75,8 @@ func CalcGasLimit(parent, block *types.Block) *big.Int {
|
||||
|
||||
type ChainManager struct {
|
||||
//eth EthManager
|
||||
db ethutil.Database
|
||||
blockDb ethutil.Database
|
||||
stateDb ethutil.Database
|
||||
processor types.BlockProcessor
|
||||
eventMux *event.TypeMux
|
||||
genesisBlock *types.Block
|
||||
@ -94,13 +89,16 @@ type ChainManager struct {
|
||||
|
||||
transState *state.StateDB
|
||||
txState *state.StateDB
|
||||
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
|
||||
bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
|
||||
func NewChainManager(blockDb, stateDb ethutil.Database, mux *event.TypeMux) *ChainManager {
|
||||
bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})}
|
||||
bc.setLastBlock()
|
||||
bc.transState = bc.State().Copy()
|
||||
bc.txState = bc.State().Copy()
|
||||
go bc.update()
|
||||
|
||||
return bc
|
||||
}
|
||||
@ -138,7 +136,7 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
|
||||
}
|
||||
|
||||
func (self *ChainManager) State() *state.StateDB {
|
||||
return state.New(self.CurrentBlock().Root(), self.db)
|
||||
return state.New(self.CurrentBlock().Root(), self.stateDb)
|
||||
}
|
||||
|
||||
func (self *ChainManager) TransState() *state.StateDB {
|
||||
@ -166,7 +164,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) {
|
||||
}
|
||||
|
||||
func (bc *ChainManager) setLastBlock() {
|
||||
data, _ := bc.db.Get([]byte("LastBlock"))
|
||||
data, _ := bc.blockDb.Get([]byte("LastBlock"))
|
||||
if len(data) != 0 {
|
||||
var block types.Block
|
||||
rlp.Decode(bytes.NewReader(data), &block)
|
||||
@ -174,7 +172,7 @@ func (bc *ChainManager) setLastBlock() {
|
||||
bc.lastBlockHash = block.Hash()
|
||||
|
||||
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
|
||||
bc.td = ethutil.BigD(bc.db.LastKnownTD())
|
||||
bc.td = ethutil.BigD(bc.blockDb.LastKnownTD())
|
||||
} else {
|
||||
bc.Reset()
|
||||
}
|
||||
@ -223,7 +221,7 @@ func (bc *ChainManager) Reset() {
|
||||
defer bc.mu.Unlock()
|
||||
|
||||
for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
|
||||
bc.db.Delete(block.Hash())
|
||||
bc.blockDb.Delete(block.Hash())
|
||||
}
|
||||
|
||||
// Prepare the genesis block
|
||||
@ -239,7 +237,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
|
||||
defer bc.mu.Unlock()
|
||||
|
||||
for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
|
||||
bc.db.Delete(block.Hash())
|
||||
bc.blockDb.Delete(block.Hash())
|
||||
}
|
||||
|
||||
// Prepare the genesis block
|
||||
@ -265,14 +263,14 @@ func (self *ChainManager) Export() []byte {
|
||||
|
||||
func (bc *ChainManager) insert(block *types.Block) {
|
||||
encodedBlock := ethutil.Encode(block)
|
||||
bc.db.Put([]byte("LastBlock"), encodedBlock)
|
||||
bc.blockDb.Put([]byte("LastBlock"), encodedBlock)
|
||||
bc.currentBlock = block
|
||||
bc.lastBlockHash = block.Hash()
|
||||
}
|
||||
|
||||
func (bc *ChainManager) write(block *types.Block) {
|
||||
encodedBlock := ethutil.Encode(block.RlpDataForStorage())
|
||||
bc.db.Put(block.Hash(), encodedBlock)
|
||||
bc.blockDb.Put(block.Hash(), encodedBlock)
|
||||
}
|
||||
|
||||
// Accessors
|
||||
@ -282,7 +280,7 @@ func (bc *ChainManager) Genesis() *types.Block {
|
||||
|
||||
// Block fetching methods
|
||||
func (bc *ChainManager) HasBlock(hash []byte) bool {
|
||||
data, _ := bc.db.Get(hash)
|
||||
data, _ := bc.blockDb.Get(hash)
|
||||
return len(data) != 0
|
||||
}
|
||||
|
||||
@ -291,7 +289,6 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
|
||||
if block == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
|
||||
for i := uint64(0); i < max; i++ {
|
||||
parentHash := block.Header().ParentHash
|
||||
@ -311,7 +308,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
|
||||
}
|
||||
|
||||
func (self *ChainManager) GetBlock(hash []byte) *types.Block {
|
||||
data, _ := self.db.Get(hash)
|
||||
data, _ := self.blockDb.Get(hash)
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -365,7 +362,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
|
||||
}
|
||||
|
||||
func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
|
||||
bc.db.Put([]byte("LTD"), td.Bytes())
|
||||
bc.blockDb.Put([]byte("LTD"), td.Bytes())
|
||||
bc.td = td
|
||||
}
|
||||
|
||||
@ -390,19 +387,24 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
|
||||
}
|
||||
|
||||
func (bc *ChainManager) Stop() {
|
||||
if bc.CurrentBlock != nil {
|
||||
chainlogger.Infoln("Stopped")
|
||||
}
|
||||
close(bc.quit)
|
||||
}
|
||||
|
||||
type queueEvent struct {
|
||||
queue []interface{}
|
||||
canonicalCount int
|
||||
sideCount int
|
||||
splitCount int
|
||||
}
|
||||
|
||||
func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||
println("insert chain start")
|
||||
self.tsmu.Lock()
|
||||
defer self.tsmu.Unlock()
|
||||
//self.tsmu.Lock()
|
||||
//defer self.tsmu.Unlock()
|
||||
|
||||
defer println("insert chain end")
|
||||
|
||||
for _, block := range chain {
|
||||
// A queued approach to delivering events. This is generally faster than direct delivery and requires much less mutex acquiring.
|
||||
var queue = make([]interface{}, len(chain))
|
||||
var queueEvent = queueEvent{queue: queue}
|
||||
for i, block := range chain {
|
||||
// Call in to the block processor and check for errors. It's likely that if one block fails
|
||||
// all others will fail too (unless a known block is returned).
|
||||
td, err := self.processor.Process(block)
|
||||
@ -419,7 +421,6 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||
}
|
||||
block.Td = td
|
||||
|
||||
var canonical, split bool
|
||||
self.mu.Lock()
|
||||
cblock := self.currentBlock
|
||||
{
|
||||
@ -431,41 +432,73 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
|
||||
if td.Cmp(self.td) > 0 {
|
||||
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
|
||||
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
|
||||
split = true
|
||||
|
||||
queue[i] = ChainSplitEvent{block}
|
||||
queueEvent.splitCount++
|
||||
}
|
||||
|
||||
self.setTotalDifficulty(td)
|
||||
self.insert(block)
|
||||
|
||||
canonical = true
|
||||
}
|
||||
}
|
||||
self.mu.Unlock()
|
||||
|
||||
if canonical {
|
||||
/*
|
||||
jsonlogger.LogJson(&logger.EthChainNewHead{
|
||||
BlockHash: ethutil.Bytes2Hex(block.Hash()),
|
||||
BlockNumber: block.Number(),
|
||||
ChainHeadHash: ethutil.Bytes2Hex(cblock.Hash()),
|
||||
BlockPrevHash: ethutil.Bytes2Hex(block.ParentHash()),
|
||||
})
|
||||
*/
|
||||
self.setTransState(state.New(block.Root(), self.db))
|
||||
self.eventMux.Post(ChainEvent{block, td})
|
||||
} else {
|
||||
//self.eventMux.
|
||||
}
|
||||
|
||||
if split {
|
||||
self.setTxState(state.New(block.Root(), self.db))
|
||||
self.eventMux.Post(ChainSplitEvent{block})
|
||||
self.setTransState(state.New(block.Root(), self.stateDb))
|
||||
queue[i] = ChainEvent{block}
|
||||
queueEvent.canonicalCount++
|
||||
} else {
|
||||
queue[i] = ChainSideEvent{block}
|
||||
queueEvent.sideCount++
|
||||
}
|
||||
}
|
||||
self.mu.Unlock()
|
||||
|
||||
}
|
||||
|
||||
// XXX put this in a goroutine?
|
||||
go self.eventMux.Post(queueEvent)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *ChainManager) update() {
|
||||
events := self.eventMux.Subscribe(queueEvent{})
|
||||
|
||||
out:
|
||||
for {
|
||||
select {
|
||||
case ev := <-events.Chan():
|
||||
switch ev := ev.(type) {
|
||||
case queueEvent:
|
||||
for i, event := range ev.queue {
|
||||
switch event := event.(type) {
|
||||
case ChainEvent:
|
||||
// We need some control over the mining operation. Acquiring locks and waiting for the miner to create new block takes too long
|
||||
// and in most cases isn't even necessary.
|
||||
if i == ev.canonicalCount {
|
||||
self.eventMux.Post(ChainHeadEvent{event.Block})
|
||||
}
|
||||
case ChainSplitEvent:
|
||||
// On chain splits we need to reset the transaction state. We can't be sure whether the actual
|
||||
// state of the accounts are still valid.
|
||||
if i == ev.splitCount {
|
||||
self.setTxState(state.New(event.Block.Root(), self.stateDb))
|
||||
}
|
||||
}
|
||||
|
||||
self.eventMux.Post(event)
|
||||
}
|
||||
}
|
||||
case <-self.quit:
|
||||
break out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Satisfy state query interface
|
||||
func (self *ChainManager) GetAccount(addr []byte) *state.StateObject {
|
||||
return self.State().GetAccount(addr)
|
||||
|
@ -257,9 +257,9 @@ func TestChainInsertions(t *testing.T) {
|
||||
}
|
||||
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
txPool := NewTxPool(&eventMux)
|
||||
blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
|
||||
blockMan := NewBlockProcessor(db, nil, txPool, chainMan, &eventMux)
|
||||
chainMan.SetProcessor(blockMan)
|
||||
|
||||
const max = 2
|
||||
@ -303,9 +303,9 @@ func TestChainMultipleInsertions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
txPool := NewTxPool(&eventMux)
|
||||
blockMan := NewBlockProcessor(db, txPool, chainMan, &eventMux)
|
||||
blockMan := NewBlockProcessor(db, nil, txPool, chainMan, &eventMux)
|
||||
chainMan.SetProcessor(blockMan)
|
||||
done := make(chan bool, max)
|
||||
for i, chain := range chains {
|
||||
@ -332,7 +332,7 @@ func TestGetAncestors(t *testing.T) {
|
||||
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
var eventMux event.TypeMux
|
||||
chainMan := NewChainManager(db, &eventMux)
|
||||
chainMan := NewChainManager(db, db, &eventMux)
|
||||
chain, err := loadChain("valid1", t)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -146,3 +146,19 @@ func IsKnownBlockErr(e error) bool {
|
||||
_, ok := e.(*KnownBlockError)
|
||||
return ok
|
||||
}
|
||||
|
||||
type ValueTransferError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func ValueTransferErr(str string, v ...interface{}) *ValueTransferError {
|
||||
return &ValueTransferError{fmt.Sprintf(str, v...)}
|
||||
}
|
||||
|
||||
func (self *ValueTransferError) Error() string {
|
||||
return self.message
|
||||
}
|
||||
func IsValueTransferErr(e error) bool {
|
||||
_, ok := e.(*ValueTransferError)
|
||||
return ok
|
||||
}
|
||||
|
@ -16,3 +16,13 @@ type NewMinedBlockEvent struct{ Block *types.Block }
|
||||
|
||||
// ChainSplit is posted when a new head is detected
|
||||
type ChainSplitEvent struct{ Block *types.Block }
|
||||
|
||||
type ChainEvent struct{ Block *types.Block }
|
||||
|
||||
type ChainSideEvent struct{ Block *types.Block }
|
||||
|
||||
type ChainHeadEvent struct{ Block *types.Block }
|
||||
|
||||
// Mining operation events
|
||||
type StartMining struct{}
|
||||
type TopMining struct{}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
@ -26,7 +25,10 @@ func (self *Execution) Addr() []byte {
|
||||
|
||||
func (self *Execution) Call(codeAddr []byte, caller vm.ContextRef) ([]byte, error) {
|
||||
// Retrieve the executing code
|
||||
code := self.env.State().GetCode(codeAddr)
|
||||
var code []byte
|
||||
if self.env.State().GetStateObject(codeAddr) != nil {
|
||||
code = self.env.State().GetCode(codeAddr)
|
||||
}
|
||||
|
||||
return self.exec(code, codeAddr, caller)
|
||||
}
|
||||
@ -55,7 +57,7 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ContextRef) (ret
|
||||
|
||||
caller.ReturnGas(self.Gas, self.price)
|
||||
|
||||
return nil, fmt.Errorf("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
|
||||
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance())
|
||||
}
|
||||
|
||||
snapshot := env.State().Copy()
|
||||
|
@ -13,6 +13,7 @@ type Backend interface {
|
||||
PeerCount() int
|
||||
IsListening() bool
|
||||
Peers() []*p2p.Peer
|
||||
Db() ethutil.Database
|
||||
BlockDb() ethutil.Database
|
||||
StateDb() ethutil.Database
|
||||
EventMux() *event.TypeMux
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
|
||||
}
|
||||
}
|
||||
if err = self.UseGas(big.NewInt(dgas)); err != nil {
|
||||
return
|
||||
return nil, InvalidTxError(err)
|
||||
}
|
||||
|
||||
//stateCopy := self.env.State().Copy()
|
||||
@ -230,10 +230,16 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
|
||||
*/
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
self.UseGas(self.gas)
|
||||
if err != nil && IsValueTransferErr(err) {
|
||||
return nil, InvalidTxError(err)
|
||||
}
|
||||
|
||||
/*
|
||||
if err != nil {
|
||||
self.UseGas(self.gas)
|
||||
}
|
||||
*/
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user