mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
api feat: adds method to get accessList of txs in a block
This commit is contained in:
parent
2ae2e331c9
commit
1bbd9879a4
3 changed files with 102 additions and 0 deletions
|
|
@ -704,6 +704,81 @@ func (api *API) executeTx(ctx context.Context, index int, block *types.Block, tx
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type txAccessList struct {
|
||||||
|
Accesslist *types.AccessList `json:"accessList"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Hash common.Hash `json:"hash"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) GetBlockAccessLists(ctx context.Context, blockNum uint64) ([]txAccessList, error) {
|
||||||
|
|
||||||
|
if blockNum == 0 {
|
||||||
|
return []txAccessList{}, errors.New("genesis block is not applicable")
|
||||||
|
}
|
||||||
|
block, err := api.blockByNumber(ctx, rpc.BlockNumber(blockNum))
|
||||||
|
if err != nil {
|
||||||
|
return []txAccessList{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNum-1), block.ParentHash())
|
||||||
|
if err != nil {
|
||||||
|
return []txAccessList{}, fmt.Errorf("failed to get parent block: parent: %s, err %v", block.ParentHash().Hex(), err)
|
||||||
|
}
|
||||||
|
//generate the state at the parent block
|
||||||
|
statedb, release, err := api.backend.StateAtBlock(ctx, parent, defaultTraceReexec, nil, true, false)
|
||||||
|
if err != nil {
|
||||||
|
return []txAccessList{}, fmt.Errorf("failed to generate state at the parent block: err %v", err)
|
||||||
|
}
|
||||||
|
defer release()
|
||||||
|
|
||||||
|
return api.blockAccessLists(ctx, block, statedb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) blockAccessLists(ctx context.Context, block *types.Block, statedb *state.StateDB) ([]txAccessList, error) {
|
||||||
|
|
||||||
|
var (
|
||||||
|
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
|
||||||
|
postMerge = block.Difficulty().Sign() == 0
|
||||||
|
chainConfig = api.backend.ChainConfig()
|
||||||
|
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
|
precompiles = vm.ActivePrecompiles(api.backend.ChainConfig().Rules(block.Number(), postMerge, block.Time()))
|
||||||
|
evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
|
||||||
|
acls []txAccessList
|
||||||
|
)
|
||||||
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm)
|
||||||
|
}
|
||||||
|
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), evm)
|
||||||
|
}
|
||||||
|
|
||||||
|
var to common.Address
|
||||||
|
for ind, tx := range block.Transactions() {
|
||||||
|
from, _ := types.Sender(signer, tx)
|
||||||
|
// create an access list tracer
|
||||||
|
if tx.To() != nil {
|
||||||
|
to = *tx.To()
|
||||||
|
}
|
||||||
|
tracer := logger.NewAccessListTracer(nil, from, to, precompiles)
|
||||||
|
evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true})
|
||||||
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
|
statedb.SetTxContext(tx.Hash(), ind)
|
||||||
|
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
|
if err != nil {
|
||||||
|
return acls, fmt.Errorf("failed to apply tx: err %v", err)
|
||||||
|
}
|
||||||
|
acl := tracer.AccessList()
|
||||||
|
// tracer.PrintAccessList()
|
||||||
|
txAcl := txAccessList{Accesslist: &acl, Hash: tx.Hash()}
|
||||||
|
if res.Err != nil {
|
||||||
|
txAcl.Error = res.Err.Error()
|
||||||
|
}
|
||||||
|
acls = append(acls, txAcl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acls, nil
|
||||||
|
}
|
||||||
|
|
||||||
// StandardTraceBadBlockToFile dumps the structured logs created during the
|
// StandardTraceBadBlockToFile dumps the structured logs created during the
|
||||||
// execution of EVM against a block pulled from the pool of bad ones to the
|
// execution of EVM against a block pulled from the pool of bad ones to the
|
||||||
// local file system and returns a list of files to the caller.
|
// local file system and returns a list of files to the caller.
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// accessList is an accumulator for the set of accounts and storage slots an EVM
|
// accessList is an accumulator for the set of accounts and storage slots an EVM
|
||||||
|
|
@ -93,6 +94,17 @@ func (al accessList) accessList() types.AccessList {
|
||||||
return acl
|
return acl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (al accessList) Print() {
|
||||||
|
log.Info("printing access list")
|
||||||
|
for k, v := range al {
|
||||||
|
log.Info("entry", "address", k)
|
||||||
|
for s := range v {
|
||||||
|
log.Info("slot", "hash", s.Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// AccessListTracer is a tracer that accumulates touched accounts and storage
|
// AccessListTracer is a tracer that accumulates touched accounts and storage
|
||||||
// slots into an internal set.
|
// slots into an internal set.
|
||||||
type AccessListTracer struct {
|
type AccessListTracer struct {
|
||||||
|
|
@ -159,6 +171,15 @@ func (a *AccessListTracer) AccessList() types.AccessList {
|
||||||
return a.list.accessList()
|
return a.list.accessList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AccessListTracer) PrintAccessList() {
|
||||||
|
log.Info("excluded access entries, this may contain precompiled contracts")
|
||||||
|
for k, _ := range a.excl {
|
||||||
|
log.Info("entry", "address", k.Hex())
|
||||||
|
}
|
||||||
|
log.Info("Printing other accesses")
|
||||||
|
a.list.Print()
|
||||||
|
}
|
||||||
|
|
||||||
// Equal returns if the content of two access list traces are equal.
|
// Equal returns if the content of two access list traces are equal.
|
||||||
func (a *AccessListTracer) Equal(other *AccessListTracer) bool {
|
func (a *AccessListTracer) Equal(other *AccessListTracer) bool {
|
||||||
return a.list.equal(other.list)
|
return a.list.equal(other.list)
|
||||||
|
|
|
||||||
|
|
@ -392,6 +392,12 @@ web3._extend({
|
||||||
params: 2,
|
params: 2,
|
||||||
inputFormatter: [null, null],
|
inputFormatter: [null, null],
|
||||||
}),
|
}),
|
||||||
|
new web3._extend.Method({
|
||||||
|
name: 'getBlockAccessLists',
|
||||||
|
call: 'debug_getBlockAccessLists',
|
||||||
|
params: 1,
|
||||||
|
inputFormatter: [null],
|
||||||
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'traceBlockByHash',
|
name: 'traceBlockByHash',
|
||||||
call: 'debug_traceBlockByHash',
|
call: 'debug_traceBlockByHash',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue