diff --git a/cmd/rpcdaemon/commands/tracing.go b/cmd/rpcdaemon/commands/tracing.go index 513144385..32b4b1cc8 100644 --- a/cmd/rpcdaemon/commands/tracing.go +++ b/cmd/rpcdaemon/commands/tracing.go @@ -71,6 +71,10 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp return fmt.Errorf("invalid arguments; block with hash %x not found", hash) } + if config.BorTraceEnabled == nil { + config.BorTraceEnabled = newBoolPtr(false) + } + chainConfig, err := api.chainConfig(tx) if err != nil { stream.WriteNil() @@ -87,7 +91,14 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp signer := types.MakeSigner(chainConfig, block.NumberU64()) rules := chainConfig.Rules(block.NumberU64(), block.Time()) stream.WriteArrayStart() - for idx, txn := range block.Transactions() { + + borTx, _, _, _ := rawdb.ReadBorTransactionForBlock(tx, block) + txns := block.Transactions() + if borTx != nil && *config.BorTraceEnabled { + txns = append(txns, borTx) + } + + for idx, txn := range txns { stream.WriteObjectStart() stream.WriteObjectField("result") select { @@ -112,6 +123,12 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp GasPrice: msg.GasPrice(), } + if borTx != nil && idx == len(txns)-1 { + if *config.BorTraceEnabled { + config.BorTx = newBoolPtr(true) + } + } + err = transactions.TraceTx(ctx, msg, blockCtx, txCtx, ibs, config, chainConfig, stream, api.evmCallTimeout) if err == nil { err = ibs.FinalizeTx(rules, state.NewNoopWriter()) @@ -128,7 +145,7 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp return err } } - if idx != len(block.Transactions())-1 { + if idx != len(txns)-1 { stream.WriteMore() } stream.Flush() @@ -460,3 +477,8 @@ func (api *PrivateDebugAPIImpl) TraceCallMany(ctx context.Context, bundles []Bun stream.WriteArrayEnd() return nil } + +func newBoolPtr(bb bool) *bool { + b := bb + return &b +} diff --git a/consensus/bor/statefull/processor.go b/consensus/bor/statefull/processor.go index b822914f8..475a13bcd 100644 --- a/consensus/bor/statefull/processor.go +++ b/consensus/bor/statefull/processor.go @@ -1,9 +1,13 @@ package statefull import ( + "github.com/holiman/uint256" + ethereum "github.com/ledgerwatch/erigon" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" ) type ChainContext struct { @@ -18,3 +22,39 @@ func (c ChainContext) Engine() consensus.Engine { func (c ChainContext) GetHeader(hash libcommon.Hash, number uint64) *types.Header { return c.Chain.GetHeader(hash, number) } + +// callmsg implements core.Message to allow passing it as a transaction simulator. +type Callmsg struct { + ethereum.CallMsg +} + +func (m Callmsg) From() libcommon.Address { return m.CallMsg.From } +func (m Callmsg) Nonce() uint64 { return 0 } +func (m Callmsg) CheckNonce() bool { return false } +func (m Callmsg) To() *libcommon.Address { return m.CallMsg.To } +func (m Callmsg) GasPrice() *uint256.Int { return m.CallMsg.GasPrice } +func (m Callmsg) Gas() uint64 { return m.CallMsg.Gas } +func (m Callmsg) Value() *uint256.Int { return m.CallMsg.Value } +func (m Callmsg) Data() []byte { return m.CallMsg.Data } + +func ApplyBorMessage(vmenv vm.EVM, msg Callmsg) (*core.ExecutionResult, error) { + initialGas := msg.Gas() + + // Apply the transaction to the current state (included in the env) + ret, gasLeft, err := vmenv.Call( + vm.AccountRef(msg.From()), + *msg.To(), + msg.Data(), + msg.Gas(), + msg.Value(), + false, + ) + + gasUsed := initialGas - gasLeft + + return &core.ExecutionResult{ + UsedGas: gasUsed, + Err: err, + ReturnData: ret, + }, nil +} diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 7f205fd6e..d24649992 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -16,4 +16,7 @@ type TraceConfig struct { Reexec *uint64 NoRefunds *bool // Turns off gas refunds when tracing StateOverrides *ethapi.StateOverrides + + BorTraceEnabled *bool + BorTx *bool } diff --git a/turbo/transactions/tracing.go b/turbo/transactions/tracing.go index 9d8f515f0..4b007ca60 100644 --- a/turbo/transactions/tracing.go +++ b/turbo/transactions/tracing.go @@ -9,10 +9,12 @@ import ( "time" jsoniter "github.com/json-iterator/go" + ethereum "github.com/ledgerwatch/erigon" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" "github.com/ledgerwatch/erigon-lib/kv" "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/bor/statefull" "github.com/ledgerwatch/erigon/core" "github.com/ledgerwatch/erigon/core/state" "github.com/ledgerwatch/erigon/core/types" @@ -184,7 +186,15 @@ func TraceTx( stream.WriteObjectField("structLogs") stream.WriteArrayStart() } - result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), refunds, false /* gasBailout */) + + var result *core.ExecutionResult + if config.BorTx != nil && *config.BorTx { + callmsg := prepareCallMessage(message) + result, err = statefull.ApplyBorMessage(*vmenv, callmsg) + } else { + result, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), refunds, false /* gasBailout */) + } + if err != nil { if streaming { stream.WriteArrayEnd() @@ -221,3 +231,16 @@ func TraceTx( } return nil } + +func prepareCallMessage(msg core.Message) statefull.Callmsg { + return statefull.Callmsg{ + CallMsg: ethereum.CallMsg{ + From: msg.From(), + To: msg.To(), + Gas: msg.Gas(), + GasPrice: msg.GasPrice(), + Value: msg.Value(), + Data: msg.Data(), + AccessList: msg.AccessList(), + }} +}