Skip to content

Commit 0180842

Browse files
authored
core/state: return error when storage trie can't be opened (#26350)
This changes the StorageTrie method to return an error when the trie is not available. It used to return an 'empty trie' in this case, but that's not possible anymore under PBSS.
1 parent b818e73 commit 0180842

File tree

6 files changed

+96
-40
lines changed

6 files changed

+96
-40
lines changed

core/state/dump.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,12 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
168168
}
169169
if !conf.SkipStorage {
170170
account.Storage = make(map[common.Hash]string)
171-
storageIt := trie.NewIterator(obj.getTrie(s.db).NodeIterator(nil))
171+
tr, err := obj.getTrie(s.db)
172+
if err != nil {
173+
log.Error("Failed to load storage trie", "err", err)
174+
continue
175+
}
176+
storageIt := trie.NewIterator(tr.NodeIterator(nil))
172177
for storageIt.Next() {
173178
_, content, _, err := rlp.Split(storageIt.Value)
174179
if err != nil {

core/state/state_object.go

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ func (s *stateObject) touch() {
148148
}
149149
}
150150

151-
func (s *stateObject) getTrie(db Database) Trie {
151+
// getTrie returns the associated storage trie. The trie will be opened
152+
// if it's not loaded previously. An error will be returned if trie can't
153+
// be loaded.
154+
func (s *stateObject) getTrie(db Database) (Trie, error) {
152155
if s.trie == nil {
153156
// Try fetching from prefetcher first
154157
// We don't prefetch empty tries
@@ -158,15 +161,14 @@ func (s *stateObject) getTrie(db Database) Trie {
158161
s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
159162
}
160163
if s.trie == nil {
161-
var err error
162-
s.trie, err = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root)
164+
tr, err := db.OpenStorageTrie(s.db.originalRoot, s.addrHash, s.data.Root)
163165
if err != nil {
164-
s.trie, _ = db.OpenStorageTrie(s.db.originalRoot, s.addrHash, common.Hash{})
165-
s.setError(fmt.Errorf("can't create storage trie: %v", err))
166+
return nil, err
166167
}
168+
s.trie = tr
167169
}
168170
}
169-
return s.trie
171+
return s.trie, nil
170172
}
171173

172174
// GetState retrieves a value from the account storage trie.
@@ -221,7 +223,12 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
221223
// If the snapshot is unavailable or reading from it fails, load from the database.
222224
if s.db.snap == nil || err != nil {
223225
start := time.Now()
224-
enc, err = s.getTrie(db).TryGet(key.Bytes())
226+
tr, err := s.getTrie(db)
227+
if err != nil {
228+
s.setError(err)
229+
return common.Hash{}
230+
}
231+
enc, err = tr.TryGet(key.Bytes())
225232
if metrics.EnabledExpensive {
226233
s.db.StorageReads += time.Since(start)
227234
}
@@ -304,23 +311,29 @@ func (s *stateObject) finalise(prefetch bool) {
304311
}
305312

306313
// updateTrie writes cached storage modifications into the object's storage trie.
307-
// It will return nil if the trie has not been loaded and no changes have been made
308-
func (s *stateObject) updateTrie(db Database) Trie {
314+
// It will return nil if the trie has not been loaded and no changes have been
315+
// made. An error will be returned if the trie can't be loaded/updated correctly.
316+
func (s *stateObject) updateTrie(db Database) (Trie, error) {
309317
// Make sure all dirty slots are finalized into the pending storage area
310318
s.finalise(false) // Don't prefetch anymore, pull directly if need be
311319
if len(s.pendingStorage) == 0 {
312-
return s.trie
320+
return s.trie, nil
313321
}
314322
// Track the amount of time wasted on updating the storage trie
315323
if metrics.EnabledExpensive {
316324
defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now())
317325
}
318326
// The snapshot storage map for the object
319-
var storage map[common.Hash][]byte
327+
var (
328+
storage map[common.Hash][]byte
329+
hasher = s.db.hasher
330+
)
331+
tr, err := s.getTrie(db)
332+
if err != nil {
333+
s.setError(err)
334+
return nil, err
335+
}
320336
// Insert all the pending updates into the trie
321-
tr := s.getTrie(db)
322-
hasher := s.db.hasher
323-
324337
usedStorage := make([][]byte, 0, len(s.pendingStorage))
325338
for key, value := range s.pendingStorage {
326339
// Skip noop changes, persist actual changes
@@ -331,12 +344,18 @@ func (s *stateObject) updateTrie(db Database) Trie {
331344

332345
var v []byte
333346
if (value == common.Hash{}) {
334-
s.setError(tr.TryDelete(key[:]))
347+
if err := tr.TryDelete(key[:]); err != nil {
348+
s.setError(err)
349+
return nil, err
350+
}
335351
s.db.StorageDeleted += 1
336352
} else {
337353
// Encoding []byte cannot fail, ok to ignore the error.
338354
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
339-
s.setError(tr.TryUpdate(key[:], v))
355+
if err := tr.TryUpdate(key[:], v); err != nil {
356+
s.setError(err)
357+
return nil, err
358+
}
340359
s.db.StorageUpdated += 1
341360
}
342361
// If state snapshotting is active, cache the data til commit
@@ -358,37 +377,47 @@ func (s *stateObject) updateTrie(db Database) Trie {
358377
if len(s.pendingStorage) > 0 {
359378
s.pendingStorage = make(Storage)
360379
}
361-
return tr
380+
return tr, nil
362381
}
363382

364-
// UpdateRoot sets the trie root to the current root hash of
383+
// UpdateRoot sets the trie root to the current root hash of. An error
384+
// will be returned if trie root hash is not computed correctly.
365385
func (s *stateObject) updateRoot(db Database) {
386+
tr, err := s.updateTrie(db)
387+
if err != nil {
388+
s.setError(fmt.Errorf("updateRoot (%x) error: %w", s.address, err))
389+
return
390+
}
366391
// If nothing changed, don't bother with hashing anything
367-
if s.updateTrie(db) == nil {
392+
if tr == nil {
368393
return
369394
}
370395
// Track the amount of time wasted on hashing the storage trie
371396
if metrics.EnabledExpensive {
372397
defer func(start time.Time) { s.db.StorageHashes += time.Since(start) }(time.Now())
373398
}
374-
s.data.Root = s.trie.Hash()
399+
s.data.Root = tr.Hash()
375400
}
376401

377402
// commitTrie submits the storage changes into the storage trie and re-computes
378403
// the root. Besides, all trie changes will be collected in a nodeset and returned.
379404
func (s *stateObject) commitTrie(db Database) (*trie.NodeSet, error) {
380-
// If nothing changed, don't bother with hashing anything
381-
if s.updateTrie(db) == nil {
382-
return nil, nil
405+
tr, err := s.updateTrie(db)
406+
if err != nil {
407+
return nil, err
383408
}
384409
if s.dbErr != nil {
385410
return nil, s.dbErr
386411
}
412+
// If nothing changed, don't bother with committing anything
413+
if tr == nil {
414+
return nil, nil
415+
}
387416
// Track the amount of time wasted on committing the storage trie
388417
if metrics.EnabledExpensive {
389418
defer func(start time.Time) { s.db.StorageCommits += time.Since(start) }(time.Now())
390419
}
391-
root, nodes, err := s.trie.Commit(false)
420+
root, nodes, err := tr.Commit(false)
392421
if err == nil {
393422
s.data.Root = root
394423
}

core/state/statedb.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,19 @@ func (s *StateDB) GetProofByHash(addrHash common.Hash) ([][]byte, error) {
339339

340340
// GetStorageProof returns the Merkle proof for given storage slot.
341341
func (s *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byte, error) {
342-
var proof proofList
343-
trie := s.StorageTrie(a)
342+
trie, err := s.StorageTrie(a)
343+
if err != nil {
344+
return nil, err
345+
}
344346
if trie == nil {
345-
return proof, errors.New("storage trie for requested address does not exist")
347+
return nil, errors.New("storage trie for requested address does not exist")
346348
}
347-
err := trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
348-
return proof, err
349+
var proof proofList
350+
err = trie.Prove(crypto.Keccak256(key.Bytes()), 0, &proof)
351+
if err != nil {
352+
return nil, err
353+
}
354+
return proof, nil
349355
}
350356

351357
// GetCommittedState retrieves a value from the given account's committed storage trie.
@@ -362,15 +368,18 @@ func (s *StateDB) Database() Database {
362368
return s.db
363369
}
364370

365-
// StorageTrie returns the storage trie of an account.
366-
// The return value is a copy and is nil for non-existent accounts.
367-
func (s *StateDB) StorageTrie(addr common.Address) Trie {
371+
// StorageTrie returns the storage trie of an account. The return value is a copy
372+
// and is nil for non-existent accounts. An error will be returned if storage trie
373+
// is existent but can't be loaded correctly.
374+
func (s *StateDB) StorageTrie(addr common.Address) (Trie, error) {
368375
stateObject := s.getStateObject(addr)
369376
if stateObject == nil {
370-
return nil
377+
return nil, nil
371378
}
372379
cpy := stateObject.deepCopy(s)
373-
cpy.updateTrie(s.db)
380+
if _, err := cpy.updateTrie(s.db); err != nil {
381+
return nil, err
382+
}
374383
return cpy.getTrie(s.db)
375384
}
376385

@@ -654,7 +663,11 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
654663
if so == nil {
655664
return nil
656665
}
657-
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
666+
tr, err := so.getTrie(db.db)
667+
if err != nil {
668+
return err
669+
}
670+
it := trie.NewIterator(tr.NodeIterator(nil))
658671

659672
for it.Next() {
660673
key := common.BytesToHash(db.trie.GetKey(it.Key))

eth/api.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,10 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash,
417417
}
418418
defer release()
419419

420-
st := statedb.StorageTrie(contractAddress)
420+
st, err := statedb.StorageTrie(contractAddress)
421+
if err != nil {
422+
return StorageRangeResult{}, err
423+
}
421424
if st == nil {
422425
return StorageRangeResult{}, fmt.Errorf("account %x doesn't exist", contractAddress)
423426
}

eth/api_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,11 @@ func TestStorageRangeAt(t *testing.T) {
209209
},
210210
}
211211
for _, test := range tests {
212-
result, err := storageRangeAt(state.StorageTrie(addr), test.start, test.limit)
212+
tr, err := state.StorageTrie(addr)
213+
if err != nil {
214+
t.Error(err)
215+
}
216+
result, err := storageRangeAt(tr, test.start, test.limit)
213217
if err != nil {
214218
t.Error(err)
215219
}

internal/ethapi/api.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -660,8 +660,10 @@ func (s *BlockChainAPI) GetProof(ctx context.Context, address common.Address, st
660660
if state == nil || err != nil {
661661
return nil, err
662662
}
663-
664-
storageTrie := state.StorageTrie(address)
663+
storageTrie, err := state.StorageTrie(address)
664+
if err != nil {
665+
return nil, err
666+
}
665667
storageHash := types.EmptyRootHash
666668
codeHash := state.GetCodeHash(address)
667669
storageProof := make([]StorageResult, len(storageKeys))

0 commit comments

Comments
 (0)