aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorGustav Simonsson <gustav.simonsson@gmail.com>2015-10-06 22:35:55 +0800
committerGustav Simonsson <gustav.simonsson@gmail.com>2015-10-16 08:22:06 +0800
commit1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8 (patch)
treefefd9cfe28ce5b409d58c70b03cf4a6d6dc84873 /core
parentf466243417f60531998e8b500f2bb043af5b3d2a (diff)
downloadgo-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar.gz
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar.bz2
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar.lz
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar.xz
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.tar.zst
go-tangerine-1b1f293082044c43d8d1c5df9ac40aab8fdb2ae8.zip
core/state, core, miner: handle missing root error from state.New
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go5
-rw-r--r--core/block_processor_test.go2
-rw-r--r--core/blockchain.go2
-rw-r--r--core/chain_makers.go5
-rw-r--r--core/chain_makers_test.go2
-rw-r--r--core/genesis.go7
-rw-r--r--core/state/managed_state_test.go2
-rw-r--r--core/state/state_test.go6
-rw-r--r--core/state/statedb.go10
-rw-r--r--core/transaction_pool.go51
-rw-r--r--core/transaction_pool_test.go53
11 files changed, 97 insertions, 48 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index 783e15687..a07d79bcf 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 ba8bd7bcd..e0e5607b9 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 6c555e9ee..62a306265 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 ba09b3029..4347d9173 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 b33af8d87..63825c261 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 4c5c17f60..16c1598c2 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 58e77d842..0b53a42c5 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 b5a7f4081..08fbc47fa 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 ad673aecb..a9de71409 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 a4e6ce3e2..16f66efdc 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 37cd20c96..229dcacf3 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 {