Skip to content

Commit a4466d5

Browse files
rjl493456442shekhirin
authored andcommitted
core: show db error-info in case of mismatched hash root (ethereum#26870)
When a database failure occurs, bubble it up a into statedb, and report it in suitable places, such as during a 'bad block' report.
1 parent bd5edf9 commit a4466d5

File tree

4 files changed

+17
-44
lines changed

4 files changed

+17
-44
lines changed

core/block_validator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
113113
// Validate the state root against the received state root and throw
114114
// an error if they don't match.
115115
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
116-
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
116+
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
117117
}
118118
return nil
119119
}

core/state/state_object.go

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ func (s Storage) String() (str string) {
4343
for key, value := range s {
4444
str += fmt.Sprintf("%X : %X\n", key, value)
4545
}
46-
4746
return
4847
}
4948

@@ -52,7 +51,6 @@ func (s Storage) Copy() Storage {
5251
for key, value := range s {
5352
cpy[key] = value
5453
}
55-
5654
return cpy
5755
}
5856

@@ -68,13 +66,6 @@ type stateObject struct {
6866
data types.StateAccount
6967
db *StateDB
7068

71-
// DB error.
72-
// State objects are used by the consensus core and VM which are
73-
// unable to deal with database-level errors. Any error that occurs
74-
// during a database read is memoized here and will eventually be returned
75-
// by StateDB.Commit.
76-
dbErr error
77-
7869
// Write caches.
7970
trie Trie // storage trie, which becomes non-nil on first access
8071
code Code // contract bytecode, which gets set when code is loaded
@@ -84,7 +75,7 @@ type stateObject struct {
8475
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
8576

8677
// Cache flags.
87-
// When an object is marked suicided it will be delete from the trie
78+
// When an object is marked suicided it will be deleted from the trie
8879
// during the "update" phase of the state transition.
8980
dirtyCode bool // true if the code was updated
9081
suicided bool
@@ -123,13 +114,6 @@ func (s *stateObject) EncodeRLP(w io.Writer) error {
123114
return rlp.Encode(w, &s.data)
124115
}
125116

126-
// setError remembers the first non-nil error it is called with.
127-
func (s *stateObject) setError(err error) {
128-
if s.dbErr == nil {
129-
s.dbErr = err
130-
}
131-
}
132-
133117
func (s *stateObject) markSuicided() {
134118
s.suicided = true
135119
}
@@ -214,23 +198,23 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
214198
start := time.Now()
215199
tr, err := s.getTrie(db)
216200
if err != nil {
217-
s.setError(err)
201+
s.db.setError(err)
218202
return common.Hash{}
219203
}
220204
enc, err = tr.TryGet(key.Bytes())
221205
if metrics.EnabledExpensive {
222206
s.db.StorageReads += time.Since(start)
223207
}
224208
if err != nil {
225-
s.setError(err)
209+
s.db.setError(err)
226210
return common.Hash{}
227211
}
228212
}
229213
var value common.Hash
230214
if len(enc) > 0 {
231215
_, content, _, err := rlp.Split(enc)
232216
if err != nil {
233-
s.setError(err)
217+
s.db.setError(err)
234218
}
235219
value.SetBytes(content)
236220
}
@@ -296,7 +280,7 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
296280
)
297281
tr, err := s.getTrie(db)
298282
if err != nil {
299-
s.setError(err)
283+
s.db.setError(err)
300284
return nil, err
301285
}
302286
// Insert all the pending updates into the trie
@@ -311,15 +295,15 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
311295
var v []byte
312296
if (value == common.Hash{}) {
313297
if err := tr.TryDelete(key[:]); err != nil {
314-
s.setError(err)
298+
s.db.setError(err)
315299
return nil, err
316300
}
317301
s.db.StorageDeleted += 1
318302
} else {
319303
// Encoding []byte cannot fail, ok to ignore the error.
320304
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
321305
if err := tr.TryUpdate(key[:], v); err != nil {
322-
s.setError(err)
306+
s.db.setError(err)
323307
return nil, err
324308
}
325309
s.db.StorageUpdated += 1
@@ -351,7 +335,6 @@ func (s *stateObject) updateTrie(db Database) (Trie, error) {
351335
func (s *stateObject) updateRoot(db Database) {
352336
tr, err := s.updateTrie(db)
353337
if err != nil {
354-
s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err))
355338
return
356339
}
357340
// If nothing changed, don't bother with hashing anything
@@ -372,9 +355,6 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
372355
if err != nil {
373356
return nil, err
374357
}
375-
if s.dbErr != nil {
376-
return nil, s.dbErr
377-
}
378358
// If nothing changed, don't bother with committing anything
379359
if tr == nil {
380360
return nil, nil
@@ -385,7 +365,7 @@ func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
385365
}
386366
root, nodes := tr.Commit(false)
387367
s.data.Root = root
388-
return nodes, err
368+
return nodes, nil
389369
}
390370

