mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-15 08:23:46 +00:00
Initial support for extended tracer
This commit is contained in:
parent
604da5c84b
commit
642a374b9d
6 changed files with 91 additions and 0 deletions
|
|
@ -94,6 +94,7 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
|
||||||
utils.MetricsInfluxDBBucketFlag,
|
utils.MetricsInfluxDBBucketFlag,
|
||||||
utils.MetricsInfluxDBOrganizationFlag,
|
utils.MetricsInfluxDBOrganizationFlag,
|
||||||
utils.TxLookupLimitFlag,
|
utils.TxLookupLimitFlag,
|
||||||
|
utils.VMTraceFlag,
|
||||||
}, utils.DatabasePathFlags),
|
}, utils.DatabasePathFlags),
|
||||||
Description: `
|
Description: `
|
||||||
The import command imports blocks from an RLP-encoded form. The form can be one file
|
The import command imports blocks from an RLP-encoded form. The form can be one file
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ var (
|
||||||
utils.DeveloperPeriodFlag,
|
utils.DeveloperPeriodFlag,
|
||||||
utils.DeveloperGasLimitFlag,
|
utils.DeveloperGasLimitFlag,
|
||||||
utils.VMEnableDebugFlag,
|
utils.VMEnableDebugFlag,
|
||||||
|
utils.VMTraceFlag,
|
||||||
utils.NetworkIdFlag,
|
utils.NetworkIdFlag,
|
||||||
utils.EthStatsURLFlag,
|
utils.EthStatsURLFlag,
|
||||||
utils.NoCompactionFlag,
|
utils.NoCompactionFlag,
|
||||||
|
|
|
||||||
|
|
@ -529,6 +529,11 @@ var (
|
||||||
Usage: "Record information useful for VM and contract debugging",
|
Usage: "Record information useful for VM and contract debugging",
|
||||||
Category: flags.VMCategory,
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
|
VMTraceFlag = &cli.BoolFlag{
|
||||||
|
Name: "vmtrace",
|
||||||
|
Usage: "Record internal VM operations (costly)",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
|
||||||
// API options.
|
// API options.
|
||||||
RPCGlobalGasCapFlag = &cli.Uint64Flag{
|
RPCGlobalGasCapFlag = &cli.Uint64Flag{
|
||||||
|
|
@ -2164,6 +2169,9 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
if ctx.IsSet(VMTraceFlag.Name) {
|
||||||
|
chain.SetLogger(tracers.NewPrinter())
|
||||||
|
}
|
||||||
return chain, chainDb
|
return chain, chainDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,12 @@ var defaultCacheConfig = &CacheConfig{
|
||||||
SnapshotWait: true,
|
SnapshotWait: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BlockchainLogger interface {
|
||||||
|
vm.EVMLogger
|
||||||
|
CaptureBlockStart(*types.Block)
|
||||||
|
CaptureBlockEnd()
|
||||||
|
}
|
||||||
|
|
||||||
// BlockChain represents the canonical chain given a database with a genesis
|
// BlockChain represents the canonical chain given a database with a genesis
|
||||||
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
|
// block. The Blockchain manages chain imports, reverts, chain reorganisations.
|
||||||
//
|
//
|
||||||
|
|
@ -226,6 +232,7 @@ type BlockChain struct {
|
||||||
processor Processor // Block transaction processor interface
|
processor Processor // Block transaction processor interface
|
||||||
forker *ForkChoice
|
forker *ForkChoice
|
||||||
vmConfig vm.Config
|
vmConfig vm.Config
|
||||||
|
logger BlockchainLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
|
|
@ -443,6 +450,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||||
return bc, nil
|
return bc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: need to move this to NewBlockchain to capture genesis block
|
||||||
|
func (bc *BlockChain) SetLogger(l BlockchainLogger) {
|
||||||
|
bc.logger = l
|
||||||
|
bc.vmConfig.Tracer = l
|
||||||
|
}
|
||||||
|
|
||||||
// empty returns an indicator whether the blockchain is empty.
|
// empty returns an indicator whether the blockchain is empty.
|
||||||
// Note, it's a special case that we connect a non-empty ancient
|
// Note, it's a special case that we connect a non-empty ancient
|
||||||
// database with an empty node, so that we can plugin the ancient
|
// database with an empty node, so that we can plugin the ancient
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
allLogs []*types.Log
|
allLogs []*types.Log
|
||||||
gp = new(GasPool).AddGas(block.GasLimit())
|
gp = new(GasPool).AddGas(block.GasLimit())
|
||||||
)
|
)
|
||||||
|
if p.bc.logger != nil {
|
||||||
|
p.bc.logger.CaptureBlockStart(block)
|
||||||
|
defer p.bc.logger.CaptureBlockEnd()
|
||||||
|
}
|
||||||
// Mutate the block and state according to any hard-fork specs
|
// Mutate the block and state according to any hard-fork specs
|
||||||
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
misc.ApplyDAOHardFork(statedb)
|
misc.ApplyDAOHardFork(statedb)
|
||||||
|
|
|
||||||
64
eth/tracers/printer.go
Normal file
64
eth/tracers/printer.go
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package tracers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Printer struct{}
|
||||||
|
|
||||||
|
func NewPrinter() *Printer {
|
||||||
|
return &Printer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||||
|
func (p *Printer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
|
fmt.Printf("CaptureStart: from=%v, to=%v, create=%v, input=%v, gas=%v, value=%v\n", from, to, create, input, gas, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
|
func (p *Printer) CaptureEnd(output []byte, gasUsed uint64, err error) {
|
||||||
|
fmt.Printf("CaptureEnd: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
||||||
|
func (p *Printer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
//fmt.Printf("CaptureState: pc=%v, op=%v, gas=%v, cost=%v, scope=%v, rData=%v, depth=%v, err=%v\n", pc, op, gas, cost, scope, rData, depth, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureFault implements the EVMLogger interface to trace an execution fault.
|
||||||
|
func (p *Printer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
|
||||||
|
fmt.Printf("CaptureFault: pc=%v, op=%v, gas=%v, cost=%v, depth=%v, err=%v\n", pc, op, gas, cost, depth, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||||
|
func (p *Printer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||||
|
fmt.Printf("CaptureEnter: typ=%v, from=%v, to=%v, input=%v, gas=%v, value=%v\n", typ, from, to, input, gas, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||||
|
// execute any code.
|
||||||
|
func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
||||||
|
fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) CaptureTxStart(gasLimit uint64) {
|
||||||
|
fmt.Printf("CaptureTxStart: gasLimit=%v\n", gasLimit)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) CaptureTxEnd(restGas uint64) {
|
||||||
|
fmt.Printf("CaptureTxEnd: restGas=%v\n", restGas)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) CaptureBlockStart(b *types.Block) {
|
||||||
|
fmt.Printf("CaptureBlockStart: b=%v\n", b.NumberU64())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Printer) CaptureBlockEnd() {
|
||||||
|
fmt.Printf("CaptureBlockEnd\n")
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue