mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
internal/ethapi: CreateAccessList with stateOverrides (#31497)
Add support for state overrides in eth_createAccessList. This will make the method consistent with other execution methods. --------- Co-authored-by: Sina Mahmoodi <itz.s1na@gmail.com>
This commit is contained in:
parent
a82303f4e3
commit
6143c350ae
2 changed files with 86 additions and 3 deletions
|
|
@ -1117,12 +1117,13 @@ type accessListResult struct {
|
||||||
|
|
||||||
// CreateAccessList creates an EIP-2930 type AccessList for the given transaction.
|
// CreateAccessList creates an EIP-2930 type AccessList for the given transaction.
|
||||||
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
|
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
|
||||||
func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
|
// StateOverrides can be used to create the accessList while taking into account state changes from previous transactions.
|
||||||
|
func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, stateOverrides *override.StateOverride) (*accessListResult, error) {
|
||||||
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
if blockNrOrHash != nil {
|
if blockNrOrHash != nil {
|
||||||
bNrOrHash = *blockNrOrHash
|
bNrOrHash = *blockNrOrHash
|
||||||
}
|
}
|
||||||
acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args)
|
acl, gasUsed, vmerr, err := AccessList(ctx, api.b, bNrOrHash, args, stateOverrides)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1136,13 +1137,22 @@ func (api *BlockChainAPI) CreateAccessList(ctx context.Context, args Transaction
|
||||||
// AccessList creates an access list for the given transaction.
|
// AccessList creates an access list for the given transaction.
|
||||||
// If the accesslist creation fails an error is returned.
|
// If the accesslist creation fails an error is returned.
|
||||||
// If the transaction itself fails, an vmErr is returned.
|
// If the transaction itself fails, an vmErr is returned.
|
||||||
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
|
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs, stateOverrides *override.StateOverride) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
|
||||||
// Retrieve the execution context
|
// Retrieve the execution context
|
||||||
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
if db == nil || err != nil {
|
if db == nil || err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply state overrides immediately after StateAndHeaderByNumberOrHash.
|
||||||
|
// If not applied here, there could be cases where user-specified overrides (e.g., nonce)
|
||||||
|
// may conflict with default values from the database, leading to inconsistencies.
|
||||||
|
if stateOverrides != nil {
|
||||||
|
if err := stateOverrides.Apply(db, nil); err != nil {
|
||||||
|
return nil, 0, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure any missing fields are filled, extract the recipient and input data
|
// Ensure any missing fields are filled, extract the recipient and input data
|
||||||
if err = args.setFeeDefaults(ctx, b, header); err != nil {
|
if err = args.setFeeDefaults(ctx, b, header); err != nil {
|
||||||
return nil, 0, nil, err
|
return nil, 0, nil, err
|
||||||
|
|
|
||||||
|
|
@ -3529,3 +3529,76 @@ func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc s
|
||||||
func addressToHash(a common.Address) common.Hash {
|
func addressToHash(a common.Address) common.Hash {
|
||||||
return common.BytesToHash(a.Bytes())
|
return common.BytesToHash(a.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateAccessListWithStateOverrides(t *testing.T) {
|
||||||
|
// Initialize test backend
|
||||||
|
genesis := &core.Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7"): {Balance: big.NewInt(1000000000000000000)},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
backend := newTestBackend(t, 1, genesis, ethash.NewFaker(), nil)
|
||||||
|
|
||||||
|
// Create a new BlockChainAPI instance
|
||||||
|
api := NewBlockChainAPI(backend)
|
||||||
|
|
||||||
|
// Create test contract code - a simple storage contract
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// pragma solidity ^0.8.0;
|
||||||
|
//
|
||||||
|
// contract SimpleStorage {
|
||||||
|
// uint256 private value;
|
||||||
|
//
|
||||||
|
// function retrieve() public view returns (uint256) {
|
||||||
|
// return value;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
var (
|
||||||
|
contractCode = hexutil.Bytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80632e64cec114602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60008054905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056"))
|
||||||
|
// Create state overrides with more complete state
|
||||||
|
contractAddr = common.HexToAddress("0x1234567890123456789012345678901234567890")
|
||||||
|
nonce = hexutil.Uint64(1)
|
||||||
|
overrides = &override.StateOverride{
|
||||||
|
contractAddr: override.OverrideAccount{
|
||||||
|
Code: &contractCode,
|
||||||
|
Balance: (*hexutil.Big)(big.NewInt(1000000000000000000)),
|
||||||
|
Nonce: &nonce,
|
||||||
|
State: map[common.Hash]common.Hash{
|
||||||
|
common.Hash{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create transaction arguments with gas and value
|
||||||
|
var (
|
||||||
|
from = common.HexToAddress("0x71562b71999873db5b286df957af199ec94617f7")
|
||||||
|
data = hexutil.Bytes(common.Hex2Bytes("2e64cec1")) // retrieve()
|
||||||
|
gas = hexutil.Uint64(100000)
|
||||||
|
args = TransactionArgs{
|
||||||
|
From: &from,
|
||||||
|
To: &contractAddr,
|
||||||
|
Data: &data,
|
||||||
|
Gas: &gas,
|
||||||
|
Value: new(hexutil.Big),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// Call CreateAccessList
|
||||||
|
result, err := api.CreateAccessList(context.Background(), args, nil, overrides)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create access list: %v", err)
|
||||||
|
}
|
||||||
|
if err != nil || result == nil {
|
||||||
|
t.Fatalf("Failed to create access list: %v", err)
|
||||||
|
}
|
||||||
|
require.NotNil(t, result.Accesslist)
|
||||||
|
|
||||||
|
// Verify access list contains the contract address and storage slot
|
||||||
|
expected := &types.AccessList{{
|
||||||
|
Address: contractAddr,
|
||||||
|
StorageKeys: []common.Hash{{}},
|
||||||
|
}}
|
||||||
|
require.Equal(t, expected, result.Accesslist)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue