Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: print db failure in case of mismatched hash root #26870

Merged
merged 3 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 11 additions & 26 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@ type stateObject struct {
data types.StateAccount
db *StateDB

// DB error.
// State objects are used by the consensus core and VM which are
// unable to deal with database-level errors. Any error that occurs
// during a database read is memoized here and will eventually be returned
// by StateDB.Commit.
dbErr error

// Write caches.
trie Trie // storage trie, which becomes non-nil on first access
code Code // contract bytecode, which gets set when code is loaded
Expand Down Expand Up @@ -121,13 +114,6 @@ func (s *stateObject) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &s.data)
}

// setError remembers the first non-nil error it is called with.
func (s *stateObject) setError(err error) {
if s.dbErr == nil {
s.dbErr = err
}
}

func (s *stateObject) markSuicided() {
s.suicided = true
}
Expand Down Expand Up @@ -212,23 +198,23 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
start := time.Now()
tr, err := s.getTrie(db)
if err != nil {
s.setError(err)
s.db.setError(err)
return common.Hash{}
}
enc, err = tr.TryGet(key.Bytes())
if metrics.EnabledExpensive {
s.db.StorageReads += time.Since(start)
}
if err != nil {
s.setError(err)
s.db.setError(err)
return common.Hash{}
}
}
var value common.Hash
if len(enc) > 0 {
_, content, _, err := rlp.Split(enc)
if err != nil {
s.setError(err)
s.db.setError(err)
}
value.SetBytes(content)
}
Expand Down Expand Up @@ -294,7 +280,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
)
tr, err := s.getTrie(db)
if err != nil {
s.setError(err)
s.db.setError(err)
return nil, err
}
// Insert all the pending updates into the trie
Expand All @@ -309,15 +295,15 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
var v []byte
if (value == common.Hash{}) {
if err := tr.TryDelete(key[:]); err != nil {
s.setError(err)
s.db.setError(err)
return nil, err
}
s.db.StorageDeleted += 1
} else {
// Encoding []byte cannot fail, ok to ignore the error.
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
if err := tr.TryUpdate(key[:], v); err != nil {
s.setError(err)
s.db.setError(err)
return nil, err
}
s.db.StorageUpdated += 1
Expand Down Expand Up @@ -349,7 +335,6 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
func (s *stateObject) updateRoot(db Database) {
tr, err := s.updateTrie(db)
if err != nil {
s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This operation is removed, since the returned error is already memorized in s.updateTrie function.

return
}
// If nothing changed, don't bother with hashing anything
Expand All @@ -370,8 +355,8 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
if err != nil {
return nil, err
}
if s.dbErr != nil {
return nil, s.dbErr
if s.db.dbErr != nil {
rjl493456442 marked this conversation as resolved.
Show resolved Hide resolved
return nil, s.db.dbErr
}
// If nothing changed, don't bother with committing anything
if tr == nil {
Expand All @@ -383,7 +368,7 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
}
root, nodes := tr.Commit(false)
s.data.Root = root
return nodes, err
return nodes, nil
}

// AddBalance adds amount to s's balance.
Expand Down Expand Up @@ -455,7 +440,7 @@ func (s *stateObject) Code(db Database) []byte {
}
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash()))
if err != nil {
s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
}
s.code = code
return code
Expand All @@ -473,7 +458,7 @@ func (s *stateObject) CodeSize(db Database) int {
}
size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash()))
if err != nil {
s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
}
return size
}
Expand Down
18 changes: 7 additions & 11 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,10 @@ type StateDB struct {
// DB error.
// State objects are used by the consensus core and VM which are
// unable to deal with database-level errors. Any error that occurs
// during a database read is memoized here and will eventually be returned
// by StateDB.Commit.
// during a database read is memoized here and will eventually be
// returned by StateDB.Commit. Notably, this error is also shared
// by all cached state objects in case the database failure occurs
// when accessing state of accounts.
dbErr error

// The refund counter, also used by state transitioning.
Expand Down Expand Up @@ -187,14 +189,9 @@ func (s *StateDB) setError(err error) {
}
}

// Error returns all memorized database failure wrapped in a single
// error object.
// Error returns the memorized database failure occurs earlier.
func (s *StateDB) Error() error {
errs := []error{s.dbErr}
for _, obj := range s.stateObjects {
errs = append(errs, obj.dbErr)
}
return errors.Join(errs...) // nil error will be ignored
return s.dbErr
}

func (s *StateDB) AddLog(log *types.Log) {
Expand Down Expand Up @@ -484,13 +481,11 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash)
if prev == value {
return
}

s.journal.append(transientStorageChange{
account: &addr,
key: key,
prevalue: prev,
})

s.setTransientState(addr, key, value)
}

Expand Down Expand Up @@ -963,6 +958,7 @@ func (s *StateDB) clearJournalAndRefund() {

// Commit writes the state to the underlying in-memory trie database.
func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
// Short circuit in case any database failure occurs earlier.
rjl493456442 marked this conversation as resolved.
Show resolved Hide resolved
if s.dbErr != nil {
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
}
Expand Down