diff --git a/cmd/execution_builder.go b/cmd/execution_builder.go index c9c7899270f..3d506a70ced 100644 --- a/cmd/execution_builder.go +++ b/cmd/execution_builder.go @@ -61,7 +61,6 @@ import ( "github.com/onflow/flow-go/engine/execution/state/bootstrap" "github.com/onflow/flow-go/engine/execution/storehouse" "github.com/onflow/flow-go/fvm" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/storage/snapshot" "github.com/onflow/flow-go/fvm/systemcontracts" ledgerpkg "github.com/onflow/flow-go/ledger" @@ -527,23 +526,6 @@ func (exeNode *ExecutionNode) LoadProviderEngine( node.FvmOptions..., ) - if exeNode.exeConf.evmTracingEnabled { - var err error - evmTraceUploader := debug.NewNoopUploader() - if len(exeNode.exeConf.evmTracesGCPBucket) > 0 { - evmTraceUploader, err = debug.NewGCPUploader(exeNode.exeConf.evmTracesGCPBucket) - if err != nil { - return nil, fmt.Errorf("could not create evm trace uploader: %w", err) - } - } - evmTracer, err := debug.NewEVMCallTracer(evmTraceUploader, node.Logger) - if err != nil { - return nil, fmt.Errorf("could not create evm tracer: %w", err) - } - - opts = append(opts, fvm.WithEVMTracer(evmTracer)) - } - vmCtx := fvm.NewContext(opts...) var collector module.ExecutionMetrics diff --git a/cmd/execution_config.go b/cmd/execution_config.go index 97f808ae6e7..5e5b6556d8a 100644 --- a/cmd/execution_config.go +++ b/cmd/execution_config.go @@ -57,10 +57,6 @@ type ExecutionConfig struct { transactionExecutionMetricsEnabled bool transactionExecutionMetricsBufferSize uint - // evm tracing configuration - evmTracingEnabled bool - evmTracesGCPBucket string - computationConfig computation.ComputationConfig receiptRequestWorkers uint // common provider engine workers receiptRequestsCacheSize uint32 // common provider engine cache size @@ -125,8 +121,6 @@ func (exeConf *ExecutionConfig) SetupFlags(flags *pflag.FlagSet) { flags.IntVar(&exeConf.importCheckpointWorkerCount, "import-checkpoint-worker-count", 10, "number of workers to import checkpoint file during bootstrap") flags.BoolVar(&exeConf.transactionExecutionMetricsEnabled, "tx-execution-metrics", true, "enable collection of transaction execution metrics") flags.UintVar(&exeConf.transactionExecutionMetricsBufferSize, "tx-execution-metrics-buffer-size", 200, "buffer size for transaction execution metrics. The buffer size is the number of blocks that are kept in memory by the metrics provider engine") - flags.BoolVar(&exeConf.evmTracingEnabled, "evm-tracing-enabled", false, "enable EVM tracing, when set it will generate traces and upload them to the GCP bucket provided by the --evm-traces-gcp-bucket. Warning: this might affect speed of execution") - flags.StringVar(&exeConf.evmTracesGCPBucket, "evm-traces-gcp-bucket", "", "define GCP bucket name used for uploading EVM traces, must be used in combination with --evm-tracing-enabled. if left empty the upload step is skipped") flags.BoolVar(&exeConf.onflowOnlyLNs, "temp-onflow-only-lns", false, "do not use unless required. forces node to only request collections from onflow collection nodes") flags.BoolVar(&exeConf.enableStorehouse, "enable-storehouse", false, "enable storehouse to store registers on disk, default is false") diff --git a/fvm/context.go b/fvm/context.go index fd198633b54..0abb46e4d88 100644 --- a/fvm/context.go +++ b/fvm/context.go @@ -7,7 +7,6 @@ import ( otelTrace "go.opentelemetry.io/otel/trace" "github.com/onflow/flow-go/fvm/environment" - "github.com/onflow/flow-go/fvm/evm/debug" reusableRuntime "github.com/onflow/flow-go/fvm/runtime" "github.com/onflow/flow-go/fvm/storage/derived" "github.com/onflow/flow-go/fvm/storage/state" @@ -47,8 +46,6 @@ type Context struct { // AllowProgramCacheWritesInScripts determines if the program cache can be written to in scripts // By default, the program cache is only updated by transactions. AllowProgramCacheWritesInScripts bool - - debug.EVMTracer } // NewContext initializes a new execution context with the provided options. @@ -79,7 +76,6 @@ func defaultContext() Context { MaxStateInteractionSize: DefaultMaxInteractionSize, TransactionExecutorParams: DefaultTransactionExecutorParams(), EnvironmentParams: environment.DefaultEnvironmentParams(), - EVMTracer: debug.NopTracer, } return ctx } @@ -385,14 +381,6 @@ func WithAllowProgramCacheWritesInScriptsEnabled(enabled bool) Option { } } -// WithEVMTracer will set the evm execution tracer -func WithEVMTracer(tracer debug.EVMTracer) Option { - return func(ctx Context) Context { - ctx.EVMTracer = tracer - return ctx - } -} - // WithReadVersionFromNodeVersionBeacon sets whether the version from the node version beacon should be read // this should only be disabled for testing func WithReadVersionFromNodeVersionBeacon(enabled bool) Option { diff --git a/fvm/evm/debug/tracer.go b/fvm/evm/debug/tracer.go deleted file mode 100644 index c5e90f2bfd4..00000000000 --- a/fvm/evm/debug/tracer.go +++ /dev/null @@ -1,319 +0,0 @@ -package debug - -import ( - "encoding/json" - "fmt" - "math/big" - - gethCommon "github.com/onflow/go-ethereum/common" - "github.com/onflow/go-ethereum/core/tracing" - "github.com/onflow/go-ethereum/core/types" - "github.com/onflow/go-ethereum/eth/tracers" - "github.com/rs/zerolog" - - // this import is needed for side-effects, because the - // tracers.DefaultDirectory is relying on the init function - _ "github.com/onflow/go-ethereum/eth/tracers/native" - - "github.com/onflow/flow-go/model/flow" -) - -const ( - tracerConfig = `{ "onlyTopCall": true }` - tracerName = "callTracer" -) - -type EVMTracer interface { - WithBlockID(identifier flow.Identifier) - TxTracer() *tracers.Tracer - Collect(txID gethCommon.Hash) -} - -var _ EVMTracer = &CallTracer{} - -type CallTracer struct { - logger zerolog.Logger - tracer *tracers.Tracer - resultsByTxID map[gethCommon.Hash]json.RawMessage - tracerConfig []byte - uploader Uploader - blockID flow.Identifier -} - -func NewEVMCallTracer(uploader Uploader, logger zerolog.Logger) (*CallTracer, error) { - tracerConfig := json.RawMessage(tracerConfig) - - tracer, err := tracers.DefaultDirectory.New(tracerName, &tracers.Context{}, tracerConfig) - if err != nil { - return nil, err - } - - return &CallTracer{ - logger: logger.With().Str("module", "evm-tracer").Logger(), - tracer: tracer, - resultsByTxID: make(map[gethCommon.Hash]json.RawMessage), - tracerConfig: tracerConfig, - uploader: uploader, - }, nil -} - -func (t *CallTracer) TxTracer() *tracers.Tracer { - return NewSafeTxTracer(t) -} - -func (t *CallTracer) ResetTracer() error { - var err error - t.tracer, err = tracers.DefaultDirectory.New(tracerName, &tracers.Context{}, json.RawMessage(tracerConfig)) - return err -} - -func (t *CallTracer) WithBlockID(id flow.Identifier) { - t.blockID = id -} - -func (t *CallTracer) GetResultByTxHash(txID gethCommon.Hash) json.RawMessage { - return t.resultsByTxID[txID] -} - -func (t *CallTracer) Collect(txID gethCommon.Hash) { - l := t.logger.With(). - Str("tx-id", txID.String()). - Str("block-id", t.blockID.String()). - Logger() - - // collect the trace result - res, found := t.resultsByTxID[txID] - if !found { - l.Error().Msg("trace result not found") - return - } - // remove the result - delete(t.resultsByTxID, txID) - - // generate the trace ID, outside the go-routine - traceID := TraceID(txID, t.blockID) - - // upload is concurrent and it doesn't produce any errors, as the - // client doesn't expect it, we don't want to break execution flow, - // in case there are errors we retry, and if we fail after retries - // we log them and continue. - go func() { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - - l.Err(err). - Stack(). - Msg("failed to collect EVM traces") - } - }() - if err := t.uploader.Upload(traceID, res); err != nil { - l.Error().Err(err). - Str("traces", string(res)). - Msg("failed to upload trace results, no more retries") - return - } - l.Debug().Msg("evm traces uploaded successfully") - }() - -} - -var NopTracer = &nopTracer{} - -var _ EVMTracer = &nopTracer{} - -type nopTracer struct{} - -func (n nopTracer) TxTracer() *tracers.Tracer { - return nil -} - -func (n nopTracer) WithBlockID(identifier flow.Identifier) {} - -func (n nopTracer) Collect(_ gethCommon.Hash) {} - -func TraceID(txID gethCommon.Hash, blockID flow.Identifier) string { - return fmt.Sprintf("%s-%s", blockID.String(), txID.String()) -} - -func NewSafeTxTracer(ct *CallTracer) *tracers.Tracer { - wrapped := &tracers.Tracer{ - Hooks: &tracing.Hooks{}, - } - - l := ct.logger.With(). - Str("block-id", ct.blockID.String()). - Logger() - - wrapped.OnTxStart = func( - vm *tracing.VMContext, - tx *types.Transaction, - from gethCommon.Address, - ) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnTxStart trace collection failed") - } - }() - l.Debug().Msg("tracing OnTxStart is called") - if ct.tracer.OnTxStart != nil { - ct.tracer.OnTxStart(vm, tx, from) - } - } - - wrapped.OnTxEnd = func(receipt *types.Receipt, err error) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnTxEnd trace collection failed") - } - }() - l.Debug().Msg("tracing OnTxEnd is called") - if ct.tracer.OnTxEnd != nil { - ct.tracer.OnTxEnd(receipt, err) - } - - // collect results for the tracer - res, err := ct.tracer.GetResult() - if err != nil { - l.Error().Err(err).Msg("failed to produce trace results") - return - } - ct.resultsByTxID[receipt.TxHash] = res - - // reset tracing to have fresh state - if err := ct.ResetTracer(); err != nil { - l.Error().Err(err). - Msg("failed to reset tracer") - return - } - } - - wrapped.OnEnter = func( - depth int, - typ byte, - from, to gethCommon.Address, - input []byte, - gas uint64, - value *big.Int, - ) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnEnter trace collection failed") - } - }() - l.Debug().Int("depth", depth).Msg("tracing OnEnter is called") - if ct.tracer.OnEnter != nil { - ct.tracer.OnEnter(depth, typ, from, to, input, gas, value) - } - } - - wrapped.OnExit = func(depth int, output []byte, gasUsed uint64, err error, reverted bool) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnExit trace collection failed") - } - }() - l.Debug().Int("depth", depth).Msg("tracing OnExit is called") - if ct.tracer.OnExit != nil { - ct.tracer.OnExit(depth, output, gasUsed, err, reverted) - } - } - - wrapped.OnOpcode = func( - pc uint64, - op byte, - gas, cost uint64, - scope tracing.OpContext, - rData []byte, - depth int, - err error, - ) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnOpcode trace collection failed") - } - }() - l.Debug().Msg("tracing OnOpcode is called") - if ct.tracer.OnOpcode != nil { - ct.tracer.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) - } - } - wrapped.OnFault = func( - pc uint64, - op byte, - gas, cost uint64, - scope tracing.OpContext, - depth int, - err error) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnFault trace collection failed") - } - }() - l.Debug().Msg("tracing OnFault is called") - if ct.tracer.OnFault != nil { - ct.tracer.OnFault(pc, op, gas, cost, scope, depth, err) - } - } - - wrapped.OnGasChange = func(old, new uint64, reason tracing.GasChangeReason) { - defer func() { - if r := recover(); r != nil { - err, ok := r.(error) - if !ok { - err = fmt.Errorf("panic: %v", r) - } - l.Err(err). - Stack(). - Msg("OnGasChange trace collection failed") - } - }() - l.Debug().Msg("tracing OnGasChange is called") - if ct.tracer.OnGasChange != nil { - ct.tracer.OnGasChange(old, new, reason) - } - } - - wrapped.GetResult = ct.tracer.GetResult - wrapped.Stop = ct.tracer.Stop - return wrapped -} diff --git a/fvm/evm/debug/tracer_test.go b/fvm/evm/debug/tracer_test.go deleted file mode 100644 index 32e694b4ae7..00000000000 --- a/fvm/evm/debug/tracer_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package debug_test - -import ( - "encoding/json" - "math/big" - "testing" - - gethCommon "github.com/onflow/go-ethereum/common" - gethTypes "github.com/onflow/go-ethereum/core/types" - "github.com/onflow/go-ethereum/core/vm" - "github.com/rs/zerolog" - "github.com/stretchr/testify/require" - - "github.com/onflow/flow-go/fvm/evm/debug" - "github.com/onflow/flow-go/fvm/evm/testutils" - "github.com/onflow/flow-go/model/flow" -) - -func Test_CallTracer(t *testing.T) { - t.Run("collect traces and upload them", func(t *testing.T) { - var txID gethCommon.Hash - blockID := flow.Identifier{0x01} - var res json.RawMessage - - mockUpload := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, res, message) - return nil - }, - } - - tracer, err := debug.NewEVMCallTracer(mockUpload, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(blockID) - - from := gethCommon.HexToAddress("0x01") - to := gethCommon.HexToAddress("0x02") - nonce := uint64(10) - data := []byte{0x02, 0x04} - amount := big.NewInt(1) - - tr := tracer.TxTracer() - require.NotNil(t, tr) - - tx := gethTypes.NewTransaction(nonce, to, amount, 100, big.NewInt(10), data) - txID = tx.Hash() - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, 0, from, to, []byte{0x01, 0x02}, 10, big.NewInt(1)) - tr.OnEnter(1, byte(vm.ADD), from, to, data, 20, big.NewInt(2)) - tr.OnExit(1, nil, 10, nil, false) - tr.OnExit(0, []byte{0x02}, 200, nil, false) - tr.OnTxEnd(&gethTypes.Receipt{TxHash: txID}, nil) - res = tracer.GetResultByTxHash(txID) - tracer.Collect(txID) - }) - - t.Run("collect traces and upload them (after a failed transaction)", func(t *testing.T) { - blockID := flow.Identifier{0x01} - var txID gethCommon.Hash - var res json.RawMessage - - mockUpload := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, res, message) - return nil - }, - } - - tracer, err := debug.NewEVMCallTracer(mockUpload, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(blockID) - - from := gethCommon.HexToAddress("0x01") - to := gethCommon.HexToAddress("0x02") - nonce := uint64(10) - data := []byte{0x02, 0x04} - amount := big.NewInt(1) - - tr := tracer.TxTracer() - require.NotNil(t, tr) - - // failed transaction (no exit and collect call) - tx := gethTypes.NewTransaction(nonce, to, amount, 300, big.NewInt(30), data) - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, 0, from, to, []byte{0x01, 0x02}, 10, big.NewInt(1)) - tr.OnEnter(1, byte(vm.ADD), from, to, data, 20, big.NewInt(2)) - - // success - tx = gethTypes.NewTransaction(nonce, to, amount, 400, big.NewInt(40), data) - txID = tx.Hash() - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, 0, from, to, []byte{0x01, 0x02}, 10, big.NewInt(1)) - tr.OnExit(0, []byte{0x02}, 200, nil, false) - tr.OnTxEnd(&gethTypes.Receipt{TxHash: txID}, nil) - res = tracer.GetResultByTxHash(txID) - tracer.Collect(txID) - }) - - t.Run("collector panic recovery", func(t *testing.T) { - txID := gethCommon.Hash{0x05} - blockID := flow.Identifier{0x01} - - mockUpload := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - panic("nooooo") - }, - } - - tracer, err := debug.NewEVMCallTracer(mockUpload, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(blockID) - - require.NotPanics(t, func() { - tracer.Collect(txID) - }) - }) - - t.Run("nop tracer", func(t *testing.T) { - tracer := debug.NopTracer - require.Nil(t, tracer.TxTracer()) - }) -} diff --git a/fvm/evm/debug/uploader.go b/fvm/evm/debug/uploader.go deleted file mode 100644 index 5f6de7e2980..00000000000 --- a/fvm/evm/debug/uploader.go +++ /dev/null @@ -1,71 +0,0 @@ -package debug - -import ( - "context" - "encoding/json" - "fmt" - "time" - - "cloud.google.com/go/storage" -) - -type Uploader interface { - Upload(id string, data json.RawMessage) error -} - -var _ Uploader = &GCPUploader{} - -type GCPUploader struct { - bucket *storage.BucketHandle -} - -func NewGCPUploader(bucketName string) (*GCPUploader, error) { - // no need to close the client according to documentation - // https://pkg.go.dev/cloud.google.com/go/storage#Client.Close - ctx := context.Background() - client, err := storage.NewClient(ctx) - if err != nil { - return nil, fmt.Errorf("cannot create GCP Bucket client: %w", err) - } - bucket := client.Bucket(bucketName) - - // try accessing buckets to validate settings - _, err = bucket.Attrs(ctx) - if err != nil { - return nil, fmt.Errorf("error while listing bucket attributes: %w", err) - } - - return &GCPUploader{ - bucket: bucket, - }, nil -} - -// Upload traces to the GCP for the given id. -// The upload will be retried by the client if the error is transient. -func (g *GCPUploader) Upload(id string, data json.RawMessage) error { - const uploadTimeout = time.Minute * 5 - ctx, cancel := context.WithTimeout(context.Background(), uploadTimeout) - defer cancel() - - wc := g.bucket.Object(id).NewWriter(ctx) - if _, err := wc.Write(data); err != nil { - return err - } - - if err := wc.Close(); err != nil { - return err - } - - return nil -} - -// NewNoopUploader constructs a new noop uploader -func NewNoopUploader() Uploader { - return &NoopUploader{} -} - -type NoopUploader struct{} - -func (np *NoopUploader) Upload(id string, data json.RawMessage) error { - return nil -} diff --git a/fvm/evm/debug/uploader_test.go b/fvm/evm/debug/uploader_test.go deleted file mode 100644 index b531ad74d3b..00000000000 --- a/fvm/evm/debug/uploader_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package debug_test - -import ( - "context" - "encoding/json" - "fmt" - "io" - "math/big" - "math/rand" - "testing" - - "cloud.google.com/go/storage" - gethCommon "github.com/onflow/go-ethereum/common" - gethTypes "github.com/onflow/go-ethereum/core/types" - "github.com/onflow/go-ethereum/core/vm" - "github.com/rs/zerolog" - "github.com/stretchr/testify/require" - - "github.com/onflow/flow-go/fvm/evm/debug" - "github.com/onflow/flow-go/model/flow" - testutils "github.com/onflow/flow-go/utils/unittest" -) - -// we use previewnet bucket for integraiton test -const bucket = "previewnet1-evm-execution-traces" - -func Test_Uploader(t *testing.T) { - testutils.SkipUnless(t, testutils.TEST_REQUIRES_GCP_ACCESS, "requires GCP Bucket setup") - - t.Run("successfuly upload traces", func(t *testing.T) { - uploader, err := debug.NewGCPUploader(bucket) - require.NoError(t, err) - - const testID = "test_p" - - data := json.RawMessage(fmt.Sprintf(`{ "test": %d }`, rand.Int())) - - err = uploader.Upload(testID, data) - require.NoError(t, err) - - // check uploaded object - client, err := storage.NewClient(context.Background()) - require.NoError(t, err) - bucket := client.Bucket(bucket) - - reader, err := bucket.Object(testID).NewReader(context.Background()) - require.NoError(t, err) - - readBytes, err := io.ReadAll(reader) - require.NoError(t, err) - - require.Equal(t, []byte(data), readBytes) - }) -} - -func Test_TracerUploaderIntegration(t *testing.T) { - testutils.SkipUnless(t, testutils.TEST_REQUIRES_GCP_ACCESS, "requires GCP Bucket setup") - - t.Run("successfuly uploads traces", func(t *testing.T) { - uploader, err := debug.NewGCPUploader(bucket) - require.NoError(t, err) - - tracer, err := debug.NewEVMCallTracer(uploader, zerolog.Nop()) - require.NoError(t, err) - - tr := tracer.TxTracer() - require.NotNil(t, tr) - - from := gethCommon.HexToAddress("0x01") - to := gethCommon.HexToAddress("0x02") - nonce := uint64(10) - gas := uint64(100) - gasPrice := big.NewInt(1) - value := big.NewInt(2) - input := []byte{0x01} - tx := gethTypes.NewTransaction(nonce, to, value, gas, gasPrice, input) - - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, byte(vm.ADD), from, to, input, gas, value) - tr.OnTxEnd(&gethTypes.Receipt{}, nil) - - traces, err := tr.GetResult() - require.NoError(t, err) - - id := gethCommon.BytesToHash([]byte("test-tx")) - blockID := flow.Identifier{0x02} - tracer.WithBlockID(blockID) - tracer.Collect(id) - - // check uploaded object - client, err := storage.NewClient(context.Background()) - require.NoError(t, err) - bucket := client.Bucket(bucket) - - reader, err := bucket. - Object(id.String()). - NewReader(context.Background()) - require.NoError(t, err) - - readBytes, err := io.ReadAll(reader) - require.NoError(t, err) - - require.Equal(t, []byte(traces), readBytes) - }) -} diff --git a/fvm/evm/emulator/emulator_test.go b/fvm/evm/emulator/emulator_test.go index 79d20378be5..5453a13e672 100644 --- a/fvm/evm/emulator/emulator_test.go +++ b/fvm/evm/emulator/emulator_test.go @@ -2,22 +2,18 @@ package emulator_test import ( "encoding/hex" - "encoding/json" "fmt" "math" "math/big" "strings" "testing" - "time" gethCommon "github.com/onflow/go-ethereum/common" gethTypes "github.com/onflow/go-ethereum/core/types" gethVM "github.com/onflow/go-ethereum/core/vm" gethParams "github.com/onflow/go-ethereum/params" - "github.com/rs/zerolog" "github.com/stretchr/testify/require" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/testutils" "github.com/onflow/flow-go/fvm/evm/testutils/contracts" @@ -1138,361 +1134,6 @@ func TestCallingExtraPrecompiles(t *testing.T) { }) } -func TestTransactionTracing(t *testing.T) { - - // runWithDeployedContract is a helper function that will deploy a contract we can use to interact with - runWithDeployedContract := func(t *testing.T, f func(*testutils.TestContract, *testutils.EOATestAccount, *emulator.Emulator)) { - testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { - testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { - testutils.RunWithEOATestAccount(t, backend, rootAddr, func(testAccount *testutils.EOATestAccount) { - RunWithNewEmulator(t, backend, rootAddr, func(emu *emulator.Emulator) { - testContract := testutils.GetStorageTestContract(t) - nonce := testAccount.Nonce() - - // deploy contract - RunWithNewBlockView(t, emu, func(blk types.BlockView) { - call := types.NewDeployCall( - testAccount.Address(), - testContract.ByteCode, - math.MaxUint64, - big.NewInt(0), - nonce) - - res, err := blk.DirectCall(call) - require.NoError(t, err) - require.NotNil(t, res.DeployedContractAddress) - testAccount.SetNonce(testAccount.Nonce() + 1) - testContract.DeployedAt = *res.DeployedContractAddress - f(testContract, testAccount, emu) - }) - }) - }) - }) - }) - } - - // manually create block with the provided tracer injected - blockWithTracer := func(t *testing.T, emu *emulator.Emulator) (types.BlockView, *testutils.MockUploader, *debug.CallTracer) { - uploader := &testutils.MockUploader{} - tracer, err := debug.NewEVMCallTracer(uploader, zerolog.Nop()) - require.NoError(t, err) - - // manually create block with provided tracer - ctx := types.NewDefaultBlockContext(1) - ctx.Tracer = tracer.TxTracer() - blk, err := emu.NewBlockView(ctx) - require.NoError(t, err) - - return blk, uploader, tracer - } - - t.Run("contract interaction using direct call", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, uploader, tracer := blockWithTracer(t, emu) - - var txID gethCommon.Hash - var trace json.RawMessage - - blockID := flow.Identifier{0x01} - uploaded := make(chan struct{}) - - uploader.UploadFunc = func(id string, message json.RawMessage) error { - uploaded <- struct{}{} - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, trace, message) - require.Greater(t, len(message), 0) - return nil - } - - tracer.WithBlockID(blockID) - - // interact and record trace - res, err := blk.DirectCall( - types.NewContractCall( - testAccount.Address(), - testContract.DeployedAt, - testContract.MakeCallData(t, "store", big.NewInt(2)), - 1_000_000, - big.NewInt(0), - testAccount.Nonce(), - ), - ) - require.NoError(t, err) - require.NoError(t, res.ValidationError) - require.NoError(t, res.VMError) - txID = res.TxHash - trace = tracer.GetResultByTxHash(txID) - require.NotEmpty(t, trace) - tracer.Collect(txID) - - testAccount.SetNonce(testAccount.Nonce() + 1) - require.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload did not execute") - }) - }) - - t.Run("contract deploy at using direct call", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, uploader, tracer := blockWithTracer(t, emu) - - var txID gethCommon.Hash - var trace json.RawMessage - - uploaded := make(chan struct{}) - blockID := flow.Identifier{0x01} - - uploader.UploadFunc = func(id string, message json.RawMessage) error { - uploaded <- struct{}{} - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, trace, message) - require.Greater(t, len(message), 0) - return nil - } - - // interact and record trace - res, err := blk.DirectCall( - types.NewDeployCallWithTargetAddress( - testAccount.Address(), - types.Address{0x01, 0x02}, - testContract.ByteCode, - 2_000_000, - big.NewInt(0), - testAccount.Nonce(), - ), - ) - requireSuccessfulExecution(t, err, res) - txID = res.TxHash - trace = tracer.GetResultByTxHash(txID) - require.NotEmpty(t, trace) - tracer.WithBlockID(blockID) - tracer.Collect(txID) - - testAccount.SetNonce(testAccount.Nonce() + 1) - require.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload did not execute") - }) - }) - - t.Run("contract interaction using run transaction", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, uploader, tracer := blockWithTracer(t, emu) - - var txID gethCommon.Hash - var trace json.RawMessage - - blockID := flow.Identifier{0x02} - uploaded := make(chan struct{}) - - uploader.UploadFunc = func(id string, message json.RawMessage) error { - uploaded <- struct{}{} - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, trace, message) - require.Greater(t, len(message), 0) - return nil - } - - tx := testAccount.PrepareAndSignTx( - t, - testContract.DeployedAt.ToCommon(), - testContract.MakeCallData(t, "store", big.NewInt(2)), - big.NewInt(0), - 1_000_000, - big.NewInt(0), - ) - - // interact and record trace - res, err := blk.RunTransaction(tx) - requireSuccessfulExecution(t, err, res) - txID = res.TxHash - trace = tracer.GetResultByTxHash(txID) - require.NotEmpty(t, trace) - tracer.WithBlockID(blockID) - tracer.Collect(txID) - - testAccount.SetNonce(testAccount.Nonce() + 1) - require.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload did not execute") - }) - - }) - - t.Run("contract interaction using run transaction with proxy", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - - // deploy proxy - proxyContract := testutils.GetProxyContract(t) - RunWithNewBlockView(t, emu, func(blk types.BlockView) { - call := types.NewDeployCall( - testAccount.Address(), - proxyContract.ByteCode, - math.MaxUint64, - big.NewInt(0), - testAccount.Nonce()) - - res, err := blk.DirectCall(call) - require.NoError(t, err) - require.NotNil(t, res.DeployedContractAddress) - testAccount.SetNonce(testAccount.Nonce() + 1) - proxyContract.DeployedAt = *res.DeployedContractAddress - }) - - RunWithNewBlockView(t, emu, func(blk types.BlockView) { - // set proxy contract reference the test contract - tx := testAccount.PrepareAndSignTx( - t, - proxyContract.DeployedAt.ToCommon(), - proxyContract.MakeCallData(t, "setImplementation", testContract.DeployedAt.ToCommon()), - big.NewInt(0), - 1_000_000, - big.NewInt(0), - ) - res, err := blk.RunTransaction(tx) - requireSuccessfulExecution(t, err, res) - }) - - blk, uploader, tracer := blockWithTracer(t, emu) - - var txID gethCommon.Hash - var trace json.RawMessage - - blockID := flow.Identifier{0x02} - uploaded := make(chan struct{}) - - uploader.UploadFunc = func(id string, message json.RawMessage) error { - uploaded <- struct{}{} - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, trace, message) - require.Greater(t, len(message), 0) - return nil - } - - // make call to the proxy - tx := testAccount.PrepareAndSignTx( - t, - proxyContract.DeployedAt.ToCommon(), - testContract.MakeCallData(t, "store", big.NewInt(2)), - big.NewInt(0), - 1_000_000, - big.NewInt(0), - ) - - // interact and record trace - res, err := blk.RunTransaction(tx) - requireSuccessfulExecution(t, err, res) - txID = res.TxHash - tracer.WithBlockID(blockID) - trace = tracer.GetResultByTxHash(txID) - require.NotEmpty(t, trace) - tracer.Collect(txID) - - testAccount.SetNonce(testAccount.Nonce() + 1) - require.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload did not execute") - }) - - }) - t.Run("contract interaction run failed transaction", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, _, tracer := blockWithTracer(t, emu) - var txID gethCommon.Hash - - tx := testAccount.PrepareAndSignTx( - t, - testContract.DeployedAt.ToCommon(), - testContract.MakeCallData(t, "store", big.NewInt(2)), - big.NewInt(0), - 21210, - big.NewInt(100), - ) - - // interact and record trace - res, err := blk.RunTransaction(tx) - require.NoError(t, err) - require.EqualError(t, res.VMError, "out of gas") - - tracer.Collect(txID) - }) - - }) - - t.Run("contract interaction run invalid transaction", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, _, tracer := blockWithTracer(t, emu) - var txID gethCommon.Hash - - tx := testAccount.PrepareAndSignTx( - t, - testContract.DeployedAt.ToCommon(), - testContract.MakeCallData(t, "store", big.NewInt(2)), - big.NewInt(0), - 1_000_000, - big.NewInt(-1), - ) - - // interact and record trace - res, err := blk.RunTransaction(tx) - require.NoError(t, err) - require.EqualError(t, res.ValidationError, "max fee per gas less than block base fee: address 0x658Bdf435d810C91414eC09147DAA6DB62406379, maxFeePerGas: -1, baseFee: 0") - - tracer.Collect(txID) - }) - - }) - - t.Run("contract interaction using run batch transaction", func(t *testing.T) { - runWithDeployedContract(t, func(testContract *testutils.TestContract, testAccount *testutils.EOATestAccount, emu *emulator.Emulator) { - blk, uploader, tracer := blockWithTracer(t, emu) - - var txID gethCommon.Hash - var trace json.RawMessage - - blockID := flow.Identifier{0x02} - uploaded := make(chan struct{}) - - uploader.UploadFunc = func(id string, message json.RawMessage) error { - uploaded <- struct{}{} - require.Equal(t, debug.TraceID(txID, blockID), id) - require.Equal(t, trace, message) - require.Greater(t, len(message), 0) - return nil - } - - tx := testAccount.PrepareAndSignTx( - t, - testContract.DeployedAt.ToCommon(), - testContract.MakeCallData(t, "store", big.NewInt(2)), - big.NewInt(0), - 1_000_000, - big.NewInt(0), - ) - - // interact and record trace - results, err := blk.BatchRunTransactions([]*gethTypes.Transaction{tx}) - require.NoError(t, err) - require.Len(t, results, 1) - txID = results[0].TxHash - trace = tracer.GetResultByTxHash(txID) - tracer.WithBlockID(blockID) - tracer.Collect(txID) - - require.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload did not execute") - }) - - }) - -} - func TestTxIndex(t *testing.T) { testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { diff --git a/fvm/evm/evm.go b/fvm/evm/evm.go index 47df0257a48..9b74ac17ba3 100644 --- a/fvm/evm/evm.go +++ b/fvm/evm/evm.go @@ -1,14 +1,11 @@ package evm import ( - "fmt" - "github.com/onflow/cadence/common" "github.com/onflow/cadence/runtime" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/evm/backends" - "github.com/onflow/flow-go/fvm/evm/debug" evm "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/handler" "github.com/onflow/flow-go/fvm/evm/impl" @@ -29,7 +26,6 @@ func SetupEnvironment( chainID flow.ChainID, fvmEnv environment.Environment, runtimeEnv runtime.Environment, - tracer debug.EVMTracer, ) error { sc := systemcontracts.SystemContractsForChain(chainID) randomBeaconAddress := sc.RandomBeaconHistory.Address @@ -40,23 +36,6 @@ func SetupEnvironment( blockStore := handler.NewBlockStore(chainID, backend, StorageAccountAddress(chainID)) addressAllocator := handler.NewAddressAllocator() - if tracer != debug.NopTracer { - height, err := backend.GetCurrentBlockHeight() - if err != nil { - return err - } - - block, ok, err := backend.GetBlockAtHeight(height) - if err != nil { - return err - } - if !ok { - return fmt.Errorf("could not retrieve the block at height") - } - - tracer.WithBlockID(flow.Identifier(block.Hash)) - } - evmContractAddress := ContractAccountAddress(chainID) contractHandler := handler.NewContractHandler( @@ -68,7 +47,6 @@ func SetupEnvironment( addressAllocator, backend, emulator, - tracer, ) internalEVMContractValue := impl.NewInternalEVMContractValue( diff --git a/fvm/evm/handler/handler.go b/fvm/evm/handler/handler.go index 102ec960238..5a6b6866930 100644 --- a/fvm/evm/handler/handler.go +++ b/fvm/evm/handler/handler.go @@ -11,7 +11,6 @@ import ( "github.com/onflow/flow-go/fvm/environment" fvmErrors "github.com/onflow/flow-go/fvm/errors" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/evm/events" "github.com/onflow/flow-go/fvm/evm/handler/coa" "github.com/onflow/flow-go/fvm/evm/types" @@ -30,7 +29,6 @@ type ContractHandler struct { backend types.Backend emulator types.Emulator precompiledContracts []types.PrecompiledContract - tracer debug.EVMTracer } var _ types.ContractHandler = &ContractHandler{} @@ -45,7 +43,6 @@ func NewContractHandler( addressAllocator types.AddressAllocator, backend types.Backend, emulator types.Emulator, - tracer debug.EVMTracer, ) *ContractHandler { return &ContractHandler{ flowChainID: flowChainID, @@ -55,7 +52,6 @@ func NewContractHandler( addressAllocator: addressAllocator, backend: backend, emulator: emulator, - tracer: tracer, precompiledContracts: preparePrecompiledContracts( evmContractAddress, randomBeaconAddress, @@ -307,9 +303,6 @@ func (h *ContractHandler) batchRun(rlpEncodedTxs [][]byte) ([]*types.Result, err false, r.Failed(), ) - - // step 11 - collect traces - h.tracer.Collect(r.TxHash) } // update the block proposal @@ -437,9 +430,6 @@ func (h *ContractHandler) run(rlpEncodedTx []byte) (*types.Result, error) { res.Failed(), ) - // step 11 - collect traces - h.tracer.Collect(res.TxHash) - return res, nil } @@ -550,7 +540,6 @@ func (h *ContractHandler) getBlockContext() (types.BlockContext, error) { }, ExtraPrecompiledContracts: h.precompiledContracts, Random: bp.PrevRandao, - Tracer: h.tracer.TxTracer(), TxCountSoFar: uint(len(bp.TxHashes)), TotalGasUsedSoFar: bp.TotalGasUsed, GasFeeCollector: types.CoinbaseAddress, @@ -646,9 +635,6 @@ func (h *ContractHandler) executeAndHandleCall( res.Failed(), ) - // step 10 - collect traces - h.tracer.Collect(res.TxHash) - return res, nil } diff --git a/fvm/evm/handler/handler_test.go b/fvm/evm/handler/handler_test.go index aeebd761cc3..3db635b5fa8 100644 --- a/fvm/evm/handler/handler_test.go +++ b/fvm/evm/handler/handler_test.go @@ -1,12 +1,10 @@ package handler_test import ( - "encoding/json" "fmt" "math" "math/big" "testing" - "time" "github.com/onflow/cadence/common" gethCommon "github.com/onflow/go-ethereum/common" @@ -15,12 +13,10 @@ import ( gethVM "github.com/onflow/go-ethereum/core/vm" gethParams "github.com/onflow/go-ethereum/params" "github.com/onflow/go-ethereum/rlp" - "github.com/rs/zerolog" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/onflow/flow-go/fvm/errors" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/handler" "github.com/onflow/flow-go/fvm/evm/handler/coa" @@ -71,7 +67,7 @@ func TestHandler_TransactionRunOrPanic(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(flow.Emulator, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Emulator, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) @@ -144,7 +140,7 @@ func TestHandler_TransactionRunOrPanic(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) @@ -205,7 +201,7 @@ func TestHandler_TransactionRunOrPanic(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) assertPanic(t, errors.IsFailure, func() { tx := eoa.PrepareSignAndEncodeTx( t, @@ -477,7 +473,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), false) account.Withdraw(types.NewBalanceFromUFix64(1)) @@ -494,7 +490,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) account.Withdraw(types.NewBalanceFromUFix64(1)) @@ -511,7 +507,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) account.Withdraw(types.NewBalanceFromUFix64(0)) @@ -528,7 +524,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) account.Withdraw(types.NewBalanceFromUFix64(0)) @@ -558,7 +554,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) account.Deposit(types.NewFlowTokenVault(types.NewBalanceFromUFix64(1))) @@ -575,7 +571,7 @@ func TestHandler_COA(t *testing.T) { }, } - handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) account.Deposit(types.NewFlowTokenVault(types.NewBalanceFromUFix64(1))) @@ -775,7 +771,7 @@ func TestHandler_TransactionRun(t *testing.T) { }, nil }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) tx := eoa.PrepareSignAndEncodeTx( t, gethCommon.Address{}, @@ -824,7 +820,7 @@ func TestHandler_TransactionRun(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) tx := eoa.PrepareSignAndEncodeTx( t, @@ -862,7 +858,7 @@ func TestHandler_TransactionRun(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) @@ -959,7 +955,7 @@ func TestHandler_TransactionRun(t *testing.T) { }, nil }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em) gasLimit := uint64(100_000) @@ -1063,7 +1059,7 @@ func TestHandler_TransactionRun(t *testing.T) { return new(big.Int), nil }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) // batch run empty transactions @@ -1131,7 +1127,7 @@ func TestHandler_TransactionRun(t *testing.T) { }, } - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em, debug.NopTracer) + handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em) rs := handler.DryRun(rlpTx, from) require.Equal(t, types.StatusSuccessful, rs.Status) @@ -1143,238 +1139,6 @@ func TestHandler_TransactionRun(t *testing.T) { }) }) - t.Run("transaction run with tracing", func(t *testing.T) { - t.Parallel() - - testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { - testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { - testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { - - txID := gethCommon.HexToHash("0x1") - blockID := flow.Identifier{0x02} - uploaded := make(chan struct{}) - - result := &types.Result{ - TxHash: txID, - ReturnedData: testutils.RandomData(t), - Logs: []*gethTypes.Log{ - testutils.GetRandomLogFixture(t), - }, - } - - uploader := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - assert.NotEmpty(t, message) - assert.Equal(t, debug.TraceID(txID, blockID), id) - close(uploaded) - return nil - }, - } - - tracer, err := debug.NewEVMCallTracer(uploader, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(blockID) - - bs := handler.NewBlockStore(chainID, backend, rootAddr) - aa := handler.NewAddressAllocator() - - em := &testutils.TestEmulator{ - RunTransactionFunc: func(tx *gethTypes.Transaction) (*types.Result, error) { - tr := tracer.TxTracer() - // mock some calls - from := eoa.Address().ToCommon() - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, byte(gethVM.ADD), from, *tx.To(), tx.Data(), 20, big.NewInt(2)) - tr.OnExit(0, []byte{0x02}, 200, nil, false) - tr.OnTxEnd(result.Receipt(), nil) - return result, nil - }, - BalanceOfFunc: func(address types.Address) (*big.Int, error) { - return big.NewInt(0), nil - }, - } - - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, tracer) - - tx := eoa.PrepareSignAndEncodeTx( - t, - gethCommon.Address{}, - nil, - nil, - 100_000, - big.NewInt(1), - ) - - _ = handler.Run(tx, types.NewAddress(gethCommon.Address{})) - - assert.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload not executed") - }) - }) - }) - }) - - // this test makes sure that even if tracing process fails it doesn't affect the execution flow - // it also makes sure the upload is retried and then we panic - t.Run("test - transaction run with tracing failure", func(t *testing.T) { - t.Parallel() - - testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { - testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { - testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { - - uploaded := make(chan struct{}) - result := &types.Result{ - TxHash: gethCommon.HexToHash("0x1"), - ReturnedData: testutils.RandomData(t), - Logs: []*gethTypes.Log{ - testutils.GetRandomLogFixture(t), - }, - } - - uploader := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - close(uploaded) - panic("total failure") - }, - } - - tracer, err := debug.NewEVMCallTracer(uploader, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(flow.Identifier{0x1}) - - bs := handler.NewBlockStore(defaultChainID, backend, rootAddr) - aa := handler.NewAddressAllocator() - - em := &testutils.TestEmulator{ - RunTransactionFunc: func(tx *gethTypes.Transaction) (*types.Result, error) { - tr := tracer.TxTracer() - tr.OnTxStart(nil, tx, gethCommon.Address{}) - tr.OnEnter(0, 0, gethCommon.Address{}, *tx.To(), []byte{0x01, 0x02}, 10, big.NewInt(1)) - tr.OnExit(0, []byte{0x02}, 200, nil, false) - tr.OnTxEnd(&gethTypes.Receipt{TxHash: result.TxHash}, nil) - return result, nil - }, - BalanceOfFunc: func(address types.Address) (*big.Int, error) { - return big.NewInt(0), nil - }, - } - - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, rootAddr, bs, aa, backend, em, tracer) - - tx := eoa.PrepareSignAndEncodeTx( - t, - gethCommon.Address{}, - nil, - nil, - 100_000, - big.NewInt(1), - ) - - res := handler.Run(tx, types.NewAddress(gethCommon.Address{})) - - assert.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second*5, time.Millisecond*100, "upload not executed") - - require.Equal(t, types.StatusSuccessful, res.Status) - }) - }) - }) - }) - - t.Run("test - transaction batch run with tracing", func(t *testing.T) { - t.Parallel() - - testutils.RunWithTestBackend(t, func(backend *testutils.TestBackend) { - testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { - testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { - bs := handler.NewBlockStore(defaultChainID, backend, rootAddr) - aa := handler.NewAddressAllocator() - - const batchSize = 3 - runResults := make([]*types.Result, batchSize) - traceResults := make([]json.RawMessage, batchSize) - uploaded := make(chan struct{}, batchSize) - uploadedVals := make(map[string]json.RawMessage) - blockID := flow.Identifier{0x02} - - uploader := &testutils.MockUploader{ - UploadFunc: func(id string, message json.RawMessage) error { - uploadedVals[id] = message - uploaded <- struct{}{} - return nil - }, - } - - tracer, err := debug.NewEVMCallTracer(uploader, zerolog.Nop()) - require.NoError(t, err) - tracer.WithBlockID(blockID) - - em := &testutils.TestEmulator{ - BatchRunTransactionFunc: func(txs []*gethTypes.Transaction) ([]*types.Result, error) { - runResults = make([]*types.Result, len(txs)) - tr := tracer.TxTracer() - for i, tx := range txs { - from := gethCommon.Address{byte(i)} - tr.OnTxStart(nil, tx, from) - tr.OnEnter(0, 0, from, *tx.To(), []byte{0x01, 0x02}, 10, big.NewInt(1)) - tr.OnExit(0, []byte{0x02}, 200, nil, false) - tr.OnTxEnd(&gethTypes.Receipt{TxHash: tx.Hash()}, nil) - runResults[i] = &types.Result{ - TxHash: tx.Hash(), - Logs: []*gethTypes.Log{ - testutils.GetRandomLogFixture(t), - }, - } - traceResults[i] = tracer.GetResultByTxHash(tx.Hash()) - } - return runResults, nil - }, - BalanceOfFunc: func(address types.Address) (*big.Int, error) { - return big.NewInt(0), nil - }, - } - - handler := handler.NewContractHandler(chainID, rootAddr, flowTokenAddress, randomBeaconAddress, bs, aa, backend, em, tracer) - - coinbase := types.NewAddress(gethCommon.Address{}) - - txs := make([][]byte, batchSize) - for i := range txs { - txs[i] = eoa.PrepareSignAndEncodeTx( - t, - gethCommon.Address{}, - nil, - nil, - 100_000, - big.NewInt(1), - ) - } - - _ = handler.BatchRun(txs, coinbase) - - for i := 0; i < batchSize; i++ { - assert.Eventuallyf(t, func() bool { - <-uploaded - return true - }, time.Second, time.Millisecond*100, "upload not executed") - } - - for i, r := range runResults { - id := debug.TraceID(r.TxHash, blockID) - val, ok := uploadedVals[id] - require.True(t, ok) - require.Equal(t, traceResults[i], val) - } - }) - }) - }) - }) - t.Run("test - open tracing", func(t *testing.T) { t.Parallel() @@ -1465,7 +1229,7 @@ func TestHandler_Metrics(t *testing.T) { handler.NewAddressAllocator(), backend, em, - debug.NopTracer) + ) tx := eoa.PrepareSignAndEncodeTx( t, @@ -1557,6 +1321,5 @@ func SetupHandler(t testing.TB, backend types.Backend, rootAddr flow.Address) *h handler.NewAddressAllocator(), backend, emulator.NewEmulator(backend, rootAddr), - debug.NopTracer, ) } diff --git a/fvm/evm/testutils/handler.go b/fvm/evm/testutils/handler.go index 27081a5c778..ce895a5661b 100644 --- a/fvm/evm/testutils/handler.go +++ b/fvm/evm/testutils/handler.go @@ -3,7 +3,6 @@ package testutils import ( "github.com/onflow/cadence/common" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/handler" "github.com/onflow/flow-go/fvm/evm/types" @@ -25,7 +24,6 @@ func SetupHandler( handler.NewAddressAllocator(), backend, emulator.NewEmulator(backend, rootAddr), - debug.NopTracer, ) } diff --git a/fvm/script.go b/fvm/script.go index 4d8a86323b8..728bf236c0e 100644 --- a/fvm/script.go +++ b/fvm/script.go @@ -11,7 +11,6 @@ import ( "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm" - "github.com/onflow/flow-go/fvm/evm/debug" "github.com/onflow/flow-go/fvm/storage" "github.com/onflow/flow-go/fvm/storage/logical" "github.com/onflow/flow-go/model/flow" @@ -207,7 +206,6 @@ func (executor *scriptExecutor) executeScript() error { chain.ChainID(), executor.env, rt.ScriptRuntimeEnv, - debug.NopTracer, // we shouldn't trace during script execution ) if err != nil { return err diff --git a/fvm/transactionInvoker.go b/fvm/transactionInvoker.go index 6edf2ec5405..893687ee548 100644 --- a/fvm/transactionInvoker.go +++ b/fvm/transactionInvoker.go @@ -196,7 +196,6 @@ func (executor *transactionExecutor) preprocessTransactionBody() error { chain.ChainID(), executor.env, executor.cadenceRuntime.TxRuntimeEnv, - executor.ctx.EVMTracer, ) if err != nil { return err @@ -264,7 +263,6 @@ func (executor *transactionExecutor) ExecuteTransactionBody() error { chain.ChainID(), executor.env, executor.cadenceRuntime.TxRuntimeEnv, - executor.ctx.EVMTracer, ) if err != nil { return err