From 1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8 Mon Sep 17 00:00:00 2001 From: Gustav Simonsson Date: Tue, 6 Oct 2015 16:35:55 +0200 Subject: [PATCH] core/state, core, miner: handle missing root error from state.New --- cmd/evm/main.go | 2 +- cmd/geth/blocktestcmd.go | 10 ++++-- cmd/geth/chaincmd.go | 6 +++- core/block_processor.go | 5 ++- core/block_processor_test.go | 2 +- core/blockchain.go | 2 +- core/chain_makers.go | 5 ++- core/chain_makers_test.go | 2 +- core/genesis.go | 7 +++-- core/state/managed_state_test.go | 2 +- core/state/state_test.go | 6 ++-- core/state/statedb.go | 10 +++--- core/transaction_pool.go | 51 ++++++++++++++++++++++++------ core/transaction_pool_test.go | 53 +++++++++++++++++++------------- eth/backend.go | 3 +- eth/handler_test.go | 5 +-- eth/helper_test.go | 3 +- miner/worker.go | 15 +++++++-- rpc/api/debug.go | 6 ++-- tests/block_test_util.go | 51 +++++++++++++++--------------- tests/state_test_util.go | 4 +-- tests/vm_test_util.go | 4 +-- xeth/xeth.go | 23 +++++++++++--- 23 files changed, 182 insertions(+), 95 deletions(-) diff --git a/cmd/evm/main.go b/cmd/evm/main.go index e170dc1907..64044c4214 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -113,7 +113,7 @@ func run(ctx *cli.Context) { glog.SetV(ctx.GlobalInt(VerbosityFlag.Name)) db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) sender := statedb.CreateAccount(common.StringToAddress("sender")) receiver := statedb.CreateAccount(common.StringToAddress("receiver")) receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))) diff --git a/cmd/geth/blocktestcmd.go b/cmd/geth/blocktestcmd.go index e0a5becdc0..e4d97aa531 100644 --- a/cmd/geth/blocktestcmd.go +++ b/cmd/geth/blocktestcmd.go @@ -101,7 +101,8 @@ func runBlockTest(ctx *cli.Context) { func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, error) { cfg := utils.MakeEthConfig(ClientIdentifier, Version, ctx) - cfg.NewDB = func(path string) (ethdb.Database, error) { return ethdb.NewMemDatabase() } + db, _ := ethdb.NewMemDatabase() + cfg.NewDB = func(path string) (ethdb.Database, error) { return db, nil } cfg.MaxPeers = 0 // disable network cfg.Shh = false // disable whisper cfg.NAT = nil // disable port mapping @@ -113,7 +114,7 @@ func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, er // import the genesis block ethereum.ResetWithGenesisBlock(test.Genesis) // import pre accounts - _, err = test.InsertPreState(ethereum) + _, err = test.InsertPreState(db, cfg.AccountManager) if err != nil { return ethereum, fmt.Errorf("InsertPreState: %v", err) } @@ -123,7 +124,10 @@ func runOneBlockTest(ctx *cli.Context, test *tests.BlockTest) (*eth.Ethereum, er if err != nil { return ethereum, fmt.Errorf("Block Test load error: %v", err) } - newDB := cm.State() + newDB, err := cm.State() + if err != nil { + return ethereum, fmt.Errorf("Block Test get state error: %v", err) + } if err := test.ValidatePostState(newDB); err != nil { return ethereum, fmt.Errorf("post state validation failed: %v", err) } diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index c5bc4b66ac..80f3777d6d 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -179,7 +179,11 @@ func dump(ctx *cli.Context) { fmt.Println("{}") utils.Fatalf("block not found") } else { - state := state.New(block.Root(), chainDb) + state, err := state.New(block.Root(), chainDb) + if err != nil { + utils.Fatalf("could not create new state: %v", err) + return + } fmt.Printf("%s\n", state.Dump()) } } diff --git a/core/block_processor.go b/core/block_processor.go index 783e156876..a07d79bcf9 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -207,7 +207,10 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs vm.Logs, receipts ty func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs vm.Logs, receipts types.Receipts, err error) { // Create a new state based on the parent's root (e.g., create copy) - state := state.New(parent.Root(), sm.chainDb) + state, err := state.New(parent.Root(), sm.chainDb) + if err != nil { + return nil, nil, err + } header := block.Header() uncles := block.Uncles() txs := block.Transactions() diff --git a/core/block_processor_test.go b/core/block_processor_test.go index ba8bd7bcd5..e0e5607b9b 100644 --- a/core/block_processor_test.go +++ b/core/block_processor_test.go @@ -46,7 +46,7 @@ func TestNumber(t *testing.T) { pow := ezp.New() _, chain := proc() - statedb := state.New(chain.Genesis().Root(), chain.chainDb) + statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) header := makeHeader(chain.Genesis(), statedb) header.Number = big.NewInt(3) err := ValidateHeader(pow, header, chain.Genesis().Header(), false, false) diff --git a/core/blockchain.go b/core/blockchain.go index 6c555e9eec..62a306265e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -199,7 +199,7 @@ func (self *BlockChain) SetProcessor(proc types.BlockProcessor) { self.processor = proc } -func (self *BlockChain) State() *state.StateDB { +func (self *BlockChain) State() (*state.StateDB, error) { return state.New(self.CurrentBlock().Root(), self.chainDb) } diff --git a/core/chain_makers.go b/core/chain_makers.go index ba09b30290..4347d91733 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -156,7 +156,10 @@ func (b *BlockGen) OffsetTime(seconds int64) { // values. Inserting them into BlockChain requires use of FakePow or // a similar non-validating proof of work implementation. func GenerateChain(parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) []*types.Block { - statedb := state.New(parent.Root(), db) + statedb, err := state.New(parent.Root(), db) + if err != nil { + panic(err) + } blocks := make(types.Blocks, n) genblock := func(i int, h *types.Header) *types.Block { b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb} diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index b33af8d873..63825c2613 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -84,7 +84,7 @@ func ExampleGenerateChain() { return } - state := chainman.State() + state, _ := chainman.State() fmt.Printf("last block: #%d\n", chainman.CurrentBlock().Number()) fmt.Println("balance of addr1:", state.GetBalance(addr1)) fmt.Println("balance of addr2:", state.GetBalance(addr2)) diff --git a/core/genesis.go b/core/genesis.go index 4c5c17f601..16c1598c28 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -60,7 +60,8 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, return nil, err } - statedb := state.New(common.Hash{}, chainDb) + // creating with empty hash always works + statedb, _ := state.New(common.Hash{}, chainDb) for addr, account := range genesis.Alloc { address := common.HexToAddress(addr) statedb.AddBalance(address, common.String2Big(account.Balance)) @@ -115,9 +116,9 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, } // GenesisBlockForTesting creates a block in which addr has the given wei balance. -// The state trie of the block is written to db. +// The state trie of the block is written to db. the passed db needs to contain a state root func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block { - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) obj := statedb.GetOrNewStateObject(addr) obj.SetBalance(balance) root, err := statedb.Commit() diff --git a/core/state/managed_state_test.go b/core/state/managed_state_test.go index 58e77d842b..0b53a42c54 100644 --- a/core/state/managed_state_test.go +++ b/core/state/managed_state_test.go @@ -27,7 +27,7 @@ var addr = common.BytesToAddress([]byte("test")) func create() (*ManagedState, *account) { db, _ := ethdb.NewMemDatabase() - statedb := New(common.Hash{}, db) + statedb, _ := New(common.Hash{}, db) ms := ManageState(statedb) so := &StateObject{address: addr, nonce: 100} ms.StateDB.stateObjects[addr.Str()] = so diff --git a/core/state/state_test.go b/core/state/state_test.go index b5a7f40811..08fbc47fa2 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -77,12 +77,12 @@ func (s *StateSuite) TestDump(c *checker.C) { func (s *StateSuite) SetUpTest(c *checker.C) { db, _ := ethdb.NewMemDatabase() - s.state = New(common.Hash{}, db) + s.state, _ = New(common.Hash{}, db) } func TestNull(t *testing.T) { db, _ := ethdb.NewMemDatabase() - state := New(common.Hash{}, db) + state, _ := New(common.Hash{}, db) address := common.HexToAddress("0x823140710bf13990e4500136726d8b55") state.CreateAccount(address) @@ -122,7 +122,7 @@ func (s *StateSuite) TestSnapshot(c *checker.C) { // printing/logging in tests (-check.vv does not work) func TestSnapshot2(t *testing.T) { db, _ := ethdb.NewMemDatabase() - state := New(common.Hash{}, db) + state, _ := New(common.Hash{}, db) stateobjaddr0 := toAddr([]byte("so0")) stateobjaddr1 := toAddr([]byte("so1")) diff --git a/core/state/statedb.go b/core/state/statedb.go index ad673aecba..a9de71409c 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -52,12 +52,11 @@ type StateDB struct { } // Create a new state from a given trie -func New(root common.Hash, db ethdb.Database) *StateDB { +func New(root common.Hash, db ethdb.Database) (*StateDB, error) { tr, err := trie.NewSecure(root, db) if err != nil { - // TODO: bubble this up - tr, _ = trie.NewSecure(common.Hash{}, db) glog.Errorf("can't create state trie with root %x: %v", root[:], err) + return nil, err } return &StateDB{ db: db, @@ -65,7 +64,7 @@ func New(root common.Hash, db ethdb.Database) *StateDB { stateObjects: make(map[string]*StateObject), refund: new(big.Int), logs: make(map[common.Hash]vm.Logs), - } + }, nil } func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { @@ -297,7 +296,8 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account { // func (self *StateDB) Copy() *StateDB { - state := New(common.Hash{}, self.db) + // ignore error - we assume state-to-be-copied always exists + state, _ := New(common.Hash{}, self.db) state.trie = self.trie for k, stateObject := range self.stateObjects { state.stateObjects[k] = stateObject.Copy() diff --git a/core/transaction_pool.go b/core/transaction_pool.go index a4e6ce3e2f..16f66efdcf 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -48,7 +48,7 @@ const ( maxQueued = 64 // max limit of queued txs per address ) -type stateFn func() *state.StateDB +type stateFn func() (*state.StateDB, error) // TxPool contains all currently known transactions. Transactions // enter the pool when they are received from the network or submitted @@ -80,7 +80,7 @@ func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func( currentState: currentStateFn, gasLimit: gasLimitFn, minGasPrice: new(big.Int), - pendingState: state.ManageState(currentStateFn()), + pendingState: nil, events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}), } go pool.eventLoop() @@ -109,7 +109,17 @@ func (pool *TxPool) eventLoop() { } func (pool *TxPool) resetState() { - pool.pendingState = state.ManageState(pool.currentState()) + currentState, err := pool.currentState() + if err != nil { + glog.V(logger.Info).Infoln("failed to get current state: %v", err) + return + } + managedState := state.ManageState(currentState) + if err != nil { + glog.V(logger.Info).Infoln("failed to get managed state: %v", err) + return + } + pool.pendingState = managedState // validate the pool of pending transactions, this will remove // any transactions that have been included in the block or @@ -180,12 +190,16 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { // Make sure the account exist. Non existent accounts // haven't got funds and well therefor never pass. - if !pool.currentState().HasAccount(from) { + currentState, err := pool.currentState() + if err != nil { + return err + } + if !currentState.HasAccount(from) { return ErrNonExistentAccount } // Last but not least check for nonce errors - if pool.currentState().GetNonce(from) > tx.Nonce() { + if currentState.GetNonce(from) > tx.Nonce() { return ErrNonce } @@ -204,7 +218,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error { // Transactor should have enough funds to cover the costs // cost == V + GP * GL - if pool.currentState().GetBalance(from).Cmp(tx.Cost()) < 0 { + if currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { return ErrInsufficientFunds } @@ -257,6 +271,11 @@ func (self *TxPool) queueTx(hash common.Hash, tx *types.Transaction) { // addTx will add a transaction to the pending (processable queue) list of transactions func (pool *TxPool) addTx(hash common.Hash, addr common.Address, tx *types.Transaction) { + // init delayed since tx pool could have been started before any state sync + if pool.pendingState == nil { + pool.resetState() + } + if _, ok := pool.pending[hash]; !ok { pool.pending[hash] = tx @@ -382,14 +401,22 @@ func (pool *TxPool) RemoveTx(hash common.Hash) { // checkQueue moves transactions that have become processable to main pool. func (pool *TxPool) checkQueue() { - state := pool.pendingState + // init delayed since tx pool could have been started before any state sync + if pool.pendingState == nil { + pool.resetState() + } var addq txQueue for address, txs := range pool.queue { // guessed nonce is the nonce currently kept by the tx pool (pending state) - guessedNonce := state.GetNonce(address) + guessedNonce := pool.pendingState.GetNonce(address) // true nonce is the nonce known by the last state - trueNonce := pool.currentState().GetNonce(address) + currentState, err := pool.currentState() + if err != nil { + glog.Errorf("could not get current state: %v", err) + return + } + trueNonce := currentState.GetNonce(address) addq := addq[:0] for hash, tx := range txs { if tx.Nonce() < trueNonce { @@ -434,7 +461,11 @@ func (pool *TxPool) checkQueue() { // validatePool removes invalid and processed transactions from the main pool. func (pool *TxPool) validatePool() { - state := pool.currentState() + state, err := pool.currentState() + if err != nil { + glog.V(logger.Info).Infoln("failed to get current state: %v", err) + return + } for hash, tx := range pool.pending { from, _ := tx.From() // err already checked // perform light nonce validation diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go index 37cd20c964..229dcacf37 100644 --- a/core/transaction_pool_test.go +++ b/core/transaction_pool_test.go @@ -36,11 +36,13 @@ func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types. func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) var m event.TypeMux key, _ := crypto.GenerateKey() - return NewTxPool(&m, func() *state.StateDB { return statedb }, func() *big.Int { return big.NewInt(1000000) }), key + newPool := NewTxPool(&m, func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) + newPool.resetState() + return newPool, key } func TestInvalidTransactions(t *testing.T) { @@ -52,19 +54,20 @@ func TestInvalidTransactions(t *testing.T) { } from, _ := tx.From() - pool.currentState().AddBalance(from, big.NewInt(1)) + currentState, _ := pool.currentState() + currentState.AddBalance(from, big.NewInt(1)) if err := pool.Add(tx); err != ErrInsufficientFunds { t.Error("expected", ErrInsufficientFunds) } balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) - pool.currentState().AddBalance(from, balance) + currentState.AddBalance(from, balance) if err := pool.Add(tx); err != ErrIntrinsicGas { t.Error("expected", ErrIntrinsicGas, "got", err) } - pool.currentState().SetNonce(from, 1) - pool.currentState().AddBalance(from, big.NewInt(0xffffffffffffff)) + currentState.SetNonce(from, 1) + currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) tx = transaction(0, big.NewInt(100000), key) if err := pool.Add(tx); err != ErrNonce { t.Error("expected", ErrNonce) @@ -75,7 +78,8 @@ func TestTransactionQueue(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(100), key) from, _ := tx.From() - pool.currentState().AddBalance(from, big.NewInt(1)) + currentState, _ := pool.currentState() + currentState.AddBalance(from, big.NewInt(1)) pool.queueTx(tx.Hash(), tx) pool.checkQueue() @@ -85,7 +89,7 @@ func TestTransactionQueue(t *testing.T) { tx = transaction(1, big.NewInt(100), key) from, _ = tx.From() - pool.currentState().SetNonce(from, 2) + currentState.SetNonce(from, 2) pool.queueTx(tx.Hash(), tx) pool.checkQueue() if _, ok := pool.pending[tx.Hash()]; ok { @@ -119,7 +123,8 @@ func TestRemoveTx(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(100), key) from, _ := tx.From() - pool.currentState().AddBalance(from, big.NewInt(1)) + currentState, _ := pool.currentState() + currentState.AddBalance(from, big.NewInt(1)) pool.queueTx(tx.Hash(), tx) pool.addTx(tx.Hash(), from, tx) if len(pool.queue) != 1 { @@ -146,7 +151,8 @@ func TestNegativeValue(t *testing.T) { tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key) from, _ := tx.From() - pool.currentState().AddBalance(from, big.NewInt(1)) + currentState, _ := pool.currentState() + currentState.AddBalance(from, big.NewInt(1)) if err := pool.Add(tx); err != ErrNegativeValue { t.Error("expected", ErrNegativeValue, "got", err) } @@ -157,9 +163,10 @@ func TestTransactionChainFork(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) - pool.currentState = func() *state.StateDB { return statedb } - pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + statedb, _ := state.New(common.Hash{}, db) + pool.currentState = func() (*state.StateDB, error) { return statedb, nil } + currentState, _ := pool.currentState() + currentState.AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() } resetState() @@ -182,9 +189,10 @@ func TestTransactionDoubleNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) resetState := func() { db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) - pool.currentState = func() *state.StateDB { return statedb } - pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + statedb, _ := state.New(common.Hash{}, db) + pool.currentState = func() (*state.StateDB, error) { return statedb, nil } + currentState, _ := pool.currentState() + currentState.AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() } resetState() @@ -207,7 +215,8 @@ func TestTransactionDoubleNonce(t *testing.T) { func TestMissingNonce(t *testing.T) { pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + currentState, _ := pool.currentState() + currentState.AddBalance(addr, big.NewInt(100000000000000)) tx := transaction(1, big.NewInt(100000), key) if err := pool.add(tx); err != nil { t.Error("didn't expect error", err) @@ -224,15 +233,16 @@ func TestNonceRecovery(t *testing.T) { const n = 10 pool, key := setupTxPool() addr := crypto.PubkeyToAddress(key.PublicKey) - pool.currentState().SetNonce(addr, n) - pool.currentState().AddBalance(addr, big.NewInt(100000000000000)) + currentState, _ := pool.currentState() + currentState.SetNonce(addr, n) + currentState.AddBalance(addr, big.NewInt(100000000000000)) pool.resetState() tx := transaction(n, big.NewInt(100000), key) if err := pool.Add(tx); err != nil { t.Error(err) } // simulate some weird re-order of transactions and missing nonce(s) - pool.currentState().SetNonce(addr, n-1) + currentState.SetNonce(addr, n-1) pool.resetState() if fn := pool.pendingState.GetNonce(addr); fn != n+1 { t.Errorf("expected nonce to be %d, got %d", n+1, fn) @@ -243,7 +253,8 @@ func TestRemovedTxEvent(t *testing.T) { pool, key := setupTxPool() tx := transaction(0, big.NewInt(1000000), key) from, _ := tx.From() - pool.currentState().AddBalance(from, big.NewInt(1000000000000)) + currentState, _ := pool.currentState() + currentState.AddBalance(from, big.NewInt(1000000000000)) pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}}) pool.eventMux.Post(ChainHeadEvent{nil}) if len(pool.pending) != 1 { diff --git a/eth/backend.go b/eth/backend.go index 83eefca5b5..18900c91e0 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -389,7 +389,8 @@ func New(config *Config) (*Ethereum, error) { return nil, err } - eth.txPool = core.NewTxPool(eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) + newPool := core.NewTxPool(eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) + eth.txPool = newPool eth.blockProcessor = core.NewBlockProcessor(chainDb, eth.pow, eth.blockchain, eth.EventMux()) eth.blockchain.SetProcessor(eth.blockProcessor) diff --git a/eth/handler_test.go b/eth/handler_test.go index 2b8c6168a8..dde2ecbd51 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -443,10 +443,11 @@ func testGetNodeData(t *testing.T, protocol int) { } accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr} for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { - trie := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb) + trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb) for j, acc := range accounts { - bw := pm.blockchain.State().GetBalance(acc) + state, _ := pm.blockchain.State() + bw := state.GetBalance(acc) bh := trie.GetBalance(acc) if (bw != nil && bh == nil) || (bw == nil && bh != nil) { diff --git a/eth/helper_test.go b/eth/helper_test.go index e42fa1f82b..9314884efb 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -38,7 +38,8 @@ func newTestProtocolManager(blocks int, generator func(int, *core.BlockGen), new blockproc = core.NewBlockProcessor(db, pow, blockchain, evmux) ) blockchain.SetProcessor(blockproc) - if _, err := blockchain.InsertChain(core.GenerateChain(genesis, db, blocks, generator)); err != nil { + chain := core.GenerateChain(genesis, db, blocks, generator) + if _, err := blockchain.InsertChain(chain); err != nil { panic(err) } pm := NewProtocolManager(NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db) diff --git a/miner/worker.go b/miner/worker.go index 43f6f9909c..83653e3278 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -353,8 +353,11 @@ func (self *worker) push(work *Work) { } // makeCurrent creates a new environment for the current cycle. -func (self *worker) makeCurrent(parent *types.Block, header *types.Header) { - state := state.New(parent.Root(), self.eth.ChainDb()) +func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error { + state, err := state.New(parent.Root(), self.eth.ChainDb()) + if err != nil { + return err + } work := &Work{ state: state, ancestors: set.New(), @@ -385,6 +388,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) { work.localMinedBlocks = self.current.localMinedBlocks } self.current = work + return nil } func (w *worker) setGasPrice(p *big.Int) { @@ -464,7 +468,12 @@ func (self *worker) commitNewWork() { } previous := self.current - self.makeCurrent(parent, header) + // Could potentially happen if starting to mine in an odd state. + err := self.makeCurrent(parent, header) + if err != nil { + glog.V(logger.Info).Infoln("Could not create new env for mining, retrying on next block.") + return + } work := self.current /* //approach 1 diff --git a/rpc/api/debug.go b/rpc/api/debug.go index e193f7ad2d..003b4d9940 100644 --- a/rpc/api/debug.go +++ b/rpc/api/debug.go @@ -119,9 +119,9 @@ func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) { return nil, fmt.Errorf("block #%d not found", args.BlockNumber) } - stateDb := state.New(block.Root(), self.ethereum.ChainDb()) - if stateDb == nil { - return nil, nil + stateDb, err := state.New(block.Root(), self.ethereum.ChainDb()) + if err != nil { + return nil, err } return stateDb.RawDump(), nil diff --git a/tests/block_test_util.go b/tests/block_test_util.go index fb9ca16e68..4c329631ab 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -162,9 +162,25 @@ func runBlockTests(bt map[string]*BlockTest, skipTests []string) error { } func runBlockTest(test *BlockTest) error { - cfg := test.makeEthConfig() + ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore")) + am := accounts.NewManager(ks) + db, _ := ethdb.NewMemDatabase() + cfg := ð.Config{ + DataDir: common.DefaultDataDir(), + Verbosity: 5, + Etherbase: common.Address{}, + AccountManager: am, + NewDB: func(path string) (ethdb.Database, error) { return db, nil }, + } + cfg.GenesisBlock = test.Genesis + // import pre accounts & construct test genesis block & state root + _, err := test.InsertPreState(db, am) + if err != nil { + return fmt.Errorf("InsertPreState: %v", err) + } + ethereum, err := eth.New(cfg) if err != nil { return err @@ -175,12 +191,6 @@ func runBlockTest(test *BlockTest) error { return err } - // import pre accounts - _, err = test.InsertPreState(ethereum) - if err != nil { - return fmt.Errorf("InsertPreState: %v", err) - } - cm := ethereum.BlockChain() validBlocks, err := test.TryBlocksInsert(cm) if err != nil { @@ -193,7 +203,10 @@ func runBlockTest(test *BlockTest) error { return fmt.Errorf("lastblockhash validation mismatch: want: %x, have: %x", lastblockhash, cmlast) } - newDB := cm.State() + newDB, err := cm.State() + if err != nil { + return err + } if err = test.ValidatePostState(newDB); err != nil { return fmt.Errorf("post state validation failed: %v", err) } @@ -201,23 +214,13 @@ func runBlockTest(test *BlockTest) error { return test.ValidateImportedHeaders(cm, validBlocks) } -func (test *BlockTest) makeEthConfig() *eth.Config { - ks := crypto.NewKeyStorePassphrase(filepath.Join(common.DefaultDataDir(), "keystore")) - - return ð.Config{ - DataDir: common.DefaultDataDir(), - Verbosity: 5, - Etherbase: common.Address{}, - AccountManager: accounts.NewManager(ks), - NewDB: func(path string) (ethdb.Database, error) { return ethdb.NewMemDatabase() }, - } -} - // InsertPreState populates the given database with the genesis // accounts defined by the test. -func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, error) { - db := ethereum.ChainDb() - statedb := state.New(common.Hash{}, db) +func (t *BlockTest) InsertPreState(db ethdb.Database, am *accounts.Manager) (*state.StateDB, error) { + statedb, err := state.New(common.Hash{}, db) + if err != nil { + return nil, err + } for addrString, acct := range t.preAccounts { addr, err := hex.DecodeString(addrString) if err != nil { @@ -239,7 +242,7 @@ func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, erro if acct.PrivateKey != "" { privkey, err := hex.DecodeString(strings.TrimPrefix(acct.PrivateKey, "0x")) err = crypto.ImportBlockTestKey(privkey) - err = ethereum.AccountManager().TimedUnlock(common.BytesToAddress(addr), "", 999999*time.Second) + err = am.TimedUnlock(common.BytesToAddress(addr), "", 999999*time.Second) if err != nil { return nil, err } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index a1c066c82d..676d9ed8cb 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -103,7 +103,7 @@ func BenchStateTest(p string, conf bconf, b *testing.B) error { func benchStateTest(test VmTest, env map[string]string, b *testing.B) { b.StopTimer() db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) @@ -142,7 +142,7 @@ func runStateTests(tests map[string]VmTest, skipTests []string) error { func runStateTest(test VmTest) error { db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index b61995e31e..ddd14b1a3e 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -108,7 +108,7 @@ func BenchVmTest(p string, conf bconf, b *testing.B) error { func benchVmTest(test VmTest, env map[string]string, b *testing.B) { b.StopTimer() db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) @@ -159,7 +159,7 @@ func runVmTests(tests map[string]VmTest, skipTests []string) error { func runVmTest(test VmTest) error { db, _ := ethdb.NewMemDatabase() - statedb := state.New(common.Hash{}, db) + statedb, _ := state.New(common.Hash{}, db) for addr, account := range test.Pre { obj := StateObjectFromAccount(db, addr, account) statedb.SetStateObject(obj) diff --git a/xeth/xeth.go b/xeth/xeth.go index 13e1712709..3b487fed89 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -126,7 +126,11 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { if frontend == nil { xeth.frontend = dummyFrontend{} } - xeth.state = NewState(xeth, xeth.backend.BlockChain().State()) + state, err := xeth.backend.BlockChain().State() + if err != nil { + return nil + } + xeth.state = NewState(xeth, state) go xeth.start() @@ -207,14 +211,21 @@ func (self *XEth) RemoteMining() *miner.RemoteAgent { return self.agent } func (self *XEth) AtStateNum(num int64) *XEth { var st *state.StateDB + var err error switch num { case -2: st = self.backend.Miner().PendingState().Copy() default: if block := self.getBlockByHeight(num); block != nil { - st = state.New(block.Root(), self.backend.ChainDb()) + st, err = state.New(block.Root(), self.backend.ChainDb()) + if err != nil { + return nil + } } else { - st = state.New(self.backend.BlockChain().GetBlockByNumber(0).Root(), self.backend.ChainDb()) + st, err = state.New(self.backend.BlockChain().GetBlockByNumber(0).Root(), self.backend.ChainDb()) + if err != nil { + return nil + } } } @@ -266,7 +277,11 @@ func (self *XEth) UpdateState() (wait chan *big.Int) { wait <- n n = nil } - statedb := state.New(event.Block.Root(), self.backend.ChainDb()) + statedb, err := state.New(event.Block.Root(), self.backend.ChainDb()) + if err != nil { + glog.V(logger.Error).Infoln("Could not create new state: %v", err) + return + } self.state = NewState(self, statedb) } case n, ok = <-wait: