diff --git a/cmd/rpcdaemon/commands/trace_adhoc.go b/cmd/rpcdaemon/commands/trace_adhoc.go index 4793d8551a646424f97aecd0fd9354b30a9bfb37..c6c6c9f4edc1550cc3563f5c1ee985c82d377a98 100644 --- a/cmd/rpcdaemon/commands/trace_adhoc.go +++ b/cmd/rpcdaemon/commands/trace_adhoc.go @@ -569,6 +569,7 @@ func (api *TraceAPIImpl) ReplayTransaction(ctx context.Context, txHash common.Ha if traceTypeVmTrace { result.VmTrace = trace.VmTrace } + return trace, nil } } @@ -583,46 +584,23 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH } defer tx.Rollback() - chainConfig, err := api.chainConfig(tx) - if err != nil { - return nil, err - } - - blockNumber, blockHash, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) + blockNumber, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) if err != nil { return nil, err } - block := rawdb.ReadBlock(tx, blockHash, blockNumber) - if block == nil { - return nil, fmt.Errorf("block %d(%x) not found", blockNumber, blockHash) - } - getHeader := func(hash common.Hash, number uint64) *types.Header { - return rawdb.ReadHeader(tx, hash, number) + parentNr := blockNumber + if parentNr > 0 { + parentNr -= 1 } - - var stateReader state.StateReader - if num, ok := blockNrOrHash.Number(); ok && num == rpc.LatestBlockNumber { - stateReader = state.NewPlainStateReader(tx) - } else { - stateReader = state.NewPlainKvState(tx, blockNumber-1) + // Extract transactions from block + block, _, bErr := rawdb.ReadBlockByNumberWithSenders(tx, blockNumber) + if bErr != nil { + return nil, bErr } - ibs := state.New(stateReader) - - // Setup context so it may be cancelled the call has completed - // or, in case of unmetered gas, setup a context with a timeout. - var cancel context.CancelFunc - if callTimeout > 0 { - ctx, cancel = context.WithTimeout(ctx, callTimeout) - } else { - ctx, cancel = context.WithCancel(ctx) + if block == nil { + return nil, fmt.Errorf("could not find block %d", blockNumber) } - - // Make sure the context is cancelled when the call has completed - // this makes sure resources are cleaned up. - defer cancel() - var traceResults = make([]*TraceCallResult, block.Transactions().Len()) - traceResult := &TraceCallResult{Trace: []*ParityTrace{}} var traceTypeTrace, traceTypeStateDiff, traceTypeVmTrace bool for _, traceType := range traceTypes { switch traceType { @@ -636,57 +614,40 @@ func (api *TraceAPIImpl) ReplayBlockTransactions(ctx context.Context, blockNrOrH return nil, fmt.Errorf("unrecognized trace type: %s", traceType) } } - var ot OeTracer - ot.compat = api.compatibility - if traceTypeTrace { - ot.r = traceResult - ot.traceAddr = []int{} - } - gp := new(core.GasPool) - gp.AddGas(block.GasLimit()) + // Returns an array of trace arrays, one trace array for each transaction + traces, err := api.callManyTransactions(ctx, tx, block.Transactions(), block.ParentHash(), rpc.BlockNumber(parentNr), block.Header()) + if err != nil { + return nil, err + } if traceTypeVmTrace { return nil, fmt.Errorf("vmTrace not implemented yet") } - var initialIbs *state.IntraBlockState - usedGas := new(uint64) - var stateWriter state.StateWriter - vmConfig := vm.Config{} - if traceTypeStateDiff || traceTypeTrace { - vmConfig = vm.Config{Debug: traceTypeTrace, Tracer: &ot} - } - stateWriter = state.NewNoopWriter() - var sd *StateDiff - for i, txn := range block.Transactions() { - if err := common.Stopped(ctx.Done()); err != nil { - return nil, err + result := make([]*TraceCallResult, len(traces)) + for i, trace := range traces { + tr := &TraceCallResult{} + tr.Output = trace.Output + if traceTypeTrace { + tr.Trace = trace.Trace } - ibs.Prepare(txn.Hash(), block.Hash(), i) if traceTypeStateDiff { - sdMap := make(map[common.Address]*StateDiffAccount) - sd = &StateDiff{sdMap: sdMap} - traceResult.StateDiff = sdMap - stateWriter = sd - initialIbs = ibs.Copy() + tr.StateDiff = trace.StateDiff } - _, execResult, err := core.ApplyTransaction(chainConfig, getHeader, nil, &block.Header().Coinbase, gp, ibs, stateWriter, block.Header(), txn, usedGas, vmConfig, nil) - if err != nil { - return nil, fmt.Errorf("could not apply tx %d from block %d [%v]: %w", i, block.NumberU64(), txn.Hash().Hex(), err) + if traceTypeVmTrace { + tr.VmTrace = trace.VmTrace } - traceResult.Output = common.CopyBytes(execResult) - if traceTypeStateDiff { - sd.CompareStates(initialIbs, ibs) + result[i] = tr + for _, pt := range tr.Trace { + txpos := uint64(i) + txhash := block.Transactions()[i].Hash() + pt.TransactionHash = &txhash + pt.TransactionPosition = &txpos } - traceResults[i] = traceResult } - if traceTypeVmTrace { - return nil, fmt.Errorf("vmTrace not implemented yet") - } - - return traceResults, nil + return result, nil } // Call implements trace_call. diff --git a/cmd/rpcdaemon/commands/trace_adhoc_test.go b/cmd/rpcdaemon/commands/trace_adhoc_test.go index 602d45a11c65a9897c1c2333d927c4b23a7f72d2..6c3cb3fedb92364ae000dd8bd905aac44dd12725 100644 --- a/cmd/rpcdaemon/commands/trace_adhoc_test.go +++ b/cmd/rpcdaemon/commands/trace_adhoc_test.go @@ -75,7 +75,7 @@ func TestReplayTransaction(t *testing.T) { // Call GetTransactionReceipt for transaction which is not in the database results, err := api.ReplayTransaction(context.Background(), txnHash, []string{"stateDiff"}) if err != nil { - t.Errorf("calling CallMany: %v", err) + t.Errorf("calling ReplayTransaction: %v", err) } require.NotNil(t, results) require.NotNil(t, results.StateDiff) @@ -92,11 +92,11 @@ func TestReplayBlockTransactions(t *testing.T) { n := rpc.BlockNumber(6) results, err := api.ReplayBlockTransactions(context.Background(), rpc.BlockNumberOrHash{BlockNumber: &n}, []string{"stateDiff"}) if err != nil { - t.Errorf("calling CallMany: %v", err) + t.Errorf("calling ReplayBlockTransactions: %v", err) } require.NotNil(t, results) require.NotNil(t, results[0].StateDiff) - addrDiff := results[0].StateDiff[common.HexToAddress("0x0000000000000020000000000000000000000000")] + addrDiff := results[0].StateDiff[common.HexToAddress("0x0000000000000001000000000000000000000000")] v := addrDiff.Balance.(map[string]*hexutil.Big)["+"].ToInt().Uint64() require.Equal(t, uint64(1_000_000_000_000_000), v) }