mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-30 00:23:46 +00:00
tracetx
This commit is contained in:
parent
dd7e0db406
commit
d74ea42a7d
1 changed files with 111 additions and 16 deletions
|
|
@ -2,15 +2,21 @@ package eth
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"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/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"hash"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
type helpHash struct {
|
||||
|
|
@ -40,6 +46,14 @@ type PreExecTx struct {
|
|||
From, To, Data, Value, Gas, GasPrice, Nonce string
|
||||
}
|
||||
|
||||
type preData struct {
|
||||
block *types.Block
|
||||
tx *types.Transaction
|
||||
msg types.Message
|
||||
stateDb *state.StateDB
|
||||
header *types.Header
|
||||
}
|
||||
|
||||
// PreExecAPI provides pre exec info for rpc
|
||||
type PreExecAPI struct {
|
||||
e *Ethereum
|
||||
|
|
@ -81,36 +95,117 @@ func (api *PreExecAPI) getBlockAndMsg(origin *PreExecTx, number *big.Int) (*type
|
|||
return block, msg
|
||||
}
|
||||
|
||||
func (api *PreExecAPI) prepareData(ctx context.Context, origin *PreExecTx) (*preData, error) {
|
||||
var (
|
||||
d preData
|
||||
err error
|
||||
)
|
||||
bc := api.e.blockchain
|
||||
d.header, err = api.e.APIBackend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
latestNumber := d.header.Number
|
||||
parent := api.e.blockchain.GetBlockByNumber(latestNumber.Uint64())
|
||||
d.stateDb, err = state.New(parent.Header().Root, bc.StateCache(), bc.Snapshots())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.block, d.msg = api.getBlockAndMsg(origin, latestNumber)
|
||||
d.tx = d.block.Transactions()[0]
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
func (api *PreExecAPI) GetLogs(ctx context.Context, origin *PreExecTx) (*types.Receipt, error) {
|
||||
var (
|
||||
bc = api.e.blockchain
|
||||
)
|
||||
header, err := api.e.APIBackend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||
d, err := api.prepareData(ctx, origin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
latestNumber := header.Number
|
||||
|
||||
parent := bc.GetBlockByNumber(latestNumber.Uint64())
|
||||
stateDb, err := state.New(parent.Header().Root, bc.StateCache(), bc.Snapshots())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, msg := api.getBlockAndMsg(origin, latestNumber)
|
||||
tx := block.Transactions()[0]
|
||||
gas := tx.Gas()
|
||||
gas := d.tx.Gas()
|
||||
gp := new(core.GasPool).AddGas(gas)
|
||||
|
||||
stateDb.Prepare(tx.Hash(), block.Hash(), 0)
|
||||
d.stateDb.Prepare(d.tx.Hash(), d.block.Hash(), 0)
|
||||
receipt, err := core.ApplyTransactionForPreExec(
|
||||
bc.Config(), bc, nil, gp, stateDb, header, tx, msg, &gas, *bc.GetVMConfig())
|
||||
bc.Config(), bc, nil, gp, d.stateDb, d.header, d.tx, d.msg, &gas, *bc.GetVMConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
func (api *PreExecAPI) TraceTx(ctx context.Context, tx *PreExecTx) (interface{}, error) {
|
||||
return tx.From, nil
|
||||
func (api *PreExecAPI) TraceTx(ctx context.Context, origin *PreExecTx, config *tracers.TraceConfig) (interface{}, error) {
|
||||
var (
|
||||
bc = api.e.blockchain
|
||||
tracer vm.Tracer
|
||||
err error
|
||||
)
|
||||
d, err := api.prepareData(ctx, origin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
txContext := core.NewEVMTxContext(d.msg)
|
||||
|
||||
switch {
|
||||
case config != nil && config.Tracer != nil:
|
||||
// Define a meaningful timeout of a single transaction trace
|
||||
timeout := 5 * time.Second
|
||||
if config.Timeout != nil {
|
||||
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Constuct the JavaScript tracer to execute with
|
||||
if tracer, err = tracers.New(*config.Tracer, txContext); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Handle timeouts and RPC cancellations
|
||||
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
|
||||
go func() {
|
||||
<-deadlineCtx.Done()
|
||||
if deadlineCtx.Err() == context.DeadlineExceeded {
|
||||
tracer.(*tracers.Tracer).Stop(errors.New("execution timeout"))
|
||||
}
|
||||
}()
|
||||
defer cancel()
|
||||
|
||||
case config == nil:
|
||||
tracer = vm.NewStructLogger(nil)
|
||||
|
||||
default:
|
||||
tracer = vm.NewStructLogger(config.LogConfig)
|
||||
}
|
||||
// Run the transaction with tracing enabled.
|
||||
vmenv := vm.NewEVM(core.NewEVMBlockContext(d.header, bc, nil), txContext, d.stateDb, bc.Config(), vm.Config{Debug: true, Tracer: tracer})
|
||||
|
||||
// Call Prepare to clear out the statedb access list
|
||||
d.stateDb.Prepare(d.tx.Hash(), d.block.Hash(), 0)
|
||||
|
||||
result, err := core.ApplyMessage(vmenv, d.msg, new(core.GasPool).AddGas(d.msg.Gas()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %v", err)
|
||||
}
|
||||
// Depending on the tracer type, format and return the output.
|
||||
switch tracer := tracer.(type) {
|
||||
case *vm.StructLogger:
|
||||
// If the result contains a revert reason, return it.
|
||||
returnVal := fmt.Sprintf("%x", result.Return())
|
||||
if len(result.Revert()) > 0 {
|
||||
returnVal = fmt.Sprintf("%x", result.Revert())
|
||||
}
|
||||
return ðapi.ExecutionResult{
|
||||
Gas: result.UsedGas,
|
||||
Failed: result.Failed(),
|
||||
ReturnValue: returnVal,
|
||||
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||
}, nil
|
||||
|
||||
case *tracers.Tracer:
|
||||
return tracer.GetResult()
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("bad tracer type %T", tracer))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue