From d7b8a000a3074d446a8156137ebccb255537a24a Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva Date: Thu, 21 Nov 2024 13:02:00 +0100 Subject: [PATCH 01/19] added iterative tests for compasibility --- .../tests/neon_evm/test_interoperability.py | 93 ++++++++++++++++--- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 3e3b0c22f0..0bafab6e67 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -64,6 +64,18 @@ def _create_mint_and_accounts(evm_loader, from_wallet, to_wallet, amount) -> tup return mint, from_token_account, to_token_account +@pytest.fixture(scope="class") +def call_solana_test_contract(operator_keypair, sender_with_tokens, evm_loader, treasury_pool): + return deploy_contract( + operator_keypair, + sender_with_tokens, + "precompiled/call_solana_test", + evm_loader, + treasury_pool, + contract_name="Test", + ) + + class TestInteroperability: @pytest.fixture(scope="function") def solana_caller( @@ -106,19 +118,18 @@ def test_execute_from_instruction_for_compute_budget(self, sender_with_tokens, s check_transaction_logs_have_text(resp, "exit_status=0x11") def test_execute_from_instruction_for_call_memo( - self, sender_with_tokens, neon_api_client, operator_keypair, evm_loader, treasury_pool, sol_client, holder_acc + self, + sender_with_tokens, + neon_api_client, + operator_keypair, + evm_loader, + treasury_pool, + sol_client, + holder_acc, + call_solana_test_contract, ): - contract = deploy_contract( - operator_keypair, - sender_with_tokens, - "precompiled/call_solana_test", - evm_loader, - treasury_pool, - contract_name="Test", - ) - data = abi.function_signature_to_4byte_selector("call_memo()") - signed_tx = make_eth_transaction(evm_loader, contract.eth_address, data, sender_with_tokens) + signed_tx = make_eth_transaction(evm_loader, call_solana_test_contract.eth_address, data, sender_with_tokens) resp = evm_loader.execute_trx_from_instruction_with_solana_call( operator_keypair, @@ -130,8 +141,8 @@ def test_execute_from_instruction_for_call_memo( sender_with_tokens.balance_account_address, SOLANA_CALL_PRECOMPILED_ID, MEMO_PROGRAM_ID, - contract.balance_account_address, - contract.solana_address, + call_solana_test_contract.balance_account_address, + call_solana_test_contract.solana_address, ], ) check_transaction_logs_have_text(resp, "exit_status=0x11") @@ -418,3 +429,59 @@ def test_call_neon_instruction_by_neon_instruction( assert "Program not allowed to call itself" in decode_logs(err.args[0].data.logs) else: assert False, f"Expected error but got {resp}" + + def test_step_from_account_for_call_memo( + self, + sender_with_tokens, + neon_api_client, + operator_keypair, + evm_loader, + treasury_pool, + sol_client, + holder_acc, + call_solana_test_contract, + ): + data = abi.function_signature_to_4byte_selector("call_memo()") + signed_tx = make_eth_transaction(evm_loader, call_solana_test_contract.eth_address, data, sender_with_tokens) + evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + resp = evm_loader.execute_transaction_steps_from_account( + operator_keypair, + treasury_pool, + holder_acc, + [ + sender_with_tokens.balance_account_address, + SOLANA_CALL_PRECOMPILED_ID, + MEMO_PROGRAM_ID, + call_solana_test_contract.balance_account_address, + call_solana_test_contract.solana_address, + ], + ) + check_transaction_logs_have_text(resp, "exit_status=0x11") + + def test_step_from_instruction_for_call_memo( + self, + sender_with_tokens, + neon_api_client, + operator_keypair, + evm_loader, + treasury_pool, + sol_client, + holder_acc, + call_solana_test_contract, + ): + data = abi.function_signature_to_4byte_selector("call_memo()") + signed_tx = make_eth_transaction(evm_loader, call_solana_test_contract.eth_address, data, sender_with_tokens) + resp = evm_loader.execute_transaction_steps_from_instruction( + operator_keypair, + treasury_pool, + holder_acc, + signed_tx, + [ + sender_with_tokens.balance_account_address, + SOLANA_CALL_PRECOMPILED_ID, + MEMO_PROGRAM_ID, + call_solana_test_contract.balance_account_address, + call_solana_test_contract.solana_address, + ], + ) + check_transaction_logs_have_text(resp, "exit_status=0x11") From 2b4b2d473eb7fbc7585e025647af0ce45e22e43b Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva Date: Thu, 21 Nov 2024 17:55:00 +0100 Subject: [PATCH 02/19] added proxy tests --- contracts/precompiled/CallSolanaCaller.sol | 36 ++++++++++++++++- .../basic/evm/test_solana_interoperability.py | 40 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index 7a47095512..e0576b6a39 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -7,6 +7,12 @@ import "../external/neon-evm/call_solana.sol"; contract CallSolanaCaller { CallSolana constant _callSolana = CallSolana(0xFF00000000000000000000000000000000000006); + struct Data { + uint256 value1; + uint256 value2; + } + mapping(uint256 => Data) public dataMap; + struct ExecuteArgs { uint64 lamports; bytes instruction; @@ -28,11 +34,37 @@ contract CallSolanaCaller { } function execute(uint64 lamports, bytes calldata instruction) public { - bytes32 returnData = bytes32(_callSolana.execute(lamports, instruction)); - emit LogBytes(returnData); + bytes32 returnData = bytes32(_callSolana.execute(lamports, instruction)); + emit LogBytes(returnData); + } + + function executeInIterativeMode(uint64 lamports, bytes calldata instruction) public { + // some actions to make the call iterative + for (uint256 i = 0; i < 40; i++) { + Data memory newData = Data({ + value1: 1, + value2: 2 + }); + dataMap[i] = newData; + + } + + execute(lamports, instruction); } + function executeAndDoSomeIterativeActions(uint64 lamports, bytes calldata instruction) public { + execute(lamports, instruction); + // some actions to make the call iterative + for (uint256 i = 0; i < 40; i++) { + Data memory newData = Data({ + value1: 1, + value2: 2 + }); + dataMap[i] = newData; + } + + } function execute_with_get_return_data(uint64 lamports, bytes calldata instruction) public { _callSolana.execute(lamports, instruction); (bytes32 program, bytes memory returnData) = _callSolana.getReturnData(); diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 872c95f9c7..d788d50adb 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -303,3 +303,43 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso instruction_tx = call_solana_caller.functions.batchExecute(call_params).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 + + def test_iterative_transaction(self, counter_resource_address, call_solana_caller, get_counter_value): + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(lamports, serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + + def test_iterative_actions_after_solana_call(self, counter_resource_address, call_solana_caller, get_counter_value): + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(lamports, serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) From aeeb02ae063ef0a519cef66f45366273f5954a5a Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva Date: Wed, 27 Nov 2024 11:46:14 +0100 Subject: [PATCH 03/19] added one more test for evm --- .../tests/neon_evm/test_interoperability.py | 18 +++++++++++++ .../tests/neon_evm/utils/call_solana.py | 25 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 0bafab6e67..1629c4076f 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -485,3 +485,21 @@ def test_step_from_instruction_for_call_memo( ], ) check_transaction_logs_have_text(resp, "exit_status=0x11") + + + def test_step_from_instruction_for_counter(self, sender_with_tokens, solana_caller, evm_loader, holder_acc): + resource_addr = solana_caller.create_resource(sender_with_tokens, b"123", 8, 1000000000, COUNTER_ID) + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(resource_addr, is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + resp = solana_caller.execute_iterative(COUNTER_ID, instruction, 0, holder_acc, sender_with_tokens) + + check_transaction_logs_have_text(resp, "exit_status=0x11") + info: bytes = evm_loader.get_solana_account_data(resource_addr, COUNTER_ACCOUNT_LAYOUT.sizeof()) + layout = COUNTER_ACCOUNT_LAYOUT.parse(info) + assert layout.count == 1 diff --git a/integration/tests/neon_evm/utils/call_solana.py b/integration/tests/neon_evm/utils/call_solana.py index dea120b769..487bf8f614 100644 --- a/integration/tests/neon_evm/utils/call_solana.py +++ b/integration/tests/neon_evm/utils/call_solana.py @@ -83,6 +83,31 @@ def execute(self, program_id, instruction, lamports=0, holder_acc=None, sender=N ) return resp + def execute_iterative(self, program_id, instruction, lamports=0, holder_acc=None, sender=None, additional_accounts=None): + sender = self.owner if sender is None else sender + holder_acc = self.holder_acc if holder_acc is None else holder_acc + serialized_instructions = serialize_instruction(program_id, instruction) + signed_tx = make_contract_call_trx(self.evm_loader, + sender, self.contract, "executeInIterativeMode(uint64,bytes)", [lamports, serialized_instructions] + ) + self.evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, self.operator_keypair) + resp = self.evm_loader.execute_transaction_steps_from_account( + self.operator_keypair, + self.treasury_pool, + holder_acc, + [ + sender.balance_account_address, + sender.solana_account_address, + SOLANA_CALL_PRECOMPILED_ID, + self.contract.balance_account_address, + self.contract.solana_address, + program_id, + ] + + (additional_accounts or []) + + self._get_all_pubkeys_from_instructions([instruction]), + ) + return resp + def execute_with_seed(self, program_id, instruction, seed, lamports=0, holder_acc=None, sender=None, additional_accounts=None): sender = self.owner if sender is None else sender holder_acc = self.holder_acc if holder_acc is None else holder_acc From 76ecb68ce0cb1b2b562cc88f74789c20a1acdb99 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 12 Dec 2024 11:37:02 +0000 Subject: [PATCH 04/19] fix test_step_from_instruction_for_counter: use holder account with function scope fix test_step_from_instruction_for_counter: use holder account with function scope --- contracts/precompiled/CallSolanaCaller.sol | 6 +++--- .../tests/neon_evm/test_interoperability.py | 17 +++++++++++++++-- .../tests/neon_evm/utils/call_solana.py | 18 ++++++------------ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index e0576b6a39..b479a812f6 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -38,9 +38,9 @@ contract CallSolanaCaller { emit LogBytes(returnData); } - function executeInIterativeMode(uint64 lamports, bytes calldata instruction) public { + function executeInIterativeMode(uint256 iterations, uint64 lamports, bytes calldata instruction) public { // some actions to make the call iterative - for (uint256 i = 0; i < 40; i++) { + for (uint256 i = 0; i < iterations; i++) { Data memory newData = Data({ value1: 1, value2: 2 @@ -53,7 +53,7 @@ contract CallSolanaCaller { } - function executeAndDoSomeIterativeActions(uint64 lamports, bytes calldata instruction) public { + function executeAndDoSomeIterativeActions(uint256 iterations, uint64 lamports, bytes calldata instruction) public { execute(lamports, instruction); // some actions to make the call iterative for (uint256 i = 0; i < 40; i++) { diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 064f46bed3..47127b263d 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -487,7 +487,8 @@ def test_step_from_instruction_for_call_memo( check_transaction_logs_have_text(resp, "exit_status=0x11") - def test_step_from_instruction_for_counter(self, sender_with_tokens, solana_caller, evm_loader, holder_acc): + def test_step_from_instruction_for_counter(self, neon_api_client, sender_with_tokens, solana_caller, evm_loader, new_holder_acc): + iterations = 21 resource_addr = solana_caller.create_resource(sender_with_tokens, b"123", 8, 1000000000, COUNTER_ID) instruction = Instruction( @@ -497,7 +498,19 @@ def test_step_from_instruction_for_counter(self, sender_with_tokens, solana_call ], data=bytes([0x1]), ) - resp = solana_caller.execute_iterative(COUNTER_ID, instruction, 0, holder_acc, sender_with_tokens) + + serialized_instructions = serialize_instruction(COUNTER_ID, instruction) + + emulate_result = neon_api_client.emulate_contract_call( + sender_with_tokens.eth_address.hex(), + solana_caller.contract.eth_address.hex(), + "executeInIterativeMode(uint256,uint64,bytes)", + [iterations, 0, serialized_instructions], + ) + additional_accounts = [Pubkey.from_string(item["pubkey"]) for item in emulate_result["solana_accounts"]] + print(additional_accounts) + + resp = solana_caller.execute_iterative(COUNTER_ID, instruction, iterations, 0, new_holder_acc, sender_with_tokens, additional_accounts) check_transaction_logs_have_text(resp, "exit_status=0x11") info: bytes = evm_loader.get_solana_account_data(resource_addr, COUNTER_ACCOUNT_LAYOUT.sizeof()) diff --git a/integration/tests/neon_evm/utils/call_solana.py b/integration/tests/neon_evm/utils/call_solana.py index 487bf8f614..22f8e668d8 100644 --- a/integration/tests/neon_evm/utils/call_solana.py +++ b/integration/tests/neon_evm/utils/call_solana.py @@ -83,27 +83,20 @@ def execute(self, program_id, instruction, lamports=0, holder_acc=None, sender=N ) return resp - def execute_iterative(self, program_id, instruction, lamports=0, holder_acc=None, sender=None, additional_accounts=None): + def execute_iterative(self, program_id, instruction, iterations, lamports=0, holder_acc=None, sender=None, additional_accounts=None): sender = self.owner if sender is None else sender holder_acc = self.holder_acc if holder_acc is None else holder_acc serialized_instructions = serialize_instruction(program_id, instruction) signed_tx = make_contract_call_trx(self.evm_loader, - sender, self.contract, "executeInIterativeMode(uint64,bytes)", [lamports, serialized_instructions] + sender, self.contract, "executeInIterativeMode(uint256,uint64,bytes)", [iterations, lamports, serialized_instructions] ) self.evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, self.operator_keypair) + resp = self.evm_loader.execute_transaction_steps_from_account( self.operator_keypair, self.treasury_pool, holder_acc, - [ - sender.balance_account_address, - sender.solana_account_address, - SOLANA_CALL_PRECOMPILED_ID, - self.contract.balance_account_address, - self.contract.solana_address, - program_id, - ] - + (additional_accounts or []) + additional_accounts + self._get_all_pubkeys_from_instructions([instruction]), ) return resp @@ -199,7 +192,8 @@ def create_resource(self, sender, salt, space, lamports, owner): resource_address_pubkey, SYSTEM_PROGRAM_ID - ] ) + ] + ) check_transaction_logs_have_text(resp, "exit_status=0x12") return resource_address_pubkey From 817e0d9155437a3e31651cb2d2c8863d5f5ed3ab Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 12 Dec 2024 12:08:11 +0000 Subject: [PATCH 05/19] fix iterative transaction tests: reduce iteration lenght fix iterative transaction tests: reduce iteration lenght --- .../basic/evm/test_solana_interoperability.py | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index d788d50adb..7f245d659c 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -290,7 +290,7 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso for _ in range(24): instruction = Instruction( - program_id=COUNTER_ID, + program_id=COUNTER_ID, accounts=[ AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), ], @@ -318,12 +318,32 @@ def test_iterative_transaction(self, counter_resource_address, call_solana_calle serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeInIterativeMode(lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(29, lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + + def test_iterative_transaction_exceed_instruction_trace_length (self, counter_resource_address, call_solana_caller, get_counter_value): + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(40, lamports, serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 0 + + def test_iterative_actions_after_solana_call(self, counter_resource_address, call_solana_caller, get_counter_value): sender = self.accounts[0] lamports = 0 @@ -338,7 +358,7 @@ def test_iterative_actions_after_solana_call(self, counter_resource_address, cal serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(29, lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) From 1b4e143851e3a5177291a0f981c4ed46e16f1db2 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 12 Dec 2024 13:31:50 +0000 Subject: [PATCH 06/19] fix: new holder account for all interoperability tests fix: new holder account for all interoperability tests --- integration/tests/neon_evm/test_interoperability.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 47127b263d..8e0b0c812c 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -438,16 +438,16 @@ def test_step_from_account_for_call_memo( evm_loader, treasury_pool, sol_client, - holder_acc, + new_holder_acc, call_solana_test_contract, ): data = abi.function_signature_to_4byte_selector("call_memo()") signed_tx = make_eth_transaction(evm_loader, call_solana_test_contract.eth_address, data, sender_with_tokens) - evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + evm_loader.write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) resp = evm_loader.execute_transaction_steps_from_account( operator_keypair, treasury_pool, - holder_acc, + new_holder_acc, [ sender_with_tokens.balance_account_address, SOLANA_CALL_PRECOMPILED_ID, @@ -466,7 +466,7 @@ def test_step_from_instruction_for_call_memo( evm_loader, treasury_pool, sol_client, - holder_acc, + new_holder_acc, call_solana_test_contract, ): data = abi.function_signature_to_4byte_selector("call_memo()") @@ -474,7 +474,7 @@ def test_step_from_instruction_for_call_memo( resp = evm_loader.execute_transaction_steps_from_instruction( operator_keypair, treasury_pool, - holder_acc, + new_holder_acc, signed_tx, [ sender_with_tokens.balance_account_address, From d19510e522bf4575ab0514f1eca38b66d12fcfce Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Fri, 13 Dec 2024 04:51:24 +0000 Subject: [PATCH 07/19] add composability test cases: iterative actions + solana call/calls, deploy contracy and solana call add composability test cases: iterative actions + solana call/calls, deploy contracy and solana call --- contracts/precompiled/CallSolanaCaller.sol | 43 ++++-- .../basic/evm/test_solana_interoperability.py | 137 +++++++++++++++++- 2 files changed, 161 insertions(+), 19 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index b479a812f6..ca109185e1 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -4,6 +4,13 @@ pragma abicoder v2; import "../external/neon-evm/call_solana.sol"; +contract CallMessage { + string message; + constructor(string memory _message){ + message = _message; + } +} + contract CallSolanaCaller { CallSolana constant _callSolana = CallSolana(0xFF00000000000000000000000000000000000006); @@ -23,7 +30,6 @@ contract CallSolanaCaller { bytes instruction; } - event LogBytes(bytes32 value); event LogStr(string value); event LogData(bytes32 program, bytes value); @@ -39,32 +45,45 @@ contract CallSolanaCaller { } function executeInIterativeMode(uint256 iterations, uint64 lamports, bytes calldata instruction) public { - // some actions to make the call iterative - for (uint256 i = 0; i < iterations; i++) { - Data memory newData = Data({ - value1: 1, - value2: 2 - }); - dataMap[i] = newData; + doIterativeActions(iterations); + execute(lamports, instruction); + } + function executeAndDoSomeIterativeActions(uint256 iterations, uint64 lamports, bytes calldata instruction) public { + execute(lamports, instruction); + doIterativeActions(iterations); + } + + function executeMultipleCallsAndDoIterativeActions(uint256 calls, uint256 iterations, uint64 lamports, bytes calldata instruction) public { + for (uint256 i = 0; i < calls; i++) { + execute(lamports, instruction); } - execute(lamports, instruction); + doIterativeActions(iterations); + } + function doSomeIterativeActions(uint256 iterations) public { + doIterativeActions(iterations); + emit LogStr("iterative actions status: done"); } - function executeAndDoSomeIterativeActions(uint256 iterations, uint64 lamports, bytes calldata instruction) public { - execute(lamports, instruction); + function doIterativeActions(uint iterations) public { // some actions to make the call iterative - for (uint256 i = 0; i < 40; i++) { + for (uint256 i = 0; i < iterations; i++) { Data memory newData = Data({ value1: 1, value2: 2 }); dataMap[i] = newData; } + } + function deployCallMessageAndCallSolana(string memory message, uint64 lamports, bytes calldata instruction) public { + CallMessage contractCallMessage = new CallMessage(message); + execute(lamports, instruction); + emit LogStr(message); } + function execute_with_get_return_data(uint64 lamports, bytes calldata instruction) public { _callSolana.execute(lamports, instruction); (bytes32 program, bytes memory returnData) = _callSolana.getReturnData(); diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 7f245d659c..0cead69b17 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -1,4 +1,5 @@ import typing as tp +import web3.exceptions import pytest import spl @@ -304,7 +305,8 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 - def test_iterative_transaction(self, counter_resource_address, call_solana_caller, get_counter_value): + @pytest.mark.parametrize("iterations_number", [29, 52]) + def test_solana_call_after_iterative_actions(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): sender = self.accounts[0] lamports = 0 @@ -318,14 +320,59 @@ def test_iterative_transaction(self, counter_resource_address, call_solana_calle serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeInIterativeMode(29, lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations_number, lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + + def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter_resource_address, call_solana_caller): + iterations = 53 + sender = self.accounts[0] + lamports = 0 + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) - def test_iterative_transaction_exceed_instruction_trace_length (self, counter_resource_address, call_solana_caller, get_counter_value): + with pytest.raises( + web3.exceptions.ContractLogicError, + match="too many accounts: 65 > 64", + ): + call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) + + @pytest.mark.parametrize("iterations_number", [40, 55]) + def test_iterative_actions_no_solana_call(self, iterations_number, call_solana_caller): + sender = self.accounts[0] + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.doSomeIterativeActions(iterations_number).build_transaction(tx) + + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + + event_logs = call_solana_caller.events.LogStr().process_receipt(resp) + assert event_logs[0].args.value == "iterative actions status: done" + + def test_iterative_actions_no_solana_call_exceed_accounts_limit(self, call_solana_caller): + sender = self.accounts[0] + tx = self.web3_client.make_raw_tx(sender.address) + + with pytest.raises( + web3.exceptions.ContractLogicError, + match="too many accounts: 65 > 64", + ): + call_solana_caller.functions.doSomeIterativeActions(56).build_transaction(tx) + + @pytest.mark.parametrize("iterations_number", [29, 52]) + def test_iterative_actions_after_solana_call(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): sender = self.accounts[0] lamports = 0 @@ -339,12 +386,39 @@ def test_iterative_transaction_exceed_instruction_trace_length (self, counter_re serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeInIterativeMode(40, lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations_number, + lamports, + serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) - assert resp["status"] == 0 + assert resp["status"] == 1 + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter_resource_address, call_solana_caller, get_counter_value): + iterations = 53 + sender = self.accounts[0] + lamports = 0 - def test_iterative_actions_after_solana_call(self, counter_resource_address, call_solana_caller, get_counter_value): + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + + with pytest.raises( + web3.exceptions.ContractLogicError, + match="too many accounts: 65 > 64", + ): + call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, lamports, serialized).build_transaction(tx) + + def test_multiple_solana_calls_and_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + solana_calls = 5 + iterations = 20 sender = self.accounts[0] lamports = 0 @@ -358,8 +432,57 @@ def test_iterative_actions_after_solana_call(self, counter_resource_address, cal serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(29, lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeMultipleCallsAndDoIterativeActions(solana_calls, + iterations, + lamports, + serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + + def test_multiple_solana_calls_and_iterative_actions_instructions_limit(self, counter_resource_address, call_solana_caller, get_counter_value): + solana_calls = 15 + iterations = 40 + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.executeMultipleCallsAndDoIterativeActions(solana_calls, + iterations, + lamports, + serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 0 + + def test_deploy_contract_and_call_solana(self, counter_resource_address, call_solana_caller): + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.deployCallMessageAndCallSolana("deploy contracts status: done", + lamports, + serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + + event_logs = call_solana_caller.events.LogStr().process_receipt(resp) + assert event_logs[0].args.value == "deploy contracts status: done" From 834d901fec0dadc1f538231443e970d73a98a4f0 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Fri, 13 Dec 2024 05:03:12 +0000 Subject: [PATCH 08/19] fix deploy contract and solana call test fix deploy contract and solana call test --- contracts/precompiled/CallSolanaCaller.sol | 12 +++--------- .../tests/basic/evm/test_solana_interoperability.py | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index ca109185e1..27c4285a36 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -2,15 +2,9 @@ pragma solidity >=0.7.0 <0.9.0; pragma abicoder v2; import "../external/neon-evm/call_solana.sol"; +import "../common/StorageSoliditySource.sol"; -contract CallMessage { - string message; - constructor(string memory _message){ - message = _message; - } -} - contract CallSolanaCaller { CallSolana constant _callSolana = CallSolana(0xFF00000000000000000000000000000000000006); @@ -78,8 +72,8 @@ contract CallSolanaCaller { } } - function deployCallMessageAndCallSolana(string memory message, uint64 lamports, bytes calldata instruction) public { - CallMessage contractCallMessage = new CallMessage(message); + function deployStorageAndCallSolana(string memory message, uint64 lamports, bytes calldata instruction) public { + Storage storageContract = new Storage(); execute(lamports, instruction); emit LogStr(message); } diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 0cead69b17..2641539fab 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -478,7 +478,7 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.deployCallMessageAndCallSolana("deploy contracts status: done", + instruction_tx = call_solana_caller.functions.deployStorageAndCallSolana("deploy contracts status: done", lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) From 104b7a099fbd047f053a4bb4cdc5885c481808b9 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Fri, 13 Dec 2024 17:29:33 +0000 Subject: [PATCH 09/19] rm tests with no iterative txs check rm tests with no iterative txs check --- .../basic/evm/test_solana_interoperability.py | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 2641539fab..ed7abc1600 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -348,31 +348,9 @@ def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter ): call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) - @pytest.mark.parametrize("iterations_number", [40, 55]) - def test_iterative_actions_no_solana_call(self, iterations_number, call_solana_caller): - sender = self.accounts[0] - - tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.doSomeIterativeActions(iterations_number).build_transaction(tx) - - resp = self.web3_client.send_transaction(sender, instruction_tx) - assert resp["status"] == 1 - - event_logs = call_solana_caller.events.LogStr().process_receipt(resp) - assert event_logs[0].args.value == "iterative actions status: done" - - def test_iterative_actions_no_solana_call_exceed_accounts_limit(self, call_solana_caller): - sender = self.accounts[0] - tx = self.web3_client.make_raw_tx(sender.address) - - with pytest.raises( - web3.exceptions.ContractLogicError, - match="too many accounts: 65 > 64", - ): - call_solana_caller.functions.doSomeIterativeActions(56).build_transaction(tx) - + @pytest.mark.parametrize("iterations_number", [29, 52]) - def test_iterative_actions_after_solana_call(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): + def test_iterative_actions_before_solana_call(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): sender = self.accounts[0] lamports = 0 From 01e2828171dc005cb5b989a932bfc1447f45422b Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Fri, 13 Dec 2024 17:30:20 +0000 Subject: [PATCH 10/19] check holder account state after tx execution check holder account state after tx execution --- .../tests/neon_evm/test_interoperability.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 8e0b0c812c..2cdad8958f 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -15,6 +15,9 @@ from solders.system_program import ID as SYS_PROGRAM_ID from solana.transaction import Instruction, AccountMeta from spl.token.instructions import create_associated_token_account, TransferParams, transfer +from utils.layouts import FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT +from .utils.constants import TAG_FINALIZED_STATE +from .utils.transaction_checks import check_holder_account_tag from integration.tests.neon_evm.utils.call_solana import SolanaCaller @@ -438,16 +441,16 @@ def test_step_from_account_for_call_memo( evm_loader, treasury_pool, sol_client, - new_holder_acc, + holder_acc, call_solana_test_contract, ): data = abi.function_signature_to_4byte_selector("call_memo()") signed_tx = make_eth_transaction(evm_loader, call_solana_test_contract.eth_address, data, sender_with_tokens) - evm_loader.write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) + evm_loader.write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp = evm_loader.execute_transaction_steps_from_account( operator_keypair, treasury_pool, - new_holder_acc, + holder_acc, [ sender_with_tokens.balance_account_address, SOLANA_CALL_PRECOMPILED_ID, @@ -457,6 +460,7 @@ def test_step_from_account_for_call_memo( ], ) check_transaction_logs_have_text(resp, "exit_status=0x11") + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) def test_step_from_instruction_for_call_memo( self, @@ -466,7 +470,7 @@ def test_step_from_instruction_for_call_memo( evm_loader, treasury_pool, sol_client, - new_holder_acc, + holder_acc, call_solana_test_contract, ): data = abi.function_signature_to_4byte_selector("call_memo()") @@ -474,7 +478,7 @@ def test_step_from_instruction_for_call_memo( resp = evm_loader.execute_transaction_steps_from_instruction( operator_keypair, treasury_pool, - new_holder_acc, + holder_acc, signed_tx, [ sender_with_tokens.balance_account_address, @@ -485,9 +489,10 @@ def test_step_from_instruction_for_call_memo( ], ) check_transaction_logs_have_text(resp, "exit_status=0x11") + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - def test_step_from_instruction_for_counter(self, neon_api_client, sender_with_tokens, solana_caller, evm_loader, new_holder_acc): + def test_step_from_instruction_for_counter(self, neon_api_client, sender_with_tokens, solana_caller, evm_loader, holder_acc): iterations = 21 resource_addr = solana_caller.create_resource(sender_with_tokens, b"123", 8, 1000000000, COUNTER_ID) @@ -510,9 +515,11 @@ def test_step_from_instruction_for_counter(self, neon_api_client, sender_with_to additional_accounts = [Pubkey.from_string(item["pubkey"]) for item in emulate_result["solana_accounts"]] print(additional_accounts) - resp = solana_caller.execute_iterative(COUNTER_ID, instruction, iterations, 0, new_holder_acc, sender_with_tokens, additional_accounts) - + resp = solana_caller.execute_iterative(COUNTER_ID, instruction, iterations, 0, holder_acc, sender_with_tokens, additional_accounts) + print(resp) + check_transaction_logs_have_text(resp, "exit_status=0x11") info: bytes = evm_loader.get_solana_account_data(resource_addr, COUNTER_ACCOUNT_LAYOUT.sizeof()) layout = COUNTER_ACCOUNT_LAYOUT.parse(info) assert layout.count == 1 + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) From 53c473cbae48d51d15f0db00888988bee787f59c Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Fri, 13 Dec 2024 17:33:02 +0000 Subject: [PATCH 11/19] rename test test_solana_call_before_iterative_actions rename test test_solana_call_before_iterative_actions --- integration/tests/basic/evm/test_solana_interoperability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index ed7abc1600..9f0f2b6779 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -350,7 +350,7 @@ def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter @pytest.mark.parametrize("iterations_number", [29, 52]) - def test_iterative_actions_before_solana_call(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): + def test_solana_call_before_iterative_actions(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): sender = self.accounts[0] lamports = 0 From 8b95fbb462f3b07570e21c61c466e824e0304fbf Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Tue, 17 Dec 2024 01:55:26 +0000 Subject: [PATCH 12/19] add case: eip 1559 iterative tx check with program_id = transfer_tokens_id add case: eip 1559 iterative tx check with program_id = transfer_tokens_id --- contracts/precompiled/CallSolanaCaller.sol | 5 +- .../basic/evm/test_solana_interoperability.py | 115 ++++++++++++++---- 2 files changed, 94 insertions(+), 26 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index 27c4285a36..e9f2f7af71 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -48,12 +48,11 @@ contract CallSolanaCaller { doIterativeActions(iterations); } - function executeMultipleCallsAndDoIterativeActions(uint256 calls, uint256 iterations, uint64 lamports, bytes calldata instruction) public { + function executeMultipleInIterativeMode(uint256 calls, uint256 iterations, uint64 lamports, bytes calldata instruction) public { + doIterativeActions(iterations); for (uint256 i = 0; i < calls; i++) { execute(lamports, instruction); } - - doIterativeActions(iterations); } function doSomeIterativeActions(uint256 iterations) public { diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 9f0f2b6779..3611e83d3e 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -17,9 +17,10 @@ ) import allure +from utils.types import TransactionType from utils.accounts import EthAccounts from utils.consts import COUNTER_ID, TRANSFER_TOKENS_ID, wSOL -from utils.helpers import bytes32_to_solana_pubkey, serialize_instruction +from utils.helpers import bytes32_to_solana_pubkey, serialize_instruction, wait_condition from utils.instructions import make_wSOL from utils.web3client import NeonChainWeb3Client @@ -305,8 +306,8 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 - @pytest.mark.parametrize("iterations_number", [29, 52]) - def test_solana_call_after_iterative_actions(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): + def test_solana_call_after_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + iterations = 29 sender = self.accounts[0] lamports = 0 @@ -320,7 +321,7 @@ def test_solana_call_after_iterative_actions(self, iterations_number, counter_re serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations_number, lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) @@ -348,9 +349,8 @@ def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter ): call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) - - @pytest.mark.parametrize("iterations_number", [29, 52]) - def test_solana_call_before_iterative_actions(self, iterations_number, counter_resource_address, call_solana_caller, get_counter_value): + def test_solana_call_before_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + iterations = 29 sender = self.accounts[0] lamports = 0 @@ -364,7 +364,7 @@ def test_solana_call_before_iterative_actions(self, iterations_number, counter_r serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations_number, + instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) @@ -372,7 +372,7 @@ def test_solana_call_before_iterative_actions(self, iterations_number, counter_r event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter_resource_address, call_solana_caller, get_counter_value): + def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter_resource_address, call_solana_caller): iterations = 53 sender = self.accounts[0] lamports = 0 @@ -394,7 +394,7 @@ def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter ): call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, lamports, serialized).build_transaction(tx) - def test_multiple_solana_calls_and_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_address, call_solana_caller, get_counter_value): solana_calls = 5 iterations = 20 sender = self.accounts[0] @@ -410,18 +410,18 @@ def test_multiple_solana_calls_and_iterative_actions(self, counter_resource_addr serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeMultipleCallsAndDoIterativeActions(solana_calls, - iterations, - lamports, - serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeMultipleInIterativeMode(solana_calls, + iterations, + lamports, + serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - def test_multiple_solana_calls_and_iterative_actions_instructions_limit(self, counter_resource_address, call_solana_caller, get_counter_value): - solana_calls = 15 - iterations = 40 + def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, counter_resource_address, call_solana_caller): + solana_calls = 5 + iterations = 30 sender = self.accounts[0] lamports = 0 @@ -435,11 +435,13 @@ def test_multiple_solana_calls_and_iterative_actions_instructions_limit(self, co serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeMultipleCallsAndDoIterativeActions(solana_calls, - iterations, - lamports, - serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeMultipleInIterativeMode(solana_calls, + iterations, + lamports, + serialized).build_transaction(tx) + print("Sender: ", sender.address) resp = self.web3_client.send_transaction(sender, instruction_tx) + print(resp) assert resp["status"] == 0 def test_deploy_contract_and_call_solana(self, counter_resource_address, call_solana_caller): @@ -457,10 +459,77 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so tx = self.web3_client.make_raw_tx(sender.address) instruction_tx = call_solana_caller.functions.deployStorageAndCallSolana("deploy contracts status: done", - lamports, - serialized).build_transaction(tx) + lamports, + serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 event_logs = call_solana_caller.events.LogStr().process_receipt(resp) assert event_logs[0].args.value == "deploy contracts status: done" + + def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): + iterations = 22 + sender = self.accounts[0] + from_wallet = Keypair() + to_wallet = Keypair() + amount = 100000 + if pytestconfig.environment.use_bank: + sol_client.send_sol(bank_account, from_wallet.pubkey(), int(0.5 * 10**9)) + else: + sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) + + mint = spl.token.client.Token.create_mint( + conn=sol_client, + payer=from_wallet, + mint_authority=from_wallet.pubkey(), + decimals=9, + program_id=TOKEN_PROGRAM_ID, + ) + mint.payer = from_wallet + from_token_account = mint.create_associated_token_account(from_wallet.pubkey()) + to_token_account = mint.create_associated_token_account(to_wallet.pubkey()) + mint.mint_to( + dest=from_token_account, + mint_authority=from_wallet, + amount=amount, + opts=TxOpts(skip_confirmation=False, skip_preflight=True), + ) + + authority_pubkey: bytes = call_solana_caller.functions.getSolanaPDA(bytes(TRANSFER_TOKENS_ID), b"authority").call() + mint.set_authority( + from_token_account, + from_wallet, + spl.token.instructions.AuthorityType.ACCOUNT_OWNER, + Pubkey(authority_pubkey), + opts=TxOpts(skip_confirmation=False, skip_preflight=True), + ) + + instruction = Instruction( + program_id=TRANSFER_TOKENS_ID, + accounts=[ + AccountMeta(from_token_account, is_signer=False, is_writable=True), + AccountMeta(mint.pubkey, is_signer=False, is_writable=True), + AccountMeta(to_token_account, is_signer=False, is_writable=True), + AccountMeta(Pubkey(authority_pubkey), is_signer=False, is_writable=True), + AccountMeta(TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), + ], + data=bytes([0x0]), + ) + serialized = serialize_instruction(TRANSFER_TOKENS_ID, instruction) + + tx = self.web3_client.make_raw_tx(from_=sender.address, amount=None, data=None, tx_type=TransactionType.EIP_1559) + + instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) + + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + assert resp.type == 2 + + assert int(mint.get_balance(to_token_account, commitment=Confirmed).value.amount) == amount + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == 0 + + wait_condition( + lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, + timeout_sec=30, + ) \ No newline at end of file From 05d9542027dfcdcc87ea0e8c476c560e296f2a7c Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Tue, 17 Dec 2024 03:37:26 +0000 Subject: [PATCH 13/19] add case: failed solana call add case: failed solana call --- .../basic/evm/test_solana_interoperability.py | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 3611e83d3e..52ee7ef82c 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -326,7 +326,29 @@ def test_solana_call_after_iterative_actions(self, counter_resource_address, cal assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - + + def test_failed_solana_call_after_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + iterations = 29 + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(TRANSFER_TOKENS_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + + with pytest.raises( + web3.exceptions.ContractLogicError, + match="execution reverted: External call fails", + ): + call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) + def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter_resource_address, call_solana_caller): iterations = 53 sender = self.accounts[0] @@ -420,8 +442,8 @@ def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_addr assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, counter_resource_address, call_solana_caller): - solana_calls = 5 - iterations = 30 + solana_calls = 15 + iterations = 35 sender = self.accounts[0] lamports = 0 @@ -439,9 +461,7 @@ def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, co iterations, lamports, serialized).build_transaction(tx) - print("Sender: ", sender.address) resp = self.web3_client.send_transaction(sender, instruction_tx) - print(resp) assert resp["status"] == 0 def test_deploy_contract_and_call_solana(self, counter_resource_address, call_solana_caller): @@ -468,7 +488,7 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so assert event_logs[0].args.value == "deploy contracts status: done" def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): - iterations = 22 + iterations = 29 sender = self.accounts[0] from_wallet = Keypair() to_wallet = Keypair() @@ -531,5 +551,5 @@ def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_cal wait_condition( lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, - timeout_sec=30, + timeout_sec=60, ) \ No newline at end of file From 1604cab8311d415a8750380dea36714613708b06 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Tue, 17 Dec 2024 04:09:38 +0000 Subject: [PATCH 14/19] add case: iterative tx with solana call in sol network add case: iterative tx with solana call in sol network --- .../basic/evm/test_solana_interoperability.py | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 52ee7ef82c..30b093ab9a 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -22,7 +22,7 @@ from utils.consts import COUNTER_ID, TRANSFER_TOKENS_ID, wSOL from utils.helpers import bytes32_to_solana_pubkey, serialize_instruction, wait_condition from utils.instructions import make_wSOL -from utils.web3client import NeonChainWeb3Client +from utils.web3client import NeonChainWeb3Client, Web3Client @pytest.fixture(scope="session") @@ -42,6 +42,20 @@ def gen_increment_counter(): class TestSolanaInteroperability: accounts: EthAccounts web3_client: NeonChainWeb3Client + + @pytest.fixture(scope="class") + def account_sol_network(self, class_account_sol_chain): + return class_account_sol_chain + + @pytest.fixture(scope="class") + def call_solana_caller_sol_network(self, account_sol_network, web3_client_sol): + contract, _ = web3_client_sol.deploy_and_get_contract( + contract="precompiled/CallSolanaCaller.sol", + version="0.8.10", + contract_name="CallSolanaCaller", + account=account_sol_network, + ) + return contract def test_counter_execute_with_get_return_data( self, call_solana_caller, counter_resource_address: bytes, get_counter_value @@ -306,6 +320,31 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 + def test_solana_call_after_iterative_actions_sol_network(self, web3_client_sol, + counter_resource_address, + call_solana_caller_sol_network, + get_counter_value, + account_sol_network): + iterations = 29 + sender = account_sol_network + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = web3_client_sol.make_raw_tx(sender.address) + instruction_tx = call_solana_caller_sol_network.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) + resp = web3_client_sol.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + event_logs = call_solana_caller_sol_network.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + def test_solana_call_after_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): iterations = 29 sender = self.accounts[0] From 0392e6a070e53c34e86d67ae05c9fbd17a51962a Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Wed, 18 Dec 2024 10:04:02 +0000 Subject: [PATCH 15/19] rm dbg info rm dbg info --- integration/tests/neon_evm/test_interoperability.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 2cdad8958f..71a8f4aa94 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -513,10 +513,8 @@ def test_step_from_instruction_for_counter(self, neon_api_client, sender_with_to [iterations, 0, serialized_instructions], ) additional_accounts = [Pubkey.from_string(item["pubkey"]) for item in emulate_result["solana_accounts"]] - print(additional_accounts) resp = solana_caller.execute_iterative(COUNTER_ID, instruction, iterations, 0, holder_acc, sender_with_tokens, additional_accounts) - print(resp) check_transaction_logs_have_text(resp, "exit_status=0x11") info: bytes = evm_loader.get_solana_account_data(resource_addr, COUNTER_ACCOUNT_LAYOUT.sizeof()) From 92ddd80803f1e23f1a2b58a8d06c121c2d0a3c51 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 19 Dec 2024 09:01:44 +0000 Subject: [PATCH 16/19] add case: iterative tx with send tokens add case: iterative tx with send tokens --- contracts/precompiled/CallSolanaCaller.sol | 8 +++++ .../basic/evm/test_solana_interoperability.py | 31 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index e9f2f7af71..e5f8f621df 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -55,6 +55,14 @@ contract CallSolanaCaller { } } + function sendTokensAndExecuteInIterativeMode( + uint256 iterations, + uint64 lamports, + bytes calldata instruction + ) public payable { + executeInIterativeMode(iterations, lamports, instruction); + } + function doSomeIterativeActions(uint256 iterations) public { doIterativeActions(iterations); emit LogStr("iterative actions status: done"); diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 30b093ab9a..684ddb576a 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -591,4 +591,33 @@ def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_cal wait_condition( lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, timeout_sec=60, - ) \ No newline at end of file + ) + + def test_iterative_tx_with_send_tokens(self, counter_resource_address, call_solana_caller, get_counter_value): + iterations = 29 + sender = self.accounts[0] + lamports = 0 + balance_before = self.web3_client.get_balance(call_solana_caller.address) + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(from_=sender.address, amount=10) + + instruction_tx = call_solana_caller.functions.sendTokensAndExecuteInIterativeMode(iterations, + lamports, + serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + + balance_after = self.web3_client.get_balance(call_solana_caller.address) + assert balance_after == balance_before + 10 From 0ad085e946622c19e61fb5823f9342238cb1acb5 Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 19 Dec 2024 14:06:55 +0000 Subject: [PATCH 17/19] add case of solana call with 2 programs, minor refactoring add case of solana call with 2 programs, minor refactoring --- contracts/precompiled/CallSolanaCaller.sol | 111 ++++++++---- .../basic/evm/test_solana_interoperability.py | 164 +++++++++++------- 2 files changed, 182 insertions(+), 93 deletions(-) diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index e5f8f621df..d790cc681e 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -4,10 +4,9 @@ pragma abicoder v2; import "../external/neon-evm/call_solana.sol"; import "../common/StorageSoliditySource.sol"; - contract CallSolanaCaller { - - CallSolana constant _callSolana = CallSolana(0xFF00000000000000000000000000000000000006); + CallSolana constant _callSolana = + CallSolana(0xFF00000000000000000000000000000000000006); struct Data { uint256 value1; uint256 value2; @@ -28,33 +27,56 @@ contract CallSolanaCaller { event LogStr(string value); event LogData(bytes32 program, bytes value); - function getNeonAddress(address addr) public returns (bytes32){ + function getNeonAddress(address addr) public returns (bytes32) { bytes32 solanaAddr = _callSolana.getNeonAddress(addr); return solanaAddr; } function execute(uint64 lamports, bytes calldata instruction) public { - bytes32 returnData = bytes32(_callSolana.execute(lamports, instruction)); - emit LogBytes(returnData); + bytes32 returnData = bytes32( + _callSolana.execute(lamports, instruction) + ); + emit LogBytes(returnData); } - function executeInIterativeMode(uint256 iterations, uint64 lamports, bytes calldata instruction) public { + function executeInIterativeMode( + uint256 iterations, + uint64 lamports, + bytes calldata instruction + ) public { doIterativeActions(iterations); execute(lamports, instruction); } - function executeAndDoSomeIterativeActions(uint256 iterations, uint64 lamports, bytes calldata instruction) public { + function executeAndDoSomeIterativeActions( + uint256 iterations, + uint64 lamports, + bytes calldata instruction + ) public { execute(lamports, instruction); doIterativeActions(iterations); } - function executeMultipleInIterativeMode(uint256 calls, uint256 iterations, uint64 lamports, bytes calldata instruction) public { + function executeMultipleInIterativeMode( + uint256 calls, + uint256 iterations, + uint64 lamports, + bytes calldata instruction + ) public { doIterativeActions(iterations); for (uint256 i = 0; i < calls; i++) { execute(lamports, instruction); } } + function batchExecuteInIterativeMode( + uint256 iterations, + ExecuteArgs[] memory _args + ) public { + doIterativeActions(iterations); + batchExecute(_args); + } + function sendTokensAndExecuteInIterativeMode( uint256 iterations, uint64 lamports, @@ -71,71 +93,100 @@ contract CallSolanaCaller { function doIterativeActions(uint iterations) public { // some actions to make the call iterative for (uint256 i = 0; i < iterations; i++) { - Data memory newData = Data({ - value1: 1, - value2: 2 - }); + Data memory newData = Data({value1: 1, value2: 2}); dataMap[i] = newData; } } - function deployStorageAndCallSolana(string memory message, uint64 lamports, bytes calldata instruction) public { + function deployStorageAndCallSolana( + string memory message, + uint64 lamports, + bytes calldata instruction + ) public { Storage storageContract = new Storage(); execute(lamports, instruction); emit LogStr(message); } - function execute_with_get_return_data(uint64 lamports, bytes calldata instruction) public { + function execute_with_get_return_data( + uint64 lamports, + bytes calldata instruction + ) public { _callSolana.execute(lamports, instruction); - (bytes32 program, bytes memory returnData) = _callSolana.getReturnData(); + (bytes32 program, bytes memory returnData) = _callSolana + .getReturnData(); emit LogData(program, returnData); } function batchExecute(ExecuteArgs[] memory _args) public { - for(uint i = 0; i < _args.length; i++) { + for (uint i = 0; i < _args.length; i++) { _callSolana.execute(_args[i].lamports, _args[i].instruction); } - (bytes32 program, bytes memory returnData) = _callSolana.getReturnData(); + (bytes32 program, bytes memory returnData) = _callSolana + .getReturnData(); emit LogData(program, returnData); } - function getPayer() public returns (bytes32){ + function getPayer() public returns (bytes32) { bytes32 payer = _callSolana.getPayer(); return payer; } - function createResource(bytes32 salt, uint64 space, uint64 lamports, bytes32 owner) external returns (bytes32){ - bytes32 resource = _callSolana.createResource(salt, space, lamports, owner); + function createResource( + bytes32 salt, + uint64 space, + uint64 lamports, + bytes32 owner + ) external returns (bytes32) { + bytes32 resource = _callSolana.createResource( + salt, + space, + lamports, + owner + ); return resource; } - function getResourceAddress(bytes32 salt) external returns (bytes32){ + function getResourceAddress(bytes32 salt) external returns (bytes32) { bytes32 resource = _callSolana.getResourceAddress(salt); return resource; } - function getSolanaPDA(bytes32 program_id, bytes memory seeds) external returns (bytes32){ + function getSolanaPDA( + bytes32 program_id, + bytes memory seeds + ) external returns (bytes32) { bytes32 pda = _callSolana.getSolanaPDA(program_id, seeds); return pda; } - function getExtAuthority(bytes32 salt) external returns (bytes32){ + function getExtAuthority(bytes32 salt) external returns (bytes32) { bytes32 authority = _callSolana.getExtAuthority(salt); return authority; } - function executeWithSeed(uint64 lamports, bytes32 salt, bytes calldata instruction) public { - bytes32 returnData = bytes32(_callSolana.executeWithSeed(lamports, salt, instruction)); + function executeWithSeed( + uint64 lamports, + bytes32 salt, + bytes calldata instruction + ) public { + bytes32 returnData = bytes32( + _callSolana.executeWithSeed(lamports, salt, instruction) + ); emit LogBytes(returnData); } - function getReturnData() public returns (bytes32, bytes memory){ + function getReturnData() public returns (bytes32, bytes memory) { return _callSolana.getReturnData(); } function batchExecuteWithSeed(ExecuteWithSeedArgs[] memory _args) public { - for(uint i = 0; i < _args.length; i++) { - _callSolana.executeWithSeed(_args[i].lamports, _args[i].salt, _args[i].instruction); + for (uint i = 0; i < _args.length; i++) { + _callSolana.executeWithSeed( + _args[i].lamports, + _args[i].salt, + _args[i].instruction + ); } } -} \ No newline at end of file +} diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 684ddb576a..301ccd86b1 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -57,6 +57,47 @@ def call_solana_caller_sol_network(self, account_sol_network, web3_client_sol): ) return contract + def get_transfer_instruction(self, sol_client, from_wallet, to_wallet, amount, contract, is_set_authority=True): + mint = spl.token.client.Token.create_mint( + conn=sol_client, + payer=from_wallet, + mint_authority=from_wallet.pubkey(), + decimals=9, + program_id=TOKEN_PROGRAM_ID, + ) + mint.payer = from_wallet + from_token_account = mint.create_associated_token_account(from_wallet.pubkey()) + to_token_account = mint.create_associated_token_account(to_wallet.pubkey()) + mint.mint_to( + dest=from_token_account, + mint_authority=from_wallet, + amount=amount, + opts=TxOpts(skip_confirmation=False, skip_preflight=True), + ) + + authority_pubkey: bytes = contract.functions.getSolanaPDA(bytes(TRANSFER_TOKENS_ID), b"authority").call() + if is_set_authority: + mint.set_authority( + from_token_account, + from_wallet, + spl.token.instructions.AuthorityType.ACCOUNT_OWNER, + Pubkey(authority_pubkey), + opts=TxOpts(skip_confirmation=False, skip_preflight=True), + ) + + instruction = Instruction( + program_id=TRANSFER_TOKENS_ID, + accounts=[ + AccountMeta(from_token_account, is_signer=False, is_writable=True), + AccountMeta(mint.pubkey, is_signer=False, is_writable=True), + AccountMeta(to_token_account, is_signer=False, is_writable=True), + AccountMeta(Pubkey(authority_pubkey), is_signer=False, is_writable=True), + AccountMeta(TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), + ], + data=bytes([0x0]), + ) + return serialize_instruction(TRANSFER_TOKENS_ID, instruction), mint, [from_token_account, to_token_account] + def test_counter_execute_with_get_return_data( self, call_solana_caller, counter_resource_address: bytes, get_counter_value ): @@ -366,27 +407,28 @@ def test_solana_call_after_iterative_actions(self, counter_resource_address, cal event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - def test_failed_solana_call_after_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): + def test_failed_solana_call_after_iterative_actions(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): iterations = 29 sender = self.accounts[0] - lamports = 0 - - instruction = Instruction( - program_id=COUNTER_ID, - accounts=[ - AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), - ], - data=bytes([0x1]), - ) - serialized = serialize_instruction(TRANSFER_TOKENS_ID, instruction) + from_wallet = Keypair() + to_wallet = Keypair() + amount = 100000 + if pytestconfig.environment.use_bank: + sol_client.send_sol(bank_account, from_wallet.pubkey(), int(0.5 * 10**9)) + else: + sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) - tx = self.web3_client.make_raw_tx(sender.address) + serialized, _, _ = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller, False) + + tx = self.web3_client.make_raw_tx(from_=sender.address, estimate_gas=True) - with pytest.raises( - web3.exceptions.ContractLogicError, - match="execution reverted: External call fails", - ): - call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) + instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) + + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 0 + + event_logs = call_solana_caller.events.LogStr().process_receipt(resp) + assert len(event_logs) == 0 def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter_resource_address, call_solana_caller): iterations = 53 @@ -425,8 +467,8 @@ def test_solana_call_before_iterative_actions(self, counter_resource_address, ca serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, - lamports, + instruction_tx = call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, + lamports, serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 @@ -527,7 +569,7 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so assert event_logs[0].args.value == "deploy contracts status: done" def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): - iterations = 29 + iterations = 20 sender = self.accounts[0] from_wallet = Keypair() to_wallet = Keypair() @@ -537,45 +579,7 @@ def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_cal else: sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) - mint = spl.token.client.Token.create_mint( - conn=sol_client, - payer=from_wallet, - mint_authority=from_wallet.pubkey(), - decimals=9, - program_id=TOKEN_PROGRAM_ID, - ) - mint.payer = from_wallet - from_token_account = mint.create_associated_token_account(from_wallet.pubkey()) - to_token_account = mint.create_associated_token_account(to_wallet.pubkey()) - mint.mint_to( - dest=from_token_account, - mint_authority=from_wallet, - amount=amount, - opts=TxOpts(skip_confirmation=False, skip_preflight=True), - ) - - authority_pubkey: bytes = call_solana_caller.functions.getSolanaPDA(bytes(TRANSFER_TOKENS_ID), b"authority").call() - mint.set_authority( - from_token_account, - from_wallet, - spl.token.instructions.AuthorityType.ACCOUNT_OWNER, - Pubkey(authority_pubkey), - opts=TxOpts(skip_confirmation=False, skip_preflight=True), - ) - - instruction = Instruction( - program_id=TRANSFER_TOKENS_ID, - accounts=[ - AccountMeta(from_token_account, is_signer=False, is_writable=True), - AccountMeta(mint.pubkey, is_signer=False, is_writable=True), - AccountMeta(to_token_account, is_signer=False, is_writable=True), - AccountMeta(Pubkey(authority_pubkey), is_signer=False, is_writable=True), - AccountMeta(TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), - ], - data=bytes([0x0]), - ) - serialized = serialize_instruction(TRANSFER_TOKENS_ID, instruction) - + serialized, mint, accounts_list = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller) tx = self.web3_client.make_raw_tx(from_=sender.address, amount=None, data=None, tx_type=TransactionType.EIP_1559) instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) @@ -584,7 +588,7 @@ def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_cal assert resp["status"] == 1 assert resp.type == 2 - assert int(mint.get_balance(to_token_account, commitment=Confirmed).value.amount) == amount + assert int(mint.get_balance(accounts_list[1], commitment=Confirmed).value.amount) == amount event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == 0 @@ -616,8 +620,42 @@ def test_iterative_tx_with_send_tokens(self, counter_resource_address, call_sola resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 - event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) - assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - balance_after = self.web3_client.get_balance(call_solana_caller.address) assert balance_after == balance_before + 10 + + def test_solana_call_of_two_programs_in_one_iterative_tx(self, counter_resource_address, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): + iterations = 10 + sender = self.accounts[0] + from_wallet = Keypair() + to_wallet = Keypair() + amount = 100000 + if pytestconfig.environment.use_bank: + sol_client.send_sol(bank_account, from_wallet.pubkey(), int(0.5 * 10**9)) + else: + sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) + + serialized, mint, accounts_list = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller) + + tx = self.web3_client.make_raw_tx(sender.address) + + instruction_counter = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized_counter = serialize_instruction(COUNTER_ID, instruction_counter) + + + instruction_tx = call_solana_caller.functions.batchExecuteInIterativeMode(iterations, + [(0, serialized), (0, serialized_counter)]).build_transaction(tx) + + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + assert int(mint.get_balance(accounts_list[1], commitment=Confirmed).value.amount) == amount + + wait_condition( + lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, + timeout_sec=60, + ) \ No newline at end of file From ab96edc3f155920987cfeaf18f9a5341e22cee0d Mon Sep 17 00:00:00 2001 From: romanova-natasha Date: Thu, 19 Dec 2024 17:04:00 +0000 Subject: [PATCH 18/19] fix review fix review --- contracts/common/StorageSoliditySource.sol | 2 +- contracts/precompiled/CallSolanaCaller.sol | 33 ++++++++++--------- .../basic/evm/test_solana_interoperability.py | 10 +++--- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/contracts/common/StorageSoliditySource.sol b/contracts/common/StorageSoliditySource.sol index 11d925d59f..78c7307f23 100644 --- a/contracts/common/StorageSoliditySource.sol +++ b/contracts/common/StorageSoliditySource.sol @@ -23,7 +23,7 @@ contract Storage { return msg.sender.balance; } - function storeSumOfNumbers(uint256 num1, uint256 num2) public view returns (uint256) { + function storeSumOfNumbers(uint256 num1, uint256 num2) public view returns (uint256) { if (number == 101) { num1 = 0; } diff --git a/contracts/precompiled/CallSolanaCaller.sol b/contracts/precompiled/CallSolanaCaller.sol index d790cc681e..f52cdedb43 100644 --- a/contracts/precompiled/CallSolanaCaller.sol +++ b/contracts/precompiled/CallSolanaCaller.sol @@ -25,6 +25,7 @@ contract CallSolanaCaller { event LogBytes(bytes32 value); event LogStr(string value); + event LogAddress(address value); event LogData(bytes32 program, bytes value); function getNeonAddress(address addr) public returns (bytes32) { @@ -40,59 +41,59 @@ contract CallSolanaCaller { } function executeInIterativeMode( - uint256 iterations, + uint256 actionsNumber, uint64 lamports, bytes calldata instruction ) public { - doIterativeActions(iterations); + doIterativeActions(actionsNumber); execute(lamports, instruction); } function executeAndDoSomeIterativeActions( - uint256 iterations, + uint256 actionsNumber, uint64 lamports, bytes calldata instruction ) public { execute(lamports, instruction); - doIterativeActions(iterations); + doIterativeActions(actionsNumber); } function executeMultipleInIterativeMode( uint256 calls, - uint256 iterations, + uint256 actionsNumber, uint64 lamports, bytes calldata instruction ) public { - doIterativeActions(iterations); + doIterativeActions(actionsNumber); for (uint256 i = 0; i < calls; i++) { execute(lamports, instruction); } } function batchExecuteInIterativeMode( - uint256 iterations, + uint256 actionsNumber, ExecuteArgs[] memory _args ) public { - doIterativeActions(iterations); + doIterativeActions(actionsNumber); batchExecute(_args); } function sendTokensAndExecuteInIterativeMode( - uint256 iterations, + uint256 actionsNumber, uint64 lamports, bytes calldata instruction ) public payable { - executeInIterativeMode(iterations, lamports, instruction); + executeInIterativeMode(actionsNumber, lamports, instruction); } - function doSomeIterativeActions(uint256 iterations) public { - doIterativeActions(iterations); + function doSomeIterativeActions(uint256 actionsNumber) public { + doIterativeActions(actionsNumber); emit LogStr("iterative actions status: done"); } - function doIterativeActions(uint iterations) public { + function doIterativeActions(uint actionsNumber) public { // some actions to make the call iterative - for (uint256 i = 0; i < iterations; i++) { + for (uint256 i = 0; i < actionsNumber; i++) { Data memory newData = Data({value1: 1, value2: 2}); dataMap[i] = newData; } @@ -104,8 +105,10 @@ contract CallSolanaCaller { bytes calldata instruction ) public { Storage storageContract = new Storage(); + storageContract.store(10); + require(storageContract.retrieve() == 10); execute(lamports, instruction); - emit LogStr(message); + emit LogAddress(address(storageContract)); } function execute_with_get_return_data( diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 301ccd86b1..9da5632e6f 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -497,12 +497,11 @@ def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter ): call_solana_caller.functions.executeAndDoSomeIterativeActions(iterations, lamports, serialized).build_transaction(tx) - def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_address, call_solana_caller, get_counter_value): + def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_address, call_solana_caller): solana_calls = 5 iterations = 20 sender = self.accounts[0] lamports = 0 - instruction = Instruction( program_id=COUNTER_ID, accounts=[ @@ -519,8 +518,7 @@ def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_addr serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 - event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) - assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) + assert len(call_solana_caller.events.LogBytes().process_receipt(resp)) == solana_calls def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, counter_resource_address, call_solana_caller): solana_calls = 15 @@ -565,8 +563,8 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 - event_logs = call_solana_caller.events.LogStr().process_receipt(resp) - assert event_logs[0].args.value == "deploy contracts status: done" + event_logs = call_solana_caller.events.LogAddress().process_receipt(resp) + assert event_logs[0].args.value is not None def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): iterations = 20 From 4e9f1ab9e491992fe989fc05fa03dd9a5794498f Mon Sep 17 00:00:00 2001 From: Artem Yazkov Date: Mon, 23 Dec 2024 13:19:29 +0500 Subject: [PATCH 19/19] NDEV-3380 change tests order for tests test_iterative_actions_and_multiple_solana_calls_instructions_limit, test_transfer_with_pda_signature_iterative_tx_eip_1559 --- .../basic/evm/test_solana_interoperability.py | 139 +++++++++--------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 9da5632e6f..3d1cf2bd87 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -42,11 +42,11 @@ def gen_increment_counter(): class TestSolanaInteroperability: accounts: EthAccounts web3_client: NeonChainWeb3Client - + @pytest.fixture(scope="class") def account_sol_network(self, class_account_sol_chain): return class_account_sol_chain - + @pytest.fixture(scope="class") def call_solana_caller_sol_network(self, account_sol_network, web3_client_sol): contract, _ = web3_client_sol.deploy_and_get_contract( @@ -97,7 +97,7 @@ def get_transfer_instruction(self, sol_client, from_wallet, to_wallet, amount, c data=bytes([0x0]), ) return serialize_instruction(TRANSFER_TOKENS_ID, instruction), mint, [from_token_account, to_token_account] - + def test_counter_execute_with_get_return_data( self, call_solana_caller, counter_resource_address: bytes, get_counter_value ): @@ -123,6 +123,58 @@ def test_counter_execute_with_get_return_data( assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) assert bytes32_to_solana_pubkey(event_logs[0].args.program.hex()) == COUNTER_ID + def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, counter_resource_address, call_solana_caller): + solana_calls = 15 + iterations = 35 + sender = self.accounts[0] + lamports = 0 + + instruction = Instruction( + program_id=COUNTER_ID, + accounts=[ + AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), + ], + data=bytes([0x1]), + ) + serialized = serialize_instruction(COUNTER_ID, instruction) + + tx = self.web3_client.make_raw_tx(sender.address) + instruction_tx = call_solana_caller.functions.executeMultipleInIterativeMode(solana_calls, + iterations, + lamports, + serialized).build_transaction(tx) + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 0 + + def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): + iterations = 20 + sender = self.accounts[0] + from_wallet = Keypair() + to_wallet = Keypair() + amount = 100000 + if pytestconfig.environment.use_bank: + sol_client.send_sol(bank_account, from_wallet.pubkey(), int(0.5 * 10**9)) + else: + sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) + + serialized, mint, accounts_list = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller) + tx = self.web3_client.make_raw_tx(from_=sender.address, amount=None, data=None, tx_type=TransactionType.EIP_1559) + + instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) + + resp = self.web3_client.send_transaction(sender, instruction_tx) + assert resp["status"] == 1 + assert resp.type == 2 + + assert int(mint.get_balance(accounts_list[1], commitment=Confirmed).value.amount) == amount + event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) + assert int.from_bytes(event_logs[0].args.value, byteorder="little") == 0 + + wait_condition( + lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, + timeout_sec=120, + ) + def test_counter_with_seed(self, call_solana_caller, counter_resource_address: bytes, get_counter_value): sender = self.accounts[0] lamports = 0 @@ -361,6 +413,7 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 + def test_solana_call_after_iterative_actions_sol_network(self, web3_client_sol, counter_resource_address, call_solana_caller_sol_network, @@ -385,7 +438,7 @@ def test_solana_call_after_iterative_actions_sol_network(self, web3_client_sol, assert resp["status"] == 1 event_logs = call_solana_caller_sol_network.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - + def test_solana_call_after_iterative_actions(self, counter_resource_address, call_solana_caller, get_counter_value): iterations = 29 sender = self.accounts[0] @@ -406,7 +459,7 @@ def test_solana_call_after_iterative_actions(self, counter_resource_address, cal assert resp["status"] == 1 event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) assert int.from_bytes(event_logs[0].args.value, byteorder="little") == next(get_counter_value) - + def test_failed_solana_call_after_iterative_actions(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): iterations = 29 sender = self.accounts[0] @@ -419,17 +472,18 @@ def test_failed_solana_call_after_iterative_actions(self, call_solana_caller, so sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) serialized, _, _ = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller, False) - + tx = self.web3_client.make_raw_tx(from_=sender.address, estimate_gas=True) instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) - + resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 0 - + event_logs = call_solana_caller.events.LogStr().process_receipt(resp) assert len(event_logs) == 0 - + + def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter_resource_address, call_solana_caller): iterations = 53 sender = self.accounts[0] @@ -445,7 +499,7 @@ def test_solana_call_after_iterative_actions_exceed_accounts_limit(self, counter serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - + with pytest.raises( web3.exceptions.ContractLogicError, match="too many accounts: 65 > 64", @@ -490,7 +544,7 @@ def test_iterative_actions_after_solana_call_exceed_accounts_limit(self, counter serialized = serialize_instruction(COUNTER_ID, instruction) tx = self.web3_client.make_raw_tx(sender.address) - + with pytest.raises( web3.exceptions.ContractLogicError, match="too many accounts: 65 > 64", @@ -519,30 +573,7 @@ def test_iterative_actions_and_multiple_solana_calls(self, counter_resource_addr resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 assert len(call_solana_caller.events.LogBytes().process_receipt(resp)) == solana_calls - - def test_iterative_actions_and_multiple_solana_calls_instructions_limit(self, counter_resource_address, call_solana_caller): - solana_calls = 15 - iterations = 35 - sender = self.accounts[0] - lamports = 0 - instruction = Instruction( - program_id=COUNTER_ID, - accounts=[ - AccountMeta(Pubkey(counter_resource_address), is_signer=False, is_writable=True), - ], - data=bytes([0x1]), - ) - serialized = serialize_instruction(COUNTER_ID, instruction) - - tx = self.web3_client.make_raw_tx(sender.address) - instruction_tx = call_solana_caller.functions.executeMultipleInIterativeMode(solana_calls, - iterations, - lamports, - serialized).build_transaction(tx) - resp = self.web3_client.send_transaction(sender, instruction_tx) - assert resp["status"] == 0 - def test_deploy_contract_and_call_solana(self, counter_resource_address, call_solana_caller): sender = self.accounts[0] lamports = 0 @@ -562,38 +593,10 @@ def test_deploy_contract_and_call_solana(self, counter_resource_address, call_so serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 - + event_logs = call_solana_caller.events.LogAddress().process_receipt(resp) assert event_logs[0].args.value is not None - def test_transfer_with_pda_signature_iterative_tx_eip_1559(self, call_solana_caller, sol_client, solana_account, pytestconfig, bank_account): - iterations = 20 - sender = self.accounts[0] - from_wallet = Keypair() - to_wallet = Keypair() - amount = 100000 - if pytestconfig.environment.use_bank: - sol_client.send_sol(bank_account, from_wallet.pubkey(), int(0.5 * 10**9)) - else: - sol_client.request_airdrop(from_wallet.pubkey(), 1000 * 10**9, commitment=Confirmed) - - serialized, mint, accounts_list = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller) - tx = self.web3_client.make_raw_tx(from_=sender.address, amount=None, data=None, tx_type=TransactionType.EIP_1559) - - instruction_tx = call_solana_caller.functions.executeInIterativeMode(iterations, 0, serialized).build_transaction(tx) - - resp = self.web3_client.send_transaction(sender, instruction_tx) - assert resp["status"] == 1 - assert resp.type == 2 - - assert int(mint.get_balance(accounts_list[1], commitment=Confirmed).value.amount) == amount - event_logs = call_solana_caller.events.LogBytes().process_receipt(resp) - assert int.from_bytes(event_logs[0].args.value, byteorder="little") == 0 - - wait_condition( - lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, - timeout_sec=60, - ) def test_iterative_tx_with_send_tokens(self, counter_resource_address, call_solana_caller, get_counter_value): iterations = 29 @@ -617,7 +620,7 @@ def test_iterative_tx_with_send_tokens(self, counter_resource_address, call_sola serialized).build_transaction(tx) resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 - + balance_after = self.web3_client.get_balance(call_solana_caller.address) assert balance_after == balance_before + 10 @@ -635,7 +638,7 @@ def test_solana_call_of_two_programs_in_one_iterative_tx(self, counter_resource_ serialized, mint, accounts_list = self.get_transfer_instruction(sol_client, from_wallet, to_wallet, amount, call_solana_caller) tx = self.web3_client.make_raw_tx(sender.address) - + instruction_counter = Instruction( program_id=COUNTER_ID, accounts=[ @@ -648,12 +651,12 @@ def test_solana_call_of_two_programs_in_one_iterative_tx(self, counter_resource_ instruction_tx = call_solana_caller.functions.batchExecuteInIterativeMode(iterations, [(0, serialized), (0, serialized_counter)]).build_transaction(tx) - + resp = self.web3_client.send_transaction(sender, instruction_tx) assert resp["status"] == 1 assert int(mint.get_balance(accounts_list[1], commitment=Confirmed).value.amount) == amount - + wait_condition( lambda: self.web3_client.is_trx_iterative(resp["transactionHash"].hex()) is True, timeout_sec=60, - ) \ No newline at end of file + )