diff --git a/core/state/dump.go b/core/state/dump.go index 9acb8a0244..45f4deb708 100644 --- a/core/state/dump.go +++ b/core/state/dump.go @@ -45,7 +45,7 @@ func (self *StateDB) RawDump() World { it := self.trie.Iterator() for it.Next() { addr := self.trie.GetKey(it.Key) - stateObject := NewStateObjectFromBytes(common.BytesToAddress(addr), it.Value, self.db) + stateObject, _ := NewStateObjectFromBytes(common.BytesToAddress(addr), it.Value, self.db) account := Account{Balance: stateObject.balance.String(), Nonce: stateObject.nonce, Root: common.Bytes2Hex(stateObject.Root()), CodeHash: common.Bytes2Hex(stateObject.codeHash)} account.Storage = make(map[string]string) diff --git a/core/state/managed_state.go b/core/state/managed_state.go index 4df0479791..0f756cecbe 100644 --- a/core/state/managed_state.go +++ b/core/state/managed_state.go @@ -91,7 +91,8 @@ func (ms *ManagedState) GetNonce(addr common.Address) uint64 { account := ms.getAccount(addr) return uint64(len(account.nonces)) + account.nstart } else { - return ms.StateDB.GetNonce(addr) + nonce, _ := ms.StateDB.GetNonce(addr) + return nonce } } @@ -100,7 +101,7 @@ func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) { ms.mu.Lock() defer ms.mu.Unlock() - so := ms.GetOrNewStateObject(addr) + so, _ := ms.GetOrNewStateObject(addr) so.SetNonce(nonce) ms.accounts[addr.Str()] = newAccount(so) @@ -122,12 +123,12 @@ func (ms *ManagedState) hasAccount(addr common.Address) bool { func (ms *ManagedState) getAccount(addr common.Address) *account { straddr := addr.Str() if account, ok := ms.accounts[straddr]; !ok { - so := ms.GetOrNewStateObject(addr) + so, _ := ms.GetOrNewStateObject(addr) ms.accounts[straddr] = newAccount(so) } else { // Always make sure the state account nonce isn't actually higher // than the tracked one. - so := ms.StateDB.GetStateObject(addr) + so, _ := ms.StateDB.GetStateObject(addr) if so != nil && uint64(len(account.nonces))+account.nstart < so.nonce { ms.accounts[straddr] = newAccount(so) } diff --git a/core/state/state_object.go b/core/state/state_object.go index 40af9ed9c4..1d6d275097 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -96,7 +96,7 @@ func NewStateObject(address common.Address, db ethdb.Database) *StateObject { return object } -func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) *StateObject { +func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Database) (*StateObject, error) { var extobject struct { Nonce uint64 Balance *big.Int @@ -106,13 +106,13 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Datab err := rlp.Decode(bytes.NewReader(data), &extobject) if err != nil { glog.Errorf("can't decode state object %x: %v", address, err) - return nil + return nil, err } trie, err := trie.NewSecure(extobject.Root, db) if err != nil { // TODO: bubble this up or panic glog.Errorf("can't create account trie with root %x: %v", extobject.Root[:], err) - return nil + return nil, err } object := &StateObject{address: address, db: db} @@ -122,8 +122,12 @@ func NewStateObjectFromBytes(address common.Address, data []byte, db ethdb.Datab object.trie = trie object.storage = make(map[string]common.Hash) object.gasPool = new(big.Int) - object.code, _ = db.Get(extobject.CodeHash) - return object + object.code, err = db.Get(extobject.CodeHash) + if err != nil { + glog.Errorf("can't retrieve contract code %x: %v", extobject.CodeHash, err) + return nil, err + } + return object, nil } func (self *StateObject) MarkForDeletion() { @@ -135,10 +139,14 @@ func (self *StateObject) MarkForDeletion() { } } -func (c *StateObject) getAddr(addr common.Hash) common.Hash { +func (c *StateObject) getAddr(addr common.Hash) (common.Hash, error) { var ret []byte - rlp.DecodeBytes(c.trie.Get(addr[:]), &ret) - return common.BytesToHash(ret) + value, err := c.trie.Get(addr[:]) + if err != nil { + return common.Hash{}, err + } + rlp.DecodeBytes(value, &ret) + return common.BytesToHash(ret), nil } func (c *StateObject) setAddr(addr []byte, value common.Hash) { @@ -154,17 +162,21 @@ func (self *StateObject) Storage() Storage { return self.storage } -func (self *StateObject) GetState(key common.Hash) common.Hash { +func (self *StateObject) GetState(key common.Hash) (common.Hash, error) { strkey := key.Str() value, exists := self.storage[strkey] if !exists { - value = self.getAddr(key) + var err error + value, err = self.getAddr(key) + if err != nil { + return common.Hash{}, err + } if (value != common.Hash{}) { self.storage[strkey] = value } } - return value + return value, nil } func (self *StateObject) SetState(k, value common.Hash) { diff --git a/core/state/statedb.go b/core/state/statedb.go index ad673aecba..859ec76035 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -99,105 +99,152 @@ func (self *StateDB) AddRefund(gas *big.Int) { self.refund.Add(self.refund, gas) } -func (self *StateDB) HasAccount(addr common.Address) bool { - return self.GetStateObject(addr) != nil +func (self *StateDB) HasAccount(addr common.Address) (bool, error) { + acc, err := self.GetStateObject(addr) + if err != nil { + return false, err + } + return acc != nil, nil } -func (self *StateDB) Exist(addr common.Address) bool { - return self.GetStateObject(addr) != nil +func (self *StateDB) Exist(addr common.Address) (bool, error) { + acc, err := self.GetStateObject(addr) + if err != nil { + return false, err + } + return acc != nil, nil } -func (self *StateDB) GetAccount(addr common.Address) vm.Account { - return self.GetStateObject(addr) +func (self *StateDB) GetAccount(addr common.Address) (vm.Account, error) { + acc, err := self.GetStateObject(addr) + if err != nil { + return nil, err + } + return acc, nil } // Retrieve the balance from the given address or 0 if object not found -func (self *StateDB) GetBalance(addr common.Address) *big.Int { - stateObject := self.GetStateObject(addr) +func (self *StateDB) GetBalance(addr common.Address) (*big.Int, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return nil, err + } if stateObject != nil { - return stateObject.balance + return stateObject.balance, nil } - return common.Big0 + return common.Big0, nil } -func (self *StateDB) GetNonce(addr common.Address) uint64 { - stateObject := self.GetStateObject(addr) - if stateObject != nil { - return stateObject.nonce +func (self *StateDB) GetNonce(addr common.Address) (uint64, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return 0, err } - return 0 -} - -func (self *StateDB) GetCode(addr common.Address) []byte { - stateObject := self.GetStateObject(addr) if stateObject != nil { - return stateObject.code + return stateObject.nonce, nil } - return nil + return 0, nil } -func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { - stateObject := self.GetStateObject(a) +func (self *StateDB) GetCode(addr common.Address) ([]byte, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return nil, err + } + if stateObject != nil { + return stateObject.code, nil + } + return nil, nil +} + +func (self *StateDB) GetState(a common.Address, b common.Hash) (common.Hash, error) { + stateObject, err := self.GetStateObject(a) + if err != nil { + return common.Hash{}, err + } if stateObject != nil { return stateObject.GetState(b) } - return common.Hash{} + return common.Hash{}, nil } -func (self *StateDB) IsDeleted(addr common.Address) bool { - stateObject := self.GetStateObject(addr) - if stateObject != nil { - return stateObject.remove +func (self *StateDB) IsDeleted(addr common.Address) (bool, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return false, err } - return false + if stateObject != nil { + return stateObject.remove, nil + } + return false, nil } /* * SETTERS */ -func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) { - stateObject := self.GetOrNewStateObject(addr) +func (self *StateDB) AddBalance(addr common.Address, amount *big.Int) error { + stateObject, err := self.GetOrNewStateObject(addr) + if err != nil { + return err + } + if stateObject != nil { stateObject.AddBalance(amount) } + return nil } -func (self *StateDB) SetNonce(addr common.Address, nonce uint64) { - stateObject := self.GetOrNewStateObject(addr) +func (self *StateDB) SetNonce(addr common.Address, nonce uint64) error { + stateObject, err := self.GetOrNewStateObject(addr) + if err != nil { + return err + } if stateObject != nil { stateObject.SetNonce(nonce) } + return nil } -func (self *StateDB) SetCode(addr common.Address, code []byte) { - stateObject := self.GetOrNewStateObject(addr) +func (self *StateDB) SetCode(addr common.Address, code []byte) error { + stateObject, err := self.GetOrNewStateObject(addr) + if err != nil { + return err + } if stateObject != nil { stateObject.SetCode(code) } + return nil } -func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) { - stateObject := self.GetOrNewStateObject(addr) +func (self *StateDB) SetState(addr common.Address, key common.Hash, value common.Hash) error { + stateObject, err := self.GetOrNewStateObject(addr) + if err != nil { + return err + } if stateObject != nil { stateObject.SetState(key, value) } + return nil } -func (self *StateDB) Delete(addr common.Address) bool { - stateObject := self.GetStateObject(addr) +func (self *StateDB) Delete(addr common.Address) (bool, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return false, err + } if stateObject != nil { stateObject.MarkForDeletion() stateObject.balance = new(big.Int) - return true + return true, nil } - return false + return false, nil } // @@ -225,25 +272,28 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) { } // Retrieve a state object given my the address. Nil if not found -func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject) { +func (self *StateDB) GetStateObject(addr common.Address) (stateObject *StateObject, err error) { stateObject = self.stateObjects[addr.Str()] if stateObject != nil { if stateObject.deleted { stateObject = nil } - return stateObject + return stateObject, nil } - data := self.trie.Get(addr[:]) - if len(data) == 0 { - return nil + data, err := self.trie.Get(addr[:]) + if err != nil { + return nil, err } - stateObject = NewStateObjectFromBytes(addr, []byte(data), self.db) + stateObject, err = NewStateObjectFromBytes(addr, []byte(data), self.db) + if err != nil { + return nil, err + } self.SetStateObject(stateObject) - return stateObject + return stateObject, nil } func (self *StateDB) SetStateObject(object *StateObject) { @@ -251,13 +301,16 @@ func (self *StateDB) SetStateObject(object *StateObject) { } // Retrieve a state object or create a new state object if nil -func (self *StateDB) GetOrNewStateObject(addr common.Address) *StateObject { - stateObject := self.GetStateObject(addr) +func (self *StateDB) GetOrNewStateObject(addr common.Address) (*StateObject, error) { + stateObject, err := self.GetStateObject(addr) + if err != nil { + return nil, err + } if stateObject == nil || stateObject.deleted { - stateObject = self.CreateStateObject(addr) + stateObject, err = self.CreateStateObject(addr) } - return stateObject + return stateObject, err } // NewStateObject create a state object whether it exist in the trie or not @@ -274,9 +327,12 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject { } // Creates creates a new state object and takes ownership. This is different from "NewStateObject" -func (self *StateDB) CreateStateObject(addr common.Address) *StateObject { +func (self *StateDB) CreateStateObject(addr common.Address) (*StateObject, error) { // Get previous (if any) - so := self.GetStateObject(addr) + so, err := self.GetStateObject(addr) + if err != nil { + return nil, err + } // Create a new one newSo := self.newStateObject(addr) @@ -285,10 +341,10 @@ func (self *StateDB) CreateStateObject(addr common.Address) *StateObject { newSo.balance = so.balance } - return newSo + return newSo, nil } -func (self *StateDB) CreateAccount(addr common.Address) vm.Account { +func (self *StateDB) CreateAccount(addr common.Address) (vm.Account, error) { return self.CreateStateObject(addr) } diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 47d1934d05..79d27d12c5 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -62,7 +62,7 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -func (t *SecureTrie) Get(key []byte) []byte { +func (t *SecureTrie) Get(key []byte) ([]byte, error) { return t.Trie.Get(t.hashKey(key)) } diff --git a/trie/trie.go b/trie/trie.go index aa8d39fe2f..100cf6f9f3 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -25,8 +25,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto/sha3" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rlp" ) @@ -40,6 +38,8 @@ var ( ) var ErrMissingRoot = errors.New("missing root node") +var ErrMissingNode = errors.New("missing trie node") +var ErrInvalidNode = errors.New("invalid trie node") // Database must be implemented by backing stores for the trie. type Database interface { @@ -94,29 +94,30 @@ func (t *Trie) Iterator() *Iterator { // Get returns the value for key stored in the trie. // The value bytes must not be modified by the caller. -func (t *Trie) Get(key []byte) []byte { +func (t *Trie) Get(key []byte) ([]byte, error) { key = compactHexDecode(key) tn := t.root for len(key) > 0 { switch n := tn.(type) { case shortNode: if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { - return nil + return nil, ErrInvalidNode } tn = n.Val key = key[len(n.Key):] case fullNode: tn = n[key[0]] key = key[1:] - case nil: - return nil case hashNode: tn = t.resolveHash(n) + if tn == nil { + return nil, ErrMissingNode + } default: panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) } } - return tn.(valueNode) + return tn.(valueNode), nil } // Update associates key with value in the trie. Subsequent calls to @@ -295,14 +296,6 @@ func (t *Trie) resolveHash(n hashNode) node { } enc, err := t.db.Get(n) if err != nil || enc == nil { - // TODO: This needs to be improved to properly distinguish errors. - // Disk I/O errors shouldn't produce nil (and cause a - // consensus failure or weird crash), but it is unclear how - // they could be handled because the entire stack above the trie isn't - // prepared to cope with missing state nodes. - if glog.V(logger.Error) { - glog.Errorf("Dangling hash node ref %x: %v", n, err) - } return nil } dec := mustDecodeNode(n, enc) diff --git a/xeth/xeth.go b/xeth/xeth.go index 13e1712709..bbedbed249 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -490,8 +490,12 @@ func (self *XEth) StorageAt(addr, storageAddr string) string { return self.State().state.GetState(common.HexToAddress(addr), common.HexToHash(storageAddr)).Hex() } -func (self *XEth) BalanceAt(addr string) string { - return common.ToHex(self.State().state.GetBalance(common.HexToAddress(addr)).Bytes()) +func (self *XEth) BalanceAt(addr string) (string, error) { + val, err := self.State().state.GetBalance(common.HexToAddress(addr)) + if err != nil { + return nil, err + } + return common.ToHex(val.Bytes()) } func (self *XEth) TxCountAt(address string) int {