From d4e332e268c6bc859f02ce41bd5a0596975a8eb0 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 3 Aug 2023 16:20:17 +0200 Subject: [PATCH] fix storage clearing --- core/state/state_object.go | 9 +++ core/state/statedb.go | 3 + internal/ethapi/api_test.go | 117 ++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/core/state/state_object.go b/core/state/state_object.go index 1e28b4c12e..bde64d541f 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -418,6 +418,15 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject { return stateObject } +// clearStorageCache clears the various storage caches +// belonging to the state object. +// It is only used for RPC. +func (s *stateObject) clearStorageCache() { + s.dirtyStorage = make(Storage) + s.originStorage = make(Storage) + s.pendingStorage = make(Storage) +} + // // Attribute accessors // diff --git a/core/state/statedb.go b/core/state/statedb.go index 9dc3b9839f..777fc17d13 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -448,6 +448,9 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common // to a previous incarnation of the object. s.stateObjectsDestruct[addr] = struct{}{} stateObject := s.GetOrNewStateObject(addr) + // If object was already in memory, it might have cached + // storage slots. These should be cleared. + stateObject.clearStorageCache() for k, v := range storage { stateObject.SetState(s.db, k, v) } diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 24e9525c2f..01afa58856 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -640,6 +640,7 @@ func TestMulticallV1(t *testing.T) { genBlocks = 10 signer = types.HomesteadSigner{} cac = common.HexToAddress("0x0000000000000000000000000000000000000cac") + bab = common.HexToAddress("0x0000000000000000000000000000000000000bab") coinbase = "0x000000000000000000000000000000000000ffff" genesis = &core.Genesis{ Config: params.TestChainConfig, @@ -655,6 +656,30 @@ func TestMulticallV1(t *testing.T) { // } // } cac: {Balance: big.NewInt(params.Ether), Code: common.Hex2Bytes("610dad80ff")}, + bab: { + Balance: big.NewInt(1), + // object "Test" { + // code { + // let value1 := sload(1) + // let value2 := sload(2) + // + // // Shift value1 by 128 bits to the left by multiplying it with 2^128 + // value1 := mul(value1, 0x100000000000000000000000000000000) + // + // // Concatenate value1 and value2 + // let concatenatedValue := add(value1, value2) + // + // // Store the result in memory and return it + // mstore(0, concatenatedValue) + // return(0, 0x20) + // } + // } + Code: common.FromHex("0x600154600254700100000000000000000000000000000000820291508082018060005260206000f3"), + Storage: map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(10)), + common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(12)), + }, + }, }, } n10hash = crypto.Keccak256Hash([]byte{0xa}).Hex() @@ -1195,6 +1220,11 @@ func TestMulticallV1(t *testing.T) { // } Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), }}, + }, { + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + Input: hex2Bytes("610cac610dad600082311115601357600080fd5b6000823b1115602157600080fd5b6000813103602e57600080fd5b5050"), + }}, }}, want: []blockRes{{ Number: "0xa", @@ -1213,6 +1243,18 @@ func TestMulticallV1(t *testing.T) { Logs: []types.Log{}, Status: "0x1", }}, + }, { + Number: "0xa", + Hash: n10hash, + GasLimit: "0x47e7c4", + GasUsed: "0xe6d9", + FeeRecipient: coinbase, + Calls: []callRes{{ + ReturnValue: "0x", + GasUsed: "0xe6d9", + Logs: []types.Log{}, + Status: "0x1", + }}, }}, }, // Enable validation checks. @@ -1242,6 +1284,76 @@ func TestMulticallV1(t *testing.T) { }}, }}, }, + // Clear storage. + { + name: "clear-storage", + tag: latest, + blocks: []CallBatch{{ + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + Code: newBytes(genesis.Alloc[bab].Code), + StateDiff: &map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(2)), + common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(3)), + }, + }, + bab: { + State: &map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(1)), + }, + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + }, { + From: &accounts[0].addr, + To: &bab, + }}, + }, { + StateOverrides: &StateOverride{ + randomAccounts[2].addr: { + State: &map[common.Hash]common.Hash{ + common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)), + }, + }, + }, + Calls: []TransactionArgs{{ + From: &accounts[0].addr, + To: &randomAccounts[2].addr, + }}, + }}, + want: []blockRes{{ + Number: "0xa", + Hash: n10hash, + GasLimit: "0x47e7c4", + GasUsed: "0xc542", + FeeRecipient: coinbase, + Calls: []callRes{{ + ReturnValue: "0x0000000000000000000000000000000200000000000000000000000000000003", + GasUsed: "0x62a1", + Logs: []types.Log{}, + Status: "0x1", + }, { + ReturnValue: "0x0000000000000000000000000000000100000000000000000000000000000000", + GasUsed: "0x62a1", + Logs: []types.Log{}, + Status: "0x1", + }}, + }, { + Number: "0xa", + Hash: n10hash, + GasLimit: "0x47e7c4", + GasUsed: "0x62a1", + FeeRecipient: coinbase, + Calls: []callRes{{ + ReturnValue: "0x0000000000000000000000000000000500000000000000000000000000000000", + GasUsed: "0x62a1", + Logs: []types.Log{}, + Status: "0x1", + }}, + }}, + }, } for _, tc := range testSuite { @@ -1318,6 +1430,11 @@ func newUint64(v uint64) *hexutil.Uint64 { return &rpcUint64 } +func newBytes(b []byte) *hexutil.Bytes { + rpcBytes := hexutil.Bytes(b) + return &rpcBytes +} + // testHasher is the helper tool for transaction/receipt list hashing. // The original hasher is trie, in order to get rid of import cycle, // use the testing hasher instead.