From 971c251c63f1d43491e7d728c3fa589be79ed1d9 Mon Sep 17 00:00:00 2001 From: tiennam Date: Tue, 7 Nov 2023 15:13:35 +0700 Subject: [PATCH] feat(api_simulation): use call tracer instead of the custom tracer --- core/types/simulated_tx.go | 24 +-- eth/api_simulation.go | 81 ++++------ eth/tracers/native/internal_transaction.go | 170 --------------------- 3 files changed, 34 insertions(+), 241 deletions(-) delete mode 100644 eth/tracers/native/internal_transaction.go diff --git a/core/types/simulated_tx.go b/core/types/simulated_tx.go index b87a7e1977c0..63d604a9381f 100644 --- a/core/types/simulated_tx.go +++ b/core/types/simulated_tx.go @@ -1,32 +1,18 @@ package types -import "math/big" +import ( + "encoding/json" + "math/big" +) type SimulationDebugInfoResponse struct { StartSimulateMs int64 `json:"start_simulate_ms"` EndSimulateMs int64 `json:"end_simulate_ms"` } -type InternalTxResponse struct { - Type string `json:"type"` - From string `json:"from"` - To string `json:"to"` - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gas_used"` - Input string `json:"input"` - Value string `json:"value"` -} - -type EventLogResponse struct { - Address string `json:"address"` - Topics []string `json:"topics"` - Data string `json:"data"` -} - type SimulationTxResponse struct { PendingBlockNumber uint64 `json:"pending_block_number"` BaseFee *big.Int `json:"base_fee"` - InternalTxs []InternalTxResponse `json:"internal_transactions"` DebugInfo SimulationDebugInfoResponse `json:"debug_info"` - Logs []EventLogResponse `json:"logs"` + CallFrame json.RawMessage `json:"call_frame"` } diff --git a/eth/api_simulation.go b/eth/api_simulation.go index d86b56594d4d..1be931852583 100644 --- a/eth/api_simulation.go +++ b/eth/api_simulation.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/ethereum/go-ethereum/common" "math" - "strings" "sync" "sync/atomic" "time" @@ -20,7 +19,6 @@ import ( "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/eth/tracers/native" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" ) @@ -46,6 +44,20 @@ func (l *list) findSnapshotByNonce(nonce uint64) *state.StateDB { return l.snapshots[nonce] } +const ( + enableCheckpointFlag = false +) + +var ( + tracerCfgBytes []byte +) + +func init() { + tracerCfgBytes, _ = json.Marshal(map[string]interface{}{ + "withLog": true, + }) +} + // SimulationAPIBackend creates a new simulation API type SimulationAPIBackend struct { eth Backend @@ -195,18 +207,20 @@ func (b *SimulationAPIBackend) simulate(tx *types.Transaction, stateDb *state.St ) // load the checkpoint db if exists var currentList *list - if enc, found := b.stateDbCheckpoint.Load(msg.From.Hex()); found && enc != nil { - list, ok := enc.(*list) - if ok && list != nil { - currentList = list - checkpointStateDb := list.findSnapshotByNonce(msg.Nonce) - if checkpointStateDb != nil { - stateDb = checkpointStateDb.Copy() + if enableCheckpointFlag { + if enc, found := b.stateDbCheckpoint.Load(msg.From.Hex()); found && enc != nil { + list, ok := enc.(*list) + if ok && list != nil { + currentList = list + checkpointStateDb := list.findSnapshotByNonce(msg.Nonce) + if checkpointStateDb != nil { + stateDb = checkpointStateDb.Copy() + } } } } - internalTransactionTracer, err := tracers.DefaultDirectory.New(native.InternalTransactionTracerName, tracerCtx, json.RawMessage{}) + internalTransactionTracer, err := tracers.DefaultDirectory.New("callTracer", tracerCtx, tracerCfgBytes) if err != nil { log.Error("Failed to create call tracer", "error", err) return nil, err @@ -224,7 +238,10 @@ func (b *SimulationAPIBackend) simulate(tx *types.Transaction, stateDb *state.St log.Error("Failed to apply the message", "hash", tx.Hash().String(), "number", currentBlock.NumberU64(), "err", err) return nil, err } - b.storeSnapshot(stateDb, currentList, msg.Nonce, msg.From) + + if enableCheckpointFlag { + b.storeSnapshot(stateDb, currentList, msg.Nonce, msg.From) + } if executionResult == nil { log.Warn("Simulation result is empty", "tx_hash", tx.Hash().String()) @@ -246,54 +263,14 @@ func (b *SimulationAPIBackend) simulate(tx *types.Transaction, stateDb *state.St return nil, nil } - var internalTxTracerOutput native.InternalTxTracerOutput - - if err := json.Unmarshal(tracerResultBytes, &internalTxTracerOutput); err != nil { - log.Error("Failed to unmarshal the internal transactions tracers", "err", err) - return nil, err - } - - internalTxsResponse := make([]types.InternalTxResponse, 0, len(internalTxTracerOutput.InternalTxs)) - for _, internalTx := range internalTxTracerOutput.InternalTxs { - to := "" - value := "0" - if internalTx.To != nil { - to = internalTx.To.String() - } - if internalTx.Value != nil { - value = internalTx.Value.String() - } - internalTxsResponse = append(internalTxsResponse, types.InternalTxResponse{ - Type: internalTx.Type.String(), - From: strings.ToLower(internalTx.From.String()), - To: strings.ToLower(to), - Gas: internalTx.Gas, - GasUsed: internalTx.GasUsed, - Input: internalTx.Input, - Value: value, - }) - } - eventLogs := make([]types.EventLogResponse, 0, len(internalTxTracerOutput.EventLogs)) - for _, eventLog := range internalTxTracerOutput.EventLogs { - topics := make([]string, 0, len(eventLog.Topics)) - for _, topic := range eventLog.Topics { - topics = append(topics, topic.Hex()) - } - eventLogs = append(eventLogs, types.EventLogResponse{ - Data: hexutil.Encode(eventLog.Data), - Address: eventLog.Address.String(), - Topics: topics, - }) - } return &types.SimulationTxResponse{ - InternalTxs: internalTxsResponse, + CallFrame: tracerResultBytes, DebugInfo: types.SimulationDebugInfoResponse{ StartSimulateMs: startTraceTimeMs, EndSimulateMs: time.Now().UnixMilli(), }, PendingBlockNumber: currentBlock.NumberU64() + 1, BaseFee: currentBlock.BaseFee(), - Logs: eventLogs, }, nil } diff --git a/eth/tracers/native/internal_transaction.go b/eth/tracers/native/internal_transaction.go deleted file mode 100644 index 224a559754bc..000000000000 --- a/eth/tracers/native/internal_transaction.go +++ /dev/null @@ -1,170 +0,0 @@ -package native - -import ( - "encoding/json" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/core/vm" - "github.com/ethereum/go-ethereum/eth/tracers" - "math/big" - "sync/atomic" -) - -func init() { - tracers.DefaultDirectory.Register(InternalTransactionTracerName, NewInternalTransactionTracer, false) -} - -type InternalTx struct { - Type vm.OpCode `json:"type"` - From common.Address `json:"from"` - To *common.Address `json:"to"` // can be empty when the transaction is a creation tx - Gas uint64 `json:"gas"` - GasUsed uint64 `json:"gas_used"` - Input string `json:"input"` - Value *big.Int `json:"value,omitempty"` -} - -type InternalTxs []InternalTx - -type InternalTxTracerOutput struct { - InternalTxs InternalTxs `json:"internal_txs,omitempty"` - EventLogs []types.Log `json:"event_logs"` -} - -type internalTransactionTracer struct { - // transaction info - gasLimit uint64 - interrupt atomic.Bool - err error - - // output - internalTransactions InternalTxs - eventLogs []types.Log -} - -const InternalTransactionTracerName = "internalTransactionTracer" - -func NewInternalTransactionTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) { - return &internalTransactionTracer{}, nil -} - -func (t *internalTransactionTracer) CaptureTxStart(gasLimit uint64) { - t.gasLimit = gasLimit -} -func (t *internalTransactionTracer) CaptureTxEnd(restGas uint64) { - t.internalTransactions[0].GasUsed = t.gasLimit - restGas -} -func (t *internalTransactionTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) { - toAddress := to - - var ( - opCode = vm.CALL - ) - if create { - opCode = vm.CREATE - } - - t.internalTransactions = append(t.internalTransactions, InternalTx{ - Type: opCode, - From: from, - To: &toAddress, - Input: "0x" + common.Bytes2Hex(input), - Gas: t.gasLimit, - Value: value, - }) - -} -func (t *internalTransactionTracer) CaptureEnd(output []byte, gasUsed uint64, err error) { - if err != nil { - t.err = err - return - } -} - -// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct). -func (t *internalTransactionTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - if t.interrupt.Load() { - return - } - - if typ != vm.CALL { - return - } - - toCopied := to - t.internalTransactions = append(t.internalTransactions, InternalTx{ - Type: typ, - From: from, - To: &toCopied, - Input: "0x" + common.Bytes2Hex(input), - Gas: gas, - Value: value, - }) -} -func (t *internalTransactionTracer) CaptureExit(output []byte, gasUsed uint64, err error) { - if err != nil { - t.err = err - return - } - size := len(t.internalTransactions) - if size <= 0 { - return - } - - t.internalTransactions[size-1].Gas = gasUsed -} - -// CaptureState implements the EVMLogger interface to trace a single step of VM execution. -func (t *internalTransactionTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { - if err != nil { - t.err = err - return - } - - switch op { - case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4: - // TODO(tiennampham23): uncomment if we need the logs from the transactions - size := int(op - vm.LOG0) - - stack := scope.Stack - stackData := stack.Data() - - // Don't modify the stack - mStart := stackData[len(stackData)-1] - mSize := stackData[len(stackData)-2] - topics := make([]common.Hash, size) - for i := 0; i < size; i++ { - topic := stackData[len(stackData)-2-(i+1)] - topics[i] = topic.Bytes32() - } - - data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64())) - if err != nil { - return - } - - t.eventLogs = append(t.eventLogs, types.Log{ - Address: scope.Contract.Address(), - Topics: topics, - Data: data, - }) - } -} -func (t *internalTransactionTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { -} - -func (t *internalTransactionTracer) GetResult() (json.RawMessage, error) { - output := InternalTxTracerOutput{ - InternalTxs: t.internalTransactions, - EventLogs: t.eventLogs, - } - b, err := json.Marshal(output) - if err != nil { - return nil, err - } - return b, nil -} - -func (t *internalTransactionTracer) Stop(err error) { - t.interrupt.Store(true) -}