Skip to content
This repository has been archived by the owner on Jun 9, 2024. It is now read-only.

Commit

Permalink
feat(rpc): implement debug api (#1340)
Browse files Browse the repository at this point in the history
NOTE: endpoints that require tracing "bad blocks" are currently not supported (debug_traceBadBlock, debug_intermediateRoots, debug_standardTraceBadBlockToFile)


## Summary by CodeRabbit

- **New Features**
  - Enhanced tracing capabilities with new backend methods for state retrieval at specific blocks and transactions.
  - Expanded API services for "web3" and "debug" namespaces to improve user interactions and debugging processes.

- **Documentation**
  - Updated public interface documentation to reflect newly added methods and functionalities.
  • Loading branch information
itsdevbear committed Dec 18, 2023
1 parent 58177db commit a41940c
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 24 deletions.
5 changes: 0 additions & 5 deletions eth/core/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,6 @@ func (bc *blockchain) PreparePlugins(ctx context.Context) {
}
}

// ChainConfig returns the Ethereum chain config of the chain.
func (bc *blockchain) Config() *params.ChainConfig {
return bc.config
}

// loadLastState loads the last known chain state from the database. This method
// assumes that the chain manager mutex is held.
func (bc *blockchain) loadLastState(number uint64) error {
Expand Down
114 changes: 114 additions & 0 deletions eth/core/chain_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,38 @@
package core

import (
"context"
"errors"
"fmt"

"github.com/berachain/polaris/eth/core/state"

"github.com/ethereum/go-ethereum/common"
gethcore "github.com/ethereum/go-ethereum/core"
ethtypes "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/params"
)

// ChainResources is the interface that defines functions for code paths within the chain to
// acquire resources to use in execution such as StateDBss and EVMss.
type ChainResources interface {
// state snapshots
StateAtBlockNumber(uint64) (state.StateDB, error)
StateAt(root common.Hash) (state.StateDB, error)

// state for tracing
StateAtBlock(
_ context.Context, block *ethtypes.Block, _ uint64,
_ state.StateDB, _ bool, _ bool,
) (state.StateDB, tracers.StateReleaseFunc, error)
StateAtTransaction(
ctx context.Context, block *ethtypes.Block,
txIndex int, reexec uint64,
) (*gethcore.Message, vm.BlockContext, state.StateDB, tracers.StateReleaseFunc, error)

// vm/chain config
GetVMConfig() *vm.Config
Config() *params.ChainConfig
}
Expand Down Expand Up @@ -76,7 +94,103 @@ func (bc *blockchain) HasBlockAndState(hash common.Hash, number uint64) bool {
return true
}

// StateAtBlock retrieves the state database associated with a certain block.
// If no state is locally available for the given block, a number of blocks
// are attempted to be reexecuted to generate the desired state. The optional
// base layer statedb can be provided which is regarded as the statedb of the
// parent block.
//
// An additional release function will be returned if the requested state is
// available. Release is expected to be invoked when the returned state is no
// longer needed. Its purpose is to prevent resource leaking. Though it can be
// noop in some cases.
//
// Parameters:
// - block: The block for which we want the state(state = block.Root)
// - reexec: The maximum number of blocks to reprocess trying to obtain the desired state
// - base: If the caller is tracing multiple blocks, the caller can provide the parent
// state continuously from the callsite.
// - readOnly: If true, then the live 'blockchain' state database is used. No mutation should
// be made from caller, e.g. perform Commit or other 'save-to-disk' changes.
// Otherwise, the trash generated by caller may be persisted permanently.
// - preferDisk: This arg can be used by the caller to signal that even though the 'base' is
// provided, it would be preferable to start from a fresh state, if we have it
// on disk.
func (bc *blockchain) StateAtBlock(
_ context.Context, block *ethtypes.Block, _ uint64,
_ state.StateDB, _ bool, _ bool,
) (state.StateDB, tracers.StateReleaseFunc, error) {
// Check if the requested state is available in the live chain.
statedb, err := bc.StateAtBlockNumber(block.Number().Uint64())
if err != nil {
// If there is an error, it means the state is not available.
// TODO: Historic state is not supported in path-based scheme.
// Fully archive node in pbss will be implemented by relying
// on state history, but needs more work on top.
return nil, nil, errors.Join(
err, errors.New("historical state not available in path scheme yet"),
)
}

// If there is no error, return the state, a no-op function, and no error.
return statedb, func() {}, nil
}

// StateAtTransaction returns the execution environment of a certain transaction.
func (bc *blockchain) StateAtTransaction(
ctx context.Context, block *ethtypes.Block,
txIndex int, reexec uint64,
) (*gethcore.Message, vm.BlockContext, state.StateDB, tracers.StateReleaseFunc, error) {
// Short circuit if it's genesis block.
if block.NumberU64() == 0 {
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
}
// Create the parent state database
parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("parent %#x not found", block.ParentHash())
}
// Lookup the statedb of parent block from the live database,
// otherwise regenerate it on the flight.
statedb, release, err := bc.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, vm.BlockContext{}, nil, nil, err
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil
}
// Recompute transactions up to the target index.
signer := ethtypes.MakeSigner(bc.Config(), block.Number(), block.Time())
for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset
msg, _ := gethcore.TransactionToMessage(tx, signer, block.BaseFee())
txContext := gethcore.NewEVMTxContext(msg)
context := gethcore.NewEVMBlockContext(block.Header(), bc, nil)
if idx == txIndex {
return msg, context, statedb, release, nil
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, bc.Config(), vm.Config{})
statedb.SetTxContext(tx.Hash(), idx)
if _, err = gethcore.ApplyMessage(vmenv,
msg, new(gethcore.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil,
fmt.Errorf("transaction %s failed: %w", tx.Hash().Hex(), err)
}
// Ensure any modifications are committed to the state
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
return nil, vm.BlockContext{}, nil, nil,
fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
}

// GetVMConfig returns the vm.Config for the current chain.
func (bc *blockchain) GetVMConfig() *vm.Config {
return bc.vmConfig
}

// Config returns the Ethereum chain config from the host chain.
func (bc *blockchain) Config() *params.ChainConfig {
return bc.config
}
3 changes: 3 additions & 0 deletions eth/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ require (
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/deepmap/oapi-codegen v1.13.4 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect
github.com/fjl/memsize v0.0.1 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
Expand All @@ -59,6 +61,7 @@ require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.15.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/goccy/go-json v0.10.2 // indirect
Expand Down
Loading

0 comments on commit a41940c

Please sign in to comment.