Skip to content

add subscription #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: extended-tracer
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions core/blockchain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
}
192 changes: 192 additions & 0 deletions core/types/trace.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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
}
2 changes: 2 additions & 0 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,4 +45,5 @@ type EVMLogger interface {
CaptureKeccakPreimage(hash common.Hash, data []byte)
// Misc
OnGasConsumed(gas, amount uint64)
EventLoop(bc core.BlockChain)
}
4 changes: 4 additions & 0 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
30 changes: 30 additions & 0 deletions eth/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading