diff --git a/contracts/EIPs/ERC20/MultipleActions.sol b/contracts/EIPs/ERC20/MultipleActions.sol index ecc8db598..581ce5903 100644 --- a/contracts/EIPs/ERC20/MultipleActions.sol +++ b/contracts/EIPs/ERC20/MultipleActions.sol @@ -115,6 +115,22 @@ contract MultipleActionsERC20 { erc20.transfer(transfer_to, transfer_amount); } + + function transferReadBalanceTransfer( + uint256 transfer_amount, + address transfer_to + ) public { + uint current_balance; + uint balance_before = erc20.balanceOf(address(this)); + uint expected_balance = balance_before - transfer_amount; + erc20.transfer(transfer_to, transfer_amount); + for (uint256 i = 0; i < 50; i++) { + current_balance = erc20.balanceOf(address(this)); + require(current_balance == expected_balance, "balance not updated"); + } + erc20.transfer(transfer_to, transfer_amount); + } + function mintMint( uint256 mint_amount1, uint256 mint_amount2 diff --git a/contracts/common/Block.sol b/contracts/common/Block.sol index c4f9e9300..06b857eab 100644 --- a/contracts/common/Block.sol +++ b/contracts/common/Block.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.10; + import "../libraries/CarefulMath.sol"; contract BlockTimestamp is CarefulMath { event Result(uint256 block_timestamp); + uint256 public a; uint public accrualBlockTimestamp; uint public accrualBlockNumber; @@ -13,7 +15,9 @@ contract BlockTimestamp is CarefulMath { uint256 value1; uint256 value2; } + mapping(uint256 => Data) public dataByTimestamp; + event DataAdded(uint256 timestamp, uint256 value1, uint256 value2); constructor() { @@ -50,6 +54,7 @@ contract BlockTimestamp is CarefulMath { accrualBlockNumber = currentBlockTimestamp; } + function addDataToMapping(uint256 _value1, uint256 _value2) public { uint256 currentTimestamp = block.timestamp % 1000000; for (uint256 i = 0; i < 20; i++) { @@ -72,6 +77,7 @@ contract BlockTimestamp is CarefulMath { contract BlockTimestampDeployer { BlockTimestamp public blockTimestamp; + event Log(address indexed addr); constructor() { @@ -84,6 +90,7 @@ contract BlockTimestampDeployer { contract BlockNumber is CarefulMath { event Log(address indexed sender, string message); event Result(uint256 block_number); + bytes32[64] public b; @@ -93,6 +100,7 @@ contract BlockNumber is CarefulMath { uint256 value1; uint256 value2; } + mapping(uint256 => Data) public dataByNumber; uint256 public a; @@ -148,4 +156,20 @@ contract BlockNumber is CarefulMath { accrualBlockNumber = currentBlockNumber; } + + + function accrueInterestIterative() public { + uint currentBlockNumber = block.number; + uint accrualBlockNumberPrior = accrualBlockNumber; + + bytes memory result = new bytes(1000); + for (uint256 i = 0; i < 1000; i++) { + result[i] = "a"; + } + + (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior); + require(mathErr == MathError.NO_ERROR, "calc block delta error"); + + accrualBlockNumber = currentBlockNumber; + } } \ No newline at end of file diff --git a/deploy/cli/infrastructure.py b/deploy/cli/infrastructure.py index 0e29cce76..7bdc4f651 100644 --- a/deploy/cli/infrastructure.py +++ b/deploy/cli/infrastructure.py @@ -5,6 +5,7 @@ import typing as tp import pathlib import logging +import time from paramiko.client import SSHClient from scp import SCPClient @@ -57,22 +58,56 @@ def deploy_infrastructure( os.environ["TF_VAR_proxy_model_commit"] = proxy_branch os.environ["TF_VAR_dockerhub_org_name"] = os.environ.get("GITHUB_REPOSITORY_OWNER") os.environ["TF_VAR_devnet_solana_url"] = devnet_solana_url - os.environ["TF_LOG"] = "DEBUG" if use_real_price: os.environ["TF_VAR_use_real_price"] = "1" + instance_types = ["cpx51", "cx52", "cpx41", "cx42", "ccx33", "ccx43"] + locations = ["nbg1", "hel1", "fsn1", "ash", "hil", "sin"] + instances = [{"server_type": i, "location": j} for i in instance_types for j in locations] + print("Possible instance options: ", instances) + + retry_amount = 10 + retry_amount = ( + len(instances) if len(instances) > retry_amount else retry_amount + ) # Verify that we can try all regions and locations + terraform.init(backend_config=TF_BACKEND_CONFIG) - return_code, stdout, stderr = terraform.apply(skip_plan=True) - print(f"code: {return_code}") - print(f"stdout: {stdout}") - print(f"stderr: {stderr}") - with open("terraform.log", "w") as file: - file.write(stdout) - file.write(stderr) - if return_code != 0: + + instance_iterator = 0 + retry_iterator = 0 + while retry_iterator < retry_amount: + return_code, stdout, stderr = terraform.apply( + skip_plan=True, + capture_output=True, + var={ + "server_type": instances[instance_iterator]["server_type"], + "location": instances[instance_iterator]["location"], + }, + ) + print(f"code: {return_code}") + print(f"stdout: {stdout}") + print(f"stderr: {stderr}") + if return_code == 0: + break + elif return_code != 0: + retry_iterator += 1 + if "(resource_unavailable)" in stderr: + instance_iterator += 1 + print( + "Resource_unavailable; ", + instances[instance_iterator], + " Trying to recreate instances with another region / another instance type...", + ) + else: + print("Retry because ", stderr, "; Retries left: ", retry_amount - retry_iterator) + time.sleep(3) + if retry_iterator >= retry_amount: + print("Retries left: ", retry_amount - retry_iterator) + print("Terraform apply failed:", stderr) print("Terraform infrastructure is not built correctly") sys.exit(1) + output = terraform.output(json=True) print(f"output: {output}") proxy_ip = output["proxy_ip"]["value"] diff --git a/deploy/hetzner/main.tf b/deploy/hetzner/main.tf index bcd80a12c..95f29e3fc 100644 --- a/deploy/hetzner/main.tf +++ b/deploy/hetzner/main.tf @@ -21,12 +21,12 @@ resource "hcloud_server" "proxy" { content = data.template_file.proxy_init.rendered destination = "/tmp/proxy_init.sh" - connection { - type = "ssh" - user = "root" - host = hcloud_server.proxy.ipv4_address - private_key = file("/tmp/ci-stands") - } + connection { + type = "ssh" + user = "root" + host = hcloud_server.proxy.ipv4_address + private_key = file("/tmp/ci-stands") + } } @@ -37,18 +37,18 @@ resource "hcloud_server" "proxy" { "chmod a+x /tmp/proxy_init.sh", "sudo /tmp/proxy_init.sh" ] - connection { - type = "ssh" - user = "root" - host = hcloud_server.proxy.ipv4_address - private_key = file("/tmp/ci-stands") - } + connection { + type = "ssh" + user = "root" + host = hcloud_server.proxy.ipv4_address + private_key = file("/tmp/ci-stands") + } } labels = { environment = "ci" - purpose = "ci-oz-full-tests" + purpose = "ci-oz-full-tests" } depends_on = [ hcloud_server.solana diff --git a/deploy/hetzner/vars.tf b/deploy/hetzner/vars.tf index 7a913c7ce..462c9efbb 100644 --- a/deploy/hetzner/vars.tf +++ b/deploy/hetzner/vars.tf @@ -16,6 +16,6 @@ variable "dockerhub_org_name" { } variable "use_real_price" { - type = number + type = number default = 0 } \ No newline at end of file diff --git a/docs/tests/audit/erc/test_ERC20SPL.md b/docs/tests/audit/erc/test_ERC20SPL.md index 8dc0d5fed..eda43bf92 100644 --- a/docs/tests/audit/erc/test_ERC20SPL.md +++ b/docs/tests/audit/erc/test_ERC20SPL.md @@ -5,61 +5,60 @@ tokens # Tests list -| Test case | Description | XFailed | -|-------------------------------------------------------------------------------|-----------------------------------------------------------------------------|---------| -| TestERC20wrapperContract::test_metaplex_data_mintable | Get metaplex data from mintable contract | | -| TestERC20wrapperContract::test_metaplex_data | Get metaplex data from contract | | -| TestERC20wrapperContract::test_balanceOf | Get user balance | | -| TestERC20wrapperContract::test_balanceOf_with_incorrect_address | Get balance from incorrect address | | -| TestERC20wrapperContract::test_mint_to_self | Verify mint to sender | | -| TestERC20wrapperContract::test_mint_to_another_account | Verify mint to another account | | -| TestERC20wrapperContract::test_mint_by_no_minter_role | Verify error if minter is not owner | | -| TestERC20wrapperContract::test_mint_with_incorrect_address | Mint to incorrect address | | -| TestERC20wrapperContract::test_mint_with_too_big_amount | Expect error on mint with big amount | | -| TestERC20wrapperContract::test_mint_no_enough_gas | Error on mint with not enough gas | | -| TestERC20wrapperContract::test_totalSupply | Get totalSupply | | -| TestERC20wrapperContract::test_totalSupply_mintable | Get totalSupply on mintable | | -| TestERC20wrapperContract::test_decimals | Get decimals | | -| TestERC20wrapperContract::test_symbol | Get symbol | | -| TestERC20wrapperContract::test_name | Get name | | -| TestERC20wrapperContract::test_burn | Verify burn work | | -| TestERC20wrapperContract::test_burn_incorrect_address | Burn to incorrect address | | -| TestERC20wrapperContract::test_burn_more_than_total_supply | Try to burn more than supply | | -| TestERC20wrapperContract::test_burn_no_enough_gas | Burn with not enough gas | | -| TestERC20wrapperContract::test_burnFrom | Verify burnFrom | | -| TestERC20wrapperContract::test_burnFrom_without_allowance | Verify burnFrom without allowance | | -| TestERC20wrapperContract::test_burnFrom_more_than_allowanced | Verify burnFrom more allowed | | -| TestERC20wrapperContract::test_burnFrom_incorrect_address | Verify burnFrom with incorrect address | | -| TestERC20wrapperContract::test_burnFrom_no_enough_gas | Verify burnFrom with not enough gas | | -| TestERC20wrapperContract::test_approve_more_than_total_supply | Try to approve more than supply | | -| TestERC20wrapperContract::test_approve_incorrect_address | Try to approve incorrect address | | -| TestERC20wrapperContract::test_approve_no_enough_gas | Try to approve with not enough gas | | -| TestERC20wrapperContract::test_allowance_incorrect_address | Check allowance method with incorrect address | | -| TestERC20wrapperContract::test_allowance_for_new_account | Check allowance method for new account | | -| TestERC20wrapperContract::test_transfer | Verify transfer | | -| TestERC20wrapperContract::test_transfer_incorrect_address | Verify transfer for incorrect address | | -| TestERC20wrapperContract::test_transfer_more_than_balance | Expect error on transfer more than balance | | -| TestERC20wrapperContract::test_transfer_no_enough_gas | Expect error with not enough gas | | -| TestERC20wrapperContract::test_transferFrom | Verify transferFrom | | -| TestERC20wrapperContract::test_transferFrom_without_allowance | Verify transferFrom without allowance | | -| TestERC20wrapperContract::test_transferFrom_more_than_allowance | Verify transferFrom with more than allowance | | -| TestERC20wrapperContract::test_transferFrom_incorrect_address | Verify transferFrom with incorrect address | | -| TestERC20wrapperContract::test_transferFrom_more_than_balance | Expect error on transferFrom more than balance | | -| TestERC20wrapperContract::test_transferFrom_no_enough_gas | Expect error with not enough gas | | -| TestERC20wrapperContract::test_transferSolana | Check transferSolana method | | -| TestERC20wrapperContract::test_approveSolana | Check approveSolana method | | -| TestERC20wrapperContract::test_claim | Check claim | | -| TestERC20wrapperContract::test_claimTo | Check claimTo | | -| TestMultipleActionsForERC20::test_mint_transfer_burn | Verify mint -> transfer -> burn in one transaction | | -| TestMultipleActionsForERC20::test_mint_transfer_transfer_one_recipient | Verify mint -> transfer -> transfer for one account in one transaction | | -| TestMultipleActionsForERC20::test_mint_transfer_transfer_different_recipients | Verify mint -> transfer -> transfer for several accounts in one transaction | | -| TestMultipleActionsForERC20::test_transfer_mint_burn | Verify transfer -> mint -> burn in one transaction | | -| TestMultipleActionsForERC20::test_transfer_mint_transfer_burn | Verify transfer -> mint -> transfer -> burn in one transaction | | -| TestMultipleActionsForERC20::test_mint_burn_transfer | Verify mint -> burn -> transfer in one transaction | | -| TestMultipleActionsForERC20::test_mint_mint | Verify mint -> mint in one transaction | | -| TestMultipleActionsForERC20::test_mint_mint_transfer_transfer | Verify mint -> mint -> transfer -> transfer in one transaction | | -| TestMultipleActionsForERC20::test_burn_transfer_burn_transfer | Verify burn -> transfer -> burn in one transaction | | -| TestMultipleActionsForERC20::test_burn_mint_transfer | Verify burn -> mint -> transfer in one transaction | | - - - +| Test case | Description | XFailed | +|--------------------------------------------------------------------------------|-----------------------------------------------------------------------------|---------| +| TestERC20wrapperContract::test_metaplex_data_mintable | Get metaplex data from mintable contract | | +| TestERC20wrapperContract::test_metaplex_data | Get metaplex data from contract | | +| TestERC20wrapperContract::test_balanceOf | Get user balance | | +| TestERC20wrapperContract::test_balanceOf_with_incorrect_address | Get balance from incorrect address | | +| TestERC20wrapperContract::test_mint_to_self | Verify mint to sender | | +| TestERC20wrapperContract::test_mint_to_another_account | Verify mint to another account | | +| TestERC20wrapperContract::test_mint_by_no_minter_role | Verify error if minter is not owner | | +| TestERC20wrapperContract::test_mint_with_incorrect_address | Mint to incorrect address | | +| TestERC20wrapperContract::test_mint_with_too_big_amount | Expect error on mint with big amount | | +| TestERC20wrapperContract::test_mint_no_enough_gas | Error on mint with not enough gas | | +| TestERC20wrapperContract::test_totalSupply | Get totalSupply | | +| TestERC20wrapperContract::test_totalSupply_mintable | Get totalSupply on mintable | | +| TestERC20wrapperContract::test_decimals | Get decimals | | +| TestERC20wrapperContract::test_symbol | Get symbol | | +| TestERC20wrapperContract::test_name | Get name | | +| TestERC20wrapperContract::test_burn | Verify burn work | | +| TestERC20wrapperContract::test_burn_incorrect_address | Burn to incorrect address | | +| TestERC20wrapperContract::test_burn_more_than_total_supply | Try to burn more than supply | | +| TestERC20wrapperContract::test_burn_no_enough_gas | Burn with not enough gas | | +| TestERC20wrapperContract::test_burnFrom | Verify burnFrom | | +| TestERC20wrapperContract::test_burnFrom_without_allowance | Verify burnFrom without allowance | | +| TestERC20wrapperContract::test_burnFrom_more_than_allowanced | Verify burnFrom more allowed | | +| TestERC20wrapperContract::test_burnFrom_incorrect_address | Verify burnFrom with incorrect address | | +| TestERC20wrapperContract::test_burnFrom_no_enough_gas | Verify burnFrom with not enough gas | | +| TestERC20wrapperContract::test_approve_more_than_total_supply | Try to approve more than supply | | +| TestERC20wrapperContract::test_approve_incorrect_address | Try to approve incorrect address | | +| TestERC20wrapperContract::test_approve_no_enough_gas | Try to approve with not enough gas | | +| TestERC20wrapperContract::test_allowance_incorrect_address | Check allowance method with incorrect address | | +| TestERC20wrapperContract::test_allowance_for_new_account | Check allowance method for new account | | +| TestERC20wrapperContract::test_transfer | Verify transfer | | +| TestERC20wrapperContract::test_transfer_and_check_sol_account_list_is_correct | Check account list doesn't contain program address of precompiled contract | | +| TestERC20wrapperContract::test_transfer_incorrect_address | Verify transfer for incorrect address | | +| TestERC20wrapperContract::test_transfer_more_than_balance | Expect error on transfer more than balance | | +| TestERC20wrapperContract::test_transfer_no_enough_gas | Expect error with not enough gas | | +| TestERC20wrapperContract::test_transferFrom | Verify transferFrom | | +| TestERC20wrapperContract::test_transferFrom_without_allowance | Verify transferFrom without allowance | | +| TestERC20wrapperContract::test_transferFrom_more_than_allowance | Verify transferFrom with more than allowance | | +| TestERC20wrapperContract::test_transferFrom_incorrect_address | Verify transferFrom with incorrect address | | +| TestERC20wrapperContract::test_transferFrom_more_than_balance | Expect error on transferFrom more than balance | | +| TestERC20wrapperContract::test_transferFrom_no_enough_gas | Expect error with not enough gas | | +| TestERC20wrapperContract::test_transferSolana | Check transferSolana method | | +| TestERC20wrapperContract::test_approveSolana | Check approveSolana method | | +| TestERC20wrapperContract::test_claim | Check claim | | +| TestERC20wrapperContract::test_claimTo | Check claimTo | | +| TestMultipleActionsForERC20::test_mint_transfer_burn | Verify mint -> transfer -> burn in one transaction | | +| TestMultipleActionsForERC20::test_mint_transfer_transfer_one_recipient | Verify mint -> transfer -> transfer for one account in one transaction | | +| TestMultipleActionsForERC20::test_mint_transfer_transfer_different_recipients | Verify mint -> transfer -> transfer for several accounts in one transaction | | +| TestMultipleActionsForERC20::test_transfer_mint_burn | Verify transfer -> mint -> burn in one transaction | | +| TestMultipleActionsForERC20::test_transfer_mint_transfer_burn | Verify transfer -> mint -> transfer -> burn in one transaction | | +| TestMultipleActionsForERC20::test_mint_burn_transfer | Verify mint -> burn -> transfer in one transaction | | +| TestMultipleActionsForERC20::test_mint_mint | Verify mint -> mint in one transaction | | +| TestMultipleActionsForERC20::test_mint_mint_transfer_transfer | Verify mint -> mint -> transfer -> transfer in one transaction | | +| TestMultipleActionsForERC20::test_burn_transfer_burn_transfer | Verify burn -> transfer -> burn in one transaction | | +| TestMultipleActionsForERC20::test_burn_mint_transfer | Verify burn -> mint -> transfer in one transaction | | +| TestMultipleActionsForERC20::test_parallel_trxs_transfer_read_balance_transfer | Verify spl balance isn't cashed | | diff --git a/docs/tests/audit/indexer/test_instruction_parsing.md b/docs/tests/audit/indexer/test_instruction_parsing.md index f5223d817..40b46972d 100644 --- a/docs/tests/audit/indexer/test_instruction_parsing.md +++ b/docs/tests/audit/indexer/test_instruction_parsing.md @@ -2,13 +2,12 @@ Tests for instructions -| Test case | Description | XFailed | -|---------------------------------------------------------|-------------------------------------------------|---------| -| TestInstruction::test_tx_exec_from_data | Check TxExecFromData | | -| TestInstruction::test_tx_step_from_data | Check TxStepFromData | | -| TestInstruction::test_cancel_with_hash | Check CancelWithHash | | -| TestInstruction::test_tx_exec_from_data_solana_call | Check TxExecFromDataSolanaCall | | -| TestInstruction::test_tx_step_from_account_no_chain_id | Check TxStepFromAccountNoChainId | | -| TestInstruction::test_holder_write_tx_exec_from_account | Check HolderWrite & TxExecFromAccount | | -| TestInstruction::test_step_from_account | Check TxStepFromAccount & HolderWrite | | -| TestInstruction::test_tx_exec_from_account_solana_call | Check HolderWrite & TxExecFromAccountSolanaCall | | \ No newline at end of file +| Test case | Description | XFailed | +|---------------------------------------------------------------|----------------------------------------------------|---------| +| TestInstruction::test_tx_exec_from_data | Check TxExecFromData | | +| TestInstruction::test_cancel_with_hash | Check CancelWithHash | | +| TestInstruction::test_tx_exec_from_data_solana_call | Check TxExecFromDataSolanaCall | | +| TestInstruction::test_tx_iterative_with_and_without_chain_id | Check TxStepFromAccountNoChainId & TxStepFromData | +| TestInstruction::test_holder_write_tx_exec_from_account | Check HolderWrite & TxExecFromAccount | | +| TestInstruction::test_step_from_account | Check TxStepFromAccount & HolderWrite | | +| TestInstruction::test_tx_exec_from_account_solana_call | Check HolderWrite & TxExecFromAccountSolanaCall | | \ No newline at end of file diff --git a/integration/tests/basic/erc/test_EIP2535.py b/integration/tests/basic/erc/test_EIP2535.py index d65409881..8343bc606 100644 --- a/integration/tests/basic/erc/test_EIP2535.py +++ b/integration/tests/basic/erc/test_EIP2535.py @@ -5,7 +5,7 @@ from web3.exceptions import ContractLogicError from utils.consts import ZERO_ADDRESS -from utils.helpers import get_selectors, decode_function_signature +from utils.helpers import get_selectors from utils.web3client import NeonChainWeb3Client from utils.accounts import EthAccounts @@ -20,66 +20,6 @@ class TestDiamond: web3_client: NeonChainWeb3Client accounts: EthAccounts - @pytest.fixture(scope="class") - def diamond_init(self, web3_client_session, accounts): - contract, _ = web3_client_session.deploy_and_get_contract( - "EIPs/EIP2535/upgradeInitializers/DiamondInit.sol", - "0.8.10", - accounts[0], - contract_name="DiamondInit", - ) - return contract - - @pytest.fixture(scope="class") - def facet_cuts(self, diamond_cut_facet, diamond_loupe_facet, ownership_facet): - facet_cuts = [] - for facet in [diamond_cut_facet, diamond_loupe_facet, ownership_facet]: - facet_cuts.append((facet.address, facet_cut_action["Add"], get_selectors(facet.abi))) - return facet_cuts - - @pytest.fixture(scope="class") - def diamond_cut_facet(self, web3_client_session, accounts): - contract, _ = web3_client_session.deploy_and_get_contract( - "EIPs/EIP2535/facets/DiamondCutFacet", - "0.8.10", - accounts[0], - contract_name="DiamondCutFacet", - ) - return contract - - @pytest.fixture(scope="class") - def diamond_loupe_facet(self, web3_client_session, accounts): - contract, _ = web3_client_session.deploy_and_get_contract( - "EIPs/EIP2535/facets/DiamondLoupeFacet.sol", - "0.8.10", - accounts[0], - contract_name="DiamondLoupeFacet", - ) - return contract - - @pytest.fixture(scope="class") - def ownership_facet(self, web3_client_session, accounts): - contract, _ = web3_client_session.deploy_and_get_contract( - "EIPs/EIP2535/facets/OwnershipFacet", - "0.8.10", - accounts[0], - contract_name="OwnershipFacet", - ) - return contract - - @pytest.fixture(scope="class") - def diamond(self, web3_client_session, diamond_init, facet_cuts, accounts): - calldata = decode_function_signature("init()") - diamond_args = [accounts[0].address, diamond_init.address, calldata] - contract, tx = web3_client_session.deploy_and_get_contract( - "EIPs/EIP2535/Diamond", - "0.8.10", - accounts[0], - contract_name="Diamond", - constructor_args=[facet_cuts, diamond_args], - ) - return contract - def test_facet_addresses(self, diamond, facet_cuts): addresses = self.web3_client.call_function_at_address(diamond.address, "facetAddresses()", None, ["address[]"]) assert len(addresses) == 3 @@ -114,6 +54,7 @@ def test_add_and_remove_function(self, diamond, diamond_cut_facet): tx = self.web3_client.make_raw_tx(account, diamond.address, 0, data=calldata, estimate_gas=True) self.web3_client.send_transaction(account, tx) + result = self.web3_client.call_function_at_address( diamond.address, "facetFunctionSelectors(address)", diff --git a/integration/tests/basic/erc/test_ERC20SPL.py b/integration/tests/basic/erc/test_ERC20SPL.py index 096df7a97..306a2365e 100644 --- a/integration/tests/basic/erc/test_ERC20SPL.py +++ b/integration/tests/basic/erc/test_ERC20SPL.py @@ -11,8 +11,9 @@ from spl.token import instructions from spl.token.constants import TOKEN_PROGRAM_ID +from integration.tests.basic.helpers.rpc_checks import assert_solana_address_was_not_used_in_trx from utils import metaplex -from utils.consts import ZERO_ADDRESS +from utils.consts import ZERO_ADDRESS, METAPLEX_ADDRESS, SPL_TOKEN_ADDRESS, CALL_SOLANA_ADDRESS, SOLANA_NATIVE_ADDRESS from utils.erc20wrapper import ERC20Wrapper from utils.helpers import gen_hash_of_block, wait_condition, create_invalid_address from utils.web3client import NeonChainWeb3Client @@ -213,6 +214,17 @@ def test_transfer(self, erc20_contract, restore_balance): assert balance_acc2_after == balance_acc2_before + amount assert total_before == total_after + def test_transfer_and_check_sol_account_list_is_correct(self, erc20_contract, restore_balance, evm_loader): + new_account = self.accounts.create_account() + + receipt = erc20_contract.transfer(erc20_contract.account, new_account.address, 100) + precompiled_addresses = [METAPLEX_ADDRESS, SPL_TOKEN_ADDRESS, CALL_SOLANA_ADDRESS, SOLANA_NATIVE_ADDRESS] + for precompiled_address in precompiled_addresses: + program_address = evm_loader.ether2program(precompiled_address[2:])[0] + assert_solana_address_was_not_used_in_trx( + receipt["transactionHash"].hex(), program_address, self.web3_client, evm_loader + ) + @pytest.mark.parametrize( "block_len, expected_exception, msg", [ @@ -978,6 +990,31 @@ def test_burn_mint_transfer(self, multiple_actions_erc20): ), "Contract balance is not correct" assert user_balance == transfer_amount + user_balance_before, "User balance is not correct" + def test_parallel_trxs_transfer_read_balance_transfer(self, multiple_actions_erc20, faucet, solana_account): + sender_account = self.accounts[0] + receiver_account = self.accounts[1] + acc, contract = multiple_actions_erc20 + trx_amount = 10 + transfer_amount = 100 + + tx = self.web3_client.make_raw_tx(sender_account) + instruction_tx = contract.functions.mint(transfer_amount * trx_amount * 2).build_transaction(tx) + self.web3_client.send_transaction(sender_account, instruction_tx) + + hashes = [] + nonce = self.web3_client.get_nonce(sender_account.address) + for i in range(trx_amount): + tx = self.web3_client.make_raw_tx(sender_account, nonce=nonce + i) + transaction = contract.functions.transferReadBalanceTransfer( + transfer_amount, receiver_account.address + ).build_transaction(tx) + instruction_tx = self.web3_client._web3.eth.account.sign_transaction(transaction, sender_account.key) + signature = self.web3_client._web3.eth.send_raw_transaction(instruction_tx.rawTransaction) + hashes.append(signature.hex()) + for tx_hash in hashes: + resp = self.web3_client.wait_for_transaction_receipt(tx_hash) + assert resp.status == 1, f"Transaction {tx_hash} failed" + @pytest.fixture(scope="class") def new_factory_contract(web3_client, erc20_spl_mintable): diff --git a/integration/tests/basic/evm/conftest.py b/integration/tests/basic/evm/conftest.py index 0f474531f..27315adbd 100644 --- a/integration/tests/basic/evm/conftest.py +++ b/integration/tests/basic/evm/conftest.py @@ -3,12 +3,10 @@ from web3.contract import Contract from utils import helpers from utils.accounts import EthAccounts +from utils.consts import SPL_TOKEN_ADDRESS, METAPLEX_ADDRESS from utils.solana_client import SolanaClient from utils.web3client import Web3Client -SPL_TOKEN_ADDRESS = "0xFf00000000000000000000000000000000000004" -METAPLEX_ADDRESS = "0xff00000000000000000000000000000000000005" - @pytest.fixture(scope="class") def precompiled_contract(web3_client, faucet, accounts): diff --git a/integration/tests/basic/evm/opcodes/test_extcodehash.py b/integration/tests/basic/evm/opcodes/test_extcodehash.py index 3477927ce..ae1048d64 100644 --- a/integration/tests/basic/evm/opcodes/test_extcodehash.py +++ b/integration/tests/basic/evm/opcodes/test_extcodehash.py @@ -103,7 +103,7 @@ def test_extcodehash_with_send_tx_for_destroyed_contract(self, eip1052_checker): def test_extcodehash_for_reverted_destroyed_contract(self, eip1052_checker, json_rpc_client, destroyable_contract): # Check the EXTCODEHASH of an account that selfdestructed and later the selfdestruct has been reverted. sender_account = self.accounts[0] - destroyCaller, _ = self.web3_client.deploy_and_get_contract( + destroy_caller, _ = self.web3_client.deploy_and_get_contract( "EIPs/EIP1052Extcodehash", "0.8.10", sender_account, @@ -112,7 +112,7 @@ def test_extcodehash_for_reverted_destroyed_contract(self, eip1052_checker, json tx = self.web3_client.make_raw_tx(sender_account) instruction_tx = eip1052_checker.functions.getHashForDestroyedContractAfterRevert( - destroyable_contract.address, destroyCaller.address + destroyable_contract.address, destroy_caller.address ).build_transaction(tx) receipt = self.web3_client.send_transaction(sender_account, instruction_tx) neon_logs = json_rpc_client.send_rpc( @@ -125,23 +125,37 @@ def test_extcodehash_for_reverted_destroyed_contract(self, eip1052_checker, json assert all(x == data[0] for x in data) @pytest.mark.only_stands - def test_extcodehash_for_precompiled_contract(self, eip1052_checker): - # Check the EXTCODEHASH of a precompiled contract. - precompiled_acc = AccountData(address="0xFf00000000000000000000000000000000000004") + @pytest.mark.parametrize( + "address,expected_hash", + [ + ("0x0000000000000000000000000000000000000004", ZERO_HASH), + ("0xFf00000000000000000000000000000000000004", keccak(hexstr="0xFE").hex()), + ], + ) + def test_extcodehash_for_precompiled_contract(self, eip1052_checker, address, expected_hash): + # Check the EXTCODEHASH of a ethereum precompiled contract. + precompiled_acc = AccountData(address=address) contract_hash = eip1052_checker.functions.getContractHash(precompiled_acc.address).call() - assert contract_hash.hex() == ZERO_HASH + assert contract_hash.hex() == expected_hash @pytest.mark.only_stands - def test_extcodehash_with_send_tx_for_precompiled_contract(self, eip1052_checker): + @pytest.mark.parametrize( + "address,expected_hash", + [ + ("0x0000000000000000000000000000000000000004", ZERO_HASH), + ("0xFf00000000000000000000000000000000000004", keccak(hexstr="0xFE").hex()), + ], + ) + def test_extcodehash_with_send_tx_for_precompiled_contract(self, eip1052_checker, address, expected_hash): # Check the EXTCODEHASH of a precompiled contract with send_tx. sender_account = self.accounts[0] tx = self.web3_client.make_raw_tx(sender_account) - precompiled_acc = AccountData(address="0xFf00000000000000000000000000000000000004") + precompiled_acc = AccountData(address=address) instruction_tx = eip1052_checker.functions.getContractHashWithLog(precompiled_acc.address).build_transaction(tx) receipt = self.web3_client.send_transaction(sender_account, instruction_tx) event_logs = eip1052_checker.events.ReceivedHash().process_receipt(receipt) contract_hash = event_logs[0]["args"]["hash"] - assert contract_hash.hex() == ZERO_HASH + assert contract_hash.hex() == expected_hash @pytest.mark.only_stands def test_extcodehash_for_new_account_with_changed_balance(self, eip1052_checker, common_contract): diff --git a/integration/tests/basic/evm/test_precompiled_contracts.py b/integration/tests/basic/evm/test_precompiled_contracts.py index 6369f2976..f38ddee31 100644 --- a/integration/tests/basic/evm/test_precompiled_contracts.py +++ b/integration/tests/basic/evm/test_precompiled_contracts.py @@ -126,13 +126,7 @@ def test_delegatecall_via_contract(self, precompiled_contract, address, input_da @pytest.mark.xdist_group("precompiled_contract_balance") @pytest.mark.parametrize(**parametrized_data) def test_call_via_send_trx( - self, - web3_client: NeonChainWeb3Client, - address, - input_data, - expected, - request, - pytestconfig, + self, web3_client: NeonChainWeb3Client, address, input_data, request, pytestconfig, expected, evm_loader ): if request.node.callspec.id == "blake2f-vector 8": pytest.skip("NDEV-1961") @@ -155,6 +149,7 @@ def test_call_via_send_trx( ]: receipt = self.web3_client.send_transaction(sender_account, instruction_tx) assert receipt["status"] == 1 + if pytestconfig.getoption("--network") not in ["devnet", "night-stand"]: assert self.web3_client.get_balance(address) - balance_before == amount else: diff --git a/integration/tests/basic/evm/test_solana_interoperability.py b/integration/tests/basic/evm/test_solana_interoperability.py index 1eef24e4d..0ea97cb27 100644 --- a/integration/tests/basic/evm/test_solana_interoperability.py +++ b/integration/tests/basic/evm/test_solana_interoperability.py @@ -26,7 +26,7 @@ from utils.web3client import NeonChainWeb3Client -@pytest.fixture(scope="function") +@pytest.fixture(scope="class") def get_counter_value() -> tp.Iterator[int]: def gen_increment_counter(): count = 0 @@ -371,7 +371,7 @@ def test_limit_of_simple_instr_in_one_trx(self, call_solana_caller, counter_reso sender = self.accounts[0] call_params = [] - for _ in range(24): + for _ in range(26): instruction = Instruction( program_id=COUNTER_ID, accounts=[ @@ -505,7 +505,7 @@ def test_failed_solana_call_after_iterative_actions(self, call_solana_caller, so def test_solana_call_after_iterative_actions_exceed_accounts_limit( self, counter_resource_address: bytes, call_solana_caller ): - iterations = 53 + loop_count = 54 sender = self.accounts[0] lamports = 0 @@ -524,7 +524,7 @@ def test_solana_call_after_iterative_actions_exceed_accounts_limit( web3.exceptions.ContractLogicError, match="too many accounts: 65 > 64", ): - call_solana_caller.functions.executeInIterativeMode(iterations, lamports, serialized).build_transaction(tx) + call_solana_caller.functions.executeInIterativeMode(loop_count, lamports, serialized).build_transaction(tx) def test_solana_call_inside_iterative_actions( self, counter_resource_address: bytes, call_solana_caller, get_counter_value @@ -551,7 +551,14 @@ def test_solana_call_inside_iterative_actions( assert resp["status"] == 1 event_logs_bytes = call_solana_caller.events.LogBytes().process_receipt(resp) - assert int.from_bytes(event_logs_bytes[0].args.value, byteorder="little") == next(get_counter_value) + for i in range(matrix_lenght - 1): + next(get_counter_value) + + all_logs_value = [ + int.from_bytes(event_logs_byte.args.value, byteorder="little") for event_logs_byte in event_logs_bytes + ] + + assert max(all_logs_value) == next(get_counter_value) event_logs_int = call_solana_caller.events.LogInt().process_receipt(resp) assert event_logs_int[0].args.value == sum(sum(row) for row in matrix) diff --git a/integration/tests/basic/helpers/rpc_checks.py b/integration/tests/basic/helpers/rpc_checks.py index e05217c25..279ffe31d 100644 --- a/integration/tests/basic/helpers/rpc_checks.py +++ b/integration/tests/basic/helpers/rpc_checks.py @@ -2,13 +2,17 @@ from collections import Counter from types import SimpleNamespace +import allure from hexbytes import HexBytes +from solders.pubkey import Pubkey from web3 import types from clickfile import EnvName from integration.tests.basic.helpers.assert_message import AssertMessage from integration.tests.basic.helpers.basic import NeonEventType, SolanaInstruction from utils.models.result import NeonGetTransactionResult, SolanaByNeonTransaction +from utils.solana_client import SolanaClient +from utils.web3client import Web3Client NoneType = type(None) @@ -420,3 +424,12 @@ def assert_solana_trxs_in_neon_receipt(rpc_client, trx_hash, neon_receipt: NeonG solana_trxs_by_neon = [trx.solanaTransactionSignature for trx in neon_receipt.result.solanaTransactions] assert set(solana_transactions.result) == set(solana_trxs_by_neon) + + +@allure.step("Assert that {solana_address} was not used in the transaction") +def assert_solana_address_was_not_used_in_trx( + neon_trx: str, solana_address: str, web3_client: Web3Client, sol_client: SolanaClient +): + sol_trx = web3_client.get_solana_trx_by_neon(neon_trx)["result"][0] + sol_accounts = sol_client.get_account_keys_for_transaction(sol_trx) + assert Pubkey.from_string(solana_address) not in sol_accounts, f"Address {solana_address} is in the account list" diff --git a/integration/tests/basic/indexer/test_instruction_parsing.py b/integration/tests/basic/indexer/test_instruction_parsing.py index 63b6e3755..761f13662 100644 --- a/integration/tests/basic/indexer/test_instruction_parsing.py +++ b/integration/tests/basic/indexer/test_instruction_parsing.py @@ -1,4 +1,5 @@ import pytest +from eth_utils import keccak from solana.transaction import AccountMeta, Instruction import allure @@ -10,8 +11,8 @@ count_instructions, ) from utils.accounts import EthAccounts -from utils.consts import COUNTER_ID -from utils.helpers import gen_hash_of_block, generate_text, serialize_instruction +from utils.consts import COUNTER_ID, ZERO_ADDRESS +from utils.helpers import gen_hash_of_block, generate_text, serialize_instruction, get_selectors from utils.models.result import NeonGetTransactionResult from utils.solana_client import SolanaClient from utils.web3client import NeonChainWeb3Client @@ -38,19 +39,6 @@ def test_tx_exec_from_data(self, json_rpc_client): assert "TxExecFromData" in count_instructions(validated_response).keys() assert_solana_trxs_in_neon_receipt(json_rpc_client, resp["transactionHash"], validated_response) - def test_tx_step_from_data(self, counter_contract, json_rpc_client): - sender_account = self.accounts[0] - tx = self.web3_client.make_raw_tx(sender_account, estimate_gas=True) - - instruction_tx = counter_contract.functions.moreInstructionWithLogs(5, 2000).build_transaction(tx) - resp = self.web3_client.send_transaction(sender_account, instruction_tx) - - response = json_rpc_client.get_neon_trx_receipt(resp["transactionHash"]) - validated_response = NeonGetTransactionResult(**response) - assert_instructions(validated_response) - assert "TxStepFromData" in count_instructions(validated_response).keys() - assert_solana_trxs_in_neon_receipt(json_rpc_client, resp["transactionHash"], validated_response) - def test_cancel_with_hash(self, json_rpc_client, expected_error_checker): sender_account = self.accounts[0] tx = self.web3_client.make_raw_tx(sender_account) @@ -90,20 +78,26 @@ def test_tx_exec_from_data_solana_call(self, call_solana_caller, counter_resourc assert "TxExecFromDataSolanaCall" in count_instructions(validated_response).keys() assert_solana_trxs_in_neon_receipt(json_rpc_client, resp["transactionHash"], validated_response) - def test_tx_step_from_account_no_chain_id(self, counter_contract, json_rpc_client, faucet): + @pytest.mark.parametrize( + "remove_chain_id, expected_instruction", + [(True, "TxStepFromAccountNoChainId"), (False, "TxStepFromData")], + ) + def test_tx_iterative_with_and_without_chain_id( + self, counter_contract, json_rpc_client, remove_chain_id, expected_instruction + ): sender_account = self.accounts[0] - faucet.request_neon(sender_account.address, 1000) tx = self.web3_client.make_raw_tx(sender_account, estimate_gas=True) - tx["chainId"] = None + if remove_chain_id: + tx["chainId"] = None + instruction_tx = counter_contract.functions.moreInstructionWithLogs(0, 1000).build_transaction(tx) - instruction_tx = counter_contract.functions.moreInstructionWithLogs(0, 3).build_transaction(tx) resp = self.web3_client.send_transaction(sender_account, instruction_tx) response = json_rpc_client.get_neon_trx_receipt(resp["transactionHash"]) validated_response = NeonGetTransactionResult(**response) assert_instructions(validated_response) - assert "TxStepFromAccountNoChainId" in count_instructions(validated_response).keys() + assert expected_instruction in count_instructions(validated_response).keys() assert_solana_trxs_in_neon_receipt(json_rpc_client, resp["transactionHash"], validated_response) def test_holder_write_tx_exec_from_account(self, multiple_actions_erc721, json_rpc_client): @@ -131,20 +125,24 @@ def test_holder_write_tx_exec_from_account(self, multiple_actions_erc721, json_r assert "TxExecFromAccount" in count_instructions(validated_response).keys() assert_solana_trxs_in_neon_receipt(json_rpc_client, resp["transactionHash"], validated_response) - def test_step_from_account(self, multiple_actions_erc721, json_rpc_client): + def test_step_from_account(self, json_rpc_client, diamond): sender_account = self.accounts[0] - acc, contract = multiple_actions_erc721 + from eth_abi import abi - tx = self.web3_client.make_raw_tx(sender_account) - seed_1 = self.web3_client.text_to_bytes32(gen_hash_of_block(10)) - seed_2 = self.web3_client.text_to_bytes32(gen_hash_of_block(10)) - uri_1 = generate_text(min_len=10, max_len=200) - uri_2 = generate_text(min_len=10, max_len=200) - instruction_tx = contract.functions.mintMintTransferTransfer( - seed_1, uri_1, seed_2, uri_2, acc.address, acc.address - ).build_transaction(tx) - resp = self.web3_client.send_transaction(sender_account, instruction_tx) + new_facet, _ = self.web3_client.deploy_and_get_contract( + "EIPs/EIP2535/facets/Test1Facet", + "0.8.10", + sender_account, + contract_name="Test1Facet", + ) + facet_cuts = [(new_facet.address, 0, get_selectors(new_facet.abi))] + calldata = keccak(text="diamondCut((address,uint8,bytes4[])[],address,bytes)")[:4] + abi.encode( + ["(address,uint8,bytes4[])[]", "address", "bytes"], + [facet_cuts, ZERO_ADDRESS, b"0x"], + ) + tx = self.web3_client.make_raw_tx(sender_account, diamond.address, 0, data=calldata, estimate_gas=True) + resp = self.web3_client.send_transaction(sender_account, tx) response = json_rpc_client.get_neon_trx_receipt(resp["transactionHash"]) validated_response = NeonGetTransactionResult(**response) diff --git a/integration/tests/conftest.py b/integration/tests/conftest.py index 10f874105..1c8acf778 100644 --- a/integration/tests/conftest.py +++ b/integration/tests/conftest.py @@ -30,6 +30,7 @@ from utils.erc20 import ERC20 from utils.erc20wrapper import ERC20Wrapper from utils.evm_loader import EvmLoader +from utils.helpers import decode_function_signature, get_selectors from utils.operator import Operator from utils.solana_client import SolanaClient from utils.prices import get_sol_price_with_retry @@ -553,13 +554,13 @@ def multiple_actions_erc721(web3_client, accounts): return accounts[0], contract -@pytest.fixture(scope="function") +@pytest.fixture(scope="class") def call_solana_caller(accounts, web3_client): contract, _ = web3_client.deploy_and_get_contract("precompiled/CallSolanaCaller.sol", "0.8.10", accounts[0]) return contract -@pytest.fixture(scope="function") +@pytest.fixture(scope="class") def counter_resource_address(call_solana_caller, accounts, web3_client) -> bytes: tx = web3_client.make_raw_tx(accounts[0].address) salt = web3_client.text_to_bytes32("".join(random.choices(string.ascii_letters, k=5))) @@ -645,3 +646,69 @@ def eip1559_setup( pause = min_pause - (time.time() - start) if pause > 0: time.sleep(pause) + + +@pytest.fixture(scope="class") +def diamond_init(web3_client_session, accounts): + contract, _ = web3_client_session.deploy_and_get_contract( + "EIPs/EIP2535/upgradeInitializers/DiamondInit.sol", + "0.8.10", + accounts[0], + contract_name="DiamondInit", + ) + return contract + + +@pytest.fixture(scope="class") +def facet_cuts(diamond_cut_facet, diamond_loupe_facet, ownership_facet): + facet_cuts = [] + for facet in [diamond_cut_facet, diamond_loupe_facet, ownership_facet]: + facet_cuts.append((facet.address, 0, get_selectors(facet.abi))) + return facet_cuts + + +@pytest.fixture(scope="class") +def diamond_cut_facet(web3_client_session, accounts): + contract, _ = web3_client_session.deploy_and_get_contract( + "EIPs/EIP2535/facets/DiamondCutFacet", + "0.8.10", + accounts[0], + contract_name="DiamondCutFacet", + ) + return contract + + +@pytest.fixture(scope="class") +def diamond_loupe_facet(web3_client_session, accounts): + contract, _ = web3_client_session.deploy_and_get_contract( + "EIPs/EIP2535/facets/DiamondLoupeFacet.sol", + "0.8.10", + accounts[0], + contract_name="DiamondLoupeFacet", + ) + return contract + + +@pytest.fixture(scope="class") +def ownership_facet(web3_client_session, accounts): + contract, _ = web3_client_session.deploy_and_get_contract( + "EIPs/EIP2535/facets/OwnershipFacet", + "0.8.10", + accounts[0], + contract_name="OwnershipFacet", + ) + return contract + + +@pytest.fixture(scope="class") +def diamond(web3_client_session, diamond_init, facet_cuts, accounts): + calldata = decode_function_signature("init()") + diamond_args = [accounts[0].address, diamond_init.address, calldata] + contract, tx = web3_client_session.deploy_and_get_contract( + "EIPs/EIP2535/Diamond", + "0.8.10", + accounts[0], + contract_name="Diamond", + constructor_args=[facet_cuts, diamond_args], + ) + return contract diff --git a/integration/tests/migrations/test_account_migration.py b/integration/tests/migrations/test_account_migration.py index f2f546912..c9bedf133 100644 --- a/integration/tests/migrations/test_account_migration.py +++ b/integration/tests/migrations/test_account_migration.py @@ -3,11 +3,12 @@ import os import time +import typing as tp import eth_abi import pytest from eth_utils import abi - +from web3.contract import Contract from web3.logs import DISCARD from integration.tests.economy.steps import assert_profit @@ -15,10 +16,12 @@ from utils.erc20wrapper import ERC20Wrapper from utils.erc721ForMetaplex import ERC721ForMetaplex from utils.helpers import gen_hash_of_block +from utils.solana_client import SolanaClient +from utils.web3client import NeonChainWeb3Client @pytest.fixture(scope="class") -def accounts(web3_client): +def accounts(web3_client) -> tp.Generator[list[LocalAccount], None, None]: print("VERSIONS", web3_client.get_neon_versions()) account_keys = os.environ.get("ACCOUNTS").split(",") @@ -138,6 +141,22 @@ def erc721(web3_client, faucet, bob): return erc721 +@pytest.fixture(scope="class") +def block(web3_client, accounts) -> Contract: + contract_address = os.environ.get("BLOCK_ADDRESS") + if contract_address: + contract = web3_client.get_deployed_contract( + contract_address, contract_file="common/Block.sol", contract_name="BlockNumber" + ) + print(f"Using BlockNumber deployed earlier at {contract_address}") + else: + contract, _ = web3_client.deploy_and_get_contract( + "common/Block.sol", "0.8.10", contract_name="BlockNumber", account=accounts[0] + ) + print(f"BlockNumber deployed at address: {contract.address}") + return contract + + def check_counter(sender, contract, web3_client, sol_client): tx = web3_client.make_raw_tx(sender.address) @@ -167,7 +186,7 @@ def get_solana_accounts_by_emulation(web3_client, sender, contract, function_sig signed_tx = web3_client.eth.account.sign_transaction(tx, sender.key) result = web3_client.get_neon_emulate(str(signed_tx.rawTransaction.hex())[2:]) print(result) - return [item["pubkey"] for item in result["result"]["solana_accounts"]] + return [item["pubkey"] for item in result["result"]["solanaAccounts"]] def print_solana_accounts_info(sol_client, accounts, action): @@ -197,7 +216,7 @@ def check_operator_balance( token_diff = web3_client.to_main_currency(token_balance_after - token_balance_before) assert_profit(sol_diff, sol_price, token_diff, neon_price, web3_client.native_token_name) - def test_transfers(self, alice, bob, accounts, web3_client, trx_list, check_operator_balance): + def test_transfers(self, alice, bob, accounts, web3_client, trx_list): web3_client.send_neon(alice, bob, 5) for i in range(5): receipt = web3_client.send_neon(alice, accounts[i + 1], 5) @@ -207,10 +226,10 @@ def test_transfers(self, alice, bob, accounts, web3_client, trx_list, check_oper trx_list.append(receipt["transactionHash"]) assert receipt["status"] == 1 - def test_contract_deploy_economics(self, alice, bob, web3_client, check_operator_balance): + def test_contract_deploy_economics(self, alice, bob, web3_client): web3_client.deploy_and_get_contract("common/EventCaller", "0.8.12", bob) - def test_contract_deploy_and_interact(self, web3_client, accounts, trx_list, check_operator_balance): + def test_contract_deploy_and_interact(self, web3_client, accounts, trx_list): acc1 = accounts[7] acc2 = accounts[8] contract_a, receipt = web3_client.deploy_and_get_contract( @@ -246,13 +265,11 @@ def test_contract_deploy_and_interact(self, web3_client, accounts, trx_list, che for log in (event_b2_logs, event_c1_logs, event_c2_logs): assert log == (), f"Trx shouldn't contain logs for the events: eventB2, eventC1, eventC2_log0. Log: {log}" - def test_economics_for_erc721_mint(self, erc721, web3_client, check_operator_balance): + def test_economics_for_erc721_mint(self, erc721, web3_client): seed = web3_client.text_to_bytes32(gen_hash_of_block(8)) erc721.mint(seed, erc721.account.address, "uri") - def test_erc721_interaction( - self, erc721, web3_client, sol_client, bob, alice, accounts, trx_list, check_operator_balance - ): + def test_erc721_interaction(self, erc721, web3_client, sol_client, bob, alice, accounts, trx_list): seed = web3_client.text_to_bytes32(gen_hash_of_block(8)) solana_accounts = get_solana_accounts_by_emulation( @@ -314,7 +331,7 @@ def test_erc721_interaction( assert balance_usr1_after - balance_usr1_before == -1 assert balance_usr2_after - balance_usr2_before == 1 - def test_erc20_interaction(self, erc20, web3_client, bob, alice, accounts, trx_list, check_operator_balance): + def test_erc20_interaction(self, erc20, web3_client, bob, alice, accounts, trx_list): balance_before = erc20.contract.functions.balanceOf(erc20.account.address).call() amount = 500 resp = erc20.mint_tokens(erc20.account, erc20.account.address, amount) @@ -333,7 +350,7 @@ def test_erc20_interaction(self, erc20, web3_client, bob, alice, accounts, trx_l balance_before = erc20.contract.functions.balanceOf(tom.address).call() total_before = erc20.contract.functions.totalSupply().call() - resp = erc20.burn(tom, tom.address, amount) + resp = erc20.burn(tom, amount) trx_list.append(resp["transactionHash"]) balance_after = erc20.contract.functions.balanceOf(tom.address).call() @@ -386,3 +403,16 @@ def test_simple_counter(self, web3_client, accounts, counter, sol_client): def test_counter_with_map(self, web3_client, accounts, counter_with_map, sol_client): sender = accounts[9] check_counter(sender, counter_with_map, web3_client, sol_client) + + def test_tx_with_timestamp( + self, + web3_client: NeonChainWeb3Client, + accounts: list[LocalAccount], + block: Contract, + sol_client: SolanaClient, + ): + sender = accounts[9] + tx = web3_client.make_raw_tx(sender) + tx = block.functions.accrueInterestIterative().build_transaction(tx) + receipt = web3_client.send_transaction(sender, tx) + assert receipt.status == 1 diff --git a/integration/tests/neon_evm/solana_native/test_multiple_scheduled_transactions.py b/integration/tests/neon_evm/solana_native/test_multiple_scheduled_transactions.py index db45d1646..98076561d 100644 --- a/integration/tests/neon_evm/solana_native/test_multiple_scheduled_transactions.py +++ b/integration/tests/neon_evm/solana_native/test_multiple_scheduled_transactions.py @@ -4,6 +4,7 @@ from eth_utils import abi from solders.pubkey import Pubkey +from integration.tests.basic.evm.conftest import SPL_TOKEN_ADDRESS from integration.tests.neon_evm.utils.assert_messages import InstructionAsserts from integration.tests.neon_evm.utils.contract import get_contract_bin from integration.tests.neon_evm.utils.ethereum import create_contract_address @@ -285,6 +286,11 @@ def test_call_precompiled_by_scheduled_trx( additional_accounts = [Pubkey.from_string(item["pubkey"]) for item in emulate_result["solana_accounts"]] + # check emulated accounts don't contain precompiled program address + assert ( + Pubkey.from_string(evm_loader.ether2program(SPL_TOKEN_ADDRESS[2:])[0]) not in additional_accounts + ), "Precompiled program address is in the list of accounts" + tx0 = ScheduledTransaction( neon_user.neon_address, None, nonce, target=spl_token_caller.eth_address, index=0, value=0, call_data=data ) diff --git a/integration/tests/neon_evm/test_interoperability.py b/integration/tests/neon_evm/test_interoperability.py index 1e64ef3f3..a0ba34f59 100644 --- a/integration/tests/neon_evm/test_interoperability.py +++ b/integration/tests/neon_evm/test_interoperability.py @@ -18,7 +18,8 @@ from conftest import EnvironmentConfig from integration.tests.neon_evm.utils.call_solana import SolanaCaller -from .utils.transaction_checks import check_holder_account_tag, check_transaction_logs_have_text, decode_logs +from utils.solana_logs_helper import decode_logs +from .utils.transaction_checks import check_holder_account_tag, check_transaction_logs_have_text from integration.tests.neon_evm.utils.ethereum import make_eth_transaction, make_contract_call_trx diff --git a/integration/tests/neon_evm/utils/transaction_checks.py b/integration/tests/neon_evm/utils/transaction_checks.py index 4b3da5a2d..293abee24 100644 --- a/integration/tests/neon_evm/utils/transaction_checks.py +++ b/integration/tests/neon_evm/utils/transaction_checks.py @@ -1,9 +1,8 @@ -import base64 - from solana.rpc.commitment import Confirmed from solders.rpc.responses import GetTransactionResp, SendTransactionResp from utils.solana_client import SolanaClient +from utils.solana_logs_helper import decode_logs def check_transaction_logs_have_text( @@ -17,21 +16,6 @@ def check_transaction_logs_have_text( assert text in logs, f"Transaction logs don't contain '{text}'. Logs: {logs}" -def decode_logs(log_messages: list) -> list: - decoded_logs = "" - - for log in log_messages: - if "Program data:" in log: - decoded_logs += "Program data: " - encoded_part = log.replace("Program data: ", "") - for item in encoded_part.split(" "): - decoded_logs += " " + str(base64.b64decode(item)) - else: - decoded_logs += log - decoded_logs += " " - return decoded_logs - - def check_holder_account_tag(solana_client: SolanaClient, storage_account, layout, expected_tag): account_data = solana_client.get_account_info(storage_account, commitment=Confirmed).value.data parsed_data = layout.parse(account_data) diff --git a/utils/consts.py b/utils/consts.py index 594ef1e7e..6432f84c1 100644 --- a/utils/consts.py +++ b/utils/consts.py @@ -18,6 +18,11 @@ TRANSFER_TOKENS_ID: Pubkey = Pubkey.from_string("BFsGPJUwgE1rz4eoL322HaKZYNZ5wDLafwYtKwomv2XF") TEST_INVOKE_ID: Pubkey = Pubkey.from_string("AkAMQQTRE1sf4gKCgJy1qqQ7FVA17HZkQxMm5mGK4yQS") +SPL_TOKEN_ADDRESS = "0xFf00000000000000000000000000000000000004" +METAPLEX_ADDRESS = "0xff00000000000000000000000000000000000005" +CALL_SOLANA_ADDRESS = "0xFF00000000000000000000000000000000000006" +SOLANA_NATIVE_ADDRESS = "0xfF00000000000000000000000000000000000007" + class Time: MINUTE = 60 @@ -42,7 +47,7 @@ def lower(self): class InputTestConstants(Enum): - NEW_USER_REQUEST_AMOUNT = 500 + NEW_USER_REQUEST_AMOUNT = 800 DEFAULT_TRANSFER_AMOUNT = 0.1 SAMPLE_AMOUNT = 0.5 ROUND_DIGITS = 3 diff --git a/utils/evm_loader.py b/utils/evm_loader.py index 7deee65d2..7dd7caa05 100644 --- a/utils/evm_loader.py +++ b/utils/evm_loader.py @@ -25,7 +25,7 @@ from integration.tests.neon_evm.utils.contract import get_contract_bin from integration.tests.neon_evm.utils.ethereum import create_contract_address, make_deployment_transaction from integration.tests.neon_evm.utils.neon_api_client import NeonApiClient -from integration.tests.neon_evm.utils.transaction_checks import check_transaction_logs_have_text, decode_logs +from integration.tests.neon_evm.utils.transaction_checks import check_transaction_logs_have_text from utils.scheduled_trx import ScheduledTransaction from utils.neon_user import NeonUser from integration.tests.neon_evm.utils.constants import TREASURY_POOL_SEED @@ -61,6 +61,7 @@ OPERATOR_BALANCE_ACCOUNT_LAYOUT, ) from utils.solana_client import SolanaClient +from utils.solana_logs_helper import decode_logs from utils.types import Caller, Contract, TreasuryPool EVM_STEPS = 500 diff --git a/utils/solana_client.py b/utils/solana_client.py index a5ac0ae69..17420ccf8 100644 --- a/utils/solana_client.py +++ b/utils/solana_client.py @@ -213,3 +213,8 @@ def do_tx_instructions_contain_program_id_index( return True else: return False + + @allure.step("Get account keys for solana transaction") + def get_account_keys_for_transaction(self, sol_trx: str): + resp = self.get_transaction(Signature.from_string(sol_trx), commitment=Confirmed) + return resp.value.transaction.transaction.message.account_keys diff --git a/utils/solana_logs_helper.py b/utils/solana_logs_helper.py new file mode 100644 index 000000000..e06093870 --- /dev/null +++ b/utils/solana_logs_helper.py @@ -0,0 +1,33 @@ +import base64 + +from solana.rpc.commitment import Confirmed +from solders.signature import Signature + +from utils.web3client import Web3Client + + +def decode_logs(log_messages: list) -> str: + decoded_logs = "" + + for log in log_messages: + if "Program data:" in log: + decoded_logs += "Program data: " + encoded_part = log.replace("Program data: ", "") + for item in encoded_part.split(" "): + decoded_logs += " " + str(base64.b64decode(item)) + else: + decoded_logs += log + decoded_logs += " " + return decoded_logs + + +def get_all_solana_logs_for_neon_trx(web3_client: Web3Client, solana_client, trx_hash): + sol_trxs = web3_client.get_solana_trx_by_neon(trx_hash)["result"] + logs = [] + for trx in sol_trxs: + encoded_log = solana_client.get_transaction( + Signature.from_string(trx), commitment=Confirmed + ).value.transaction.meta.log_messages + logs.append(decode_logs(encoded_log)) + + return logs