diff --git a/core/state/statedb.go b/core/state/statedb.go index 769c8504c2..5d3db16014 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -129,6 +129,8 @@ type StateDB struct { // Transient storage transientStorage transientStorage + // Overrides to apply after Prepare() + pendingTransientOverrides map[common.Address]map[common.Hash]common.Hash // Journal of state modifications. This is the backbone of // Snapshot and RevertToSnapshot. @@ -1465,6 +1467,22 @@ func (s *StateDB) Prepare(rules params.Rules, sender, coinbase common.Address, d } // Reset transient storage at the beginning of transaction execution s.transientStorage = newTransientStorage() + + // Apply any pending transient storage overrides after reset + if s.pendingTransientOverrides != nil { + for addr, storage := range s.pendingTransientOverrides { + for key, value := range storage { + s.transientStorage.Set(addr, key, value) + } + } + s.pendingTransientOverrides = nil // Clear after applying + } +} + +// SetPendingTransientOverrides stores transient storage overrides to be applied +// after the next Prepare() call. This ensures overrides are applied to a clean state. +func (s *StateDB) SetPendingTransientOverrides(overrides map[common.Address]map[common.Hash]common.Hash) { + s.pendingTransientOverrides = overrides } // AddAddressToAccessList adds the given address to the access list diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index f88923dbf3..1f39d4047b 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -1301,8 +1301,8 @@ func TestCall(t *testing.T) { }, overrides: override.StateOverride{ randomAccounts[2].addr: override.OverrideAccount{ - // PUSH1 0x01 PUSH1 0x00 TSTORE PUSH1 0x00 TLOAD PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN - Code: hex2Bytes("0x600160005d60005c60005260206000f3"), + // PUSH1 0x00 TLOAD PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN + Code: hex2Bytes("0x60005c60005260206000f3"), TransientStorage: map[common.Hash]common.Hash{ common.Hash{}: common.HexToHash("0xabcd"), }, diff --git a/internal/ethapi/override/override.go b/internal/ethapi/override/override.go index 47d01d7259..21f30f540e 100644 --- a/internal/ethapi/override/override.go +++ b/internal/ethapi/override/override.go @@ -61,6 +61,19 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi if diff == nil { return nil } + // Get transient storage overrides to apply after Prepare() + transientOverrides := make(map[common.Address]map[common.Hash]common.Hash) + for addr, account := range *diff { + if account.TransientStorage != nil && len(account.TransientStorage) > 0 { + transientOverrides[addr] = account.TransientStorage + } + } + + // Store transient storage overrides + if len(transientOverrides) > 0 { + statedb.SetPendingTransientOverrides(transientOverrides) + } + // Iterate in deterministic order so error messages and behavior are stable (e.g. for tests). addrs := slices.SortedFunc(maps.Keys(*diff), common.Address.Cmp) @@ -118,12 +131,6 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi statedb.SetState(addr, key, value) } } - // Apply transient storage overrides. - if account.TransientStorage != nil { - for key, value := range account.TransientStorage { - statedb.SetTransientState(addr, key, value) - } - } } // Now finalize the changes. Finalize is normally performed between transactions. // By using finalize, the overrides are semantically behaving as