mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
WIP: create the 'debug_traceRip7560Validation' API
This commit is contained in:
parent
8064306e4b
commit
94156da356
4 changed files with 220 additions and 6 deletions
|
|
@ -1022,6 +1022,9 @@ func APIs(backend Backend) []rpc.API {
|
||||||
{
|
{
|
||||||
Namespace: "debug",
|
Namespace: "debug",
|
||||||
Service: NewAPI(backend),
|
Service: NewAPI(backend),
|
||||||
|
}, {
|
||||||
|
Namespace: "debug",
|
||||||
|
Service: NewRip7560API(backend),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
141
eth/tracers/api_tracing_rip7560.go
Normal file
141
eth/tracers/api_tracing_rip7560.go
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
package tracers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"log"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rip7560API is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||||
|
type Rip7560API struct {
|
||||||
|
backend Backend
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRip7560API(backend Backend) *Rip7560API {
|
||||||
|
return &Rip7560API{backend: backend}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceRip7560Validation mostly copied from 'tracers/api.go' file
|
||||||
|
func (api *Rip7560API) TraceRip7560Validation(
|
||||||
|
ctx context.Context,
|
||||||
|
args ethapi.TransactionArgs,
|
||||||
|
blockNrOrHash rpc.BlockNumberOrHash,
|
||||||
|
config *TraceCallConfig,
|
||||||
|
) (interface{}, error) {
|
||||||
|
number, _ := blockNrOrHash.Number()
|
||||||
|
block, err := api.blockByNumber(ctx, number)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
reexec := defaultTraceReexec
|
||||||
|
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer release()
|
||||||
|
|
||||||
|
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
|
||||||
|
if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
msg = args.ToMessage(vmctx.BaseFee)
|
||||||
|
tx = args.ToTransaction()
|
||||||
|
traceConfig *TraceConfig
|
||||||
|
)
|
||||||
|
if config != nil {
|
||||||
|
traceConfig = &config.TraceConfig
|
||||||
|
}
|
||||||
|
traceResult, err := api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Println("TraceRip7560Validation result")
|
||||||
|
log.Println(string(traceResult.(json.RawMessage)))
|
||||||
|
return traceResult, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//////// copy-pasted code
|
||||||
|
|
||||||
|
// blockByNumber is the wrapper of the chain access function offered by the backend.
|
||||||
|
// It will return an error if the block is not found.
|
||||||
|
func (api *Rip7560API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||||
|
block, err := api.backend.BlockByNumber(ctx, number)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if block == nil {
|
||||||
|
return nil, fmt.Errorf("block #%d not found", number)
|
||||||
|
}
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// chainContext constructs the context reader which is used by the evm for reading
|
||||||
|
// the necessary chain context.
|
||||||
|
func (api *Rip7560API) chainContext(ctx context.Context) core.ChainContext {
|
||||||
|
return ethapi.NewChainContext(ctx, api.backend)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Rip7560API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||||
|
var (
|
||||||
|
tracer *Tracer
|
||||||
|
err error
|
||||||
|
timeout = defaultTraceTimeout
|
||||||
|
usedGas uint64
|
||||||
|
)
|
||||||
|
if config == nil {
|
||||||
|
config = &TraceConfig{}
|
||||||
|
}
|
||||||
|
// Default tracer is the struct logger
|
||||||
|
//if config.Tracer == nil {
|
||||||
|
// logger := logger.NewStructLogger(config.Config)
|
||||||
|
// tracer = &Tracer{
|
||||||
|
// Hooks: logger.Hooks(),
|
||||||
|
// GetResult: logger.GetResult,
|
||||||
|
// Stop: logger.Stop,
|
||||||
|
// }
|
||||||
|
//} else {
|
||||||
|
tracer, err = DefaultDirectory.New("rip7560Validation", txctx, config.TracerConfig)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
||||||
|
statedb.SetLogger(tracer.Hooks)
|
||||||
|
|
||||||
|
// Define a meaningful timeout of a single transaction trace
|
||||||
|
if config.Timeout != nil {
|
||||||
|
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||||
|
go func() {
|
||||||
|
<-deadlineCtx.Done()
|
||||||
|
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
|
||||||
|
tracer.Stop(errors.New("execution timeout"))
|
||||||
|
// Stop evm execution. Note cancellation is not necessarily immediate.
|
||||||
|
vmenv.Cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// Call Prepare to clear out the statedb access list
|
||||||
|
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
|
message.IsRip7560Frame = true
|
||||||
|
_, err = core.ApplyTransactionWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||||
|
}
|
||||||
|
return tracer.GetResult()
|
||||||
|
}
|
||||||
70
eth/tracers/native/rip7560_validation.go
Normal file
70
eth/tracers/native/rip7560_validation.go
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
package native
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
tracers.DefaultDirectory.Register("rip7560Validation", newRip7560Tracer, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRip7560Tracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
|
||||||
|
var config prestateTracerConfig
|
||||||
|
if cfg != nil {
|
||||||
|
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t := &rip7560ValidationTracer{
|
||||||
|
TraceResults: make([]stateMap, 0),
|
||||||
|
UsedOpcodes: make([]map[byte]bool, 0),
|
||||||
|
Created: make([]map[common.Address]bool, 0),
|
||||||
|
Deleted: make([]map[common.Address]bool, 0),
|
||||||
|
}
|
||||||
|
return &tracers.Tracer{
|
||||||
|
Hooks: &tracing.Hooks{
|
||||||
|
OnTxStart: t.OnTxStart,
|
||||||
|
OnTxEnd: t.OnTxEnd,
|
||||||
|
OnOpcode: t.OnOpcode,
|
||||||
|
},
|
||||||
|
GetResult: t.GetResult,
|
||||||
|
Stop: t.Stop,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array fields contain of all access details of all validation frames
|
||||||
|
type rip7560ValidationTracer struct {
|
||||||
|
env *tracing.VMContext
|
||||||
|
TraceResults []stateMap `json:"traceResults"`
|
||||||
|
UsedOpcodes []map[byte]bool `json:"usedOpcodes"`
|
||||||
|
Created []map[common.Address]bool `json:"created"`
|
||||||
|
Deleted []map[common.Address]bool `json:"deleted"`
|
||||||
|
// todo
|
||||||
|
//interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||||
|
//reason error // Textual reason for the interruption
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rip7560ValidationTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rip7560ValidationTracer) OnTxEnd(receipt *types.Receipt, err error) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rip7560ValidationTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||||
|
fmt.Printf("%s %d %d", vm.OpCode(opcode).String(), cost, depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rip7560ValidationTracer) GetResult() (json.RawMessage, error) {
|
||||||
|
jsonResult, err := json.MarshalIndent(*t, "", " ")
|
||||||
|
return jsonResult, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *rip7560ValidationTracer) Stop(err error) {
|
||||||
|
}
|
||||||
|
|
@ -79,13 +79,13 @@ type TransactionArgs struct {
|
||||||
Sender *common.Address `json:"sender"`
|
Sender *common.Address `json:"sender"`
|
||||||
Signature *hexutil.Bytes
|
Signature *hexutil.Bytes
|
||||||
Paymaster *common.Address `json:"paymaster,omitempty"`
|
Paymaster *common.Address `json:"paymaster,omitempty"`
|
||||||
PaymasterData *hexutil.Bytes `json:"paymasterData"`
|
PaymasterData *hexutil.Bytes `json:"paymasterData,omitempty"`
|
||||||
Deployer *common.Address `json:"deployer,omitempty"`
|
Deployer *common.Address `json:"factory,omitempty"`
|
||||||
DeployerData *hexutil.Bytes
|
DeployerData *hexutil.Bytes `json:"factoryData,omitempty"`
|
||||||
BuilderFee *hexutil.Big
|
BuilderFee *hexutil.Big
|
||||||
ValidationGas *hexutil.Uint64
|
ValidationGas *hexutil.Uint64 `json:"verificationGasLimit"`
|
||||||
PaymasterGas *hexutil.Uint64
|
PaymasterGas *hexutil.Uint64 `json:"paymasterVerificationGasLimit"`
|
||||||
PostOpGas *hexutil.Uint64
|
PostOpGas *hexutil.Uint64 `json:"paymasterPostOpGasLimit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// from retrieves the transaction sender address.
|
// from retrieves the transaction sender address.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue