Skip to content
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

Use current block data when constructing BlockContext for trace generation #709

Merged
merged 2 commits into from
Dec 16, 2024
Merged
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
44 changes: 20 additions & 24 deletions api/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"errors"
"fmt"
"math/big"
"slices"
"strings"

"github.com/goccy/go-json"
"github.com/onflow/flow-go/fvm/evm/offchain/query"
Expand All @@ -29,6 +29,8 @@ import (
"github.com/onflow/flow-evm-gateway/storage/pebble"
flowEVM "github.com/onflow/flow-go/fvm/evm"

offchain "github.com/onflow/flow-go/fvm/evm/offchain/storage"

// this import is needed for side-effects, because the
// tracers.DefaultDirectory is relying on the init function
_ "github.com/onflow/go-ethereum/eth/tracers/js"
Expand Down Expand Up @@ -302,15 +304,7 @@ func (d *DebugAPI) traceTransaction(
return nil, err
}

// We need to re-execute the given transaction and all the
// transactions that precede it in the same block, based on
// the previous block state, to generate the correct trace.
previousBlock, err := d.blocks.GetByHeight(block.Height - 1)
if err != nil {
return nil, err
}

blockExecutor, err := d.executorAtBlock(previousBlock)
blockExecutor, err := d.executorAtBlock(block)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -383,14 +377,7 @@ func (d *DebugAPI) traceBlockByNumber(
return results, nil
}

// We need to re-execute all the transactions from the given block,
// on top of the previous block state, to generate the correct traces.
previousBlock, err := d.blocks.GetByHeight(block.Height - 1)
if err != nil {
return nil, err
}

blockExecutor, err := d.executorAtBlock(previousBlock)
blockExecutor, err := d.executorAtBlock(block)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -424,19 +411,28 @@ func (d *DebugAPI) traceBlockByNumber(
}

func (d *DebugAPI) executorAtBlock(block *models.Block) (*evm.BlockExecutor, error) {
snapshot, err := d.registerStore.GetSnapshotAt(block.Height)
previousBlock, err := d.blocks.GetByHeight(block.Height - 1)
if err != nil {
return nil, err
}

// We need to re-execute all the transactions from the given block,
// on top of the previous block state, to generate the correct traces.
snapshot, err := d.registerStore.GetSnapshotAt(previousBlock.Height)
if err != nil {
return nil, fmt.Errorf(
"failed to get register snapshot at block height %d: %w",
block.Height,
previousBlock.Height,
err,
)
}
ledger := storage.NewRegisterDelta(snapshot)

// create storage
state := offchain.NewEphemeralStorage(offchain.NewReadOnlyStorage(snapshot))

return evm.NewBlockExecutor(
block,
ledger,
state,
d.config.FlowNetworkID,
d.blocks,
d.receipts,
Expand Down Expand Up @@ -484,6 +480,6 @@ func isDefaultCallTracer(config *tracers.TraceConfig) bool {
return false
}

tracerConfig := json.RawMessage(replayer.TracerConfig)
return slices.Equal(config.TracerConfig, tracerConfig)
trimmedConfig := strings.ReplaceAll(string(config.TracerConfig), " ", "")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add comments why we need this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I'll include some comments in a follow-up PR.

return trimmedConfig == replayer.TracerConfig
}
45 changes: 22 additions & 23 deletions services/evm/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/onflow/atree"
"github.com/onflow/flow-go/fvm/evm"
"github.com/onflow/flow-go/fvm/evm/emulator"
"github.com/onflow/flow-go/fvm/evm/offchain/blocks"
"github.com/onflow/flow-go/fvm/evm/precompiles"
"github.com/onflow/flow-go/fvm/evm/types"
flowGo "github.com/onflow/flow-go/model/flow"
Expand Down Expand Up @@ -98,6 +99,13 @@ func (s *BlockExecutor) Run(
s.gasUsed += res.GasConsumed
s.txIndex++

if res.GasConsumed != receipt.GasUsed {
return fmt.Errorf(
"used gas mismatch, expected: %d, got: %d",
receipt.GasUsed,
res.GasConsumed,
)
}
l.Debug().Msg("transaction executed successfully")

return nil
Expand All @@ -110,25 +118,11 @@ func (s *BlockExecutor) blockContext(
receipt *models.Receipt,
tracer *tracers.Tracer,
) (types.BlockContext, error) {
ctx := types.BlockContext{
ChainID: types.EVMChainIDFromFlowChainID(s.chainID),
BlockNumber: s.block.Height,
BlockTimestamp: s.block.Timestamp,
DirectCallBaseGasUsage: types.DefaultDirectCallBaseGasUsage,
DirectCallGasPrice: types.DefaultDirectCallGasPrice,
GasFeeCollector: types.CoinbaseAddress,
GetHashFunc: func(n uint64) common.Hash {
// For block heights greater than or equal to the current,
// return an empty block hash.
if n >= s.block.Height {
return common.Hash{}
}
// If the given block height, is more than 256 blocks
// in the past, return an empty block hash.
if s.block.Height-n > 256 {
return common.Hash{}
}

ctx, err := blocks.NewBlockContext(
s.chainID,
s.block.Height,
s.block.Timestamp,
func(n uint64) common.Hash {
block, err := s.blocks.GetByHeight(n)
if err != nil {
return common.Hash{}
Expand All @@ -140,12 +134,17 @@ func (s *BlockExecutor) blockContext(

return blockHash
},
Random: s.block.PrevRandao,
TxCountSoFar: s.txIndex,
TotalGasUsedSoFar: s.gasUsed,
Tracer: tracer,
s.block.PrevRandao,
tracer,
)

if err != nil {
return types.BlockContext{}, err
}

ctx.TxCountSoFar = s.txIndex
ctx.TotalGasUsedSoFar = s.gasUsed

// only add precompile cadence arch contract if we have a receipt
if receipt != nil {
calls, err := types.AggregatedPrecompileCallsFromEncoded(receipt.PrecompiledCalls)
Expand Down
Loading