Skip to content

Commit 83a8465

Browse files
committed
internal/ethapi: add transient storage override support for eth_call
1 parent 1601f39 commit 83a8465

File tree

4 files changed

+94
-9
lines changed

4 files changed

+94
-9
lines changed

ethclient/gethclient/gethclient.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -301,21 +301,26 @@ type OverrideAccount struct {
301301

302302
// StateDiff allows overriding individual storage slots.
303303
StateDiff map[common.Hash]common.Hash
304+
305+
// TransientStorage allows overriding transient storage slots.
306+
TransientStorage map[common.Hash]common.Hash
304307
}
305308

306309
func (a OverrideAccount) MarshalJSON() ([]byte, error) {
307310
type acc struct {
308-
Nonce hexutil.Uint64 `json:"nonce,omitempty"`
309-
Code string `json:"code,omitempty"`
310-
Balance *hexutil.Big `json:"balance,omitempty"`
311-
State interface{} `json:"state,omitempty"`
312-
StateDiff map[common.Hash]common.Hash `json:"stateDiff,omitempty"`
311+
Nonce hexutil.Uint64 `json:"nonce,omitempty"`
312+
Code string `json:"code,omitempty"`
313+
Balance *hexutil.Big `json:"balance,omitempty"`
314+
State interface{} `json:"state,omitempty"`
315+
StateDiff map[common.Hash]common.Hash `json:"stateDiff,omitempty"`
316+
TransientStorage map[common.Hash]common.Hash `json:"transientStorage,omitempty"`
313317
}
314318

315319
output := acc{
316-
Nonce: hexutil.Uint64(a.Nonce),
317-
Balance: (*hexutil.Big)(a.Balance),
318-
StateDiff: a.StateDiff,
320+
Nonce: hexutil.Uint64(a.Nonce),
321+
Balance: (*hexutil.Big)(a.Balance),
322+
StateDiff: a.StateDiff,
323+
TransientStorage: a.TransientStorage,
319324
}
320325
if a.Code != nil {
321326
output.Code = hexutil.Encode(a.Code)

internal/ethapi/api_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,24 @@ func TestCall(t *testing.T) {
12261226
},
12271227
expectErr: errors.New(`block override "withdrawals" is not supported for this RPC method`),
12281228
},
1229+
// Test transient storage override
1230+
{
1231+
name: "transient storage override takes effect",
1232+
call: TransactionArgs{
1233+
From: &accounts[1].addr,
1234+
To: &randomAccounts[2].addr,
1235+
},
1236+
overrides: override.StateOverride{
1237+
randomAccounts[2].addr: override.OverrideAccount{
1238+
// PUSH1 0x00 TLOAD PUSH1 0x00 MSTORE PUSH1 0x20 PUSH1 0x00 RETURN
1239+
Code: hex2Bytes("0x60005c60005260206000f3"),
1240+
TransientStorage: map[common.Hash]common.Hash{
1241+
common.Hash{}: common.HexToHash("0xabcd"),
1242+
},
1243+
},
1244+
},
1245+
want: "0x000000000000000000000000000000000000000000000000000000000000abcd",
1246+
},
12291247
}
12301248
for _, tc := range testSuite {
12311249
result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)

internal/ethapi/override/override.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333
// OverrideAccount indicates the overriding fields of account during the execution
3434
// of a message call.
3535
// Note, state and stateDiff can't be specified at the same time. If state is
36-
// set, message execution will only use the data in the given state. Otherwise
36+
// set, message execution will only use the data in the given state. Otherwise,
3737
// if stateDiff is set, all diff will be applied first and then execute the call
3838
// message.
3939
type OverrideAccount struct {
@@ -42,6 +42,7 @@ type OverrideAccount struct {
4242
Balance *hexutil.Big `json:"balance"`
4343
State map[common.Hash]common.Hash `json:"state"`
4444
StateDiff map[common.Hash]common.Hash `json:"stateDiff"`
45+
TransientStorage map[common.Hash]common.Hash `json:"transientStorage"`
4546
MovePrecompileTo *common.Address `json:"movePrecompileToAddress"`
4647
}
4748

@@ -111,6 +112,12 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi
111112
statedb.SetState(addr, key, value)
112113
}
113114
}
115+
// Apply transient storage overrides.
116+
if account.TransientStorage != nil {
117+
for key, value := range account.TransientStorage {
118+
statedb.SetTransientState(addr, key, value)
119+
}
120+
}
114121
}
115122
// Now finalize the changes. Finalize is normally performed between transactions.
116123
// By using finalize, the overrides are semantically behaving as

internal/ethapi/override/override_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,58 @@ func hex2Bytes(str string) *hexutil.Bytes {
128128
rpcBytes := hexutil.Bytes(common.FromHex(str))
129129
return &rpcBytes
130130
}
131+
132+
func TestStateOverrideTransientStorage(t *testing.T) {
133+
db := state.NewDatabase(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil), nil)
134+
statedb, err := state.New(types.EmptyRootHash, db)
135+
if err != nil {
136+
t.Fatalf("failed to create statedb: %v", err)
137+
}
138+
139+
addr := common.BytesToAddress([]byte{0x1})
140+
key1 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001")
141+
key2 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002")
142+
value1 := common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")
143+
value2 := common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222")
144+
145+
// Verify initial state is empty
146+
if got := statedb.GetTransientState(addr, key1); got != (common.Hash{}) {
147+
t.Fatalf("expected initial transient state to be empty, got %s", got.Hex())
148+
}
149+
if got := statedb.GetTransientState(addr, key2); got != (common.Hash{}) {
150+
t.Fatalf("expected initial transient state to be empty, got %s", got.Hex())
151+
}
152+
153+
// Apply override with transient storage
154+
override := StateOverride{
155+
addr: OverrideAccount{
156+
TransientStorage: map[common.Hash]common.Hash{
157+
key1: value1,
158+
key2: value2,
159+
},
160+
},
161+
}
162+
163+
if err := override.Apply(statedb, nil); err != nil {
164+
t.Fatalf("failed to apply override: %v", err)
165+
}
166+
167+
// Verify transient storage was set
168+
if got := statedb.GetTransientState(addr, key1); got != value1 {
169+
t.Errorf("expected transient state for key1 to be %s, got %s", value1.Hex(), got.Hex())
170+
}
171+
if got := statedb.GetTransientState(addr, key2); got != value2 {
172+
t.Errorf("expected transient state for key2 to be %s, got %s", value2.Hex(), got.Hex())
173+
}
174+
175+
// Verify other addresses/keys remain empty
176+
otherAddr := common.BytesToAddress([]byte{0x2})
177+
if got := statedb.GetTransientState(otherAddr, key1); got != (common.Hash{}) {
178+
t.Errorf("expected transient state for different address to be empty, got %s", got.Hex())
179+
}
180+
181+
otherKey := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000003")
182+
if got := statedb.GetTransientState(addr, otherKey); got != (common.Hash{}) {
183+
t.Errorf("expected transient state for different key to be empty, got %s", got.Hex())
184+
}
185+
}

0 commit comments

Comments
 (0)