mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-30 02:07:36 +00:00
core/state: fix account prefetching for absent accounts (#35256)
This commit is contained in:
parent
68671a4530
commit
04bf045303
2 changed files with 46 additions and 5 deletions
|
|
@ -614,16 +614,17 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
}
|
||||
s.AccountReads += time.Since(start)
|
||||
|
||||
// Short circuit if the account is not found
|
||||
if acct == nil {
|
||||
return nil
|
||||
}
|
||||
// Schedule the resolved account for prefetching if it's enabled.
|
||||
// Schedule the account path for prefetching if it's enabled. Even if the
|
||||
// account is absent, the trie path proves its non-existence for witnesses.
|
||||
if s.prefetcher != nil {
|
||||
if err = s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, []common.Address{addr}, nil, true); err != nil {
|
||||
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
||||
}
|
||||
}
|
||||
// Short circuit if the account is not found
|
||||
if acct == nil {
|
||||
return nil
|
||||
}
|
||||
// Insert into the live set
|
||||
obj := newObject(s, addr, acct)
|
||||
s.setStateObject(obj)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -998,6 +999,45 @@ func TestDeleteCreateRevert(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestWitnessIncludesAbsentAccountReads(t *testing.T) {
|
||||
db := NewDatabaseForTesting()
|
||||
state, _ := New(types.EmptyRootHash, db)
|
||||
for i := byte(0); i < 3; i++ {
|
||||
addr := common.Address{i + 1}
|
||||
state.SetBalance(addr, uint256.NewInt(uint64(i+1)), tracing.BalanceChangeUnspecified)
|
||||
}
|
||||
root, err := state.Commit(0, false, false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to commit initial state: %v", err)
|
||||
}
|
||||
state, err = New(root, db)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to reopen state: %v", err)
|
||||
}
|
||||
|
||||
witness := &stateless.Witness{
|
||||
Codes: make(map[string]struct{}),
|
||||
State: make(map[string]struct{}),
|
||||
}
|
||||
state.StartPrefetcher("test", witness)
|
||||
missing := common.HexToAddress("0x017655eac00c837122cabbbc0dd604a196906648")
|
||||
if balance := state.GetBalance(missing); balance.Sign() != 0 {
|
||||
t.Fatalf("unexpected balance for absent account: %v", balance)
|
||||
}
|
||||
if err := state.Error(); err != nil {
|
||||
t.Fatalf("unexpected state error after read: %v", err)
|
||||
}
|
||||
if got := state.IntermediateRoot(false); got != root {
|
||||
t.Fatalf("unexpected root after read-only access: have %x want %x", got, root)
|
||||
}
|
||||
if err := state.Error(); err != nil {
|
||||
t.Fatalf("unexpected state error after root calculation: %v", err)
|
||||
}
|
||||
if len(witness.State) == 0 {
|
||||
t.Fatal("missing witness nodes for absent account read")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMissingTrieNodes tests that if the StateDB fails to load parts of the trie,
|
||||
// the Commit operation fails with an error
|
||||
// If we are missing trie nodes, we should not continue writing to the trie
|
||||
|
|
|
|||
Loading…
Reference in a new issue