Skip to content

Commit

Permalink
check for free messages when calling trace_transaction (#7073)
Browse files Browse the repository at this point in the history
Gateway reported an issue with a trace returning an odd result, similar
to the recent problem we'd seen with gnosis. I found that
debug_traceTransaction worked fine so found where the differences were.
trace_transaction wasn't checking for service transactions so the trace
failed around fees when it shouldn't.

A number of code paths use callManyTransactions so they should all now
check for service messages where needed.
  • Loading branch information
hexoscott authored Mar 13, 2023
1 parent 470547f commit 9f6b842
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
15 changes: 2 additions & 13 deletions cmd/rpcdaemon/commands/trace_adhoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,15 +744,8 @@ func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash libcommon
}
}

bn := hexutil.Uint64(blockNum)

parentNr := bn
if parentNr > 0 {
parentNr -= 1
}

// Returns an array of trace arrays, one trace array for each transaction
traces, err := api.callManyTransactions(ctx, tx, block.Transactions(), traceTypes, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header(), int(txnIndex), types.MakeSigner(chainConfig, blockNum), chainConfig.Rules(blockNum, block.Time()))
traces, err := api.callManyTransactions(ctx, tx, block, traceTypes, int(txnIndex), types.MakeSigner(chainConfig, blockNum), chainConfig)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -808,10 +801,6 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH
return nil, err
}

parentNr := blockNumber
if parentNr > 0 {
parentNr -= 1
}
// Extract transactions from block
block, bErr := api.blockByNumberWithSenders(tx, blockNumber)
if bErr != nil {
Expand All @@ -835,7 +824,7 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH
}

