|
18 | 18 |
|
19 | 19 | EMPTY_CONTRACT_WAT = (Path(__file__).parent / 'data' / 'wasm' / 'empty.wat').resolve(strict=True) |
20 | 20 | ARGS_CONTRACT_WAT = (Path(__file__).parent / 'data' / 'wasm' / 'args.wat').resolve(strict=True) |
| 21 | +ADDER_CONTRACT_WAT = (Path(__file__).parent / 'data' / 'wasm' / 'adder.wat').resolve(strict=True) |
21 | 22 |
|
22 | 23 |
|
23 | 24 | def wat_to_wasm(wat_path: Path) -> bytes: |
@@ -445,3 +446,55 @@ def invoke(func: str, args: list[xdr.SCVal]) -> None: |
445 | 446 | ], |
446 | 447 | ) |
447 | 448 | invoke('test_symbol', [xdr.SCVal(type=SCValType.SCV_SYMBOL, sym=xdr.SCSymbol(sc_symbol=b'hello'))]) |
| 449 | + |
| 450 | + |
| 451 | +def test_call_tx_with_return_value(server: StellarRpcServer) -> None: |
| 452 | + """A contract invocation that returns a non-Void value succeeds. |
| 453 | +
|
| 454 | + Regression test: transactions used to be decoded into ``callTx(..., Void)``, which |
| 455 | + asserts the call returns Void. Invoking ``add(2, 3)`` (returning U32(5)) therefore got |
| 456 | + stuck in the semantics and was recorded as FAILED. ``uncheckedCallTx`` drops the return |
| 457 | + value check. |
| 458 | + """ |
| 459 | + keypair = Keypair.random() |
| 460 | + account = Account(keypair.public_key, sequence=0) |
| 461 | + |
| 462 | + def send(tb: TransactionBuilder) -> None: |
| 463 | + env = tb.set_timeout(30).build() |
| 464 | + env.sign(keypair) |
| 465 | + res = _rpc(server.port(), 'sendTransaction', {'transaction': env.to_xdr()}) |
| 466 | + assert res['result']['status'] == 'PENDING' |
| 467 | + tx_hash = res['result']['hash'] |
| 468 | + get_res = _rpc(server.port(), 'getTransaction', {'hash': tx_hash})['result'] |
| 469 | + assert get_res['status'] == 'SUCCESS', f'Transaction failed: {get_res}' |
| 470 | + |
| 471 | + def builder() -> TransactionBuilder: |
| 472 | + return TransactionBuilder(account, Network.TESTNET_NETWORK_PASSPHRASE) |
| 473 | + |
| 474 | + # Set up: create account, upload adder.wat, deploy contract |
| 475 | + send(builder().append_create_account_op(keypair.public_key, '1000')) |
| 476 | + |
| 477 | + wasm_bytecode = wat_to_wasm(ADDER_CONTRACT_WAT) |
| 478 | + send(builder().append_upload_contract_wasm_op(wasm_bytecode)) |
| 479 | + |
| 480 | + from stellar_sdk.utils import sha256 |
| 481 | + |
| 482 | + wasm_hash = sha256(wasm_bytecode) |
| 483 | + salt = b'\x00' * 32 |
| 484 | + send(builder().append_create_contract_op(wasm_hash, keypair.public_key, None, salt)) |
| 485 | + |
| 486 | + # add(2, 3) returns U32(5), not Void — the send() helper asserts SUCCESS. |
| 487 | + contract_address = server.encoder.contract_address_from_deployer_address(keypair.public_key, salt) |
| 488 | + send( |
| 489 | + builder().append_invoke_contract_function_op( |
| 490 | + contract_address, |
| 491 | + 'add', |
| 492 | + [ |
| 493 | + xdr.SCVal(type=SCValType.SCV_U32, u32=xdr.Uint32(2)), |
| 494 | + xdr.SCVal(type=SCValType.SCV_U32, u32=xdr.Uint32(3)), |
| 495 | + ], |
| 496 | + ) |
| 497 | + ) |
| 498 | + |
| 499 | + # All four transactions, including the non-Void invocation, advanced the ledger. |
| 500 | + assert _rpc(server.port(), 'getLatestLedger', {})['result']['sequence'] == 4 |
0 commit comments