diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index 4ee67918dda..416e2b58d0e 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -113,12 +113,12 @@ func (bl *BlockView) DirectCall(call *types.DirectCall) (*types.Result, error) { } switch call.SubType { case types.DepositCallSubType: - return proc.mintTo(call.To, call.Value) + return proc.mintTo(call.To, call.Value, txHash) case types.WithdrawCallSubType: - return proc.withdrawFrom(call.From, call.Value) + return proc.withdrawFrom(call.From, call.Value, txHash) case types.DeployCallSubType: if !call.EmptyToField() { - return proc.deployAt(call.From, call.To, call.Data, call.GasLimit, call.Value) + return proc.deployAt(call.From, call.To, call.Data, call.GasLimit, call.Value, txHash) } fallthrough default: @@ -199,11 +199,16 @@ func (proc *procedure) commit() error { return nil } -func (proc *procedure) mintTo(address types.Address, amount *big.Int) (*types.Result, error) { +func (proc *procedure) mintTo( + address types.Address, + amount *big.Int, + txHash gethCommon.Hash, +) (*types.Result, error) { addr := address.ToCommon() res := &types.Result{ GasConsumed: proc.config.DirectCallBaseGasUsage, TxType: types.DirectCallTxType, + TxHash: txHash, } // create account if not exist @@ -218,12 +223,17 @@ func (proc *procedure) mintTo(address types.Address, amount *big.Int) (*types.Re return res, proc.commit() } -func (proc *procedure) withdrawFrom(address types.Address, amount *big.Int) (*types.Result, error) { +func (proc *procedure) withdrawFrom( + address types.Address, + amount *big.Int, + txHash gethCommon.Hash, +) (*types.Result, error) { addr := address.ToCommon() res := &types.Result{ GasConsumed: proc.config.DirectCallBaseGasUsage, TxType: types.DirectCallTxType, + TxHash: txHash, } // check if account exists @@ -264,6 +274,7 @@ func (proc *procedure) deployAt( data types.Code, gasLimit uint64, value *big.Int, + txHash gethCommon.Hash, ) (*types.Result, error) { if value.Sign() < 0 { return nil, types.ErrInvalidBalance @@ -271,6 +282,7 @@ func (proc *procedure) deployAt( res := &types.Result{ TxType: types.DirectCallTxType, + TxHash: txHash, } addr := to.ToCommon() diff --git a/fvm/evm/emulator/emulator_test.go b/fvm/evm/emulator/emulator_test.go index 619a0587bd0..77c0f75c928 100644 --- a/fvm/evm/emulator/emulator_test.go +++ b/fvm/evm/emulator/emulator_test.go @@ -48,9 +48,13 @@ func TestNativeTokenBridging(t *testing.T) { t.Run("mint tokens to the first account", func(t *testing.T) { RunWithNewEmulator(t, backend, rootAddr, func(env *emulator.Emulator) { RunWithNewBlockView(t, env, func(blk types.BlockView) { - res, err := blk.DirectCall(types.NewDepositCall(testAccount, originalBalance, nonce)) + call := types.NewDepositCall(testAccount, originalBalance, nonce) + res, err := blk.DirectCall(call) require.NoError(t, err) require.Equal(t, defaultCtx.DirectCallBaseGasUsage, res.GasConsumed) + expectedHash, err := call.Hash() + require.NoError(t, err) + require.Equal(t, expectedHash, res.TxHash) nonce += 1 }) }) @@ -66,9 +70,13 @@ func TestNativeTokenBridging(t *testing.T) { }) RunWithNewEmulator(t, backend, rootAddr, func(env *emulator.Emulator) { RunWithNewBlockView(t, env, func(blk types.BlockView) { - res, err := blk.DirectCall(types.NewWithdrawCall(testAccount, amount, nonce)) + call := types.NewWithdrawCall(testAccount, amount, nonce) + res, err := blk.DirectCall(call) require.NoError(t, err) require.Equal(t, defaultCtx.DirectCallBaseGasUsage, res.GasConsumed) + expectedHash, err := call.Hash() + require.NoError(t, err) + require.Equal(t, expectedHash, res.TxHash) nonce += 1 }) }) @@ -111,16 +119,18 @@ func TestContractInteraction(t *testing.T) { t.Run("deploy contract", func(t *testing.T) { RunWithNewEmulator(t, backend, rootAddr, func(env *emulator.Emulator) { RunWithNewBlockView(t, env, func(blk types.BlockView) { - res, err := blk.DirectCall( - types.NewDeployCall( - testAccount, - testContract.ByteCode, - math.MaxUint64, - amountToBeTransfered, - nonce), - ) + call := types.NewDeployCall( + testAccount, + testContract.ByteCode, + math.MaxUint64, + amountToBeTransfered, + nonce) + res, err := blk.DirectCall(call) require.NoError(t, err) contractAddr = res.DeployedContractAddress + expectedHash, err := call.Hash() + require.NoError(t, err) + require.Equal(t, expectedHash, res.TxHash) nonce += 1 }) RunWithNewReadOnlyBlockView(t, env, func(blk types.ReadOnlyBlockView) { diff --git a/fvm/evm/types/call.go b/fvm/evm/types/call.go index 43f4cc2b36e..c16fea37af7 100644 --- a/fvm/evm/types/call.go +++ b/fvm/evm/types/call.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" gethCommon "github.com/ethereum/go-ethereum/common" @@ -51,6 +52,15 @@ type DirectCall struct { Nonce uint64 } +// DirectCallFromEncoded constructs a DirectCall from encoded data +func DirectCallFromEncoded(encoded []byte) (*DirectCall, error) { + if encoded[0] != DirectCallTxType { + return nil, fmt.Errorf("tx type mismatch") + } + dc := &DirectCall{} + return dc, rlp.DecodeBytes(encoded[1:], dc) +} + // Encode encodes the direct call it also adds the type // as the very first byte, similar to how evm encodes types. func (dc *DirectCall) Encode() ([]byte, error) {