// Returns an array of trace arrays, one trace array for each transaction
traces, err := api.callManyTransactions(ctx, tx, block.Transactions(), traceTypes, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header(), -1 /* all tx indices */, types.MakeSigner(chainConfig, blockNumber), chainConfig.Rules(blockNumber, block.Time()))
traces, err := api.callManyTransactions(ctx, tx, block, traceTypes, -1 /* all tx indices */, types.MakeSigner(chainConfig, blockNumber), chainConfig)
if err != nil {
return nil, err
}
Expand Down
67 changes: 53 additions & 14 deletions cmd/rpcdaemon/commands/trace_filtering.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ import (
"github.com/ledgerwatch/erigon-lib/kv/iter"
"github.com/ledgerwatch/erigon-lib/kv/order"
"github.com/ledgerwatch/erigon-lib/kv/rawdbv3"

"github.com/ledgerwatch/erigon/common/hexutil"
"github.com/ledgerwatch/erigon/consensus"
"github.com/ledgerwatch/erigon/consensus/ethash"
"github.com/ledgerwatch/erigon/core"
"github.com/ledgerwatch/erigon/core/rawdb"
"github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/state/temporal"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/eth/stagedsync"
"github.com/ledgerwatch/erigon/ethdb"
"github.com/ledgerwatch/erigon/rpc"
"github.com/ledgerwatch/erigon/turbo/rpchelper"
Expand Down Expand Up @@ -85,14 +88,10 @@ func (api *TraceAPIImpl) Transaction(ctx context.Context, txHash common.Hash) (P
}
bn := hexutil.Uint64(blockNumber)

parentNr := bn
if parentNr > 0 {
parentNr -= 1
}
hash := block.Hash()

// Returns an array of trace arrays, one trace array for each transaction
traces, err := api.callManyTransactions(ctx, tx, block.Transactions(), []string{TraceTypeTrace}, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header(), txIndex, types.MakeSigner(chainConfig, blockNumber), chainConfig.Rules(blockNumber, block.Time()))
traces, err := api.callManyTransactions(ctx, tx, block, []string{TraceTypeTrace}, txIndex, types.MakeSigner(chainConfig, blockNumber), chainConfig)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -164,16 +163,11 @@ func (api *TraceAPIImpl) Block(ctx context.Context, blockNr rpc.BlockNumber) (Pa
return nil, fmt.Errorf("could not find block %d", uint64(bn))
}

parentNr := bn
if parentNr > 0 {
parentNr -= 1
}

chainConfig, err := api.chainConfig(tx)
if err != nil {
return nil, err
}
traces, err := api.callManyTransactions(ctx, tx, block.Transactions(), []string{TraceTypeTrace}, block.ParentHash(), rpc.BlockNumber(parentNr), block.Header(), -1 /* all tx indices */, types.MakeSigner(chainConfig, blockNum), chainConfig.Rules(blockNum, block.Time()))
traces, err := api.callManyTransactions(ctx, tx, block, []string{TraceTypeTrace}, -1 /* all tx indices */, types.MakeSigner(chainConfig, blockNum), chainConfig)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -443,7 +437,7 @@ func (api *TraceAPIImpl) Filter(ctx context.Context, req TraceFilterRequest, str
isPos = header.Difficulty.Cmp(common.Big0) == 0 || header.Difficulty.Cmp(chainConfig.TerminalTotalDifficulty) >= 0
}
txs := block.Transactions()
t, tErr := api.callManyTransactions(ctx, dbtx, txs, []string{TraceTypeTrace}, block.ParentHash(), rpc.BlockNumber(block.NumberU64()-1), block.Header(), -1 /* all tx indices */, types.MakeSigner(chainConfig, b), chainConfig.Rules(b, block.Time()))
t, tErr := api.callManyTransactions(ctx, dbtx, block, []string{TraceTypeTrace}, -1 /* all tx indices */, types.MakeSigner(chainConfig, b), chainConfig)
if tErr != nil {
if first {
first = false
Expand Down Expand Up @@ -938,8 +932,39 @@ func filter_trace(pt *ParityTrace, fromAddresses map[common.Address]struct{}, to
return false
}

func (api *TraceAPIImpl) callManyTransactions(ctx context.Context, dbtx kv.Tx, txs []types.Transaction, traceTypes []string, parentHash common.Hash, parentNo rpc.BlockNumber, header *types.Header, txIndex int, signer *types.Signer, rules *chain.Rules) ([]*TraceCallResult, error) {
func (api *TraceAPIImpl) callManyTransactions(
ctx context.Context,
dbtx kv.Tx,
block *types.Block,
traceTypes []string,
txIndex int,
signer *types.Signer,
cfg *chain.Config,
) ([]*TraceCallResult, error) {
blockNumber := block.NumberU64()
pNo := blockNumber
if pNo > 0 {
pNo -= 1
}
parentNo := rpc.BlockNumber(pNo)
rules := cfg.Rules(blockNumber, block.Time())
header := block.Header()
txs := block.Transactions()
callParams := make([]TraceCallParam, 0, len(txs))
reader, err := rpchelper.CreateHistoryStateReader(dbtx, blockNumber, txIndex, api.historyV3(dbtx), cfg.ChainName)
if err != nil {
return nil, err
}
stateDb := state.New(reader)
if err != nil {
return nil, err
}
engine := api.engine()
consensusHeaderReader := stagedsync.NewChainReaderImpl(cfg, dbtx, nil)
err = core.InitializeBlockExecution(engine.(consensus.Engine), consensusHeaderReader, nil, block.HeaderNoCopy(), block.Transactions(), block.Uncles(), cfg, stateDb)
if err != nil {
return nil, err
}
msgs := make([]types.Message, len(txs))
for i, tx := range txs {
hash := tx.Hash()
Expand All @@ -948,11 +973,25 @@ func (api *TraceAPIImpl) callManyTransactions(ctx context.Context, dbtx kv.Tx, t
traceTypes: traceTypes,
})
var err error
if msgs[i], err = tx.AsMessage(*signer, header.BaseFee, rules); err != nil {

msg, err := tx.AsMessage(*signer, header.BaseFee, rules)
if err != nil {
return nil, fmt.Errorf("convert tx into msg: %w", err)
}

// gnosis might have a fee free account here
if msg.FeeCap().IsZero() && engine != nil {
syscall := func(contract common.Address, data []byte) ([]byte, error) {
return core.SysCallContract(contract, data, *cfg, stateDb, header, engine, true /* constCall */)
}
msg.SetIsFree(engine.IsServiceTransaction(msg.From(), syscall))
}

msgs[i] = msg
}

parentHash := block.ParentHash()

traces, cmErr := api.doCallMany(ctx, dbtx, msgs, callParams, &rpc.BlockNumberOrHash{
BlockNumber: &parentNo,
BlockHash: &parentHash,
Expand Down

0 comments on commit 9f6b842

Please sign in to comment.