github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/integration/rpctransact/call_test.go (about)

     1  // +build integration
     2  
     3  package rpctransact
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"fmt"
     9  	"math/big"
    10  	"sync"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/burrow/execution/errors"
    14  	"github.com/hyperledger/burrow/execution/evm/abi"
    15  	"golang.org/x/crypto/sha3"
    16  
    17  	"github.com/hyperledger/burrow/integration"
    18  
    19  	"github.com/hyperledger/burrow/binary"
    20  	"github.com/hyperledger/burrow/core"
    21  	"github.com/hyperledger/burrow/crypto"
    22  	"github.com/hyperledger/burrow/execution/evm/asm"
    23  	"github.com/hyperledger/burrow/execution/evm/asm/bc"
    24  	"github.com/hyperledger/burrow/execution/exec"
    25  	"github.com/hyperledger/burrow/execution/solidity"
    26  	"github.com/hyperledger/burrow/integration/rpctest"
    27  	"github.com/hyperledger/burrow/rpc/rpcquery"
    28  	"github.com/hyperledger/burrow/rpc/rpctransact"
    29  	"github.com/hyperledger/burrow/txs/payload"
    30  	"github.com/stretchr/testify/assert"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func TestCallTx(t *testing.T) {
    35  	kern, shutdown := integration.RunNode(t, rpctest.GenesisDoc, rpctest.PrivateAccounts)
    36  	defer shutdown()
    37  	t.Parallel()
    38  	testCallTx(t, kern, rpctest.NewTransactClient(t, kern.GRPCListenAddress().String()))
    39  }
    40  
    41  func TestCallTxNoConsensus(t *testing.T) {
    42  	kern, shutdown := integration.RunNode(t, rpctest.GenesisDoc, rpctest.PrivateAccounts, integration.NoConsensus)
    43  	t.Parallel()
    44  	defer shutdown()
    45  	testCallTx(t, kern, rpctest.NewTransactClient(t, kern.GRPCListenAddress().String()))
    46  }
    47  
    48  func TestCallTxNoConsensusCommitImmediately(t *testing.T) {
    49  	kern, shutdown := integration.RunNode(t, rpctest.GenesisDoc, rpctest.PrivateAccounts, integration.NoConsensus, integration.CommitImmediately)
    50  	t.Parallel()
    51  	defer shutdown()
    52  	testCallTx(t, kern, rpctest.NewTransactClient(t, kern.GRPCListenAddress().String()))
    53  }
    54  
    55  func testCallTx(t *testing.T, kern *core.Kernel, cli rpctransact.TransactClient) {
    56  	// We need an outer group so that the defer does not run before all parallel tests have run. TestCallTx will block
    57  	// until all it's parallel tests have run, but that is after any statements or defers have run
    58  	t.Run("Group", func(t *testing.T) {
    59  		t.Run("NoCode", func(t *testing.T) {
    60  			t.Parallel()
    61  			// Flip flops between sending private key and input address to test private key and address based signing
    62  			toAddress := rpctest.PrivateAccounts[2].GetAddress()
    63  
    64  			numCreates := 1000
    65  			expecter := rpctest.ExpectTxs(kern.Emitter, "NoCode")
    66  			for i := 0; i < numCreates; i++ {
    67  				receipt, err := cli.CallTxAsync(context.Background(), &payload.CallTx{
    68  					Input: &payload.TxInput{
    69  						Address: inputAddress,
    70  						Amount:  2,
    71  					},
    72  					Address:  &toAddress,
    73  					Data:     []byte{},
    74  					Fee:      2,
    75  					GasLimit: 10000 + uint64(i),
    76  				})
    77  				require.NoError(t, err)
    78  				expecter.Expect(receipt.TxHash)
    79  				assert.False(t, receipt.CreatesContract)
    80  				assert.Equal(t, toAddress, receipt.ContractAddress)
    81  			}
    82  			expecter.AssertCommitted(t)
    83  		})
    84  
    85  		t.Run("CreateContract", func(t *testing.T) {
    86  			t.Parallel()
    87  			numGoroutines := 100
    88  			numCreates := 50
    89  			wg := new(sync.WaitGroup)
    90  			wg.Add(numGoroutines)
    91  			errCh := make(chan error, 2*numGoroutines)
    92  			expecter := rpctest.ExpectTxs(kern.Emitter, "CreateContract")
    93  			for i := 0; i < numGoroutines; i++ {
    94  				go func() {
    95  					defer wg.Done()
    96  					for j := 0; j < numCreates; j++ {
    97  						receipt, err := cli.CallTxAsync(context.Background(), &payload.CallTx{
    98  							Input: &payload.TxInput{
    99  								Address: inputAddress,
   100  								Amount:  2,
   101  							},
   102  							Address:  nil,
   103  							Data:     solidity.Bytecode_StrangeLoop,
   104  							Fee:      2,
   105  							GasLimit: 10000,
   106  						})
   107  						if err != nil {
   108  							errCh <- err
   109  							return
   110  						}
   111  						if !receipt.CreatesContract {
   112  							errCh <- fmt.Errorf("should have created contract")
   113  						}
   114  						expecter.Expect(receipt.TxHash)
   115  					}
   116  				}()
   117  			}
   118  			wg.Wait()
   119  			close(errCh)
   120  			for err := range errCh {
   121  				require.NoError(t, err)
   122  			}
   123  
   124  			expecter.AssertCommitted(t)
   125  		})
   126  
   127  		t.Run("Sync", func(t *testing.T) {
   128  			t.Parallel()
   129  			numGoroutines := 40
   130  			numRuns := 5
   131  			spec, err := abi.ReadSpec(solidity.Abi_StrangeLoop)
   132  			require.NoError(t, err)
   133  			data, _, err := spec.Pack("UpsieDownsie")
   134  			require.NoError(t, err)
   135  			expecter := rpctest.ExpectTxs(kern.Emitter, "Sync")
   136  			errCh := make(chan error, 2*numGoroutines)
   137  			wg := new(sync.WaitGroup)
   138  			wg.Add(numGoroutines)
   139  			for i := 0; i < numGoroutines; i++ {
   140  				go func() {
   141  					defer wg.Done()
   142  					for j := 0; j < numRuns; j++ {
   143  						createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_StrangeLoop, nil)
   144  						if err != nil {
   145  							errCh <- err
   146  							return
   147  						}
   148  						expecter.Expect(createTxe.TxHash)
   149  						callTxe, err := rpctest.CallContract(cli, inputAddress, lastCall(createTxe.Events).CallData.Callee, data)
   150  						if err != nil {
   151  							errCh <- err
   152  							return
   153  						}
   154  						expecter.Expect(callTxe.TxHash)
   155  						var depth int64
   156  						err = spec.Unpack(lastCall(callTxe.Events).Return, "UpsieDownsie", &depth)
   157  						if err != nil {
   158  							errCh <- err
   159  							return
   160  						}
   161  						// Would give 23 if taken from wrong frame (i.e. not the outer stackdepth == 0 one)
   162  						assert.Equal(t, 18, int(depth))
   163  					}
   164  				}()
   165  			}
   166  			wg.Wait()
   167  			close(errCh)
   168  			for err := range errCh {
   169  				require.NoError(t, err)
   170  			}
   171  			expecter.AssertCommitted(t)
   172  		})
   173  
   174  		t.Run("CallCodeSim", func(t *testing.T) {
   175  			t.Parallel()
   176  			// add two integers and return the result
   177  			var i, j byte = 123, 21
   178  			_, contractCode, expectedReturn := simpleContract(i, j)
   179  			txe, err := cli.CallCodeSim(context.Background(), &rpctransact.CallCodeParam{
   180  				FromAddress: inputAddress,
   181  				Code:        contractCode,
   182  			})
   183  			require.NoError(t, err)
   184  			assert.Equal(t, expectedReturn, txe.Result.Return)
   185  
   186  			// pass two ints as calldata, add, and return the result
   187  			txe, err = cli.CallCodeSim(context.Background(), &rpctransact.CallCodeParam{
   188  				FromAddress: inputAddress,
   189  				Code: bc.MustSplice(asm.PUSH1, 0x0, asm.CALLDATALOAD, asm.PUSH1, 0x20, asm.CALLDATALOAD, asm.ADD, asm.PUSH1,
   190  					0x0, asm.MSTORE, asm.PUSH1, 0x20, asm.PUSH1, 0x0, asm.RETURN),
   191  				Data: bc.MustSplice(binary.LeftPadWord256([]byte{i}), binary.LeftPadWord256([]byte{j})),
   192  			})
   193  			require.NoError(t, err)
   194  			assert.Equal(t, expectedReturn, txe.Result.Return)
   195  			return
   196  		})
   197  
   198  		t.Run("CallContract", func(t *testing.T) {
   199  			t.Parallel()
   200  			initCode, _, expectedReturn := simpleContract(43, 1)
   201  			txe, err := cli.CallTxSync(context.Background(), &payload.CallTx{
   202  				Input: &payload.TxInput{
   203  					Address: inputAddress,
   204  					Amount:  uint64(6969),
   205  				},
   206  				Address:  nil,
   207  				Data:     initCode,
   208  				Fee:      uint64(1000),
   209  				GasLimit: uint64(1000),
   210  			})
   211  			require.NoError(t, err)
   212  			assert.Equal(t, true, txe.Receipt.CreatesContract, "This transaction should"+
   213  				" create a contract")
   214  			assert.NotEqual(t, 0, len(txe.TxHash), "Receipt should contain a"+
   215  				" transaction hash")
   216  			contractAddress := txe.Receipt.ContractAddress
   217  			assert.NotEqual(t, crypto.ZeroAddress, contractAddress, "Transactions claims to have"+
   218  				" created a contract but the contract address is empty")
   219  
   220  			txe, err = cli.CallTxSync(context.Background(), &payload.CallTx{
   221  				Input: &payload.TxInput{
   222  					Address: inputAddress,
   223  					Amount:  uint64(6969),
   224  				},
   225  				Address:  &contractAddress,
   226  				Fee:      uint64(1000),
   227  				GasLimit: uint64(1000),
   228  			})
   229  			require.NoError(t, err)
   230  
   231  			assert.Equal(t, expectedReturn, txe.Result.Return)
   232  			return
   233  		})
   234  
   235  		t.Run("NestedCall", func(t *testing.T) {
   236  			t.Parallel()
   237  			// create two contracts, one of which calls the other
   238  			code, _, expectedReturn := simpleContract(5, 6)
   239  
   240  			// Deploy callee contract
   241  			txe, err := cli.CallTxSync(context.Background(), &payload.CallTx{
   242  				Input: &payload.TxInput{
   243  					Address: inputAddress,
   244  					Amount:  uint64(6969),
   245  				},
   246  				Data:     code,
   247  				GasLimit: 10000,
   248  			})
   249  			require.NoError(t, err)
   250  			assert.True(t, txe.Receipt.CreatesContract)
   251  			calleeContractAddress := txe.Receipt.ContractAddress
   252  
   253  			// Deploy caller contract
   254  			code, _, _ = simpleCallContract(calleeContractAddress)
   255  			txe, err = cli.CallTxSync(context.Background(), &payload.CallTx{
   256  				Input: &payload.TxInput{
   257  					Address: inputAddress,
   258  					Amount:  uint64(6969),
   259  				},
   260  				Data:     code,
   261  				GasLimit: 10000,
   262  			})
   263  			require.NoError(t, err)
   264  			assert.True(t, txe.Receipt.CreatesContract)
   265  			callerContractAddress := txe.Receipt.ContractAddress
   266  
   267  			// Call caller contract
   268  			txe, err = cli.CallTxSync(context.Background(), &payload.CallTx{
   269  				Input: &payload.TxInput{
   270  					Address: inputAddress,
   271  					Amount:  uint64(6969),
   272  				},
   273  				Address:  &callerContractAddress,
   274  				GasLimit: 10000,
   275  			})
   276  			require.NoError(t, err)
   277  			assert.Equal(t, expectedReturn, txe.Result.Return)
   278  			return
   279  		})
   280  
   281  		t.Run("CallEvents", func(t *testing.T) {
   282  			t.Parallel()
   283  			createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_StrangeLoop, nil)
   284  			require.NoError(t, err)
   285  			address := lastCall(createTxe.Events).CallData.Callee
   286  			spec, err := abi.ReadSpec(solidity.Abi_StrangeLoop)
   287  			require.NoError(t, err)
   288  			data, _, err := spec.Pack("UpsieDownsie")
   289  			require.NoError(t, err)
   290  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, data)
   291  			require.NoError(t, err)
   292  			callEvents := filterCalls(callTxe.Events)
   293  			require.Len(t, callEvents, rpctest.UpsieDownsieCallCount, "should see 30 recursive call events")
   294  			for i, ev := range callEvents {
   295  				assert.Equal(t, uint64(rpctest.UpsieDownsieCallCount-i-1), ev.StackDepth)
   296  			}
   297  			return
   298  		})
   299  
   300  		t.Run("DeployAbis", func(t *testing.T) {
   301  			t.Parallel()
   302  			createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_A, []rpctest.MetadataMap{
   303  				{DeployedCode: solidity.DeployedBytecode_A, Abi: solidity.Abi_A},
   304  				{DeployedCode: solidity.DeployedBytecode_B, Abi: solidity.Abi_B},
   305  				{DeployedCode: solidity.DeployedBytecode_C, Abi: solidity.Abi_C},
   306  			})
   307  			require.NoError(t, err)
   308  			addressA := lastCall(createTxe.Events).CallData.Callee
   309  			// Check ABI for new contract A
   310  			qcli := rpctest.NewQueryClient(t, kern.GRPCListenAddress().String())
   311  			res, err := qcli.GetMetadata(context.Background(), &rpcquery.GetMetadataParam{Address: &addressA})
   312  			require.NoError(t, err)
   313  			assert.Equal(t, string(solidity.Abi_A), res.Metadata)
   314  			// CreateB
   315  			spec, err := abi.ReadSpec(solidity.Abi_A)
   316  			require.NoError(t, err)
   317  			data, _, err := spec.Pack("createB")
   318  			require.NoError(t, err)
   319  			callTxe, err := rpctest.CallContract(cli, inputAddress, addressA, data)
   320  			require.NoError(t, err)
   321  			var addressB crypto.Address
   322  			err = spec.Unpack(callTxe.Result.Return, "createB", &addressB)
   323  			// check ABI for contract B
   324  			res, err = qcli.GetMetadata(context.Background(), &rpcquery.GetMetadataParam{Address: &addressB})
   325  			require.NoError(t, err)
   326  			assert.Equal(t, string(solidity.Abi_B), res.Metadata)
   327  			// CreateC
   328  			spec, err = abi.ReadSpec(solidity.Abi_B)
   329  			require.NoError(t, err)
   330  			data, _, err = spec.Pack("createC")
   331  			require.NoError(t, err)
   332  			callTxe, err = rpctest.CallContract(cli, inputAddress, addressB, data)
   333  			require.NoError(t, err)
   334  			var addressC crypto.Address
   335  			err = spec.Unpack(callTxe.Result.Return, "createC", &addressC)
   336  			// check abi for contract C
   337  			res, err = qcli.GetMetadata(context.Background(), &rpcquery.GetMetadataParam{Address: &addressC})
   338  			require.NoError(t, err)
   339  			assert.Equal(t, string(solidity.Abi_C), res.Metadata)
   340  			return
   341  		})
   342  
   343  		t.Run("LogEvents", func(t *testing.T) {
   344  			t.Parallel()
   345  			createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_StrangeLoop, nil)
   346  			require.NoError(t, err)
   347  			address := lastCall(createTxe.Events).CallData.Callee
   348  			spec, err := abi.ReadSpec(solidity.Abi_StrangeLoop)
   349  			require.NoError(t, err)
   350  			data, _, err := spec.Pack("UpsieDownsie")
   351  			require.NoError(t, err)
   352  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, data)
   353  			require.NoError(t, err)
   354  			evs := filterLogs(callTxe.Events)
   355  			require.Len(t, evs, rpctest.UpsieDownsieCallCount-2)
   356  			log := evs[0]
   357  			var direction string
   358  			var depth int64
   359  			evAbi := spec.EventsByName["ChangeLevel"]
   360  			err = abi.UnpackEvent(evAbi, log.Topics, log.Data, &direction, &depth)
   361  			require.NoError(t, err)
   362  			assert.Equal(t, evAbi.ID.Bytes(), log.Topics[0].Bytes())
   363  			assert.Equal(t, int64(18), depth)
   364  			assert.Equal(t, "Upsie!", direction)
   365  			return
   366  		})
   367  
   368  		t.Run("EventEmitter", func(t *testing.T) {
   369  			t.Parallel()
   370  			createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_EventEmitter, nil)
   371  			require.NoError(t, err)
   372  			address := lastCall(createTxe.Events).CallData.Callee
   373  			spec, err := abi.ReadSpec(solidity.Abi_EventEmitter)
   374  			require.NoError(t, err)
   375  			calldata, _, err := spec.Pack("EmitOne")
   376  			require.NoError(t, err)
   377  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, calldata)
   378  			require.NoError(t, err)
   379  			evs := filterLogs(callTxe.Events)
   380  			log := evs[0]
   381  			evAbi := spec.EventsByName["ManyTypes"]
   382  			data := abi.GetPackingTypes(evAbi.Inputs)
   383  			// Check signature
   384  			assert.Equal(t, evAbi.ID.Bytes(), log.Topics[0].Bytes())
   385  			err = abi.UnpackEvent(evAbi, log.Topics, log.Data.Bytes(), data...)
   386  			require.NoError(t, err)
   387  
   388  			h := sha3.NewLegacyKeccak256()
   389  			h.Write([]byte("hash"))
   390  			expectedHash := h.Sum(nil)
   391  			// "Downsie!", true, "Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", 102, 42, 'hash')
   392  			b := *data[0].(*[]byte)
   393  			assert.Equal(t, evAbi.ID.Bytes(), log.Topics[0].Bytes())
   394  			assert.Equal(t, "Downsie!", string(bytes.Trim(b, "\x00")))
   395  			assert.Equal(t, true, *data[1].(*bool))
   396  			assert.Equal(t, "Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", *data[2].(*string))
   397  			assert.Equal(t, int64(102), *data[3].(*int64))
   398  			assert.Equal(t, int64(42), data[4].(*big.Int).Int64())
   399  			assert.Equal(t, expectedHash, *data[5].(*[]byte))
   400  			return
   401  		})
   402  
   403  		t.Run("EventEmitterBytes32isString", func(t *testing.T) {
   404  			t.Parallel()
   405  			/*
   406  			 * Any indexed string (or dynamic array) will be hashed, so we might want to store strings
   407  			 * in bytes32. This shows how we would automatically map this to string
   408  			 */
   409  			createTxe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_EventEmitter, nil)
   410  			require.NoError(t, err)
   411  			address := lastCall(createTxe.Events).CallData.Callee
   412  			spec, err := abi.ReadSpec(solidity.Abi_EventEmitter)
   413  			require.NoError(t, err)
   414  			calldata, _, err := spec.Pack("EmitOne")
   415  			require.NoError(t, err)
   416  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, calldata)
   417  			require.NoError(t, err)
   418  			evs := filterLogs(callTxe.Events)
   419  			log := evs[0]
   420  			evAbi := spec.EventsByName["ManyTypes"]
   421  			data := abi.GetPackingTypes(evAbi.Inputs)
   422  			for i, a := range evAbi.Inputs {
   423  				if a.Indexed && !a.Hashed && a.EVM.GetSignature() == "bytes32" {
   424  					data[i] = new(string)
   425  				}
   426  			}
   427  			err = abi.UnpackEvent(evAbi, log.Topics, log.Data.Bytes(), data...)
   428  			require.NoError(t, err)
   429  
   430  			h := sha3.NewLegacyKeccak256()
   431  			h.Write([]byte("hash"))
   432  			expectedHash := h.Sum(nil)
   433  			// "Downsie!", true, "Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", 102, 42, 'hash')
   434  			assert.Equal(t, "Downsie!", *data[0].(*string))
   435  			assert.Equal(t, true, *data[1].(*bool))
   436  			assert.Equal(t, "Donaudampfschifffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft", *data[2].(*string))
   437  			assert.Equal(t, int64(102), *data[3].(*int64))
   438  			assert.Equal(t, int64(42), data[4].(*big.Int).Int64())
   439  			assert.Equal(t, expectedHash, *data[5].(*[]byte))
   440  			return
   441  		})
   442  
   443  		t.Run("Revert", func(t *testing.T) {
   444  			t.Parallel()
   445  			txe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_Revert, nil)
   446  			require.NoError(t, err)
   447  			spec, err := abi.ReadSpec(solidity.Abi_Revert)
   448  			require.NoError(t, err)
   449  			data, _, err := spec.Pack("RevertAt", 4)
   450  			require.NoError(t, err)
   451  			txe, err = rpctest.CallContract(cli, inputAddress, txe.Receipt.ContractAddress, data)
   452  			require.NoError(t, err)
   453  			assert.Equal(t, errors.Codes.ExecutionReverted, errors.GetCode(txe.Exception))
   454  			revertReason, err := abi.UnpackRevert(txe.Result.Return)
   455  			require.NoError(t, err)
   456  			require.NotNil(t, revertReason)
   457  			assert.Equal(t, *revertReason, "I have reverted")
   458  			return
   459  		})
   460  
   461  		t.Run("RevertWithoutReason", func(t *testing.T) {
   462  			t.Parallel()
   463  			txe, err := rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_Revert, nil)
   464  			require.NoError(t, err)
   465  			spec, err := abi.ReadSpec(solidity.Abi_Revert)
   466  			require.NoError(t, err)
   467  			data, _, err := spec.Pack("RevertNoReason")
   468  			require.NoError(t, err)
   469  			txe, err = rpctest.CallContract(cli, inputAddress, txe.Receipt.ContractAddress, data)
   470  			require.NoError(t, err)
   471  			assert.Equal(t, errors.Codes.ExecutionReverted, errors.GetCode(txe.Exception))
   472  			revertReason, err := abi.UnpackRevert(txe.Result.Return)
   473  			require.NoError(t, err)
   474  			assert.Nil(t, revertReason)
   475  			return
   476  		})
   477  
   478  		t.Run("SimpleWasm", func(t *testing.T) {
   479  			t.Parallel()
   480  			txe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   481  			require.NoError(t, err)
   482  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   483  			require.NoError(t, err)
   484  			data, _, err := spec.Pack("get_number")
   485  			require.NoError(t, err)
   486  			txe, err = rpctest.CallContract(cli, inputAddress, txe.Receipt.ContractAddress, data)
   487  			require.NoError(t, err)
   488  			var number int64
   489  			err = spec.Unpack(txe.Result.Return, "get_number", &number)
   490  			require.NoError(t, err)
   491  			assert.Equal(t, number, int64(54321))
   492  			return
   493  		})
   494  
   495  		t.Run("WasmRevertWithoutReason", func(t *testing.T) {
   496  			t.Parallel()
   497  			txe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   498  			require.NoError(t, err)
   499  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   500  			require.NoError(t, err)
   501  			data, _, err := spec.Pack("try_revert")
   502  			require.NoError(t, err)
   503  			txe, err = rpctest.CallContract(cli, inputAddress, txe.Receipt.ContractAddress, data)
   504  			require.NoError(t, err)
   505  			assert.Equal(t, errors.Codes.ExecutionReverted, errors.GetCode(txe.Exception))
   506  			revertReason, err := abi.UnpackRevert(txe.Result.Return)
   507  			require.NoError(t, err)
   508  			assert.Nil(t, revertReason)
   509  			return
   510  		})
   511  
   512  		t.Run("WasmCallEvm", func(t *testing.T) {
   513  			t.Parallel()
   514  			txe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   515  			require.NoError(t, err)
   516  			wasmContract := txe.Receipt.ContractAddress
   517  			txe, err = rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_evm, nil)
   518  			require.NoError(t, err)
   519  			evmContract := txe.Receipt.ContractAddress
   520  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   521  			require.NoError(t, err)
   522  			data, _, err := spec.Pack("call_get_vm", evmContract)
   523  			require.NoError(t, err)
   524  			txe, err = rpctest.CallContract(cli, inputAddress, wasmContract, data)
   525  			require.NoError(t, err)
   526  			var res string
   527  			err = spec.Unpack(txe.Result.Return, "call_get_vm", &res)
   528  			require.NoError(t, err)
   529  			assert.Equal(t, res, "ewasm called evm")
   530  			return
   531  		})
   532  
   533  		t.Run("EvmCallWasm", func(t *testing.T) {
   534  			t.Parallel()
   535  			txe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   536  			require.NoError(t, err)
   537  			wasmContract := txe.Receipt.ContractAddress
   538  			txe, err = rpctest.CreateEVMContract(cli, inputAddress, solidity.Bytecode_evm, nil)
   539  			require.NoError(t, err)
   540  			evmContract := txe.Receipt.ContractAddress
   541  			spec, err := abi.ReadSpec(solidity.Abi_evm)
   542  			require.NoError(t, err)
   543  			data, _, err := spec.Pack("call_get_vm", wasmContract)
   544  			require.NoError(t, err)
   545  			txe, err = rpctest.CallContract(cli, inputAddress, evmContract, data)
   546  			require.NoError(t, err)
   547  			var res string
   548  			err = spec.Unpack(txe.Result.Return, "call_get_vm", &res)
   549  			require.NoError(t, err)
   550  			assert.Equal(t, res, "evm called ewasm")
   551  			return
   552  		})
   553  
   554  		t.Run("WasmHashPrecompiles", func(t *testing.T) {
   555  			t.Parallel()
   556  			txe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   557  			require.NoError(t, err)
   558  			wasmContract := txe.Receipt.ContractAddress
   559  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   560  			require.NoError(t, err)
   561  			data, _, err := spec.Pack("hash_tests", wasmContract)
   562  			require.NoError(t, err)
   563  			txe, err = rpctest.CallContract(cli, inputAddress, wasmContract, data)
   564  			require.NoError(t, err)
   565  			return
   566  		})
   567  
   568  		t.Run("WasmLogEvents", func(t *testing.T) {
   569  			t.Parallel()
   570  			createTxe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   571  			require.NoError(t, err)
   572  			address := lastCall(createTxe.Events).CallData.Callee
   573  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   574  			require.NoError(t, err)
   575  			data, _, err := spec.Pack("test_events")
   576  			require.NoError(t, err)
   577  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, data)
   578  			require.NoError(t, err)
   579  			evs := filterLogs(callTxe.Events)
   580  			require.Len(t, evs, 1)
   581  			log := evs[0]
   582  			var f1 int64
   583  			var f2 string
   584  			var f3 bool
   585  			evAbi := spec.EventsByName["L"]
   586  			err = abi.UnpackEvent(evAbi, log.Topics, log.Data, &f1, &f2, &f3)
   587  			require.NoError(t, err)
   588  			assert.Equal(t, evAbi.ID.Bytes(), log.Topics[0].Bytes())
   589  			assert.Equal(t, int64(102), f1)
   590  			assert.Equal(t, "Hello from wasm", f2)
   591  			assert.Equal(t, true, f3)
   592  			return
   593  		})
   594  
   595  		t.Run("WasmPrint", func(t *testing.T) {
   596  			t.Parallel()
   597  			createTxe, err := rpctest.CreateWASMContract(cli, inputAddress, solidity.Bytecode_ewasm, nil)
   598  			require.NoError(t, err)
   599  			address := lastCall(createTxe.Events).CallData.Callee
   600  			spec, err := abi.ReadSpec(solidity.Abi_ewasm)
   601  			require.NoError(t, err)
   602  			data, _, err := spec.Pack("test_print", 102, "Fishy")
   603  			require.NoError(t, err)
   604  			callTxe, err := rpctest.CallContract(cli, inputAddress, address, data)
   605  			require.NoError(t, err)
   606  			evs := filterPrint(callTxe.Events)
   607  			require.Len(t, evs, 1)
   608  			assert.Equal(t, string(evs[0].Data), "arg1:102 arg2:Fishy")
   609  			return
   610  		})
   611  	})
   612  }
   613  
   614  func BenchmarkCreateContract(b *testing.B) {
   615  	kern, shutdown := integration.RunNode(b, rpctest.GenesisDoc, rpctest.PrivateAccounts)
   616  	defer shutdown()
   617  	cli := rpctest.NewTransactClient(b, kern.GRPCListenAddress().String())
   618  	for i := 0; i < b.N; i++ {
   619  		create, err := cli.CallTxAsync(context.Background(), &payload.CallTx{
   620  			Input: &payload.TxInput{
   621  				Address: inputAddress,
   622  				Amount:  2,
   623  			},
   624  			Address:  nil,
   625  			Data:     solidity.Bytecode_StrangeLoop,
   626  			Fee:      2,
   627  			GasLimit: 10000,
   628  		})
   629  		require.NoError(b, err)
   630  		assert.True(b, create.CreatesContract)
   631  	}
   632  }
   633  
   634  func filterCalls(evs []*exec.Event) []*exec.CallEvent {
   635  	var callEvs []*exec.CallEvent
   636  	for _, ev := range evs {
   637  		if ev.Call != nil {
   638  			callEvs = append(callEvs, ev.Call)
   639  		}
   640  	}
   641  	return callEvs
   642  }
   643  
   644  func filterLogs(evs []*exec.Event) []*exec.LogEvent {
   645  	var logEvs []*exec.LogEvent
   646  	for _, ev := range evs {
   647  		if ev.Log != nil {
   648  			logEvs = append(logEvs, ev.Log)
   649  		}
   650  	}
   651  	return logEvs
   652  }
   653  
   654  func filterPrint(evs []*exec.Event) []*exec.PrintEvent {
   655  	var printEvs []*exec.PrintEvent
   656  	for _, ev := range evs {
   657  		if ev.Print != nil {
   658  			printEvs = append(printEvs, ev.Print)
   659  		}
   660  	}
   661  	return printEvs
   662  }
   663  
   664  func lastCall(evs []*exec.Event) *exec.CallEvent {
   665  	callEvs := filterCalls(evs)
   666  	return callEvs[len(callEvs)-1]
   667  }
   668  
   669  // simple contract returns 5 + 6 = 0xb
   670  func simpleContract(i, j byte) ([]byte, []byte, []byte) {
   671  	// this is the code we want to run when the contract is called
   672  	contractCode := bc.MustSplice(asm.PUSH1, i, asm.PUSH1, j, asm.ADD, asm.PUSH1, 0x0, asm.MSTORE, asm.PUSH1, 0x20, asm.PUSH1,
   673  		0x0, asm.RETURN)
   674  	// the is the code we need to return the contractCode when the contract is initialized
   675  	lenCode := len(contractCode)
   676  	// push code to the stack
   677  	initCode := bc.MustSplice(asm.PUSH32, binary.RightPadWord256(contractCode),
   678  		// store it in memory
   679  		asm.PUSH1, 0x0, asm.MSTORE,
   680  		// return whats in memory
   681  		asm.PUSH1, lenCode, asm.PUSH1, 0x0, asm.RETURN)
   682  	// return init code, contract code, expected return
   683  	return initCode, contractCode, binary.LeftPadBytes([]byte{i + j}, 32)
   684  }
   685  
   686  func simpleCallContract(address crypto.Address) ([]byte, []byte, []byte) {
   687  	gas1, gas2 := byte(0x1), byte(0x1)
   688  	value := byte(0x1)
   689  	inOff, inSize := byte(0x0), byte(0x0) // no call data
   690  	retOff, retSize := byte(0x0), byte(0x20)
   691  	// this is the code we want to run (call a contract and return)
   692  	contractCode := []byte{0x60, retSize, 0x60, retOff, 0x60, inSize, 0x60, inOff,
   693  		0x60, value, 0x73}
   694  	contractCode = append(contractCode, address.Bytes()...)
   695  	contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20,
   696  		0x60, 0x0, 0xf3}...)
   697  
   698  	// the is the code we need to return; the contractCode when the contract is initialized
   699  	// it should copy the code from the input into memory
   700  	lenCode := len(contractCode)
   701  	memOff := byte(0x0)
   702  	inOff = byte(0xc) // length of code before codeContract
   703  	length := byte(lenCode)
   704  
   705  	code := []byte{0x60, length, 0x60, inOff, 0x60, memOff, 0x37}
   706  	// return whats in memory
   707  	code = append(code, []byte{0x60, byte(lenCode), 0x60, 0x0, 0xf3}...)
   708  	code = append(code, contractCode...)
   709  	// return init code, contract code, expected return
   710  	return code, contractCode, binary.LeftPadBytes([]byte{0xb}, 32)
   711  }