From 7f03588b57301f46fce5ed68d826db01c50932f1 Mon Sep 17 00:00:00 2001
From: joohhnnn <386201195@qq.com>
Date: Fri, 7 Jul 2023 00:45:55 +0800
Subject: [PATCH 1/2] add type&subscribe_function demo
---
core/types/trace.go | 192 +++++++++++++++++++++++++++++++++++
eth/filters/api.go | 30 ++++++
eth/filters/filter_system.go | 20 ++++
3 files changed, 242 insertions(+)
create mode 100644 core/types/trace.go
diff --git a/core/types/trace.go b/core/types/trace.go
new file mode 100644
index 000000000000..46bcf1c0d38c
--- /dev/null
+++ b/core/types/trace.go
@@ -0,0 +1,192 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package types
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+//go:generate go run github.com/fjl/gencodec -type Log -field-override logMarshaling -out gen_log_json.go
+
+// CaptureStartData stores data when a new transaction starts executing
+type CaptureStartData struct {
+ From common.Address // Sender of the transaction
+ To common.Address // Recipient of the transaction
+ Create bool // Indicates whether the transaction creates a contract
+ Input []byte // Input data of the transaction
+ Gas uint64 // Gas provided for the transaction execution
+ Value *big.Int // Amount of ether transferred in the transaction
+}
+
+// CaptureEndData stores data when a transaction finishes executing
+type CaptureEndData struct {
+ Output []byte // Output data from the transaction execution
+ GasUsed uint64 // Amount of gas consumed by the transaction
+ Err error // Error that occurred during transaction execution, if any
+}
+
+// CaptureStateData stores data at each step during a transaction's execution
+type CaptureStateData struct {
+ Pc uint64 // Current program counter in the EVM code
+ Op vm.OpCode // Opcode being executed at the current step
+ Gas uint64 // Remaining gas for the transaction
+ Cost uint64 // Cost of the current operation
+ Scope *vm.ScopeContext // Contextual information about the execution environment
+ RData []byte // Return data from executed operations
+ Depth int // Current call depth
+ Err error // Error that occurred during execution, if any
+}
+
+// CaptureFaultData stores data when an execution fault occurs during a transaction's execution
+type CaptureFaultData struct {
+ Pc uint64 // Current program counter in the EVM code
+ Op vm.OpCode // Opcode being executed at the fault
+ Gas uint64 // Remaining gas for the transaction
+ Cost uint64 // Cost of the faulted operation
+ Depth int // Current call depth
+ Err error // Error that occurred leading to the fault
+}
+
+// CaptureKeccakPreimageData stores the data input to the KECCAK256 opcode.
+type CaptureKeccakPreimageData struct {
+ Hash common.Hash // The KECCAK256 hash of the data
+ Data []byte // The original data
+}
+
+// CaptureEnterData stores data when the EVM enters a new execution scope
+type CaptureEnterData struct {
+ Type vm.OpCode // Opcode that caused the new scope
+ From common.Address // Address of the scope creator
+ To common.Address // Address of the new scope
+ Input []byte // Input data to the new scope
+ Gas uint64 // Gas provided to the new scope
+ Value *big.Int // Value transferred into the new scope
+}
+
+// CaptureExitData stores data when the EVM exits a scope
+type CaptureExitData struct {
+ Output []byte // Output data from the scope
+ GasUsed uint64 // Amount of gas consumed in the scope
+ Err error // Error that occurred during scope execution, if any
+}
+
+// CaptureTxStartData stores data when a transaction begins to execute
+type CaptureTxStartData struct {
+ Env *vm.EVM // The EVM environment
+ Tx *Transaction // The transaction being executed
+}
+
+// CaptureTxEndData stores data when a transaction finishes executing
+type CaptureTxEndData struct {
+ Receipt *Receipt // The receipt generated from the transaction execution
+}
+
+// OnBlockStartData stores data when a new block begins processing
+type OnBlockStartData struct {
+ Block *Block // The block being processed
+}
+
+// OnBlockEndData stores data when a block has finished processing
+type OnBlockEndData struct {
+ Td *big.Int // Total difficulty of the blockchain after the block
+ Err error // Any error that occurred during block processing
+}
+
+// OnBlockValidationErrorData stores data when a block fails validation
+type OnBlockValidationErrorData struct {
+ Block *Block // The block that failed validation
+ Err error // The error that caused the validation failure
+}
+
+// OnGenesisBlockData stores data when the genesis block is processed
+type OnGenesisBlockData struct {
+ Block *Block // The genesis block
+}
+
+// OnBalanceChangeData stores data when the balance of an account changes
+type OnBalanceChangeData struct {
+ Address common.Address // The account whose balance changed
+ Prev *big.Int // The previous balance
+ New *big.Int // The new balance
+}
+
+// OnNonceChangeData stores data when the nonce of an account changes
+type OnNonceChangeData struct {
+ Address common.Address // The account whose nonce changed
+ Prev uint64 // The previous nonce
+ New uint64 // The new nonce
+}
+
+// OnCodeChangeData stores data when the code of an account changes
+type OnCodeChangeData struct {
+ Address common.Address // The account whose code changed
+ PrevCodeHash common.Hash // The KECCAK256 hash of the previous code
+ Prev []byte // The previous code
+ CodeHash common.Hash // The KECCAK256 hash of the new code
+ Code []byte // The new code
+}
+
+// OnStorageChangeData stores data when the storage of an account changes
+type OnStorageChangeData struct {
+ Address common.Address // The account whose storage changed
+ Key common.Hash // The storage key that changed
+ Prev common.Hash // The previous value at the key
+ New common.Hash // The new value at the key
+}
+
+// OnLogData stores data when a new log is created
+type OnLogData struct {
+ Log *Log // The new log
+}
+
+// OnNewAccountData stores data when a new account is created
+type OnNewAccountData struct {
+ Address common.Address // The address of the new account
+}
+
+// OnGasConsumedData stores data when gas is consumed during execution
+type OnGasConsumedData struct {
+ Gas uint64 // The remaining gas after consumption
+ Amount uint64 // The amount of gas consumed
+}
+
+// Trace represents chain processing operations. These events are generated by the chain operations.
+type Trace struct {
+ CaptureStart []CaptureStartData
+ CaptureEnd []CaptureEndData
+ CaptureState []CaptureStateData
+ CaptureFault []CaptureFaultData
+ CaptureKeccakPreimage []CaptureKeccakPreimageData
+ CaptureEnter []CaptureEnterData
+ CaptureExit []CaptureExitData
+ CaptureTxStart []CaptureTxStartData
+ CaptureTxEnd []CaptureTxEndData
+ OnBlockStart []OnBlockStartData
+ OnBlockEnd []OnBlockEndData
+ OnBlockValidationError []OnBlockValidationErrorData
+ OnGenesisBlock []OnGenesisBlockData
+ OnBalanceChange []OnBalanceChangeData
+ OnNonceChange []OnNonceChangeData
+ OnCodeChange []OnCodeChangeData
+ OnStorageChange []OnStorageChangeData
+ OnLog []OnLogData
+ OnNewAccount []OnNewAccountData
+ OnGasConsumed []OnGasConsumedData
+}
diff --git a/eth/filters/api.go b/eth/filters/api.go
index cc08b442e850..6b2c8c8a897f 100644
--- a/eth/filters/api.go
+++ b/eth/filters/api.go
@@ -284,6 +284,36 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc
return rpcSub, nil
}
+// Logs creates a subscription that fires for all new log that match the given filter criteria.
+func (api *FilterAPI) Traces(ctx context.Context) (*rpc.Subscription, error) {
+ notifier, supported := rpc.NotifierFromContext(ctx)
+ if !supported {
+ return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported
+ }
+
+ rpcSub := notifier.CreateSubscription()
+
+ go func() {
+ traces := make(chan *types.Trace)
+ tracesSub := api.events.SubscribeTraces(traces)
+
+ for {
+ select {
+ case s := <-traces:
+ notifier.Notify(rpcSub.ID, s)
+ case <-rpcSub.Err():
+ tracesSub.Unsubscribe()
+ return
+ case <-notifier.Closed():
+ tracesSub.Unsubscribe()
+ return
+ }
+ }
+ }()
+
+ return rpcSub, nil
+}
+
// FilterCriteria represents a request to create a new filter.
// Same as ethereum.FilterQuery but with UnmarshalJSON() method.
type FilterCriteria ethereum.FilterQuery
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 35e396c23e75..672ebba649a5 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -164,6 +164,8 @@ const (
BlocksSubscription
// LastIndexSubscription keeps track of the last index
LastIndexSubscription
+ // TracesSubscription keeps track of the normal chain processing operations
+ TracesSubscription
)
const (
@@ -185,6 +187,7 @@ type subscription struct {
logsCrit ethereum.FilterQuery
logs chan []*types.Log
txs chan []*types.Transaction
+ traces chan *types.Trace
headers chan *types.Header
installed chan struct{} // closed when the filter is installed
err chan error // closed when the filter is uninstalled
@@ -418,6 +421,23 @@ func (es *EventSystem) SubscribePendingTxs(txs chan []*types.Transaction) *Subsc
return es.subscribe(sub)
}
+// SubscribePendingTxs creates a subscription that writes transactions for
+// transactions that enter the transaction pool.
+func (es *EventSystem) SubscribeTraces(traces chan *types.Trace) *Subscription {
+ sub := &subscription{
+ id: rpc.NewID(),
+ typ: TracesSubscription,
+ created: time.Now(),
+ logs: make(chan []*types.Log),
+ txs: make(chan []*types.Transaction),
+ traces: traces,
+ headers: make(chan *types.Header),
+ installed: make(chan struct{}),
+ err: make(chan error),
+ }
+ return es.subscribe(sub)
+}
+
type filterIndex map[Type]map[rpc.ID]*subscription
func (es *EventSystem) handleLogs(filters filterIndex, ev []*types.Log) {
From 15f1a166337e565a5ffc32f03fced08b2ba3db7f Mon Sep 17 00:00:00 2001
From: john
Date: Fri, 7 Jul 2023 17:54:48 +0800
Subject: [PATCH 2/2] update
---
core/blockchain.go | 17 +--
core/blockchain_reader.go | 5 +
core/vm/logger.go | 2 +
eth/api_backend.go | 4 +
eth/filters/filter_system.go | 16 ++-
eth/tracers/printer.go | 236 ++++++++++++++++++++++++++++++++++-
6 files changed, 268 insertions(+), 12 deletions(-)
diff --git a/core/blockchain.go b/core/blockchain.go
index a3c2fa648437..859eaae0241d 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -205,6 +205,7 @@ type BlockChain struct {
chainHeadFeed event.Feed
logsFeed event.Feed
blockProcFeed event.Feed
+ tracesFeed event.Feed
scope event.SubscriptionScope
genesisBlock *types.Block
@@ -254,13 +255,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
Preimages: cacheConfig.Preimages,
})
var logger BlockchainLogger
- if vmConfig.Tracer != nil {
- l, ok := vmConfig.Tracer.(BlockchainLogger)
- if !ok {
- return nil, fmt.Errorf("only extended tracers are supported for live mode")
- }
- logger = l
- }
// Setup the genesis block, commit the provided genesis specification
// to database if the genesis block is not present yet, or load the
// stored one from database.
@@ -293,7 +287,14 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
futureBlocks: lru.NewCache[common.Hash, *types.Block](maxFutureBlocks),
engine: engine,
vmConfig: vmConfig,
- logger: logger,
+ }
+ if vmConfig.Tracer != nil {
+ l, ok := vmConfig.Tracer.(BlockchainLogger)
+ if !ok {
+ return nil, fmt.Errorf("only extended tracers are supported for live mode")
+ }
+ bc.logger = l
+ go vmConfig.Tracer.EventLoop(bc)
}
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve)
diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go
index fd65cb2db32f..811c1f284f60 100644
--- a/core/blockchain_reader.go
+++ b/core/blockchain_reader.go
@@ -409,3 +409,8 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript
func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription {
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
}
+
+// SubscribeTracesEvent registers a subscription of TracesEvent.
+func (bc *BlockChain) SubscribeTracesEvent(ch chan<- *types.Trace) event.Subscription {
+ return bc.scope.Track(bc.tracesFeed.Subscribe(ch))
+}
\ No newline at end of file
diff --git a/core/vm/logger.go b/core/vm/logger.go
index b7b0fc4d8e20..8833b8b00449 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/"
)
// EVMLogger is used to collect execution traces from an EVM transaction
@@ -44,4 +45,5 @@ type EVMLogger interface {
CaptureKeccakPreimage(hash common.Hash, data []byte)
// Misc
OnGasConsumed(gas, amount uint64)
+ EventLoop(bc core.BlockChain)
}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 18aea2d039ae..bcaf42c6f6c4 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -277,6 +277,10 @@ func (b *EthAPIBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.
return b.eth.miner.SubscribePendingLogs(ch)
}
+func (b *EthAPIBackend) SubscribeTracesEvent(ch chan<- *types.Trace) event.Subscription {
+ return b.eth.BlockChain().SubscribeChainEvent(ch)
+}
+
func (b *EthAPIBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
return b.eth.BlockChain().SubscribeChainEvent(ch)
}
diff --git a/eth/filters/filter_system.go b/eth/filters/filter_system.go
index 672ebba649a5..4fc46a8563ef 100644
--- a/eth/filters/filter_system.go
+++ b/eth/filters/filter_system.go
@@ -72,6 +72,7 @@ type Backend interface {
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription
+ SubscribeTracesEvent(ch chan<- *types.Trace) event.Subscription
BloomStatus() (uint64, uint64)
ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
@@ -207,6 +208,7 @@ type EventSystem struct {
rmLogsSub event.Subscription // Subscription for removed log event
pendingLogsSub event.Subscription // Subscription for pending log event
chainSub event.Subscription // Subscription for new chain event
+ tracesSub event.Subscription // Subscription for traces event
// Channels
install chan *subscription // install filter for event notification
@@ -216,6 +218,7 @@ type EventSystem struct {
pendingLogsCh chan []*types.Log // Channel to receive new log event
rmLogsCh chan core.RemovedLogsEvent // Channel to receive removed log event
chainCh chan core.ChainEvent // Channel to receive new chain event
+ tracesCh chan *types.Trace
}
// NewEventSystem creates a new manager that listens for event on the given mux,
@@ -244,7 +247,7 @@ func NewEventSystem(sys *FilterSystem, lightMode bool) *EventSystem {
m.rmLogsSub = m.backend.SubscribeRemovedLogsEvent(m.rmLogsCh)
m.chainSub = m.backend.SubscribeChainEvent(m.chainCh)
m.pendingLogsSub = m.backend.SubscribePendingLogsEvent(m.pendingLogsCh)
-
+ m.tracesSub = m.backend.SubscribeTracesEvent(m.tracesCh)
// Make sure none of the subscriptions are empty
if m.txsSub == nil || m.logsSub == nil || m.rmLogsSub == nil || m.chainSub == nil || m.pendingLogsSub == nil {
log.Crit("Subscribe for event system failed")
@@ -491,6 +494,15 @@ func (es *EventSystem) handleChainEvent(filters filterIndex, ev core.ChainEvent)
}
}
+func (es *EventSystem) handleTraces(filters filterIndex, ev *types.Trace) {
+ if len(ev.CaptureStart) == 0 {
+ return
+ }
+ for _, f := range filters[TracesSubscription] {
+ f.traces <- ev
+ }
+}
+
func (es *EventSystem) lightFilterNewHead(newHeader *types.Header, callBack func(*types.Header, bool)) {
oldh := es.lastHead
es.lastHead = newHeader
@@ -589,6 +601,8 @@ func (es *EventSystem) eventLoop() {
es.handlePendingLogs(index, ev)
case ev := <-es.chainCh:
es.handleChainEvent(index, ev)
+ case ev := <-es.tracesCh:
+ es.handleTraces(index, ev)
case f := <-es.install:
if f.typ == MinedAndPendingLogsSubscription {
diff --git a/eth/tracers/printer.go b/eth/tracers/printer.go
index 42855de9bd3c..1378bafb6360 100644
--- a/eth/tracers/printer.go
+++ b/eth/tracers/printer.go
@@ -7,97 +7,327 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core"
+
)
-type Printer struct{}
+type Printer struct {
+ bc core.BlockChain
+ Trace types.Trace
+ CaptureStartChan chan types.CaptureStartData
+ CaptureEndChan chan types.CaptureEndData
+ CaptureStateChan chan types.CaptureStateData
+ CaptureFaultChan chan types.CaptureFaultData
+ CaptureKeccakPreimageChan chan types.CaptureKeccakPreimageData
+ CaptureEnterChan chan types.CaptureEnterData
+ CaptureExitChan chan types.CaptureExitData
+ CaptureTxStartChan chan types.CaptureTxStartData
+ CaptureTxEndChan chan types.CaptureTxEndData
+ OnBlockStartChan chan types.OnBlockStartData
+ OnBlockEndChan chan types.OnBlockEndData
+ OnBlockValidationErrorChan chan types.OnBlockValidationErrorData
+ OnGenesisBlockChan chan types.OnGenesisBlockData
+ OnBalanceChangeChan chan types.OnBalanceChangeData
+ OnNonceChangeChan chan types.OnNonceChangeData
+ OnCodeChangeChan chan types.OnCodeChangeData
+ OnStorageChangeChan chan types.OnStorageChangeData
+ OnLogChan chan types.OnLogData
+ OnNewAccountChan chan types.OnNewAccountData
+ OnGasConsumedChan chan types.OnGasConsumedData
+ doneChan chan struct{}
+}
+// TODO: Determine the appropriate channel capacity size.
func NewPrinter() *Printer {
- return &Printer{}
+ return &Printer{
+ Trace: types.Trace{},
+ CaptureStartChan: make(chan types.CaptureStartData, 100),
+ CaptureEndChan: make(chan types.CaptureEndData, 100),
+ CaptureStateChan: make(chan types.CaptureStateData, 100),
+ CaptureFaultChan: make(chan types.CaptureFaultData, 100),
+ CaptureKeccakPreimageChan: make(chan types.CaptureKeccakPreimageData, 100),
+ CaptureEnterChan: make(chan types.CaptureEnterData, 100),
+ CaptureExitChan: make(chan types.CaptureExitData, 100),
+ CaptureTxStartChan: make(chan types.CaptureTxStartData, 100),
+ CaptureTxEndChan: make(chan types.CaptureTxEndData, 100),
+ OnBlockStartChan: make(chan types.OnBlockStartData, 100),
+ OnBlockEndChan: make(chan types.OnBlockEndData, 100),
+ OnBlockValidationErrorChan: make(chan types.OnBlockValidationErrorData, 100),
+ OnGenesisBlockChan: make(chan types.OnGenesisBlockData, 100),
+ OnBalanceChangeChan: make(chan types.OnBalanceChangeData, 100),
+ OnNonceChangeChan: make(chan types.OnNonceChangeData, 100),
+ OnCodeChangeChan: make(chan types.OnCodeChangeData, 100),
+ OnStorageChangeChan: make(chan types.OnStorageChangeData, 100),
+ OnLogChan: make(chan types.OnLogData, 100),
+ OnNewAccountChan: make(chan types.OnNewAccountData, 100),
+ OnGasConsumedChan: make(chan types.OnGasConsumedData, 100),
+ }
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (p *Printer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+ // Initialize CaptureStartData with provided arguments
+ data := types.CaptureStartData{
+ From: from,
+ To: to,
+ Create: create,
+ Input: input,
+ Gas: gas,
+ Value: value,
+ }
+
+ // Send the data to the channel
+ p.CaptureStartChan <- data
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) {
+ data := types.CaptureEndData{
+ Output: output,
+ GasUsed: gasUsed,
+ Err: err,
+ }
+ p.CaptureEndChan <- data
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) {
+/* data := types.CaptureStateData{
+ Pc: pc,
+ Op: op,
+ Gas: gas,
+ Cost: cost,
+ Scope: scope,
+ RData: rData,
+ Depth: depth,
+ Err: err,
+ }
+ p.CaptureStateChan <- data */
//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) {
+ data := types.CaptureFaultData{
+ Pc: pc,
+ Op: op,
+ Gas: gas,
+ Cost: cost,
+ Depth: depth,
+ Err: err,
+ }
+ p.CaptureFaultChan <- data
fmt.Printf("CaptureFault: pc=%v, op=%v, gas=%v, cost=%v, depth=%v, err=%v\n", pc, op, gas, cost, depth, err)
}
// CaptureKeccakPreimage is called during the KECCAK256 opcode.
-func (p *Printer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
+func (p *Printer) CaptureKeccakPreimage(hash common.Hash, data []byte) {
+/* preImageData := types.CaptureKeccakPreimageData{
+ Hash: hash,
+ Data: data,
+ }
+ p.CaptureKeccakPreimageChan <- preImageData */
+}
// 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) {
+ data := types.CaptureEnterData{
+ Type: typ,
+ From: from,
+ To: to,
+ Input: input,
+ Gas: gas,
+ Value: value,
+ }
+ p.CaptureEnterChan <- data
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) {
+ data := types.CaptureExitData{
+ Output: output,
+ GasUsed: gasUsed,
+ Err: err,
+ }
+ p.CaptureExitChan <- data
fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err)
}
func (p *Printer) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {
+ data := types.CaptureTxStartData{
+ Env: env,
+ Tx: tx,
+ }
+ p.CaptureTxStartChan <- data
fmt.Printf("CaptureTxStart: tx=%v\n", tx)
}
func (p *Printer) CaptureTxEnd(receipt *types.Receipt) {
+ data := types.CaptureTxEndData{
+ Receipt: receipt,
+ }
+ p.CaptureTxEndChan <- data
fmt.Printf("CaptureTxEnd: receipt=%v\n", receipt)
}
func (p *Printer) OnBlockStart(b *types.Block) {
+ data := types.OnBlockStartData{
+ Block: b,
+ }
+ p.OnBlockStartChan <- data
fmt.Printf("OnBlockStart: b=%v\n", b.NumberU64())
}
func (p *Printer) OnBlockEnd(td *big.Int, err error) {
+ data := types.OnBlockEndData{
+ Td: td,
+ Err: err,
+ }
+ p.OnBlockEndChan <- data
fmt.Printf("OnBlockEnd: td=%v, err=%v\n", td, err)
}
func (p *Printer) OnBlockValidationError(block *types.Block, err error) {
+ data := types.OnBlockValidationErrorData{
+ Block: block,
+ Err: err,
+ }
+ p.OnBlockValidationErrorChan <- data
fmt.Printf("OnBlockValidationError: b=%v, err=%v\n", block.NumberU64(), err)
}
func (p *Printer) OnGenesisBlock(b *types.Block) {
+ data := types.OnGenesisBlockData{
+ Block: b,
+ }
+ p.OnGenesisBlockChan <- data
fmt.Printf("OnGenesisBlock: b=%v\n", b.NumberU64())
}
func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int) {
+ data := types.OnBalanceChangeData{
+ Address: a,
+ Prev: prev,
+ New: new,
+ }
+ p.OnBalanceChangeChan <- data
fmt.Printf("OnBalanceChange: a=%v, prev=%v, new=%v\n", a, prev, new)
}
func (p *Printer) OnNonceChange(a common.Address, prev, new uint64) {
+ data := types.OnNonceChangeData{
+ Address: a,
+ Prev: prev,
+ New: new,
+ }
+ p.OnNonceChangeChan <- data
fmt.Printf("OnNonceChange: a=%v, prev=%v, new=%v\n", a, prev, new)
}
func (p *Printer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
+ data := types.OnCodeChangeData{
+ Address: a,
+ PrevCodeHash: prevCodeHash,
+ Prev: prev,
+ CodeHash: codeHash,
+ Code: code,
+ }
+ p.OnCodeChangeChan <- data
fmt.Printf("OnCodeChange: a=%v, prevCodeHash=%v, prev=%v, codeHash=%v, code=%v\n", a, prevCodeHash, prev, codeHash, code)
}
func (p *Printer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
+ data := types.OnStorageChangeData{
+ Address: a,
+ Key: k,
+ Prev: prev,
+ New: new,
+ }
+ p.OnStorageChangeChan <- data
fmt.Printf("OnStorageChange: a=%v, k=%v, prev=%v, new=%v\n", a, k, prev, new)
}
func (p *Printer) OnLog(l *types.Log) {
+ data := types.OnLogData{
+ Log: l,
+ }
+ p.OnLogChan <- data
fmt.Printf("OnLog: l=%v\n", l)
}
func (p *Printer) OnNewAccount(a common.Address) {
+ data := types.OnNewAccountData{
+ Address: a,
+ }
+ p.OnNewAccountChan <- data
fmt.Printf("OnNewAccount: a=%v\n", a)
}
func (p *Printer) OnGasConsumed(gas, amount uint64) {
+ data := types.OnGasConsumedData{
+ Gas: gas,
+ Amount: amount,
+ }
+ p.OnGasConsumedChan <- data
fmt.Printf("OnGasConsumed: gas=%v, amount=%v\n", gas, amount)
}
+
+// EventLoop receives data from channels, adds them to Trace,
+// and sends Trace when the OnBlockEnd event occurs. This function operates
+// in a loop and should typically be run in a separate goroutine.
+func (p *Printer) EventLoop(bc core.BlockChain) {
+ for {
+ select {
+ case data := <-p.CaptureStartChan:
+ p.Trace.CaptureStart = append(p.Trace.CaptureStart, data)
+ case data := <-p.CaptureEndChan:
+ p.Trace.CaptureEnd = append(p.Trace.CaptureEnd, data)
+ case data := <-p.CaptureStateChan:
+ p.Trace.CaptureState = append(p.Trace.CaptureState, data)
+ case data := <-p.CaptureFaultChan:
+ p.Trace.CaptureFault = append(p.Trace.CaptureFault, data)
+ case data := <-p.CaptureKeccakPreimageChan:
+ p.Trace.CaptureKeccakPreimage = append(p.Trace.CaptureKeccakPreimage, data)
+ case data := <-p.CaptureEnterChan:
+ p.Trace.CaptureEnter = append(p.Trace.CaptureEnter, data)
+ case data := <-p.CaptureExitChan:
+ p.Trace.CaptureExit = append(p.Trace.CaptureExit, data)
+ case data := <-p.CaptureTxStartChan:
+ p.Trace.CaptureTxStart = append(p.Trace.CaptureTxStart, data)
+ case data := <-p.CaptureTxEndChan:
+ p.Trace.CaptureTxEnd = append(p.Trace.CaptureTxEnd, data)
+ case data := <-p.OnBlockStartChan:
+ p.Trace.OnBlockStart = append(p.Trace.OnBlockStart, data)
+ case data := <-p.OnBlockEndChan:
+ p.Trace.OnBlockEnd = append(p.Trace.OnBlockEnd, data)
+ bc.tracesFeed.send(p.Trace)
+ p.Trace = types.Trace{}
+ case data := <-p.OnBlockValidationErrorChan:
+ p.Trace.OnBlockValidationError = append(p.Trace.OnBlockValidationError, data)
+ case data := <-p.OnGenesisBlockChan:
+ p.Trace.OnGenesisBlock = append(p.Trace.OnGenesisBlock, data)
+ case data := <-p.OnBalanceChangeChan:
+ p.Trace.OnBalanceChange = append(p.Trace.OnBalanceChange, data)
+ case data := <-p.OnNonceChangeChan:
+ p.Trace.OnNonceChange = append(p.Trace.OnNonceChange, data)
+ case data := <-p.OnCodeChangeChan:
+ p.Trace.OnCodeChange = append(p.Trace.OnCodeChange, data)
+ case data := <-p.OnStorageChangeChan:
+ p.Trace.OnStorageChange = append(p.Trace.OnStorageChange, data)
+ case data := <-p.OnLogChan:
+ p.Trace.OnLog = append(p.Trace.OnLog, data)
+ case data := <-p.OnNewAccountChan:
+ p.Trace.OnNewAccount = append(p.Trace.OnNewAccount, data)
+ case data := <-p.OnGasConsumedChan:
+ p.Trace.OnGasConsumed = append(p.Trace.OnGasConsumed, data)
+ case <-bc.quit:
+ return
+
+ }
+ }
+}