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 }