391371
// AddBalance adds amount to s's balance.
@@ -457,7 +437,7 @@ func (s *stateObject) Code(db Database) []byte {
457437
}
458438
code, err := db.ContractCode(s.addrHash, common.BytesToHash(s.CodeHash()))
459439
if err != nil {
460-
s.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
440+
s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
461441
}
462442
s.code = code
463443
return code
@@ -475,7 +455,7 @@ func (s *stateObject) CodeSize(db Database) int {
475455
}
476456
size, err := db.ContractCodeSize(s.addrHash, common.BytesToHash(s.CodeHash()))
477457
if err != nil {
478-
s.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
458+
s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
479459
}
480460
return size
481461
}
@@ -519,10 +499,3 @@ func (s *stateObject) Balance() *big.Int {
519499
func (s *stateObject) Nonce() uint64 {
520500
return s.data.Nonce
521501
}
522-
523-
// Value is never called, but must be present to allow stateObject to be used
524-
// as a vm.Account interface that also satisfies the vm.ContractRef
525-
// interface. Interfaces are awesome.
526-
func (s *stateObject) Value() *big.Int {
527-
panic("Value on stateObject should never be called")
528-
}

core/state/statedb.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ type StateDB struct {
8181
// DB error.
8282
// State objects are used by the consensus core and VM which are
8383
// unable to deal with database-level errors. Any error that occurs
84-
// during a database read is memoized here and will eventually be returned
85-
// by StateDB.Commit.
84+
// during a database read is memoized here and will eventually be
85+
// returned by StateDB.Commit. Notably, this error is also shared
86+
// by all cached state objects in case the database failure occurs
87+
// when accessing state of accounts.
8688
dbErr error
8789

8890
// The refund counter, also used by state transitioning.
@@ -187,6 +189,7 @@ func (s *StateDB) setError(err error) {
187189
}
188190
}
189191

192+
// Error returns the memorized database failure occurred earlier.
190193
func (s *StateDB) Error() error {
191194
return s.dbErr
192195
}
@@ -478,13 +481,11 @@ func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash)
478481
if prev == value {
479482
return
480483
}
481-
482484
s.journal.append(transientStorageChange{
483485
account: &addr,
484486
key: key,
485487
prevalue: prev,
486488
})
487-
488489
s.setTransientState(addr, key, value)
489490
}
490491

@@ -957,6 +958,7 @@ func (s *StateDB) clearJournalAndRefund() {
957958

958959
// Commit writes the state to the underlying in-memory trie database.
959960
func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
961+
// Short circuit in case any database failure occurred earlier.
960962
if s.dbErr != nil {
961963
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
962964
}

core/vm/interface.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ type StateDB interface {
7676

7777
AddLog(*types.Log)
7878
AddPreimage(common.Hash, []byte)
79-
80-
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
8179
}
8280

8381
// CallContext provides a basic interface for the EVM calling conventions. The EVM

0 commit comments

Comments
 (0)