diff --git a/state/runtime/instrumentation/tracers/structlogger/structlogger.go b/state/runtime/instrumentation/tracers/structlogger/structlogger.go index 3a4cf037ad..bd9e20afd3 100644 --- a/state/runtime/instrumentation/tracers/structlogger/structlogger.go +++ b/state/runtime/instrumentation/tracers/structlogger/structlogger.go @@ -27,6 +27,7 @@ type StructLogRes struct { Depth int `json:"depth"` Error string `json:"error,omitempty"` Stack *[]string `json:"stack,omitempty"` + ReturnData *string `json:"returnData,omitempty"` Memory *[]string `json:"memory,omitempty"` Storage *map[string]string `json:"storage,omitempty"` RefundCounter uint64 `json:"refund,omitempty"` @@ -123,6 +124,14 @@ func (l *JSONLogger) ParseTrace(result *runtime.ExecutionResult, receipt types.R structLogRes.Storage = &storage } + var returnData *string + if l.cfg.EnableReturnData && len(step.ReturnData) > 0 { + rd := hex.EncodeToHex(step.ReturnData) + returnData = &rd + } + + structLogRes.ReturnData = returnData + structLogs = append(structLogs, structLogRes) } diff --git a/state/trace.go b/state/trace.go index a1c367f067..4fcca8f08d 100644 --- a/state/trace.go +++ b/state/trace.go @@ -502,7 +502,8 @@ func (s *State) buildTrace(evm *fakevm.FakeEVM, result *runtime.ExecutionResult, } // Populate the step memory for future steps - step.Memory = memory.Data() + step.Memory = make([]byte, len(memory.Data())) + copy(step.Memory[0:], memory.Data()[0:]) // set Contract contract := fakevm.NewContract( diff --git a/test/contracts/auto/Sha.sol b/test/contracts/auto/Sha.sol new file mode 100644 index 0000000000..90621e59d2 --- /dev/null +++ b/test/contracts/auto/Sha.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.4; + +contract Sha { + function hash() public { + sha256("hello world"); + } +} diff --git a/test/contracts/bin/Sha/Sha.go b/test/contracts/bin/Sha/Sha.go new file mode 100644 index 0000000000..887d168db1 --- /dev/null +++ b/test/contracts/bin/Sha/Sha.go @@ -0,0 +1,224 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package Sha + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// ShaMetaData contains all meta data concerning the Sha contract. +var ShaMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"name\":\"hash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5060dd8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806309bd5a6014602d575b600080fd5b60336035565b005b6040516a1a195b1b1bc81ddbdc9b1960aa1b8152600290600b01602060405180830381855afa158015606b573d6000803e3d6000fd5b5050506040513d601f19601f82011682018060405250810190608c9190608f565b50565b60006020828403121560a057600080fd5b505191905056fea2646970667358221220fe50f9cdaf095e844b048d17690c0862e54c7d7b550c4e2d9045215198e571d564736f6c634300080c0033", +} + +// ShaABI is the input ABI used to generate the binding from. +// Deprecated: Use ShaMetaData.ABI instead. +var ShaABI = ShaMetaData.ABI + +// ShaBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use ShaMetaData.Bin instead. +var ShaBin = ShaMetaData.Bin + +// DeploySha deploys a new Ethereum contract, binding an instance of Sha to it. +func DeploySha(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *Sha, error) { + parsed, err := ShaMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ShaBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &Sha{ShaCaller: ShaCaller{contract: contract}, ShaTransactor: ShaTransactor{contract: contract}, ShaFilterer: ShaFilterer{contract: contract}}, nil +} + +// Sha is an auto generated Go binding around an Ethereum contract. +type Sha struct { + ShaCaller // Read-only binding to the contract + ShaTransactor // Write-only binding to the contract + ShaFilterer // Log filterer for contract events +} + +// ShaCaller is an auto generated read-only Go binding around an Ethereum contract. +type ShaCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ShaTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ShaTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ShaFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ShaFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ShaSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ShaSession struct { + Contract *Sha // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ShaCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ShaCallerSession struct { + Contract *ShaCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ShaTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ShaTransactorSession struct { + Contract *ShaTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ShaRaw is an auto generated low-level Go binding around an Ethereum contract. +type ShaRaw struct { + Contract *Sha // Generic contract binding to access the raw methods on +} + +// ShaCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ShaCallerRaw struct { + Contract *ShaCaller // Generic read-only contract binding to access the raw methods on +} + +// ShaTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ShaTransactorRaw struct { + Contract *ShaTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSha creates a new instance of Sha, bound to a specific deployed contract. +func NewSha(address common.Address, backend bind.ContractBackend) (*Sha, error) { + contract, err := bindSha(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Sha{ShaCaller: ShaCaller{contract: contract}, ShaTransactor: ShaTransactor{contract: contract}, ShaFilterer: ShaFilterer{contract: contract}}, nil +} + +// NewShaCaller creates a new read-only instance of Sha, bound to a specific deployed contract. +func NewShaCaller(address common.Address, caller bind.ContractCaller) (*ShaCaller, error) { + contract, err := bindSha(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ShaCaller{contract: contract}, nil +} + +// NewShaTransactor creates a new write-only instance of Sha, bound to a specific deployed contract. +func NewShaTransactor(address common.Address, transactor bind.ContractTransactor) (*ShaTransactor, error) { + contract, err := bindSha(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ShaTransactor{contract: contract}, nil +} + +// NewShaFilterer creates a new log filterer instance of Sha, bound to a specific deployed contract. +func NewShaFilterer(address common.Address, filterer bind.ContractFilterer) (*ShaFilterer, error) { + contract, err := bindSha(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ShaFilterer{contract: contract}, nil +} + +// bindSha binds a generic wrapper to an already deployed contract. +func bindSha(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := ShaMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Sha *ShaRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Sha.Contract.ShaCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Sha *ShaRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Sha.Contract.ShaTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Sha *ShaRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Sha.Contract.ShaTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Sha *ShaCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Sha.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Sha *ShaTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Sha.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Sha *ShaTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Sha.Contract.contract.Transact(opts, method, params...) +} + +// Hash is a paid mutator transaction binding the contract method 0x09bd5a60. +// +// Solidity: function hash() returns() +func (_Sha *ShaTransactor) Hash(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Sha.contract.Transact(opts, "hash") +} + +// Hash is a paid mutator transaction binding the contract method 0x09bd5a60. +// +// Solidity: function hash() returns() +func (_Sha *ShaSession) Hash() (*types.Transaction, error) { + return _Sha.Contract.Hash(&_Sha.TransactOpts) +} + +// Hash is a paid mutator transaction binding the contract method 0x09bd5a60. +// +// Solidity: function hash() returns() +func (_Sha *ShaTransactorSession) Hash() (*types.Transaction, error) { + return _Sha.Contract.Hash(&_Sha.TransactOpts) +} diff --git a/test/contracts/bin/triggerErrors/triggerErrors.go b/test/contracts/bin/triggerErrors/triggerErrors.go index d3778b808b..4fede2d110 100644 --- a/test/contracts/bin/triggerErrors/triggerErrors.go +++ b/test/contracts/bin/triggerErrors/triggerErrors.go @@ -32,7 +32,7 @@ var ( // TriggerErrorsMetaData contains all meta data concerning the TriggerErrors contract. var TriggerErrorsMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersKeccaks\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"test\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersPoseidon\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfCountersSteps\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"outOfGas\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040526000805534801561001457600080fd5b5061016c806100246000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806306661abd1461005c5780632621002a1461007757806331fe52e8146100835780638bd7b5381461008d578063cb4e8cd114610095575b600080fd5b61006560005481565b60405190815260200160405180910390f35b620f4240600020610065565b61008b61009d565b005b61008b6100c3565b61008b6100e9565b60005b60648110156100c0578060005580806100b89061010d565b9150506100a0565b50565b60005b620186a08110156100c0576104d2600052806100e18161010d565b9150506100c6565b60005b61c3508110156100c0578060005580806101059061010d565b9150506100ec565b600060001982141561012f57634e487b7160e01b600052601160045260246000fd5b506001019056fea264697066735822122097beacfaa873e4896937143dfea406cc278b929a28023f7e7020b6dea6e9fc7364736f6c634300080c0033", + Bin: "0x60806040526000805534801561001457600080fd5b5061016c806100246000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806306661abd1461005c5780632621002a1461007757806331fe52e8146100835780638bd7b5381461008d578063cb4e8cd114610095575b600080fd5b61006560005481565b60405190815260200160405180910390f35b620f4240600020610065565b61008b61009d565b005b61008b6100c3565b61008b6100e9565b60005b60648110156100c0578060005580806100b89061010d565b9150506100a0565b50565b60005b620186a08110156100c0576104d2600052806100e18161010d565b9150506100c6565b60005b61c3508110156100c0578060005580806101059061010d565b9150506100ec565b600060001982141561012f57634e487b7160e01b600052601160045260246000fd5b506001019056fea26469706673582212208f01c5dc055b1f376f5da5deb33e2c96ee776174bf48874c5ebba0f606de2ac564736f6c634300080c0033", } // TriggerErrorsABI is the input ABI used to generate the binding from. diff --git a/test/e2e/debug_calltracer_test.go b/test/e2e/debug_calltracer_test.go index f2a8d756fe..1c28e132c4 100644 --- a/test/e2e/debug_calltracer_test.go +++ b/test/e2e/debug_calltracer_test.go @@ -107,6 +107,7 @@ func TestDebugTraceTransactionCallTracer(t *testing.T) { {name: "log0 all zeros", prepare: prepareLog0, createSignedTx: createLog0AllZeros}, {name: "log0 empty", prepare: prepareLog0, createSignedTx: createLog0Empty}, {name: "log0 short", prepare: prepareLog0, createSignedTx: createLog0Short}, + {name: "sha256", prepare: prepareSha256, createSignedTx: createSha256}, // failed transactions {name: "sc deployment reverted", createSignedTx: createScDeployRevertedSignedTx}, diff --git a/test/e2e/debug_shared.go b/test/e2e/debug_shared.go index f0c78ed663..67fc4dbeb8 100644 --- a/test/e2e/debug_shared.go +++ b/test/e2e/debug_shared.go @@ -30,6 +30,7 @@ import ( "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Memory" "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/OpCallAux" "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Revert2" + "github.com/0xPolygonHermez/zkevm-node/test/contracts/bin/Sha" "github.com/0xPolygonHermez/zkevm-node/test/operations" "github.com/0xPolygonHermez/zkevm-node/test/testutils" "github.com/ethereum/go-ethereum" @@ -953,3 +954,29 @@ func createLog0Short(t *testing.T, ctx context.Context, auth *bind.TransactOpts, return tx, nil } + +func prepareSha256(t *testing.T, ctx context.Context, auth *bind.TransactOpts, client *ethclient.Client) (map[string]interface{}, error) { + _, tx, sc, err := Sha.DeploySha(auth, client) + require.NoError(t, err) + + err = operations.WaitTxToBeMined(ctx, client, tx, operations.DefaultTimeoutTxToBeMined) + require.NoError(t, err) + + return map[string]interface{}{ + "sc": sc, + }, nil +} + +func createSha256(t *testing.T, ctx context.Context, auth *bind.TransactOpts, client *ethclient.Client, customData map[string]interface{}) (*ethTypes.Transaction, error) { + scInterface := customData["sc"] + sc := scInterface.(*Sha.Sha) + + opts := *auth + opts.NoSend = true + opts.GasLimit = fixedTxGasLimit + + tx, err := sc.Hash(&opts) + require.NoError(t, err) + + return tx, nil +} diff --git a/test/e2e/debug_test.go b/test/e2e/debug_test.go index 0e425b4f6e..7923e67446 100644 --- a/test/e2e/debug_test.go +++ b/test/e2e/debug_test.go @@ -321,6 +321,7 @@ func TestDebugTraceTransaction(t *testing.T) { {name: "log0 all zeros", prepare: prepareLog0, createSignedTx: createLog0AllZeros}, {name: "log0 empty", prepare: prepareLog0, createSignedTx: createLog0Empty}, {name: "log0 short", prepare: prepareLog0, createSignedTx: createLog0Short}, + {name: "sha256", prepare: prepareSha256, createSignedTx: createSha256}, // failed transactions {name: "sc deployment reverted", createSignedTx: createScDeployRevertedSignedTx}, @@ -479,20 +480,27 @@ func TestDebugTraceTransaction(t *testing.T) { referenceStructLogMap := referenceStructLogsMap[structLogIndex].(map[string]interface{}) resultStructLogMap := resultStructLogsMap[structLogIndex].(map[string]interface{}) - require.Equal(t, referenceStructLogMap["pc"], resultStructLogMap["pc"], fmt.Sprintf("invalid struct log pc for network %s", networkName)) - require.Equal(t, referenceStructLogMap["op"], resultStructLogMap["op"], fmt.Sprintf("invalid struct log op for network %s", networkName)) - require.Equal(t, referenceStructLogMap["depth"], resultStructLogMap["depth"], fmt.Sprintf("invalid struct log depth for network %s", networkName)) + referencePC := referenceStructLogMap["pc"] + referenceOP := referenceStructLogMap["op"] - pc := referenceStructLogMap["pc"] - op := referenceStructLogMap["op"] + require.Equal(t, referencePC, resultStructLogMap["pc"], fmt.Sprintf("invalid struct log pc for network %s", networkName)) + require.Equal(t, referenceOP, resultStructLogMap["op"], fmt.Sprintf("invalid struct log op for network %s pc %v", networkName, referencePC)) + require.Equal(t, referenceStructLogMap["depth"], resultStructLogMap["depth"], fmt.Sprintf("invalid struct log depth for network %s pc %v op %v", networkName, referencePC, referenceOP)) + + referenceReturnData, found := referenceStructLogMap["returnData"].([]interface{}) + if found { + resultReturnData := resultStructLogMap["returnData"].([]interface{}) + + require.Equal(t, referenceReturnData, resultReturnData, fmt.Sprintf("return data doesn't match for pc %v op %v", referencePC, referenceOP)) + } referenceStack, found := referenceStructLogMap["stack"].([]interface{}) if found { resultStack := resultStructLogMap["stack"].([]interface{}) - require.Equal(t, len(referenceStack), len(resultStack), fmt.Sprintf("stack size doesn't match for pc %v op %v", pc, op)) + require.Equal(t, len(referenceStack), len(resultStack), fmt.Sprintf("stack size doesn't match for pc %v op %v", referencePC, referenceOP)) for stackIndex := range referenceStack { - require.Equal(t, referenceStack[stackIndex], resultStack[stackIndex], fmt.Sprintf("stack index %v doesn't match for pc %v op %v", stackIndex, pc, op)) + require.Equal(t, referenceStack[stackIndex], resultStack[stackIndex], fmt.Sprintf("stack index %v doesn't match for pc %v op %v", stackIndex, referencePC, referenceOP)) } } @@ -500,9 +508,9 @@ func TestDebugTraceTransaction(t *testing.T) { if found { resultMemory := resultStructLogMap["memory"].([]interface{}) - require.Equal(t, len(referenceMemory), len(resultMemory), fmt.Sprintf("memory size doesn't match for pc %v op %v", pc, op)) + require.Equal(t, len(referenceMemory), len(resultMemory), fmt.Sprintf("memory size doesn't match for pc %v op %v", referencePC, referenceOP)) for memoryIndex := range referenceMemory { - require.Equal(t, referenceMemory[memoryIndex], resultMemory[memoryIndex], fmt.Sprintf("memory index %v doesn't match for pc %v op %v", memoryIndex, pc, op)) + require.Equal(t, referenceMemory[memoryIndex], resultMemory[memoryIndex], fmt.Sprintf("memory index %v doesn't match for pc %v op %v", memoryIndex, referencePC, referenceOP)) } } @@ -510,11 +518,11 @@ func TestDebugTraceTransaction(t *testing.T) { if found { resultStorage := resultStructLogMap["storage"].(map[string]interface{}) - require.Equal(t, len(referenceStorage), len(resultStorage), fmt.Sprintf("storage size doesn't match for pc %v op %v", pc, op)) + require.Equal(t, len(referenceStorage), len(resultStorage), fmt.Sprintf("storage size doesn't match for pc %v op %v", referencePC, referenceOP)) for storageKey, referenceStorageValue := range referenceStorage { resultStorageValue, found := resultStorage[storageKey] require.True(t, found, "storage address not found") - require.Equal(t, referenceStorageValue, resultStorageValue, fmt.Sprintf("storage value doesn't match for address %v for pc %v op %v", storageKey, pc, op)) + require.Equal(t, referenceStorageValue, resultStorageValue, fmt.Sprintf("storage value doesn't match for address %v for pc %v op %v", storageKey, referencePC, referenceOP)) } } }