Skip to content

Commit

Permalink
Merge pull request ethereum#32 from ethereum-optimism/jg/custom_rpc_e…
Browse files Browse the repository at this point in the history
…rror

Fix daisy chain
  • Loading branch information
trianglesphere authored Dec 5, 2022
2 parents 3433606 + 1a7298c commit 0678a13
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 183 deletions.
4 changes: 3 additions & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,9 @@ func (st *StateTransition) innerTransitionDb() (*ExecutionResult, error) {
st.state.AddBalance(st.evm.Context.Coinbase, fee)
}

if optimismConfig := st.evm.ChainConfig().Optimism; optimismConfig != nil {
// Hack: Check that we are post bedrock to enable op-geth to be able to create pseudo pre-bedrock blocks (these are pre-bedrock, but don't follow l2 geth rules)
// Note optimismConfig will not be nil if rules.IsOptimismBedrock is true
if optimismConfig := st.evm.ChainConfig().Optimism; optimismConfig != nil && rules.IsOptimismBedrock {
st.state.AddBalance(params.OptimismBaseFeeRecipient, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee))
if cost := st.evm.Context.L1CostFunc(st.evm.Context.BlockNumber.Uint64(), st.msg); cost != nil {
st.state.AddBalance(params.OptimismL1FeeRecipient, cost)
Expand Down
102 changes: 53 additions & 49 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
"encoding/json"
"errors"
"fmt"
"math/big"
"os"
"runtime"
"sync"
"time"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
Expand Down Expand Up @@ -138,7 +138,7 @@ func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*typ
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block #%d %w", number, ethereum.NotFound)
return nil, fmt.Errorf("block #%d not found", number)
}
return block, nil
}
Expand All @@ -151,7 +151,7 @@ func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block %s %w", hash.Hex(), ethereum.NotFound)
return nil, fmt.Errorf("block %s not found", hash.Hex())
}
return block, nil
}
Expand Down Expand Up @@ -231,6 +231,7 @@ type txTraceTask struct {
// TraceChain returns the structured logs created during the execution of EVM
// between two blocks (excluding start) and returns them as a JSON object.
func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { // Fetch the block interval that we want to trace
// TODO: Need to implement a fallback for this
from, err := api.blockByNumber(ctx, start)
if err != nil {
return nil, err
Expand Down Expand Up @@ -456,33 +457,47 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// EVM and returns them as a JSON object.
func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
block, err := api.blockByNumber(ctx, number)
if errors.Is(err, ethereum.NotFound) && api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByNumber", number, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("block #%d %w", number, ethereum.NotFound)
}
return histResult, err
} else if err != nil {
if err != nil {
return nil, err
}

if api.backend.ChainConfig().IsOptimismPreBedrock(block.Number()) {
if api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByNumber", number, config)
if err != nil {
return nil, fmt.Errorf("historical backend error: %w", err)
}
return histResult, nil
} else {
return nil, rpc.ErrNoHistoricalFallback
}
}

return api.traceBlock(ctx, block, config)
}

// TraceBlockByHash returns the structured logs created during the execution of
// EVM and returns them as a JSON object.
func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
block, err := api.blockByHash(ctx, hash)
if errors.Is(err, ethereum.NotFound) && api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByHash", hash, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("block #%d %w", hash, ethereum.NotFound)
}
return histResult, err
} else if err != nil {
if err != nil {
return nil, err
}

if api.backend.ChainConfig().IsOptimismPreBedrock(block.Number()) {
if api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceBlockByHash", hash, config)
if err != nil {
return nil, fmt.Errorf("historical backend error: %w", err)
}
return histResult, nil
} else {
return nil, rpc.ErrNoHistoricalFallback
}
}

return api.traceBlock(ctx, block, config)
}

Expand Down Expand Up @@ -532,6 +547,7 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash,
// of intermediate roots: the stateroot after each transaction.
func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) {
block, _ := api.blockByHash(ctx, hash)
// TODO: Cannot get intermediate roots for pre-bedrock block without daisy chain
if block == nil {
// Check in the bad blocks
block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash)
Expand Down Expand Up @@ -823,18 +839,24 @@ func containsTx(block *types.Block, hash common.Hash) bool {
// and returns them as a JSON object.
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
// GetTransaction returns 0 for the blocknumber if the transaction is not found
tx, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
_, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash)
if err != nil {
return nil, err
}
if tx == nil && api.backend.HistoricalRPCService() != nil {
var histResult []*txTraceResult
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceTransaction", hash, config)
if err != nil && err.Error() == "not found" {
return nil, fmt.Errorf("transaction %s %w", hash, ethereum.NotFound)

if api.backend.ChainConfig().IsOptimismPreBedrock(new(big.Int).SetUint64(blockNumber)) {
if api.backend.HistoricalRPCService() != nil {
var histResult json.RawMessage
err := api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceTransaction", hash, config)
if err != nil {
return nil, fmt.Errorf("historical backend error: %w", err)
}
return histResult, nil
} else {
return nil, rpc.ErrNoHistoricalFallback
}
return histResult, err
}

// It shouldn't happen in practice.
if blockNumber == 0 {
return nil, errors.New("genesis is not traceable")
Expand Down Expand Up @@ -885,32 +907,14 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
} else {
return nil, errors.New("invalid arguments; neither block nor hash specified")
}

// If block still holds no value, but we have an error, then one of the two previous conditions
// was entered, meaning:
// 1. blockNrOrHash has either a valid block or hash
// 2. we don't have that block locally
if block == nil && errors.Is(err, ethereum.NotFound) && api.backend.HistoricalRPCService() != nil {
var histResult json.RawMessage
err = api.backend.HistoricalRPCService().CallContext(ctx, &histResult, "debug_traceCall", args, blockNrOrHash, config)
if err != nil && err.Error() == "not found" {
// Not found locally or in history. We need to return different errors based on the input
// in order match geth's native behavior
if hash, ok := blockNrOrHash.Hash(); ok {
return nil, fmt.Errorf("block %s %w", hash, ethereum.NotFound)
} else if number, ok := blockNrOrHash.Number(); ok {
return nil, fmt.Errorf("block #%d %w", number, ethereum.NotFound)
}
} else if err != nil {
return nil, fmt.Errorf("error querying historical RPC: %w", err)
}

return histResult, nil
}

if err != nil {
return nil, err
}

if api.backend.ChainConfig().IsOptimismPreBedrock(block.Number()) {
return nil, errors.New("l2geth does not have a debug_traceCall method")
}

// try to recompute the state
reexec := defaultTraceReexec
if config != nil && config.Reexec != nil {
Expand Down
Loading

0 comments on commit 0678a13

Please sign in to comment.