Skip to content

Commit 3be7814

Browse files
rjl493456442jakub-freebit
authored andcommitted
core/state: fix SetStorage override behavior (ethereum#30185)
This pull request fixes the broken feature where the entire storage set is overridden. Originally, the storage set override was achieved by marking the associated account as deleted, preventing access to the storage slot on disk. However, since ethereum#29520, this flag is also checked when accessing the account, rendering the account unreachable. A fix has been applied in this pull request, which re-creates a new state object with all account metadata inherited.
1 parent 0cdb81e commit 3be7814

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

core/state/statedb.go

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -471,20 +471,28 @@ func (s *StateDB) SetState(addr common.Address, key, value common.Hash) {
471471
// storage. This function should only be used for debugging and the mutations
472472
// must be discarded afterwards.
473473
func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common.Hash) {
474-
// SetStorage needs to wipe existing storage. We achieve this by pretending
475-
// that the account self-destructed earlier in this block, by flagging
476-
// it in stateObjectsDestruct. The effect of doing so is that storage lookups
477-
// will not hit disk, since it is assumed that the disk-data is belonging
474+
// SetStorage needs to wipe the existing storage. We achieve this by marking
475+
// the account as self-destructed in this block. The effect is that storage
476+
// lookups will not hit the disk, as it is assumed that the disk data belongs
478477
// to a previous incarnation of the object.
479478
//
480-
// TODO(rjl493456442) this function should only be supported by 'unwritable'
481-
// state and all mutations made should all be discarded afterwards.
482-
if _, ok := s.stateObjectsDestruct[addr]; !ok {
483-
s.stateObjectsDestruct[addr] = nil
479+
// TODO (rjl493456442): This function should only be supported by 'unwritable'
480+
// state, and all mutations made should be discarded afterward.
481+
obj := s.getStateObject(addr)
482+
if obj != nil {
483+
if _, ok := s.stateObjectsDestruct[addr]; !ok {
484+
s.stateObjectsDestruct[addr] = obj
485+
}
484486
}
485-
stateObject := s.getOrNewStateObject(addr)
487+
newObj := s.createObject(addr)
486488
for k, v := range storage {
487-
stateObject.SetState(k, v)
489+
newObj.SetState(k, v)
490+
}
491+
// Inherit the metadata of original object if it was existent
492+
if obj != nil {
493+
newObj.SetCode(common.BytesToHash(obj.CodeHash()), obj.code)
494+
newObj.SetNonce(obj.Nonce())
495+
newObj.SetBalance(obj.Balance(), tracing.BalanceChangeUnspecified)
488496
}
489497
}
490498

internal/ethapi/api_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,15 +781,24 @@ func TestEstimateGas(t *testing.T) {
781781

782782
func TestCall(t *testing.T) {
783783
t.Parallel()
784+
784785
// Initialize test accounts
785786
var (
786787
accounts = newAccounts(3)
788+
dad = common.HexToAddress("0x0000000000000000000000000000000000000dad")
787789
genesis = &core.Genesis{
788790
Config: params.MergedTestChainConfig,
789791
Alloc: types.GenesisAlloc{
790792
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
791793
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
792794
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
795+
dad: {
796+
Balance: big.NewInt(params.Ether),
797+
Nonce: 1,
798+
Storage: map[common.Hash]common.Hash{
799+
common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
800+
},
801+
},
793802
},
794803
}
795804
genBlocks = 10
@@ -949,6 +958,32 @@ func TestCall(t *testing.T) {
949958
},
950959
want: "0x0122000000000000000000000000000000000000000000000000000000000000",
951960
},
961+
// Clear the entire storage set
962+
{
963+
blockNumber: rpc.LatestBlockNumber,
964+
call: TransactionArgs{
965+
From: &accounts[1].addr,
966+
// Yul:
967+
// object "Test" {
968+
// code {
969+
// let dad := 0x0000000000000000000000000000000000000dad
970+
// if eq(balance(dad), 0) {
971+
// revert(0, 0)
972+
// }
973+
// let slot := sload(0)
974+
// mstore(0, slot)
975+
// return(0, 32)
976+
// }
977+
// }
978+
Input: hex2Bytes("610dad6000813103600f57600080fd5b6000548060005260206000f3"),
979+
},
980+
overrides: StateOverride{
981+
dad: OverrideAccount{
982+
State: &map[common.Hash]common.Hash{},
983+
},
984+
},
985+
want: "0x0000000000000000000000000000000000000000000000000000000000000000",
986+
},
952987
}
953988
for i, tc := range testSuite {
954989
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)

0 commit comments

Comments
 (0)