diff --git a/starknet_devnet/blueprints/gateway.py b/starknet_devnet/blueprints/gateway.py index 919d29ae7..ed6221bf5 100644 --- a/starknet_devnet/blueprints/gateway.py +++ b/starknet_devnet/blueprints/gateway.py @@ -3,6 +3,7 @@ """ from flask import Blueprint, jsonify, request +from starkware.starknet.definitions.error_codes import StarknetErrorCode from starkware.starknet.definitions.transaction_type import TransactionType from starkware.starkware_utils.error_handling import StarkErrorCode @@ -40,10 +41,10 @@ async def add_transaction(): response_dict["address"] = fixed_length_hex(contract_address) elif tx_type == TransactionType.DEPLOY: - contract_address, transaction_hash = await state.starknet_wrapper.deploy( - transaction + raise StarknetDevnetException( + code=StarknetErrorCode.DEPRECATED_TRANSACTION, + message="Deploy transaction is no longer supported.", ) - response_dict["address"] = fixed_length_hex(contract_address) elif tx_type == TransactionType.INVOKE_FUNCTION: (contract_address, transaction_hash) = await state.starknet_wrapper.invoke( diff --git a/starknet_devnet/blueprints/rpc/routes.py b/starknet_devnet/blueprints/rpc/routes.py index ac5b84245..34ec6735f 100644 --- a/starknet_devnet/blueprints/rpc/routes.py +++ b/starknet_devnet/blueprints/rpc/routes.py @@ -39,7 +39,6 @@ from starknet_devnet.blueprints.rpc.transactions import ( add_declare_transaction, add_deploy_account_transaction, - add_deploy_transaction, add_invoke_transaction, estimate_fee, get_transaction_by_block_id_and_index, @@ -73,7 +72,6 @@ "getNonce": get_nonce, "addInvokeTransaction": add_invoke_transaction, "addDeclareTransaction": add_declare_transaction, - "addDeployTransaction": add_deploy_transaction, "addDeployAccountTransaction": add_deploy_account_transaction, } diff --git a/starknet_devnet/blueprints/rpc/structures/payloads.py b/starknet_devnet/blueprints/rpc/structures/payloads.py index abb8986e7..cd411b5fd 100644 --- a/starknet_devnet/blueprints/rpc/structures/payloads.py +++ b/starknet_devnet/blueprints/rpc/structures/payloads.py @@ -26,7 +26,6 @@ TransactionType, ) from starkware.starknet.services.api.gateway.transaction import ( - Deploy, DeployAccount, DeprecatedDeclare, InvokeFunction, @@ -457,31 +456,6 @@ def make_declare(declare_transaction: RpcBroadcastedDeclareTxn) -> DeprecatedDec return declare_tx -def make_deploy(deploy_transaction: RpcBroadcastedDeployTxn) -> Deploy: - """ - Convert RpcBroadcastedDeployTxn to Deploy - """ - contract_class = deploy_transaction["contract_class"] - if "abi" not in contract_class: - contract_class["abi"] = [] - - try: - contract_class["program"] = decompress_program(contract_class["program"]) - contract_class = DeprecatedCompiledClass.load(contract_class) - except (StarkException, TypeError, MarshmallowError) as ex: - raise RpcError(code=50, message="Invalid contract class") from ex - - deploy_tx = Deploy( - contract_address_salt=int(deploy_transaction["contract_address_salt"], 16), - constructor_calldata=[ - int(data, 16) for data in deploy_transaction["constructor_calldata"] - ], - contract_definition=contract_class, - version=int(deploy_transaction["version"], 16), - ) - return deploy_tx - - def make_deploy_account( deploy_account_transaction: RpcBroadcastedDeployAccountTxn, ) -> DeployAccount: diff --git a/starknet_devnet/blueprints/rpc/transactions.py b/starknet_devnet/blueprints/rpc/transactions.py index 1e220364f..b114f45d2 100644 --- a/starknet_devnet/blueprints/rpc/transactions.py +++ b/starknet_devnet/blueprints/rpc/transactions.py @@ -14,12 +14,10 @@ from starknet_devnet.blueprints.rpc.structures.payloads import ( RpcBroadcastedDeclareTxn, RpcBroadcastedDeployAccountTxn, - RpcBroadcastedDeployTxn, RpcBroadcastedInvokeTxn, RpcBroadcastedTxn, RpcTransaction, make_declare, - make_deploy, make_deploy_account, make_invoke_function, rpc_fee_estimate, @@ -28,7 +26,6 @@ from starknet_devnet.blueprints.rpc.structures.responses import ( RpcDeclareTransactionResult, RpcDeployAccountTransactionResult, - RpcDeployTransactionResult, RpcInvokeTransactionResult, rpc_transaction_receipt, ) @@ -135,22 +132,6 @@ async def add_declare_transaction( ) -@validate_schema("addDeployTransaction") -async def add_deploy_transaction(deploy_transaction: RpcBroadcastedDeployTxn) -> dict: - """ - Submit a new deploy contract transaction - """ - deploy_transaction = make_deploy(deploy_transaction) - - contract_address, transaction_hash = await state.starknet_wrapper.deploy( - deploy_transaction=deploy_transaction - ) - return RpcDeployTransactionResult( - transaction_hash=rpc_felt(transaction_hash), - contract_address=rpc_felt(contract_address), - ) - - @validate_schema("addDeployAccountTransaction") async def add_deploy_account_transaction( deploy_account_transaction: RpcBroadcastedDeployAccountTxn, @@ -189,7 +170,7 @@ def make_transaction(txn: RpcBroadcastedTxn) -> AccountTransaction: if txn_type == "DECLARE": return make_declare(txn) if txn_type == "DEPLOY": - return make_deploy(txn) + raise RpcError(code=-1, message="DEPLOY transactions are deprecated") if txn_type == "DEPLOY_ACCOUNT": return make_deploy_account(txn) raise NotImplementedError(f"Unexpected type {txn_type}.") diff --git a/starknet_devnet/starknet_wrapper.py b/starknet_devnet/starknet_wrapper.py index c7d884b3c..5e7fa327c 100644 --- a/starknet_devnet/starknet_wrapper.py +++ b/starknet_devnet/starknet_wrapper.py @@ -25,9 +25,6 @@ from starkware.starknet.core.os.contract_class.compiled_class_hash import ( compute_compiled_class_hash, ) -from starkware.starknet.core.os.transaction_hash.transaction_hash import ( - calculate_deploy_transaction_hash, -) from starkware.starknet.definitions.error_codes import StarknetErrorCode from starkware.starknet.definitions.transaction_type import TransactionType from starkware.starknet.services.api.contract_class.contract_class import ( @@ -54,7 +51,6 @@ ) from starkware.starknet.services.api.gateway.transaction import ( Declare, - Deploy, DeployAccount, DeprecatedDeclare, InvokeFunction, @@ -114,6 +110,7 @@ DEFAULT_BLOCK_ID = LATEST_BLOCK_ID + # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-public-methods # pylint: disable=too-many-locals @@ -215,6 +212,7 @@ async def __create_genesis_block(self): deploy_data.append((account.class_hash, account.address)) for class_hash, contract_address in deploy_data: + # this might be the only place where DEPLOY tx is used internal_deploy = create_empty_internal_deploy( transaction_hash, class_hash, contract_address ) @@ -543,53 +541,6 @@ async def deploy_account(self, external_tx: DeployAccount): tx_handler.internal_tx.hash_value, ) - async def deploy(self, deploy_transaction: Deploy) -> Tuple[int, int]: - """ - Deploys the contract specified with `deploy_transaction`. - Returns (contract_address, transaction_hash). - """ - - contract_class = deploy_transaction.contract_definition - - internal_tx: InternalDeploy = InternalDeploy.from_external( - deploy_transaction, self.get_state().general_config - ) - - contract_address = internal_tx.contract_address - - if await self.is_deployed(contract_address): - tx_hash = calculate_deploy_transaction_hash( - version=deploy_transaction.version, - contract_address=contract_address, - constructor_calldata=deploy_transaction.constructor_calldata, - chain_id=self.get_state().general_config.chain_id.value, - ) - return contract_address, tx_hash - - tx_hash = internal_tx.hash_value - - async with self.__get_transaction_handler( - external_tx=deploy_transaction - ) as tx_handler: - tx_handler.internal_tx = internal_tx - state = self.get_state().state - state.contract_classes[internal_tx.class_hash] = contract_class - self._contract_classes[internal_tx.class_hash] = contract_class - - tx_handler.execution_info = await self.__deploy(internal_tx) - tx_handler.internal_calls = ( - tx_handler.execution_info.call_info.internal_calls - ) - - tx_handler.deployed_contracts.append( - ContractAddressHashPair( - address=contract_address, - class_hash=internal_tx.class_hash, - ) - ) - - return contract_address, tx_hash - async def invoke(self, external_tx: InvokeFunction): """Perform invoke according to specifications in `transaction`.""" state = self.get_state() diff --git a/test/account.py b/test/account.py index dbbb79912..8ae9b1342 100644 --- a/test/account.py +++ b/test/account.py @@ -3,7 +3,7 @@ Latest changes based on https://github.com/OpenZeppelin/nile/pull/184 """ -from typing import List, Tuple +from typing import List, Optional, Tuple import requests from starkware.crypto.signature.signature import private_to_stark_key, sign @@ -13,23 +13,38 @@ ) from starkware.starknet.core.os.transaction_hash.transaction_hash import ( calculate_declare_transaction_hash, + calculate_deploy_account_transaction_hash, calculate_deprecated_declare_transaction_hash, ) from starkware.starknet.definitions.constants import QUERY_VERSION -from starkware.starknet.definitions.general_config import StarknetChainId -from starkware.starknet.services.api.gateway.transaction import ContractClass, Declare +from starkware.starknet.definitions.general_config import ( + DEFAULT_CHAIN_ID, + StarknetChainId, +) +from starkware.starknet.definitions.transaction_type import TransactionType +from starkware.starknet.services.api.feeder_gateway.response_objects import ( + BlockIdentifier, +) +from starkware.starknet.services.api.gateway.transaction import ( + ContractClass, + Declare, + DeployAccount, +) from starknet_devnet.account_util import AccountCall, get_execute_args +from starknet_devnet.chargeable_account import ChargeableAccount +from starknet_devnet.contract_class_wrapper import DEFAULT_ACCOUNT_HASH from .settings import APP_URL from .shared import EXPECTED_UDC_ADDRESS, SUPPORTED_TX_VERSION -from .util import deploy as deploy_contract from .util import ( + assert_hex_equal, estimate_fee, extract_class_hash, extract_tx_hash, load_contract_class, run_starknet, + send_tx, ) ACCOUNT_ARTIFACTS_PATH = "starknet_devnet/accounts_artifacts" @@ -43,15 +58,19 @@ PUBLIC_KEY = private_to_stark_key(PRIVATE_KEY) -def deploy_account_contract(salt=None): - """Deploy account contract.""" - return deploy_contract(ACCOUNT_PATH, inputs=[str(PUBLIC_KEY)], salt=salt) - - -def get_nonce(account_address: str, feeder_gateway_url=APP_URL) -> int: +def get_nonce( + account_address: str, + feeder_gateway_url=APP_URL, + block_number: Optional[BlockIdentifier] = "pending", +) -> int: """Get nonce.""" + params = {"contractAddress": account_address} + if block_number is not None: + params["blockNumber"] = block_number + resp = requests.get( - f"{feeder_gateway_url}/feeder_gateway/get_nonce?contractAddress={account_address}" + f"{feeder_gateway_url}/feeder_gateway/get_nonce", + params=params, ) return int(resp.json(), 16) @@ -111,7 +130,7 @@ def get_estimated_fee( """Get estimated fee through account.""" if nonce is None: - nonce = get_nonce(account_address) + nonce = get_nonce(account_address, feeder_gateway_url=feeder_gateway_url) signature, execute_calldata = get_execute_args( calls=calls, @@ -199,19 +218,20 @@ def invoke( def declare( contract_path: str, account_address: str, - private_key: str, + private_key: int, nonce: int = None, max_fee: int = 0, + gateway_url=APP_URL, chain_id=StarknetChainId.TESTNET, ): """Wrapper around starknet declare""" if nonce is None: - nonce = get_nonce(account_address) + nonce = get_nonce(account_address, feeder_gateway_url=gateway_url) tx_hash = calculate_deprecated_declare_transaction_hash( contract_class=load_contract_class(contract_path), - chain_id=StarknetChainId.TESTNET.value, + chain_id=chain_id.value, sender_address=int(account_address, 16), max_fee=max_fee, nonce=nonce, @@ -233,7 +253,8 @@ def declare( str(max_fee), "--chain_id", hex(chain_id.value), - ] + ], + gateway_url=gateway_url, ) return { "tx_hash": extract_tx_hash(output.stdout), @@ -250,10 +271,12 @@ def deploy( unique=False, max_fee=None, gateway_url=APP_URL, + chain_id=StarknetChainId.TESTNET, ): """Wrapper around starknet deploy""" - ctor_args = [int(val, 0) for val in inputs or []] + # accepts ints or decimal strings + ctor_args = [int(val) for val in inputs or []] salt = get_salt(salt) invoke_tx_hash = invoke( @@ -274,6 +297,7 @@ def deploy( private_key=private_key, max_fee=max_fee, gateway_url=gateway_url, + chain_id=chain_id, ) contract_address = calculate_contract_address_from_hash( @@ -290,6 +314,151 @@ def deploy( } +def declare_and_deploy( + contract: str, + account_address: str, + private_key: int, + inputs=None, + salt=None, + declare_max_fee=int(1e18), + max_fee=None, + gateway_url=APP_URL, + chain_id=StarknetChainId.TESTNET, +): + """ + Declare a class and deploy its instance using the provided account. + The max_fee only refers to deployment. + Returns deploy info with class_hash. + """ + + declare_info = declare( + contract_path=contract, + account_address=account_address, + private_key=private_key, + max_fee=declare_max_fee, + gateway_url=gateway_url, + chain_id=chain_id, + ) + class_hash = declare_info["class_hash"] + # here we could benefit from asserting the status of declaration, but it would also introduce time overhead + + deploy_info = deploy( + class_hash=class_hash, + account_address=account_address, + private_key=private_key, + inputs=inputs, + salt=salt, + max_fee=max_fee, + gateway_url=gateway_url, + chain_id=chain_id, + ) + + # expand the object with the hash of the class that was deployed + deploy_info["class_hash"] = class_hash + + return deploy_info + + +def declare_and_deploy_with_chargeable( + contract: str, + inputs=None, + salt=None, + max_fee=None, + gateway_url=APP_URL, + chain_id=StarknetChainId.TESTNET, +): + """ + Declare a class and deploy its instance using the chargeable account. + The max_fee only refers to deployment. + Returns deploy info. + """ + return declare_and_deploy( + contract=contract, + account_address=hex(ChargeableAccount.ADDRESS), + private_key=ChargeableAccount.PRIVATE_KEY, + inputs=inputs, + salt=salt, + max_fee=max_fee, + gateway_url=gateway_url, + chain_id=chain_id, + ) + + +def deploy_with_chargeable( + class_hash: str, + inputs=None, + salt=None, + max_fee=None, + gateway_url=APP_URL, + chain_id=StarknetChainId.TESTNET, +): + """Deploy an instance of `contract` using the chargeable account""" + return deploy( + class_hash=class_hash, + account_address=hex(ChargeableAccount.ADDRESS), + private_key=ChargeableAccount.PRIVATE_KEY, + inputs=inputs, + salt=salt, + max_fee=max_fee, + gateway_url=gateway_url, + chain_id=chain_id, + ) + + +def deploy_account_contract( + private_key: int, + class_hash=DEFAULT_ACCOUNT_HASH, + salt=None, + max_fee=int(1e18), +): + """Deploy account contract. Defaults to using a pre-created key.""" + + constructor_calldata = [private_to_stark_key(private_key)] + salt = get_salt(salt) + account_address = calculate_contract_address_from_hash( + salt=salt, + class_hash=class_hash, + constructor_calldata=constructor_calldata, + deployer_address=0, + ) + + version = SUPPORTED_TX_VERSION + nonce = 0 + tx_hash = calculate_deploy_account_transaction_hash( + version=version, + contract_address=account_address, + class_hash=class_hash, + constructor_calldata=constructor_calldata, + max_fee=max_fee, + nonce=nonce, + salt=salt, + chain_id=DEFAULT_CHAIN_ID, + ) + + deploy_tx = DeployAccount( + version=version, + max_fee=max_fee, + signature=[int(s) for s in _get_signature(tx_hash, private_key)], + nonce=nonce, + class_hash=class_hash, + contract_address_salt=salt, + constructor_calldata=constructor_calldata, + ).dump() + + # basically we don't need the `resp`, but when it's here, why not make assertions + resp = send_tx(deploy_tx, TransactionType.DEPLOY_ACCOUNT) + + deploy_info = { + "tx_hash": hex(tx_hash), + "address": hex(account_address), + } + + assert_hex_equal(resp["transaction_hash"], deploy_info["tx_hash"]) + assert_hex_equal(resp["address"], deploy_info["address"]) + + return deploy_info + + def send_declare_v2( contract_class: ContractClass, compiled_class_hash: int, diff --git a/test/deploy.json b/test/deprecated_deploy.json similarity index 100% rename from test/deploy.json rename to test/deprecated_deploy.json diff --git a/test/expected/deploy_function_invocation.json b/test/expected/deploy_function_invocation.json index bd408c9cb..3b5fc28a3 100644 --- a/test/expected/deploy_function_invocation.json +++ b/test/expected/deploy_function_invocation.json @@ -1,6 +1,13 @@ { "call_type": "CALL", - "calldata": ["0x0"], + "calldata": [ + "0x1", + "0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf", + "0x1987cbd17808b9a23693d4de7e246a443cfe37e6e7fbaeabd7d7e6532b07c3d", + "0x0", + "0x5", + "0x5" + ], "caller_address": "0x0", "class_hash": "0x2216379233d6f7c8890a730e164e069dafdd63edf0f0218dde8181b50fabd45", "contract_address": "0x7f50463b43a30d3a60c004ab70bbf70f8ea2d16dbf802c952e94c8ef18646b2", @@ -14,5 +21,5 @@ "internal_calls": [], "messages": [], "result": [], - "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194" -} + "selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad" +} \ No newline at end of file diff --git a/test/expected/deploy_receipt.json b/test/expected/deploy_receipt.json deleted file mode 100644 index ddd03a72f..000000000 --- a/test/expected/deploy_receipt.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "actual_fee": "0x0", - "block_hash": "0x1", - "block_number": 1, - "events": [], - "execution_resources": { - "builtin_instance_counter": {}, - "n_memory_holes": 0, - "n_steps": 40 - }, - "l2_to_l1_messages": [], - "status": "ACCEPTED_ON_L2", - "transaction_hash": "0x0032ff8b9c26706c5dfdaca49231f6b642fbe540235ec60d87cc1d92a186bdea", - "transaction_index": 0 -} diff --git a/test/invoke_rpc.json b/test/invoke_rpc.json deleted file mode 100644 index 5e073ceab..000000000 --- a/test/invoke_rpc.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "entry_point_selector":"0x362398bec32bc0ebb411203221a35a0301193a96f317ebe5e40be9f60d15320", - "calldata":[ - "10", - "11" - ], - "signature":[ - - ], - "contract_address":"0x066cd141aa76c97c0ca6e513ad6789b2fe259f4b120909041219b298751423aa", - "type":"INVOKE_FUNCTION" -} diff --git a/test/rpc/conftest.py b/test/rpc/conftest.py index 60dce5e19..0818c09ff 100644 --- a/test/rpc/conftest.py +++ b/test/rpc/conftest.py @@ -5,7 +5,7 @@ from __future__ import annotations import json -from test.account import PRIVATE_KEY, PUBLIC_KEY +from test.account import deploy from test.rpc.rpc_utils import ( add_transaction, gateway_call, @@ -14,9 +14,10 @@ ) from test.test_account import SALT from test.util import load_file_content, mint -from typing import Tuple, cast +from typing import Tuple import pytest +from starkware.crypto.signature.signature import private_to_stark_key from starkware.starknet.business_logic.transaction.objects import InternalDeployAccount from starkware.starknet.core.os.contract_class.deprecated_class_hash import ( compute_deprecated_class_hash, @@ -28,11 +29,7 @@ from starkware.starknet.services.api.feeder_gateway.response_objects import ( DeployAccountSpecificInfo, ) -from starkware.starknet.services.api.gateway.transaction import ( - Deploy, - DeployAccount, - Transaction, -) +from starkware.starknet.services.api.gateway.transaction import DeployAccount from starkware.starknet.third_party.open_zeppelin.starknet_contracts import ( account_contract as oz_account_class, ) @@ -48,21 +45,14 @@ Felt, ) from starknet_devnet.blueprints.rpc.utils import rpc_felt +from starknet_devnet.chargeable_account import ChargeableAccount from starknet_devnet.constants import SUPPORTED_RPC_TX_VERSION from starknet_devnet.general_config import DEFAULT_GENERAL_CONFIG -DEPLOY_CONTENT = load_file_content("deploy_rpc.json") -INVOKE_CONTENT = load_file_content("invoke_rpc.json") DECLARE_CONTENT = load_file_content("declare_rpc.json") - -@pytest.fixture(name="contract_class") -def fixture_contract_class() -> CompiledClassBase: - """ - Make ContractDefinition from deployment transaction used in tests - """ - transaction: Deploy = cast(Deploy, Transaction.loads(DEPLOY_CONTENT)) - return transaction.contract_definition +PRIVATE_KEY = 123456789987654321 +PUBLIC_KEY = private_to_stark_key(PRIVATE_KEY) @pytest.fixture(name="class_hash") @@ -79,21 +69,21 @@ def fixture_class_hash(deploy_info) -> Felt: @pytest.fixture(name="deploy_info") def fixture_deploy_info() -> dict: """ - Deploy a contract on devnet and return deployment info dict + Deploy a contract using chargeable account. Return deployment info dict. """ - deploy_tx = json.loads(DEPLOY_CONTENT) - deploy_info = add_transaction(deploy_tx) - return {**deploy_info, **deploy_tx} + declare_tx = json.loads(DECLARE_CONTENT) + declare_info = add_transaction(declare_tx) + deploy_info = deploy( + class_hash=declare_info["class_hash"], + account_address=hex(ChargeableAccount.ADDRESS), + private_key=ChargeableAccount.PRIVATE_KEY, + inputs=[69], + salt="0x2", + max_fee=int(1e18), + ) -@pytest.fixture(name="invoke_info") -def fixture_invoke_info() -> dict: - """ - Make an invoke transaction on devnet and return invoke info dict - """ - invoke_tx = json.loads(INVOKE_CONTENT) - invoke_info = add_transaction(invoke_tx) - return {**invoke_info, **invoke_tx} + return deploy_info @pytest.fixture(name="declare_info") @@ -121,22 +111,6 @@ def fixture_deploy_account_info() -> dict: return declare_info -@pytest.fixture(name="invoke_content") -def fixture_invoke_content() -> dict: - """ - Invoke content JSON object - """ - return json.loads(INVOKE_CONTENT) - - -@pytest.fixture(name="deploy_content") -def fixture_deploy_content() -> dict: - """ - Deploy content JSON object - """ - return json.loads(DEPLOY_CONTENT) - - @pytest.fixture(name="declare_content") def fixture_declare_content() -> dict: """ @@ -150,7 +124,7 @@ def fixture_gateway_block(deploy_info) -> dict: """ Block with Deploy transaction """ - return get_block_with_transaction(deploy_info["transaction_hash"]) + return get_block_with_transaction(deploy_info["tx_hash"]) @pytest.fixture(name="latest_block") diff --git a/test/rpc/rpc_utils.py b/test/rpc/rpc_utils.py index 76ade6d7a..c917acd3f 100644 --- a/test/rpc/rpc_utils.py +++ b/test/rpc/rpc_utils.py @@ -5,14 +5,14 @@ from __future__ import annotations import re -from test.account import invoke +from test.account import declare_and_deploy_with_chargeable, invoke from test.settings import APP_URL from test.shared import ( PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, STORAGE_CONTRACT_PATH, ) -from test.util import assert_transaction, deploy +from test.util import assert_transaction from typing import List, Union import requests @@ -76,7 +76,7 @@ def gateway_call(method: str, **kwargs): def get_block_with_transaction(transaction_hash: str) -> dict: """ - Retrieve block for given transaction + Retrieve block for given transaction via gateway API """ transaction = gateway_call("get_transaction", transactionHash=transaction_hash) assert ( @@ -98,7 +98,7 @@ def deploy_and_invoke_storage_contract(value: int) -> List[str]: """ Deploy and invoke storage contract """ - deploy_dict = deploy(STORAGE_CONTRACT_PATH) + deploy_dict = declare_and_deploy_with_chargeable(STORAGE_CONTRACT_PATH) contract_address = deploy_dict["address"] invoke_tx_hash = invoke( diff --git a/test/rpc/test_data/get_events.py b/test/rpc/test_data/get_events.py index eaf415b49..6200621c0 100644 --- a/test/rpc/test_data/get_events.py +++ b/test/rpc/test_data/get_events.py @@ -78,58 +78,67 @@ def parse_block_delimiter_parameter( EVENT_FEE_ADDRESS = rpc_felt( 0xBEBE7DEC64B911AEFFECC184AFCEFA6470E3B3652A1605E42D643E1EA9093D ) -FEE_CHARGING_IN_BLOCK_2_EVENT = [ +INVOKE_1_FEE_CHARGING_EVENT = [ rpc_felt(int(PREDEPLOYED_ACCOUNT_ADDRESS, 16)), EVENT_FEE_ADDRESS, rpc_felt(0x73B00ED0C000), # WEI rpc_felt(0), ] -FEE_CHARGING_IN_BLOCK_3_EVENT = [ +INVOKE_2_FEE_CHARGING_EVENT = [ rpc_felt(int(PREDEPLOYED_ACCOUNT_ADDRESS, 16)), EVENT_FEE_ADDRESS, rpc_felt(0x015254FFDB4000), # WEI rpc_felt(0), ] +INVOKE_1_BLOCK_NUMBER = 3 # after (origin + declare + deploy) +INVOKE_2_BLOCK_NUMBER = INVOKE_1_BLOCK_NUMBER + 1 GET_EVENTS_TEST_DATA = [ ( [*PREDEPLOY_ACCOUNT_CLI_ARGS], create_get_events_filter( + from_block=INVOKE_1_BLOCK_NUMBER, keys=[ rpc_felt(FEE_CHARGED_EVENT_KEY), rpc_felt(INCREASE_BALANCE_CALLED_EVENT_KEY), - ] + ], ), [ - FEE_CHARGING_IN_BLOCK_2_EVENT, - FEE_CHARGING_IN_BLOCK_3_EVENT, + INVOKE_1_FEE_CHARGING_EVENT, + INVOKE_2_FEE_CHARGING_EVENT, ], ), ( [*PREDEPLOY_ACCOUNT_CLI_ARGS], - create_get_events_filter(from_block=rpc_felt("0x0")), + create_get_events_filter(from_block=INVOKE_1_BLOCK_NUMBER), [ - FEE_CHARGING_IN_BLOCK_2_EVENT, - FEE_CHARGING_IN_BLOCK_3_EVENT, + INVOKE_1_FEE_CHARGING_EVENT, + INVOKE_2_FEE_CHARGING_EVENT, ], ), ( [*PREDEPLOY_ACCOUNT_CLI_ARGS], - create_get_events_filter(from_block=rpc_felt("0x0"), to_block=2), - [FEE_CHARGING_IN_BLOCK_2_EVENT], + create_get_events_filter( + from_block=INVOKE_1_BLOCK_NUMBER, to_block=INVOKE_1_BLOCK_NUMBER + ), + [INVOKE_1_FEE_CHARGING_EVENT], ), ( [*PREDEPLOY_ACCOUNT_CLI_ARGS], - create_get_events_filter(from_block=3, to_block=3), - [FEE_CHARGING_IN_BLOCK_3_EVENT], + create_get_events_filter( + from_block=INVOKE_2_BLOCK_NUMBER, to_block=INVOKE_2_BLOCK_NUMBER + ), + [INVOKE_2_FEE_CHARGING_EVENT], ), ( [*PREDEPLOY_ACCOUNT_CLI_ARGS], - create_get_events_filter(from_block=2, to_block=3), + create_get_events_filter( + from_block=INVOKE_1_BLOCK_NUMBER, to_block=INVOKE_2_BLOCK_NUMBER + ), [ - FEE_CHARGING_IN_BLOCK_2_EVENT, - FEE_CHARGING_IN_BLOCK_3_EVENT, + INVOKE_1_FEE_CHARGING_EVENT, + INVOKE_2_FEE_CHARGING_EVENT, ], ), ] diff --git a/test/rpc/test_rpc_blocks.py b/test/rpc/test_rpc_blocks.py index 544e5d2c2..3b5645785 100644 --- a/test/rpc/test_rpc_blocks.py +++ b/test/rpc/test_rpc_blocks.py @@ -13,6 +13,7 @@ from starknet_devnet.blueprints.rpc.structures.types import ( BlockHashDict, BlockNumberDict, + Signature, rpc_txn_type, ) from starknet_devnet.blueprints.rpc.utils import rpc_felt, rpc_root @@ -30,7 +31,7 @@ def test_get_block_with_tx_hashes(deploy_info, gateway_block, block_id): resp = rpc_call("starknet_getBlockWithTxHashes", params={"block_id": block_id}) block = resp["result"] - transaction_hash: str = rpc_felt(deploy_info["transaction_hash"]) + transaction_hash: str = rpc_felt(deploy_info["tx_hash"]) assert block == { "block_hash": rpc_felt(block_hash), @@ -70,6 +71,7 @@ def test_get_block_with_txs(gateway_block, block_id): block_number: int = gateway_block["block_number"] new_root: str = rpc_root(gateway_block["state_root"]) block_tx = gateway_block["transactions"][0] + signature: Signature = [rpc_felt(sig) for sig in block_tx["signature"]] resp = rpc_call("starknet_getBlockWithTxs", params={"block_id": block_id}) block = resp["result"] @@ -84,12 +86,12 @@ def test_get_block_with_txs(gateway_block, block_id): "timestamp": gateway_block["timestamp"], "transactions": [ { - "class_hash": rpc_felt(block_tx["class_hash"]), - "constructor_calldata": [ - rpc_felt(data) for data in block_tx["constructor_calldata"] - ], - "contract_address_salt": rpc_felt(block_tx["contract_address_salt"]), + "calldata": [rpc_felt(data) for data in block_tx["calldata"]], + "sender_address": rpc_felt(block_tx["sender_address"]), + "max_fee": rpc_felt(block_tx["max_fee"]), + "nonce": rpc_felt(block_tx["nonce"]), "transaction_hash": rpc_felt(block_tx["transaction_hash"]), + "signature": signature, "type": rpc_txn_type(block_tx["type"]), "version": hex(SUPPORTED_RPC_TX_VERSION), } diff --git a/test/rpc/test_rpc_call.py b/test/rpc/test_rpc_call.py index 35d23ec6e..1fbea6ef4 100644 --- a/test/rpc/test_rpc_call.py +++ b/test/rpc/test_rpc_call.py @@ -154,7 +154,7 @@ def test_call_on_old_block(deploy_info): """Correctly call contract on old state""" contract_address: str = deploy_info["address"] - deployment_block = get_block_with_transaction(deploy_info["transaction_hash"]) + deployment_block = get_block_with_transaction(deploy_info["tx_hash"]) invoke_tx_hash = invoke( calls=[(contract_address, "increase_balance", [10, 20])], diff --git a/test/rpc/test_rpc_misc.py b/test/rpc/test_rpc_misc.py index 4c07e165d..06d989e6e 100644 --- a/test/rpc/test_rpc_misc.py +++ b/test/rpc/test_rpc_misc.py @@ -4,7 +4,7 @@ from __future__ import annotations -from test.account import declare, invoke +from test.account import declare, declare_and_deploy_with_chargeable, invoke from test.rpc.rpc_utils import deploy_and_invoke_storage_contract, rpc_call from test.rpc.test_data.get_events import GET_EVENTS_TEST_DATA, create_get_events_filter from test.shared import ( @@ -23,7 +23,6 @@ assert_get_events_response, assert_hex_equal, assert_transaction, - deploy, devnet_in_background, ) @@ -72,9 +71,9 @@ def test_get_state_update(): # Deploy the deployer - also deploys a contract of the declared class using the deploy syscall initial_balance_in_constructor = "5" - deployer_deploy_info = deploy( + deployer_deploy_info = declare_and_deploy_with_chargeable( contract=DEPLOYER_CONTRACT_PATH, - inputs=[contract_class_hash, initial_balance_in_constructor], + inputs=[int(contract_class_hash, 16), initial_balance_in_constructor], ) deployer_class_hash = hex(get_class_hash_at_path(DEPLOYER_CONTRACT_PATH)) deployer_address = deployer_deploy_info["address"] @@ -90,10 +89,8 @@ def test_get_state_update(): assert_hex_equal(deployed_contract_diff["class_hash"], contract_class_hash) # deployed_contract_diff["address"] is a random value - # deployer expected to be declared - assert diff_after_deploy["declared_contract_hashes"] == [ - rpc_felt(deployer_class_hash) - ] + # deployer expected to be declared one block earier, so nothing new declared + assert diff_after_deploy["declared_contract_hashes"] == [] @pytest.mark.usefixtures("devnet_with_account") @@ -205,7 +202,7 @@ def test_get_events_continuation_token(): """ Test RPC get_events returning continuation token. """ - deploy_info = deploy(EVENTS_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(EVENTS_CONTRACT_PATH) total_invokes = 3 for i in range(total_invokes): invoke( @@ -213,34 +210,44 @@ def test_get_events_continuation_token(): account_address=PREDEPLOYED_ACCOUNT_ADDRESS, private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) + + # origin (being 0) + declare + deploy = first invoke block is 3 + first_invoke_block = 3 + resp = rpc_call( "starknet_getEvents", - params=create_get_events_filter(chunk_size=total_invokes), + params=create_get_events_filter( + from_block=first_invoke_block, chunk_size=total_invokes + ), ) assert_get_events_response(resp, expected_block_length=total_invokes) resp = rpc_call( "starknet_getEvents", - params=create_get_events_filter(chunk_size=1), + params=create_get_events_filter(from_block=first_invoke_block, chunk_size=1), ) assert_get_events_response(resp, expected_block_length=1, expected_token="1") resp = rpc_call( "starknet_getEvents", - params=create_get_events_filter(chunk_size=1, continuation_token="1"), + params=create_get_events_filter( + from_block=first_invoke_block, chunk_size=1, continuation_token="1" + ), ) assert_get_events_response(resp, expected_block_length=1, expected_token="2") resp = rpc_call( "starknet_getEvents", - params=create_get_events_filter(chunk_size=1, continuation_token="2"), + params=create_get_events_filter( + from_block=first_invoke_block, chunk_size=1, continuation_token="2" + ), ) assert_get_events_response(resp, expected_block_length=1) resp = rpc_call( "starknet_getEvents", params=create_get_events_filter( - from_block=0, to_block=1, chunk_size=3, continuation_token="0" + from_block=0, to_block=0, chunk_size=3, continuation_token="0" ), ) assert_get_events_response(resp, expected_block_length=0) @@ -256,17 +263,17 @@ def test_get_events(input_data, expected_data): """ Test RPC get_events. """ - deploy_info = deploy(EVENTS_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(EVENTS_CONTRACT_PATH) for i in range(2): invoke( calls=[(deploy_info["address"], "increase_balance", [i])], account_address=PREDEPLOYED_ACCOUNT_ADDRESS, private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) - resp = rpc_call("starknet_getEvents", params=input_data) - assert len(expected_data) == len(resp["result"]["events"]) - for i, data in enumerate(expected_data): - assert resp["result"]["events"][i]["data"] == data + + events_resp = rpc_call("starknet_getEvents", params=input_data) + actual_data = [event["data"] for event in events_resp["result"]["events"]] + assert actual_data == expected_data @pytest.mark.usefixtures("devnet_with_account") diff --git a/test/rpc/test_rpc_transactions.py b/test/rpc/test_rpc_transactions.py index 77ae7e321..9731a7d90 100644 --- a/test/rpc/test_rpc_transactions.py +++ b/test/rpc/test_rpc_transactions.py @@ -4,7 +4,12 @@ from __future__ import annotations -from test.account import _get_signature, declare, get_nonce +from test.account import ( + _get_signature, + declare, + declare_and_deploy_with_chargeable, + get_nonce, +) from test.rpc.conftest import prepare_deploy_account_tx, rpc_deploy_account_from_gateway from test.rpc.rpc_utils import ( deploy_and_invoke_storage_contract, @@ -16,13 +21,14 @@ from test.shared import ( ABI_PATH, CONTRACT_PATH, + EXPECTED_UDC_ADDRESS, INCORRECT_GENESIS_BLOCK_HASH, PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, STARKNET_CLI_ACCOUNT_ABI_PATH, SUPPORTED_RPC_TX_VERSION, ) -from test.util import assert_tx_status, call, deploy, load_contract_class, mint, send_tx +from test.util import assert_tx_status, call, load_contract_class, mint, send_tx from typing import List import pytest @@ -38,13 +44,13 @@ get_selector_from_name, get_storage_var_address, ) +from starkware.starknet.services.api.gateway.transaction_utils import compress_program from starkware.starknet.wallets.open_zeppelin import sign_invoke_tx from starknet_devnet.account_util import get_execute_args from starknet_devnet.blueprints.rpc.structures.payloads import ( EntryPoints, RpcBroadcastedDeclareTxn, - RpcBroadcastedDeployTxn, RpcBroadcastedInvokeTxnV0, RpcBroadcastedInvokeTxnV1, RpcContractClass, @@ -76,9 +82,12 @@ def test_get_transaction_by_hash_deploy(deploy_info): """ Get transaction by hash """ - block = get_block_with_transaction(deploy_info["transaction_hash"]) + block = get_block_with_transaction(deploy_info["tx_hash"]) block_tx = block["transactions"][0] - transaction_hash: str = deploy_info["transaction_hash"] + transaction_hash: str = deploy_info["tx_hash"] + + signature: Signature = [rpc_felt(sig) for sig in block_tx["signature"]] + calldata: List[str] = [rpc_felt(data) for data in block_tx["calldata"]] resp = rpc_call( "starknet_getTransactionByHash", @@ -88,11 +97,13 @@ def test_get_transaction_by_hash_deploy(deploy_info): assert transaction == { "transaction_hash": rpc_felt(transaction_hash), - "class_hash": rpc_felt(block_tx["class_hash"]), "version": hex(SUPPORTED_RPC_TX_VERSION), "type": rpc_txn_type(block_tx["type"]), - "contract_address_salt": rpc_felt(block_tx["contract_address_salt"]), - "constructor_calldata": ["0x045"], + "calldata": calldata, + "max_fee": rpc_felt(block_tx["max_fee"]), + "nonce": rpc_felt(block_tx["nonce"]), + "signature": signature, + "sender_address": rpc_felt(block_tx["sender_address"]), } @@ -208,9 +219,9 @@ def test_get_transaction_by_block_id_and_index(deploy_info): """ Get transaction by block id and transaction index """ - block = get_block_with_transaction(deploy_info["transaction_hash"]) + block = get_block_with_transaction(deploy_info["tx_hash"]) block_tx = block["transactions"][0] - transaction_hash: str = deploy_info["transaction_hash"] + transaction_hash: str = deploy_info["tx_hash"] block_number: str = block["block_number"] index: int = 0 @@ -225,13 +236,16 @@ def test_get_transaction_by_block_id_and_index(deploy_info): ) transaction = resp["result"] + signature: Signature = [rpc_felt(sig) for sig in block_tx["signature"]] + calldata: List[str] = [rpc_felt(data) for data in block_tx["calldata"]] + assert transaction == { - "class_hash": rpc_felt(block_tx["class_hash"]), - "constructor_calldata": [ - rpc_felt(tx) for tx in block_tx["constructor_calldata"] - ], - "contract_address_salt": rpc_felt(block_tx["contract_address_salt"]), + "calldata": calldata, + "signature": signature, + "sender_address": rpc_felt(block_tx["sender_address"]), "transaction_hash": rpc_felt(transaction_hash), + "max_fee": rpc_felt(block_tx["max_fee"]), + "nonce": rpc_felt(block_tx["nonce"]), "type": rpc_txn_type(block_tx["type"]), "version": hex(SUPPORTED_RPC_TX_VERSION), } @@ -258,7 +272,7 @@ def test_get_transaction_by_block_id_and_index_raises_on_incorrect_index(deploy_ """ Get transaction by block hash and incorrect transaction index """ - block = get_block_with_transaction(deploy_info["transaction_hash"]) + block = get_block_with_transaction(deploy_info["tx_hash"]) block_hash: str = block["block_hash"] ex = rpc_call( @@ -360,7 +374,7 @@ def test_get_deploy_transaction_receipt(deploy_info): """ Get transaction receipt """ - transaction_hash: str = deploy_info["transaction_hash"] + transaction_hash: str = deploy_info["tx_hash"] block = get_block_with_transaction(transaction_hash) resp = rpc_call( @@ -369,16 +383,25 @@ def test_get_deploy_transaction_receipt(deploy_info): ) receipt = resp["result"] + assert len(block["transaction_receipts"]) == 1 + block_receipt = block["transaction_receipts"][0] + assert receipt == { - "contract_address": rpc_felt(deploy_info["address"]), "transaction_hash": rpc_felt(transaction_hash), - "actual_fee": rpc_felt(0), + "actual_fee": rpc_felt(block_receipt["actual_fee"]), "status": "ACCEPTED_ON_L2", "block_hash": rpc_felt(block["block_hash"]), "block_number": block["block_number"], - "type": "DEPLOY", + "type": "INVOKE", "messages_sent": [], - "events": [], + "events": [ + { + "from_address": rpc_felt(event["from_address"]), + "data": [rpc_felt(data) for data in event["data"]], + "keys": [rpc_felt(key) for key in event["keys"]], + } + for event in block_receipt["events"] + ], } @@ -423,7 +446,9 @@ def test_add_invoke_transaction(): Add invoke transaction """ initial_balance, amount1, amount2 = 100, 13, 56 - deploy_dict = deploy(CONTRACT_PATH, [str(initial_balance)]) + deploy_dict = declare_and_deploy_with_chargeable( + CONTRACT_PATH, [str(initial_balance)] + ) contract_address = deploy_dict["address"] max_fee = int(4e16) @@ -470,7 +495,9 @@ def test_add_invoke_transaction_v0(): Add invoke transaction with tx v0 """ initial_balance, amount1, amount2 = 100, 13, 56 - deploy_dict = deploy(CONTRACT_PATH, [str(initial_balance)]) + deploy_dict = declare_and_deploy_with_chargeable( + CONTRACT_PATH, [str(initial_balance)] + ) contract_address = deploy_dict["address"] invoke_transaction = RpcBroadcastedInvokeTxnV0( @@ -533,24 +560,21 @@ def test_add_declare_transaction_on_incorrect_contract(declare_content): assert ex["error"] == {"code": 50, "message": "Invalid contract class"} -@pytest.mark.usefixtures("devnet_with_account") -def test_add_declare_transaction(declare_content): - """ - Add declare transaction - """ - contract_class = declare_content["contract_class"] - pad_zero_entry_points(contract_class["entry_points_by_type"]) - max_fee = int(4e16) +def _add_declare_transaction(): + contract_class = load_contract_class(CONTRACT_PATH) + contract_class_dump = contract_class.dump() + pad_zero_entry_points(contract_class_dump["entry_points_by_type"]) rpc_contract_class = RpcContractClass( - program=contract_class["program"], - entry_points_by_type=contract_class["entry_points_by_type"], - abi=contract_class["abi"], + program=compress_program(contract_class_dump["program"]), + entry_points_by_type=contract_class_dump["entry_points_by_type"], + abi=contract_class_dump["abi"], ) + max_fee = int(4e16) nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS) tx_hash = calculate_deprecated_declare_transaction_hash( - contract_class=load_contract_class(CONTRACT_PATH), + contract_class=contract_class, chain_id=StarknetChainId.TESTNET.value, sender_address=int(PREDEPLOYED_ACCOUNT_ADDRESS, 16), max_fee=max_fee, @@ -560,7 +584,7 @@ def test_add_declare_transaction(declare_content): signature = _get_signature(tx_hash, PREDEPLOYED_ACCOUNT_PRIVATE_KEY) declare_transaction = RpcBroadcastedDeclareTxn( - type=declare_content["type"], + type="DECLARE", max_fee=rpc_felt(max_fee), version=hex(SUPPORTED_RPC_TX_VERSION), signature=[rpc_felt(sig) for sig in signature], @@ -573,11 +597,18 @@ def test_add_declare_transaction(declare_content): "starknet_addDeclareTransaction", params={"declare_transaction": declare_transaction}, ) - receipt = resp["result"] + return resp["result"] + + +@pytest.mark.usefixtures("devnet_with_account") +def test_add_declare_transaction(): + """Add declare transaction""" + receipt = _add_declare_transaction() assert set(receipt.keys()) == set(["transaction_hash", "class_hash"]) assert is_felt(receipt["transaction_hash"]) assert is_felt(receipt["class_hash"]) + assert_tx_status(receipt["transaction_hash"], "ACCEPTED_ON_L2") @pytest.mark.usefixtures("run_devnet_in_background") @@ -615,73 +646,56 @@ def test_add_declare_transaction_v0(declare_content): assert is_felt(receipt["class_hash"]) -@pytest.mark.usefixtures("run_devnet_in_background") -def test_add_deploy_transaction_on_incorrect_contract(deploy_content): - """ - Add deploy transaction on incorrect class - """ - contract_definition = deploy_content["contract_definition"] - salt = rpc_felt(deploy_content["contract_address_salt"]) - calldata = [rpc_felt(data) for data in deploy_content["constructor_calldata"]] - pad_zero_entry_points(contract_definition["entry_points_by_type"]) +@pytest.mark.usefixtures("devnet_with_account") +def test_deploy(): + """Deploy contract.cairo via UDC""" + declaration_receipt = _add_declare_transaction() + + initial_balance = 10 + ctor_args = [initial_balance] + + calls = [ + ( + EXPECTED_UDC_ADDRESS, + "deployContract", + [ + int(declaration_receipt["class_hash"], 16), + 42, # salt + 0, # unique + len(ctor_args), + *ctor_args, + ], + ) + ] - rpc_contract_class = RpcContractClass( - program="", - entry_points_by_type=contract_definition["entry_points_by_type"], - abi=contract_definition["abi"], + nonce = get_nonce(PREDEPLOYED_ACCOUNT_ADDRESS) + max_fee = int(4e16) + signature, execute_calldata = get_execute_args( + calls=calls, + account_address=PREDEPLOYED_ACCOUNT_ADDRESS, + private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, + nonce=nonce, + version=SUPPORTED_RPC_TX_VERSION, + max_fee=max_fee, ) - deploy_transaction = RpcBroadcastedDeployTxn( - contract_class=rpc_contract_class, + invoke_transaction = RpcBroadcastedInvokeTxnV1( + type="INVOKE", + max_fee=rpc_felt(max_fee), version=hex(SUPPORTED_RPC_TX_VERSION), - type=deploy_content["type"], - contract_address_salt=salt, - constructor_calldata=calldata, - ) - - ex = rpc_call( - "starknet_addDeployTransaction", - params={"deploy_transaction": deploy_transaction}, - ) - - assert ex["error"] == {"code": 50, "message": "Invalid contract class"} - - -@pytest.mark.usefixtures("run_devnet_in_background") -@pytest.mark.parametrize("version", [LEGACY_RPC_TX_VERSION, SUPPORTED_RPC_TX_VERSION]) -def test_add_deploy_transaction(deploy_content, version): - """ - Add deploy transaction - """ - contract_definition = deploy_content["contract_definition"] - pad_zero_entry_points(contract_definition["entry_points_by_type"]) - salt = rpc_felt(deploy_content["contract_address_salt"]) - calldata = [rpc_felt(data) for data in deploy_content["constructor_calldata"]] - - rpc_contract_class = RpcContractClass( - program=contract_definition["program"], - entry_points_by_type=contract_definition["entry_points_by_type"], - abi=contract_definition["abi"], - ) - - deploy_transaction = RpcBroadcastedDeployTxn( - contract_class=rpc_contract_class, - version=hex(version), - type=deploy_content["type"], - contract_address_salt=salt, - constructor_calldata=calldata, + signature=[rpc_felt(sig) for sig in signature], + nonce=rpc_felt(nonce), + sender_address=rpc_felt(PREDEPLOYED_ACCOUNT_ADDRESS), + calldata=[rpc_felt(data) for data in execute_calldata], ) resp = rpc_call( - "starknet_addDeployTransaction", - params={"deploy_transaction": deploy_transaction}, + "starknet_addInvokeTransaction", + params={"invoke_transaction": invoke_transaction}, ) - receipt = resp["result"] - - assert set(receipt.keys()) == set(["transaction_hash", "contract_address"]) - - assert is_felt(receipt["transaction_hash"]) - assert is_felt(receipt["contract_address"]) + deployment_receipt = resp["result"] + assert_tx_status(deployment_receipt["transaction_hash"], "ACCEPTED_ON_L2") + # to assert storage of the newly deployed contract, we would need to calculate it or extract it from UDC event @pytest.mark.usefixtures("run_devnet_in_background") @@ -744,7 +758,9 @@ def test_add_deploy_account_transaction(deploy_account_details): # deploy a contract for testing init_balance = 10 - contract_deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(init_balance)]) + contract_deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[str(init_balance)] + ) contract_address = contract_deploy_info["address"] # increase balance of test contract diff --git a/test/shared.py b/test/shared.py index 408ef8cac..073041fee 100644 --- a/test/shared.py +++ b/test/shared.py @@ -38,14 +38,6 @@ "916907772491729262376534102982219947830828984996257231353398618781993312401" ) -EXPECTED_SALTY_DEPLOY_ADDRESS = ( - "0x06c9b52d3297d731eaea82dbfa4d20424855d498b8594b9442a1d4d5d995a5bd" -) -EXPECTED_SALTY_DEPLOY_HASH = ( - "0x6203291c2c6978e563c220f57f0d4f7fe662bb83e8b159ef1b32d4850d8ce91" -) - -# hash of contract at CONTRACT_PATH EXPECTED_CLASS_HASH = ( "0x2216379233d6f7c8890a730e164e069dafdd63edf0f0218dde8181b50fabd45" ) diff --git a/test/test_account.py b/test/test_account.py index fec47114d..5d6abe3e1 100644 --- a/test/test_account.py +++ b/test/test_account.py @@ -4,11 +4,12 @@ import pytest import requests +from starkware.crypto.signature.signature import private_to_stark_key from .account import ( ACCOUNT_ABI_PATH, - PRIVATE_KEY, - PUBLIC_KEY, + declare_and_deploy, + declare_and_deploy_with_chargeable, deploy_account_contract, get_estimated_fee, get_nonce, @@ -26,22 +27,18 @@ from .util import ( assert_equal, assert_events, + assert_hex_equal, assert_transaction, assert_tx_status, call, - deploy, devnet_in_background, get_transaction_receipt, - load_file_content, mint, ) -INVOKE_CONTENT = load_file_content("invoke.json") -DEPLOY_CONTENT = load_file_content("deploy.json") SALTY_ACCOUNT_ADDRESS = ( "0x025b4639c321f3538c69537502f0379a23d6c91d6bf0f9dfe79fabfc3da97de2" ) -INVALID_HASH = "0x58d4d4ed7580a7a98ab608883ec9fe722424ce52c19f2f369eeea301f535914" SALT = "0x99" ACCOUNTS_SEED_DEVNET_ARGS = [ @@ -52,15 +49,30 @@ "1_000_000_000_000_000_000_000", ] +PRIVATE_KEY = 123456789987654321 +PUBLIC_KEY = private_to_stark_key(PRIVATE_KEY) + def deploy_empty_contract(): - """Deploy sample contract with balance = 0.""" - return deploy(CONTRACT_PATH, inputs=["0"], salt=SALT) + """ + Deploy sample contract with balance = 0. + This function expects to be called when running devnet in background with the usual seed + """ + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, + inputs=[0], + salt=SALT, + ) + assert_tx_status(deploy_info["tx_hash"], "ACCEPTED_ON_L2") + return deploy_info def deploy_events_contract(): """Deploy events contract with salt of 0x99.""" - return deploy(EVENTS_CONTRACT_PATH, salt=SALT) + return declare_and_deploy_with_chargeable( + contract=EVENTS_CONTRACT_PATH, + salt=SALT, + ) def get_account_balance(address: str, server_url=APP_URL) -> int: @@ -74,50 +86,89 @@ def get_account_balance(address: str, server_url=APP_URL) -> int: @devnet_in_background() def test_account_contract_deploy(): """Test account contract deploy, public key and initial nonce value.""" - account_deploy_info = deploy_account_contract(salt=SALT) + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + account_deploy_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) account_address = account_deploy_info["address"] - assert account_address == SALTY_ACCOUNT_ADDRESS + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) deployed_public_key = call("getPublicKey", account_address, ACCOUNT_ABI_PATH) assert int(deployed_public_key, 16) == PUBLIC_KEY nonce = get_nonce(account_address) - assert nonce == 0 + assert nonce == 1 # tested on alpha-goerli2: nonce is 1 right after deployment @pytest.mark.account @devnet_in_background() def test_invoking_another_contract(): """Test invoking another contract through a newly deployed (not predeployed) account.""" - max_fee = int(4e16) + # deploy the non-account contract deploy_info = deploy_empty_contract() - account_address = deploy_account_contract(salt=SALT)["address"] to_address = deploy_info["address"] - # add funds to new account - mint(account_address, max_fee) + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + deploy_account_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) + assert_tx_status(deploy_account_info["tx_hash"], "ACCEPTED_ON_L2") + account_address = deploy_account_info["address"] + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) # execute increase_balance call calls = [(to_address, "increase_balance", [10, 20])] - tx_hash = invoke(calls, account_address, PRIVATE_KEY, 0, max_fee=max_fee) + tx_hash = invoke(calls, account_address, PRIVATE_KEY) assert_tx_status(tx_hash, "ACCEPTED_ON_L2") # check if nonce is increased nonce = get_nonce(account_address) - assert nonce == 1 + assert nonce == 2 # check if balance is increased balance = call("get_balance", to_address, ABI_PATH, []) assert balance == "30" +@pytest.mark.account +@devnet_in_background() +def test_invoking_with_invalid_args(): + """Provide insufficient args. Expect failure.""" + + deploy_info = deploy_empty_contract() + to_address = deploy_info["address"] + + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + deploy_account_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) + assert_tx_status(deploy_account_info["tx_hash"], "ACCEPTED_ON_L2") + account_address = deploy_account_info["address"] + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) + + nonce_before = get_nonce(account_address) + + # execute increase_balance call + invalid_args = [10] # one param mising + calls = [(to_address, "increase_balance", invalid_args)] + tx_hash = invoke( + calls, + account_address=account_address, + private_key=PRIVATE_KEY, + max_fee=int(1e18), # prevent estimateFee - fails due to invalid args + ) + + assert_tx_status(tx_hash, "REJECTED") + + # check if nonce is increased + nonce_after = get_nonce(account_address) + assert nonce_after == nonce_before + + @pytest.mark.account @devnet_in_background() def test_estimated_fee(): """Test estimate fees.""" deploy_info = deploy_empty_contract() - account_address = deploy_account_contract(salt=SALT)["address"] + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + deploy_account_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) + account_address = deploy_account_info["address"] + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) initial_balance = call("get_balance", deploy_info["address"], abi_path=ABI_PATH) @@ -139,7 +190,11 @@ def test_estimated_fee(): def test_low_max_fee(): """Test if transaction is rejected with low max fee""" deploy_info = deploy_empty_contract() - account_address = deploy_account_contract(salt=SALT)["address"] + + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + deploy_account_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) + account_address = deploy_account_info["address"] + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) initial_balance = call("get_balance", deploy_info["address"], abi_path=ABI_PATH) @@ -162,6 +217,7 @@ def test_low_max_fee(): def test_sufficient_max_fee(): """Test invoking with a sufficient max fee.""" deploy_info = deploy_empty_contract() + account_address = PREDEPLOYED_ACCOUNT_ADDRESS private_key = PREDEPLOYED_ACCOUNT_PRIVATE_KEY initial_account_balance = get_account_balance(account_address) @@ -190,6 +246,15 @@ def test_sufficient_max_fee(): assert_equal(final_account_balance, initial_account_balance - actual_fee) +def _assert_subtraction_overflow(tx_hash: str): + assert_tx_status(tx_hash, "REJECTED") + invoke_receipt = get_transaction_receipt(tx_hash) + assert ( + "subtraction overflow" + in invoke_receipt["transaction_failure_reason"]["error_message"] + ) + + @pytest.mark.account @devnet_in_background( *PREDEPLOY_ACCOUNT_CLI_ARGS, @@ -213,14 +278,9 @@ def test_insufficient_balance(): calls = [(deploy_info["address"], "increase_balance", args)] invoke_tx_hash = invoke( calls, account_address, private_key, max_fee=10**21 - ) # big enough + ) # big enough to fail - assert_tx_status(invoke_tx_hash, "REJECTED") - invoke_receipt = get_transaction_receipt(invoke_tx_hash) - assert ( - "subtraction overflow" - in invoke_receipt["transaction_failure_reason"]["error_message"] - ) + _assert_subtraction_overflow(invoke_tx_hash) final_contract_balance = call( "get_balance", deploy_info["address"], abi_path=ABI_PATH @@ -235,26 +295,27 @@ def test_insufficient_balance(): @devnet_in_background() def test_multicall(): """Test making multiple calls.""" - max_fee = int(4e16) + deploy_info = deploy_empty_contract() - account_address = deploy_account_contract(salt=SALT)["address"] to_address = deploy_info["address"] - # add funds to new account - mint(account_address, max_fee) + mint(address=SALTY_ACCOUNT_ADDRESS, amount=int(1e18), lite=True) + deploy_account_info = deploy_account_contract(private_key=PRIVATE_KEY, salt=SALT) + account_address = deploy_account_info["address"] + assert_hex_equal(account_address, SALTY_ACCOUNT_ADDRESS) # execute increase_balance calls calls = [ (to_address, "increase_balance", [10, 20]), (to_address, "increase_balance", [30, 40]), ] - tx_hash = invoke(calls, account_address, PRIVATE_KEY, max_fee=max_fee) + tx_hash = invoke(calls, account_address, PRIVATE_KEY, max_fee=int(1e18)) assert_tx_status(tx_hash, "ACCEPTED_ON_L2") # check if nonce is increased nonce = get_nonce(account_address) - assert nonce == 1 + assert nonce == 2 # check if balance is increased balance = call("get_balance", deploy_info["address"], abi_path=ABI_PATH) @@ -266,6 +327,7 @@ def test_multicall(): def test_events(): """Test transaction receipt events""" deploy_info = deploy_events_contract() + account_address = PREDEPLOYED_ACCOUNT_ADDRESS private_key = PREDEPLOYED_ACCOUNT_PRIVATE_KEY @@ -293,7 +355,16 @@ def test_get_nonce_endpoint(): assert initial_resp.status_code == 200 assert initial_resp.json() == "0x0" - deployment_info = deploy_empty_contract() + deployment_info = declare_and_deploy( + contract=CONTRACT_PATH, + account_address=account_address, + private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, + inputs=[0], + ) + + final_resp = get_nonce_with_request(address=account_address) + assert final_resp.status_code == 200 + assert final_resp.json() == "0x2" # declare and deploy invoke_tx_hash = invoke( calls=[(deployment_info["address"], "increase_balance", [10, 20])], @@ -304,4 +375,4 @@ def test_get_nonce_endpoint(): final_resp = get_nonce_with_request(address=account_address) assert final_resp.status_code == 200 - assert final_resp.json() == "0x1" + assert final_resp.json() == "0x3" # invoke diff --git a/test/test_account_custom.py b/test/test_account_custom.py index fc40dfc2f..513e6ec38 100644 --- a/test/test_account_custom.py +++ b/test/test_account_custom.py @@ -11,7 +11,7 @@ DeprecatedCompiledClass, ) -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .shared import ( ABI_PATH, CONTRACT_PATH, @@ -22,7 +22,6 @@ from .util import ( DevnetBackgroundProc, call, - deploy, devnet_in_background, get_class_hash_at, load_file_content, @@ -76,7 +75,7 @@ def test_providing_correct_account_class(): ) assert fetched_class_hash == compute_deprecated_class_hash(expected_contract_class) - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) invoke( calls=[(deploy_info["address"], "increase_balance", [10, 20])], account_address=PREDEPLOYED_ACCOUNT_ADDRESS, diff --git a/test/test_block_number.py b/test/test_block_number.py index 3dd651dcb..7f0272ea6 100644 --- a/test/test_block_number.py +++ b/test/test_block_number.py @@ -4,7 +4,7 @@ import pytest -from .account import declare, invoke +from .account import declare, declare_and_deploy_with_chargeable, invoke from .shared import ( ARTIFACTS_PATH, FAILING_CONTRACT_PATH, @@ -13,7 +13,7 @@ PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) -from .util import call, deploy, devnet_in_background +from .util import call, devnet_in_background BLOCK_NUMBER_CONTRACT_PATH = f"{ARTIFACTS_PATH}/block_number.cairo/block_number.json" BLOCK_NUMBER_ABI_PATH = f"{ARTIFACTS_PATH}/block_number.cairo/block_number_abi.json" @@ -26,9 +26,6 @@ def my_get_block_number(address: str): ) -EXPECTED_TX_HASH = "0x79ca931a44a6736d053d48a4c0a12f05accd67a479a6be253f3a1eb9fb2f3db" - - @pytest.mark.usefixtures("run_devnet_in_background") @pytest.mark.parametrize( "run_devnet_in_background", @@ -44,11 +41,13 @@ def test_block_number_incremented(): In regular mode with salt "0x42" our expected hash is {EXPECTED_TX_HASH}. """ - deploy_info = deploy(BLOCK_NUMBER_CONTRACT_PATH, salt="0x42") - block_number_before = my_get_block_number(deploy_info["address"]) + deploy_info = declare_and_deploy_with_chargeable( + BLOCK_NUMBER_CONTRACT_PATH, salt="0x42" + ) - assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 1 - assert deploy_info["tx_hash"] == EXPECTED_TX_HASH + block_number_before = my_get_block_number(deploy_info["address"]) + # genesis + declare + deploy + assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 2 invoke( calls=[(deploy_info["address"], "write_block_number", [])], @@ -62,19 +61,21 @@ def test_block_number_incremented(): address=deploy_info["address"], abi_path=BLOCK_NUMBER_ABI_PATH, ) - assert int(written_block_number) == GENESIS_BLOCK_NUMBER + 2 + # genesis + declare + deploy + invoke + assert int(written_block_number) == GENESIS_BLOCK_NUMBER + 3 block_number_after = my_get_block_number(deploy_info["address"]) - assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 2 + assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 3 @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) def test_block_number_incremented_on_declare(): """Declare tx should increment get_block_number response""" - deploy_info = deploy(BLOCK_NUMBER_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(BLOCK_NUMBER_CONTRACT_PATH) block_number_before = my_get_block_number(deploy_info["address"]) - assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 1 + # genesis + declare + deploy + assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 2 # just to declare a new class - nothing fails here declare( @@ -84,8 +85,9 @@ def test_block_number_incremented_on_declare(): max_fee=int(4e16), ) + # genesis + declare + deploy + declare block_number_after = my_get_block_number(deploy_info["address"]) - assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 2 + assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 3 @devnet_in_background() @@ -95,14 +97,18 @@ def test_block_number_not_incremented_if_deploy_fails(): get_block_number should return an unchanged value """ - deploy_info = deploy(BLOCK_NUMBER_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(BLOCK_NUMBER_CONTRACT_PATH) block_number_before = my_get_block_number(deploy_info["address"]) - assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 1 + # genesis + declare + deploy + assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 2 - deploy(FAILING_CONTRACT_PATH) + # declare and deploy a contract whose constructor fails; + # supply max_fee to prevent failing on implicit max_fee estimation + declare_and_deploy_with_chargeable(FAILING_CONTRACT_PATH, max_fee=int(1e18)) block_number_after = my_get_block_number(deploy_info["address"]) - assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 1 + # genesis + declare + deploy + declare + assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 3 @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) @@ -112,9 +118,10 @@ def test_block_number_not_incremented_if_invoke_fails(): get_block_number should return an unchanged value """ - deploy_info = deploy(BLOCK_NUMBER_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(BLOCK_NUMBER_CONTRACT_PATH) block_number_before = my_get_block_number(deploy_info["address"]) - assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 1 + # genesis + declare + deploy + assert int(block_number_before) == GENESIS_BLOCK_NUMBER + 2 invoke( calls=[(deploy_info["address"], "fail", [])], @@ -124,4 +131,4 @@ def test_block_number_not_incremented_if_invoke_fails(): ) block_number_after = my_get_block_number(deploy_info["address"]) - assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 1 + assert int(block_number_after) == GENESIS_BLOCK_NUMBER + 2 diff --git a/test/test_blocks_on_demand.py b/test/test_blocks_on_demand.py index 4459e9187..2665e377a 100644 --- a/test/test_blocks_on_demand.py +++ b/test/test_blocks_on_demand.py @@ -7,7 +7,7 @@ from starknet_devnet.blueprints.rpc.utils import rpc_felt -from .account import get_estimated_fee, invoke +from .account import declare_and_deploy_with_chargeable, get_estimated_fee, invoke from .rpc.rpc_utils import rpc_call from .settings import APP_URL from .shared import ( @@ -28,7 +28,6 @@ assert_tx_status, call, demand_block_creation, - deploy, devnet_in_background, get_block, increase_time, @@ -55,7 +54,7 @@ def test_invokable_on_pending_block(): genesis_block_number = latest_block["block_number"] assert genesis_block_number == 0 - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) assert_tx_status(deploy_info["tx_hash"], "PENDING") def get_contract_balance(): @@ -89,13 +88,13 @@ def get_contract_balance(): latest_block = get_block(block_number="latest", parse=True) block_number_after_block_on_demand_call = latest_block["block_number"] assert block_number_after_block_on_demand_call == 1 - assert len(latest_block["transactions"]) == 2 + assert len(latest_block["transactions"]) == 3 # declare + deploy + invoke @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS, "--blocks-on-demand") def test_estimation_works_after_block_creation(): """Test estimation works only after demanding block creation.""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) assert_tx_status(deploy_info["tx_hash"], "PENDING") def estimate_invoke_fee(): @@ -123,7 +122,7 @@ def test_calling_works_after_block_creation(): Only after calling create_block balance should be increased in this mode. """ # Deploy and invoke - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) demand_block_creation() def get_contract_balance(): @@ -155,7 +154,7 @@ def test_getting_next_block(): """Test that artifacts related to block 1 are available only after creating on demand""" # some transaction, could be anything - deploy(CONTRACT_PATH, inputs=["0"]) + declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) # expect failure on block retrieval next_block_number = 1 @@ -196,7 +195,7 @@ def test_pending_block(): assert latest_block_before["status"] == "ACCEPTED_ON_L2" # some tx to generate a pending block, could be anything - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) # assert correct pending block pending_block = get_block(block_number="pending", parse=True) @@ -220,11 +219,13 @@ def test_pending_block_traces(): latest_block_traces_before = get_block_traces({"blockNumber": "latest"}) # some tx to generate a pending block, could be anything - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) pending_block_traces = get_block_traces({"blockNumber": "pending"}) + assert len(pending_block_traces.traces) == 2 assert_hex_equal( - hex(pending_block_traces.traces[0].transaction_hash), + # trace at index 0 is declare, at index 1 is deploy + hex(pending_block_traces.traces[1].transaction_hash), deploy_info["tx_hash"], ) @@ -240,7 +241,7 @@ def test_pending_state_update(): latest_state_update_before = get_state_update(block_number="latest") # some tx to generate a pending block, could be anything - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) pending_state_update = get_state_update(block_number="pending") pending_deployed = pending_state_update["state_diff"]["deployed_contracts"] @@ -277,7 +278,7 @@ def get_events(to_block): return resp - deploy_info = deploy(contract=EVENTS_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(contract=EVENTS_CONTRACT_PATH) increase_arg = 123 invoke( @@ -335,7 +336,7 @@ def test_endpoint_if_no_pending_after_creation(): Test block creation if no pending txs with on-demand flag set on and after one block has already been created """ - deploy(CONTRACT_PATH, inputs=["10"]) + declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["10"]) resp = demand_block_creation() _assert_correct_block_creation_response(resp) @@ -361,7 +362,7 @@ def test_endpoint_without_on_demand_flag(): @devnet_in_background("--blocks-on-demand") def test_endpoint_if_some_pending(): """Test block creation with some pending txs""" - deploy(CONTRACT_PATH, inputs=["10"]) + declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["10"]) resp = demand_block_creation() _assert_correct_block_creation_response(resp) @@ -369,7 +370,7 @@ def test_endpoint_if_some_pending(): @devnet_in_background("--blocks-on-demand") def test_increase_time_in_block_on_demand_mode(): """Test block creation with increase_time and pending txs""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) assert_tx_status(deploy_info["tx_hash"], "PENDING") latest_block_timestamp = get_block(block_number="latest", parse=True)["timestamp"] @@ -391,7 +392,7 @@ def test_increase_time_in_block_on_demand_mode(): @devnet_in_background("--blocks-on-demand") def test_set_time_in_block_on_demand_mode(): """Test block creation with set_time and pending txs""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) assert_tx_status(deploy_info["tx_hash"], "PENDING") latest_block_timestamp = get_block(block_number="latest", parse=True)["timestamp"] diff --git a/test/test_calls_by_block_id.py b/test/test_calls_by_block_id.py index e5732422d..15fbc284b 100644 --- a/test/test_calls_by_block_id.py +++ b/test/test_calls_by_block_id.py @@ -2,7 +2,7 @@ from starkware.starknet.definitions.error_codes import StarknetErrorCode -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .shared import ( ABI_PATH, BALANCE_KEY, @@ -18,7 +18,6 @@ assert_storage, call, demand_block_creation, - deploy, devnet_in_background, get_block, ) @@ -49,14 +48,18 @@ def test_call(): """Expect variable value not to be changed in the old state""" def assert_old_block_correct(): - value_at_1 = _get_value(contract_address, block_number="1") + # genesis (0) + declare + deploy = block number 2 + value_at_1 = _get_value(contract_address, block_number="2") assert value_at_1 == initial_value - value_at_2 = _get_value(contract_address, block_number="2") + # genesis (0) + declare + deploy + invoke = block number 3 + value_at_2 = _get_value(contract_address, block_number="3") assert value_at_2 == value_at_1 + increment_value initial_value = 5 - deploy_info = deploy(CONTRACT_PATH, inputs=[str(initial_value)]) + deploy_info = declare_and_deploy_with_chargeable( + CONTRACT_PATH, inputs=[str(initial_value)] + ) contract_address = deploy_info["address"] increment_value = 7 @@ -98,7 +101,9 @@ def assert_old_block_correct(): assert value_at_2 == value_at_1 + increment_value initial_value = 5 - deploy_info = deploy(CONTRACT_PATH, inputs=[str(initial_value)]) + deploy_info = declare_and_deploy_with_chargeable( + CONTRACT_PATH, inputs=[str(initial_value)] + ) deployment_block = get_block(block_number="latest", parse=True) deployment_block_hash = deployment_block["block_hash"] contract_address = deploy_info["address"] @@ -134,7 +139,9 @@ def test_forked(): # devnet added a genesis block at FORK_BLOCK + 1 initial_balance = 10 - deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[str(initial_balance)] + ) contract_address = deploy_info["address"] first_increment_value = 7 @@ -142,8 +149,8 @@ def test_forked(): _increment(contract_address, increment_value=5) latest_block = get_block(block_number="latest", parse=True) - # genesis + deploy + invoke + invoke - assert latest_block["block_number"] == FORK_BLOCK + 4 + # fork + genesis + declare + deploy + invoke + invoke + assert latest_block["block_number"] == FORK_BLOCK + 5 with ErrorExpector(StarknetErrorCode.OUT_OF_RANGE_BLOCK_ID): # before first devnet block @@ -151,13 +158,13 @@ def test_forked(): with ErrorExpector(StarknetErrorCode.UNINITIALIZED_CONTRACT): # at genesis block, but before deployment - _get_value(contract_address, block_number=str(FORK_BLOCK + 1)) + _get_value(contract_address, block_number=str(FORK_BLOCK + 2)) - value_after_deploy = _get_value(contract_address, block_number=str(FORK_BLOCK + 2)) + value_after_deploy = _get_value(contract_address, block_number=str(FORK_BLOCK + 3)) assert value_after_deploy == initial_balance value_after_first_invoke = _get_value( - contract_address, block_number=str(FORK_BLOCK + 3) + contract_address, block_number=str(FORK_BLOCK + 4) ) assert value_after_first_invoke == initial_balance + first_increment_value @@ -167,11 +174,13 @@ def test_after_restart(): """Call a state after calling restart - expect failure""" initial_balance = 5 - deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[str(initial_balance)] + ) contract_address = deploy_info["address"] # first assert that it's callable before the restart - assert _get_value(contract_address, block_number="1") == initial_balance + assert _get_value(contract_address, block_number="latest") == initial_balance restart() @@ -185,7 +194,9 @@ def test_old_block_generated_on_demand(): """Call old blocks generated on demand""" initial_balance = 10 - deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[str(initial_balance)] + ) contract_address = deploy_info["address"] increment_value = 5 @@ -215,7 +226,9 @@ def test_getting_storage_at_old_block(): """Call get_storage_at on old block""" initial_balance = 10 - deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[str(initial_balance)] + ) deployment_block = get_block(block_number="latest", parse=True) contract_address = deploy_info["address"] @@ -233,12 +246,14 @@ def assert_balance_in_storage( block_hash=block_hash, ) - assert_balance_in_storage(expected_value=hex(initial_balance), block_number="1") + # declaration block + assert_balance_in_storage(expected_value=hex(0), block_number="1") + assert_balance_in_storage(expected_value=hex(initial_balance), block_number="2") assert_balance_in_storage( expected_value=hex(initial_balance), block_hash=deployment_block["block_hash"], ) assert_balance_in_storage( expected_value=hex(initial_balance + increment_value), - block_number="2", + block_number="3", ) diff --git a/test/test_chain_id_cli_params.py b/test/test_chain_id_cli_params.py index afa7940af..a00f087b2 100644 --- a/test/test_chain_id_cli_params.py +++ b/test/test_chain_id_cli_params.py @@ -7,7 +7,7 @@ from starknet_devnet.devnet_config import CHAIN_IDS -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .shared import ( ABI_PATH, CONTRACT_PATH, @@ -21,7 +21,6 @@ assert_transaction, assert_tx_status, call, - deploy, read_stream, terminate_and_wait, ) @@ -73,7 +72,9 @@ def test_chain_id_invalid(chain_id): ) def test_deploy_and_invoke(chain_id): """Test deploy and invoke with MAINNET and TESTNET chain_id""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable( + CONTRACT_PATH, inputs=["0"], chain_id=chain_id + ) assert_tx_status(deploy_info["tx_hash"], "ACCEPTED_ON_L2") assert_transaction(deploy_info["tx_hash"], "ACCEPTED_ON_L2") diff --git a/test/test_compiler.py b/test/test_compiler.py index f1bc8e152..32227803b 100644 --- a/test/test_compiler.py +++ b/test/test_compiler.py @@ -32,6 +32,8 @@ ) SPECIFIED_MANIFEST = os.getenv("CAIRO_1_COMPILER_MANIFEST") +if not SPECIFIED_MANIFEST: + raise KeyError("CAIRO_1_COMPILER_MANIFEST env var not set") ACTIVE_DEVNET = DevnetBackgroundProc() @@ -80,9 +82,6 @@ def test_invalid_cairo_compiler_manifest(compiler_manifest: str): def test_valid_cairo_compiler_manifest(): """Test valid cairo compiler manifest specified via CLI""" - - assert SPECIFIED_MANIFEST, "Compiler manifest not set through env var" - execution = ACTIVE_DEVNET.start( "--cairo-compiler-manifest", SPECIFIED_MANIFEST, diff --git a/test/test_deploy.py b/test/test_deploy.py index b2f25763b..55467cdc1 100644 --- a/test/test_deploy.py +++ b/test/test_deploy.py @@ -1,7 +1,5 @@ """Test devnet contract deployment""" -from typing import List - import pytest from starkware.starknet.core.os.contract_address.contract_address import ( calculate_contract_address, @@ -15,10 +13,6 @@ from starkware.starknet.services.api.contract_class.contract_class import ( DeprecatedCompiledClass, ) -from starkware.starknet.services.api.feeder_gateway.response_objects import ( - TransactionStatus, -) -from starkware.starknet.services.api.gateway.transaction import Deploy from starkware.starknet.third_party.open_zeppelin.starknet_contracts import ( account_contract as oz_account_class, ) @@ -28,11 +22,9 @@ ) from starknet_devnet.constants import STARKNET_CLI_ACCOUNT_CLASS_HASH -from starknet_devnet.devnet_config import DevnetConfig, parse_args -from starknet_devnet.starknet_wrapper import StarknetWrapper from starknet_devnet.udc import UDC -from .account import declare, invoke +from .account import declare, declare_and_deploy_with_chargeable from .shared import ( ABI_PATH, CONTRACT_PATH, @@ -51,7 +43,6 @@ assert_hex_equal, assert_tx_status, call, - deploy, devnet_in_background, get_class_hash_at, get_transaction_receipt, @@ -67,18 +58,6 @@ def get_contract_class(): return DeprecatedCompiledClass.loads(contract_class_file.read()) -def get_deploy_transaction(inputs: List[int], salt=0): - """Get a Deploy transaction.""" - contract_class = get_contract_class() - - return Deploy( - contract_address_salt=salt, - contract_definition=contract_class, - constructor_calldata=inputs, - version=SUPPORTED_TX_VERSION, - ) - - @pytest.fixture(name="starknet_wrapper_args") def fixture_starknet_wrapper_args(request): """ @@ -87,48 +66,6 @@ def fixture_starknet_wrapper_args(request): return request.param -@pytest.mark.parametrize( - "starknet_wrapper_args, expected_block_hash", - [ - ( - [*PREDEPLOY_ACCOUNT_CLI_ARGS], - "", - ), - ( - [*PREDEPLOY_ACCOUNT_CLI_ARGS, "--lite-mode"], - "0x1", - ), - ], - indirect=True, -) -@pytest.mark.asyncio -async def test_deploy(starknet_wrapper_args, expected_block_hash): - """ - Test the deployment of a contract. - """ - devnet = StarknetWrapper(config=DevnetConfig(parse_args(starknet_wrapper_args))) - await devnet.initialize() - deploy_transaction = get_deploy_transaction(inputs=[0]) - - contract_address, tx_hash = await devnet.deploy( - deploy_transaction=deploy_transaction, - ) - expected_contract_address = calculate_contract_address( - deployer_address=0, - constructor_calldata=deploy_transaction.constructor_calldata, - salt=deploy_transaction.contract_address_salt, - contract_class=deploy_transaction.contract_definition, - ) - - assert contract_address == expected_contract_address - - tx_status = await devnet.transactions.get_transaction_status(hex(tx_hash)) - assert tx_status["tx_status"] == TransactionStatus.ACCEPTED_ON_L2.name - - if "--lite-mode" in starknet_wrapper_args: - assert tx_status["block_hash"] == expected_block_hash - - def test_predeclared_oz_account(): """Test that precomputed class matches""" assert STARKNET_CLI_ACCOUNT_CLASS_HASH == compute_deprecated_class_hash( @@ -186,7 +123,9 @@ def deploy_account_test_body(): # deploy a contract for testing init_balance = 10 - contract_deploy_info = deploy(contract=CONTRACT_PATH, inputs=[str(init_balance)]) + contract_deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[init_balance] + ) contract_address = contract_deploy_info["address"] # increase balance of test contract @@ -212,9 +151,7 @@ def deploy_account_test_body(): assert balance_after == "40" -def _assert_deployed_through_syscall( - tx_hash: str, address_index: int, initial_balance: str -): +def assert_deployed_through_syscall(tx_hash: str, initial_balance: int): """Asserts that a contract has been deployed using the deploy syscall""" assert_tx_status(tx_hash, "ACCEPTED_ON_L2") @@ -224,6 +161,7 @@ def _assert_deployed_through_syscall( # there can be multiple events, e.g. from fee_token, but the first one is ours event = events[0] + address_index = 0 # position in UDC event contract_address = event["data"][address_index] # Test deployed contract @@ -231,7 +169,7 @@ def _assert_deployed_through_syscall( assert_hex_equal(fetched_class_hash, EXPECTED_CLASS_HASH) balance = call(function="get_balance", address=contract_address, abi_path=ABI_PATH) - assert_equal(balance, initial_balance) + assert_equal(int(balance), initial_balance) @pytest.mark.declare @@ -254,15 +192,14 @@ def test_deploy_through_deployer_constructor(): assert_class_by_hash(class_hash, CONTRACT_PATH) # Deploy the deployer - also deploys a contract of the declared class using the deploy syscall - initial_balance_in_constructor = "5" - deployer_deploy_info = deploy( + initial_balance_in_constructor = 5 + deployer_deploy_info = declare_and_deploy_with_chargeable( contract=DEPLOYER_CONTRACT_PATH, - inputs=[class_hash, initial_balance_in_constructor], + inputs=[int(class_hash, 16), initial_balance_in_constructor], ) - _assert_deployed_through_syscall( + assert_deployed_through_syscall( tx_hash=deployer_deploy_info["tx_hash"], - address_index=0, initial_balance=initial_balance_in_constructor, ) @@ -280,48 +217,28 @@ def test_precomputed_udc_address(): assert_equal(UDC.ADDRESS, int(EXPECTED_UDC_ADDRESS, 16)) -@devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) -def test_deploy_with_udc(): - """Test if deploying through UDC works.""" - deploy_with_udc_test_body() - +@devnet_in_background() +def test_declare_and_deploy_happy_path(): + """Test if deploying through UDC works. Declare beforehand.""" + initial_balance = 10 + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[initial_balance], salt=hex(42) + ) -def deploy_with_udc_test_body(): - """The body of udc deployment test.""" - # Declare the class to be deployed - declare_info = declare( - contract_path=CONTRACT_PATH, - account_address=PREDEPLOYED_ACCOUNT_ADDRESS, - private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, - max_fee=int(4e16), + assert_deployed_through_syscall( + tx_hash=deploy_info["tx_hash"], + initial_balance=initial_balance, ) - class_hash = declare_info["class_hash"] - assert_hex_equal(class_hash, EXPECTED_CLASS_HASH) - assert_class_by_hash(class_hash, CONTRACT_PATH) - # Deploy a contract of the declared class through the deployer - initial_balance = "10" - ctor_args = [initial_balance] - invoke_tx_hash = invoke( - calls=[ - ( - EXPECTED_UDC_ADDRESS, - "deployContract", - [ - int(class_hash, 16), - 42, # salt - 0, # unique - len(ctor_args), - *ctor_args, - ], - ) - ], - account_address=PREDEPLOYED_ACCOUNT_ADDRESS, - private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, - ) - _assert_deployed_through_syscall( - tx_hash=invoke_tx_hash, - address_index=0, - initial_balance=initial_balance, +@devnet_in_background() +def test_declare_and_deploy_with_invalid_constructor_args(): + """Pass invalid constructor args. Expect failure.""" + invalid_constructor_args = [] # empty when it shouldn't be + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, + inputs=invalid_constructor_args, + max_fee=int(1e18), # prevent estimateFee - fails due to invalid args ) + + assert_tx_status(deploy_info["tx_hash"], "REJECTED") diff --git a/test/test_dump.py b/test/test_dump.py index 209768462..ca86c3356 100644 --- a/test/test_dump.py +++ b/test/test_dump.py @@ -10,7 +10,7 @@ import pytest import requests -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( ABI_PATH, @@ -21,13 +21,7 @@ ) from .test_account import get_account_balance from .test_fee_token import mint -from .util import ( - DevnetBackgroundProc, - call, - deploy, - devnet_in_background, - terminate_and_wait, -) +from .util import DevnetBackgroundProc, call, devnet_in_background, terminate_and_wait DUMP_PATH = "dump.pkl" @@ -100,12 +94,12 @@ def assert_not_alive(): pass -def deploy_empty_contract(): +def declare_and_deploy_empty_contract(): """ Deploy sample contract with balance = 0. Returns contract address. """ - deploy_dict = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_dict = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) contract_address = deploy_dict["address"] initial_balance = call("get_balance", contract_address, ABI_PATH) assert initial_balance == "0" @@ -202,7 +196,7 @@ def test_loading_via_cli(): """Test dumping via endpoint and loading via CLI.""" # init devnet + contract ACTIVE_DEVNET.start(*PREDEPLOY_ACCOUNT_CLI_ARGS) - contract_address = deploy_empty_contract() + contract_address = declare_and_deploy_empty_contract() invoke( calls=[(contract_address, "increase_balance", [10, 20])], @@ -243,7 +237,7 @@ def test_dumping_and_loading_via_endpoint(): """Test dumping and loading via endpoint.""" # init devnet + contract ACTIVE_DEVNET.start(*PREDEPLOY_ACCOUNT_CLI_ARGS) - contract_address = deploy_empty_contract() + contract_address = declare_and_deploy_empty_contract() invoke( calls=[(contract_address, "increase_balance", ["10", "20"])], @@ -287,7 +281,7 @@ def test_dumping_on_exit(): *PREDEPLOY_ACCOUNT_CLI_ARGS, "--dump-on", "exit", "--dump-path", DUMP_PATH ) - contract_address = deploy_empty_contract() + contract_address = declare_and_deploy_empty_contract() invoke( calls=[(contract_address, "increase_balance", ["10", "20"])], @@ -360,7 +354,7 @@ def test_dumping_on_each_tx(): ) # deploy - contract_address = deploy_empty_contract() + contract_address = declare_and_deploy_empty_contract() assert_dump_present(DUMP_PATH) dump_after_deploy_path = "dump_after_deploy.pkl" os.rename(DUMP_PATH, dump_after_deploy_path) @@ -413,7 +407,7 @@ def call_at_block(block_number: str): ) # deploy - contract_address = deploy_empty_contract() + contract_address = declare_and_deploy_empty_contract() increment_value = 10 invoke( calls=[(contract_address, "increase_balance", [increment_value, 0])], @@ -425,8 +419,9 @@ def call_at_block(block_number: str): assert_dump_present(DUMP_PATH) ACTIVE_DEVNET.start("--load-path", DUMP_PATH) - value_after_deploy = call_at_block("1") + # expected_block = genesis (0) + declare + deploy + value_after_deploy = call_at_block("2") assert value_after_deploy == 0 - value_after_invoke = call_at_block("2") + value_after_invoke = call_at_block("3") assert value_after_invoke == increment_value diff --git a/test/test_endpoints.py b/test/test_endpoints.py index 4306e7a37..a31bb037d 100644 --- a/test/test_endpoints.py +++ b/test/test_endpoints.py @@ -12,6 +12,7 @@ from starknet_devnet.constants import DEFAULT_GAS_PRICE from starknet_devnet.server import app +from .account import declare_and_deploy_with_chargeable from .settings import APP_URL from .shared import ( FAILING_CONTRACT_PATH, @@ -20,9 +21,8 @@ STORAGE_CONTRACT_PATH, ) from .support.assertions import assert_valid_schema -from .util import create_empty_block, deploy, devnet_in_background, load_file_content +from .util import create_empty_block, devnet_in_background, load_file_content -DEPLOY_CONTENT = load_file_content("deploy.json") INVOKE_CONTENT = load_file_content("invoke.json") CALL_CONTENT = load_file_content("call.json") INVALID_HASH = "0x58d4d4ed7580a7a98ab608883ec9fe722424ce52c19f2f369eeea301f535914" @@ -50,13 +50,6 @@ def send_call(req_dict: dict): ) -def assert_deploy_resp(resp: bytes): - """Asserts the validity of deploy response body.""" - resp_dict = json.loads(resp.data.decode("utf-8")) - assert set(resp_dict.keys()) == set(["address", "code", "transaction_hash"]) - assert resp_dict["code"] == "TRANSACTION_RECEIVED" - - def assert_invoke_resp(resp: bytes): """Asserts the validity of invoke response body.""" resp_dict = json.loads(resp.data.decode("utf-8")) @@ -65,21 +58,18 @@ def assert_invoke_resp(resp: bytes): @pytest.mark.deploy -def test_deploy_without_calldata(): - """Deploy with complete request data""" - req_dict = json.loads(DEPLOY_CONTENT) - del req_dict["constructor_calldata"] - resp = send_transaction(req_dict) - assert resp.status_code == 400 - - -@pytest.mark.deploy -def test_deploy_with_complete_request_data(): - """Deploy without calldata""" +def test_rejection_of_deprecated_deploy(): + """Deprecated deploy should be rejected""" resp = app.test_client().post( - "/gateway/add_transaction", content_type="application/json", data=DEPLOY_CONTENT + "/gateway/add_transaction", + content_type="application/json", + data=load_file_content("deprecated_deploy.json"), ) - assert_deploy_resp(resp) + assert resp.status_code == 500, resp.json + assert resp.json == { + "code": str(StarknetErrorCode.DEPRECATED_TRANSACTION), + "message": "Deploy transaction is no longer supported.", + } @pytest.mark.invoke @@ -100,14 +90,6 @@ def test_invoke_without_calldata(): assert resp.status_code == 400 -@pytest.mark.invoke -def test_invoke_with_complete_request_data(): - """Invoke with complete request data""" - req_dict = json.loads(INVOKE_CONTENT) - resp = send_transaction(req_dict) - assert_invoke_resp(resp) - - @pytest.mark.call def test_call_with_invalid_signature(): """Call without signature""" @@ -126,15 +108,6 @@ def test_call_without_calldata(): assert resp.status_code == 400 -@pytest.mark.call -def test_call_with_complete_request_data(): - """Call with complete request data. Previous tests (deploy+invoke) required to pass.""" - req_dict = json.loads(CALL_CONTENT) - resp = send_call(req_dict) - resp_dict = json.loads(resp.data.decode("utf-8")) - assert resp_dict == {"result": ["0xa"]} - - # Error response tests def send_transaction_with_requests(req_dict: dict): """Sends the dict in a POST request and returns the response data.""" @@ -235,18 +208,6 @@ def get_transaction_receipt_test_client(tx_hash: str): ) -@pytest.mark.deploy -@devnet_in_background() -def test_error_response_deploy_without_calldata(): - """Deploy with incomplete request data""" - req_dict = json.loads(DEPLOY_CONTENT) - del req_dict["constructor_calldata"] - resp = send_transaction_with_requests(req_dict) - - json_error_message = resp.json()["message"] - assert "Invalid tx:" in json_error_message - - @pytest.mark.call @devnet_in_background() def test_error_response_call_without_calldata(): @@ -360,14 +321,14 @@ def test_create_block_endpoint(): assert resp.get("gas_price") == hex(DEFAULT_GAS_PRICE) assert resp.get("transactions") == [] - deploy(STORAGE_CONTRACT_PATH) + declare_and_deploy_with_chargeable(STORAGE_CONTRACT_PATH) resp = get_block_by_number({"blockNumber": "latest"}).json() - assert resp.get("block_number") == GENESIS_BLOCK_NUMBER + 2 + assert resp.get("block_number") == GENESIS_BLOCK_NUMBER + 3 create_empty_block() resp = get_block_by_number({"blockNumber": "latest"}).json() - assert resp.get("block_number") == GENESIS_BLOCK_NUMBER + 3 - assert resp.get("block_hash") == hex(GENESIS_BLOCK_NUMBER + 3) + assert resp.get("block_number") == GENESIS_BLOCK_NUMBER + 4 + assert resp.get("block_hash") == hex(GENESIS_BLOCK_NUMBER + 4) @devnet_in_background() @@ -397,7 +358,9 @@ def test_get_transaction_status(): @devnet_in_background() def test_get_transaction_trace_of_rejected(): """Send a failing tx and assert its trace""" - deploy_info = deploy(contract=FAILING_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable( + contract=FAILING_CONTRACT_PATH, max_fee=int(1e18) + ) resp = get_transaction_trace(deploy_info["tx_hash"]) resp_body = resp.json() assert resp_body["code"] == str(StarknetErrorCode.NO_TRACE) diff --git a/test/test_estimate_fee.py b/test/test_estimate_fee.py index 4ae15bfc5..fcdb6fc73 100644 --- a/test/test_estimate_fee.py +++ b/test/test_estimate_fee.py @@ -14,7 +14,11 @@ from starknet_devnet.constants import DEFAULT_GAS_PRICE -from .account import get_estimate_fee_request_dict, get_nonce +from .account import ( + declare_and_deploy_with_chargeable, + get_estimate_fee_request_dict, + get_nonce, +) from .settings import APP_URL from .shared import ( ABI_PATH, @@ -26,15 +30,9 @@ PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) -from .util import ( - call, - deploy, - devnet_in_background, - estimate_message_fee, - load_file_content, -) +from .util import call, devnet_in_background, estimate_message_fee, load_file_content -DEPLOY_CONTENT = load_file_content("deploy.json") +DEPRECATED_DEPLOY_CONTENT = load_file_content("deprecated_deploy.json") INVOKE_CONTENT = load_file_content("invoke.json") @@ -74,7 +72,7 @@ def common_estimate_response( def test_estimate_fee_with_genesis_block(): """Call without transaction, expect pass with gas_price zero""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) # increase balance with 10+20 response = send_estimate_fee_with_requests( { @@ -106,7 +104,7 @@ def test_estimate_fee_in_unknown_address(): @devnet_in_background() def test_estimate_fee_with_invalid_data(): """Call estimate fee with invalid data on body""" - req_dict = json.loads(DEPLOY_CONTENT) + req_dict = json.loads(DEPRECATED_DEPLOY_CONTENT) resp = estimate_fee_local(req_dict) json_error_message = resp.json()["message"] @@ -126,7 +124,7 @@ def test_estimate_fee_with_invalid_data(): def test_estimate_fee_with_complete_request_data(request_kwargs): """Estimate fee with complete request data""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) # increase balance with 10+20 response = send_estimate_fee_with_requests( { @@ -148,7 +146,7 @@ def test_estimate_fee_with_complete_request_data(request_kwargs): def test_simulate_transaction(): """Simulate tx""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) calldata = ["10", "20"] entry_point_selector = hex(get_selector_from_name("increase_balance")) @@ -199,7 +197,9 @@ def test_estimate_message_fee(): dummy_l1_address = "0x1" user_id = "1" - l2_contract_address = deploy(contract=L1L2_CONTRACT_PATH)["address"] + l2_contract_address = declare_and_deploy_with_chargeable( + contract=L1L2_CONTRACT_PATH + )["address"] message_fee = estimate_message_fee( from_address=dummy_l1_address, @@ -259,7 +259,9 @@ def test_estimate_fee_bulk(): # contract must be deployed for fee estimation to be possible initial_balance = "10" - deploy_info = deploy(contract=CONTRACT_PATH, inputs=[initial_balance], salt="0x42") + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[initial_balance], salt="0x42" + ) contract_address = deploy_info["address"] tx_dicts = [ diff --git a/test/test_fork.py b/test/test_fork.py index 711b74907..1ba56db7f 100644 --- a/test/test_fork.py +++ b/test/test_fork.py @@ -8,7 +8,7 @@ from starknet_devnet.constants import DEFAULT_INITIAL_BALANCE -from .account import get_nonce, invoke +from .account import declare_and_deploy_with_chargeable, get_nonce, invoke from .settings import APP_URL, HOST, bind_free_port from .shared import ( ABI_PATH, @@ -20,7 +20,7 @@ PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) from .test_account import get_account_balance -from .test_deploy import deploy_account_test_body, deploy_with_udc_test_body +from .test_deploy import assert_deployed_through_syscall, deploy_account_test_body from .testnet_deployment import ( TESTNET_CONTRACT_ADDRESS, TESTNET_DEPLOYMENT_BLOCK, @@ -32,7 +32,6 @@ assert_address_has_no_class_hash, assert_tx_status, call, - deploy, devnet_in_background, mint, ) @@ -59,7 +58,6 @@ def _invoke_on_fork_and_assert_only_fork_changed( fork_url: str, origin_url: str, ): - # account nonce - before origin_nonce_before = get_nonce( account_address=PREDEPLOYED_ACCOUNT_ADDRESS, feeder_gateway_url=origin_url @@ -117,7 +115,7 @@ def test_forking_devnet_with_account_on_origin(): # deploy on origin initial_balance = "10" - deploy_info = deploy( + deploy_info = declare_and_deploy_with_chargeable( contract=CONTRACT_PATH, inputs=[initial_balance], gateway_url=ORIGIN_URL, @@ -167,9 +165,9 @@ def test_forking_devnet_with_account_on_fork(): Assert only fork changed """ - # deploy on origin + # declare_and_deploy_with_chargeable on origin initial_balance = "10" - deploy_info = deploy( + deploy_info = declare_and_deploy_with_chargeable( contract=CONTRACT_PATH, inputs=[initial_balance], gateway_url=ORIGIN_URL, @@ -251,7 +249,9 @@ def test_deploy_on_fork(origin_url): Assert usability on fork. Assert no change on origin. """ - deploy_info = deploy(contract=CONTRACT_PATH, inputs=["10"]) + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=["10"] + ) contract_address = deploy_info["address"] invoke_tx_hash = invoke( @@ -313,9 +313,17 @@ def test_deploy_account(): @devnet_in_background(*TESTNET_FORK_PARAMS) -def test_deploy_with_udc(): +def test_declare_and_deploy_happy_path(): """Test that deploying with udc works when forking""" - deploy_with_udc_test_body() + initial_balance = 10 + deploy_info = declare_and_deploy_with_chargeable( + contract=CONTRACT_PATH, inputs=[initial_balance], salt=hex(42) + ) + + assert_deployed_through_syscall( + tx_hash=deploy_info["tx_hash"], + initial_balance=initial_balance, + ) @devnet_in_background(*TESTNET_FORK_PARAMS) diff --git a/test/test_fork_feeder_gateway.py b/test/test_fork_feeder_gateway.py index 235305df6..b78d806ea 100644 --- a/test/test_fork_feeder_gateway.py +++ b/test/test_fork_feeder_gateway.py @@ -8,7 +8,7 @@ BlockIdentifier, ) -from .account import declare, invoke +from .account import declare, declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( BALANCE_KEY, @@ -46,7 +46,6 @@ assert_transaction_not_received, assert_transaction_receipt_not_received, assert_tx_status, - deploy, devnet_in_background, get_block, get_full_contract, @@ -62,7 +61,7 @@ def _deploy_to_expected_address(contract=CONTRACT_PATH): - deploy_info = deploy( + deploy_info = declare_and_deploy_with_chargeable( contract=contract, inputs=[DEPLOYMENT_INPUT], salt="0x42", diff --git a/test/test_general_workflow.py b/test/test_general_workflow.py index c6fa0ea44..d14a8c71f 100644 --- a/test/test_general_workflow.py +++ b/test/test_general_workflow.py @@ -4,14 +4,12 @@ import pytest -from .account import invoke +from .account import declare_and_deploy_with_chargeable, deploy_with_chargeable, invoke from .shared import ( ABI_PATH, BALANCE_KEY, CONTRACT_PATH, EVENTS_CONTRACT_PATH, - EXPECTED_SALTY_DEPLOY_ADDRESS, - EXPECTED_SALTY_DEPLOY_HASH, FAILING_CONTRACT_PATH, GENESIS_BLOCK_NUMBER, NONEXISTENT_TX_HASH, @@ -24,50 +22,44 @@ assert_class_by_hash, assert_contract_code_present, assert_equal, - assert_events, assert_full_contract, + assert_hex_equal, assert_negative_block_input, assert_receipt, - assert_salty_deploy, assert_storage, assert_transaction, assert_transaction_not_received, assert_transaction_receipt_not_received, assert_tx_status, call, - deploy, + devnet_in_background, get_block, get_class_hash_at, ) -EXPECTED_SALTY_DEPLOY_BLOCK_HASH_LITE_MODE = "0x1" - -def _assert_failing_deploy(contract_path): - """Run deployment for a contract that's expected to be rejected.""" - deploy_info = deploy(contract_path) - assert_tx_status(deploy_info["tx_hash"], "REJECTED") - assert_transaction(deploy_info["tx_hash"], "REJECTED") +@devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS, "--lite-mode") +def test_lite_mode_block_hash(): + """Test lite mode""" + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) + assert_tx_status(deploy_info["tx_hash"], "ACCEPTED_ON_L2") + expected_block_hash = "0x2" # after declare and deploy + assert_equal(expected_block_hash, get_block(parse=True)["block_hash"]) @pytest.mark.usefixtures("run_devnet_in_background") @pytest.mark.parametrize( - "run_devnet_in_background, expected_block_hash", + "run_devnet_in_background", [ - ( - [*PREDEPLOY_ACCOUNT_CLI_ARGS], - "", - ), - ( - [*PREDEPLOY_ACCOUNT_CLI_ARGS, "--lite-mode"], - EXPECTED_SALTY_DEPLOY_BLOCK_HASH_LITE_MODE, - ), + PREDEPLOY_ACCOUNT_CLI_ARGS, + [*PREDEPLOY_ACCOUNT_CLI_ARGS, "--lite-mode"], ], indirect=True, ) -def test_general_workflow(expected_block_hash): - """Test devnet with CLI""" - deploy_info = deploy(CONTRACT_PATH, inputs=["0"]) +@devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS, "--lite-mode") +def test_general_workflow(): + """Test main feeder gateway calls""" + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"]) assert_tx_status(deploy_info["tx_hash"], "ACCEPTED_ON_L2") assert_transaction(deploy_info["tx_hash"], "ACCEPTED_ON_L2") @@ -79,12 +71,7 @@ def test_general_workflow(expected_block_hash): # check block and receipt after deployment assert_negative_block_input() - # check if in lite mode expected block hash is 0x1 - if expected_block_hash == EXPECTED_SALTY_DEPLOY_BLOCK_HASH_LITE_MODE: - assert_equal(expected_block_hash, get_block(parse=True)["block_hash"]) - - assert_block(GENESIS_BLOCK_NUMBER + 1, deploy_info["tx_hash"]) - assert_receipt(deploy_info["tx_hash"], "test/expected/deploy_receipt.json") + assert_block(GENESIS_BLOCK_NUMBER + 2, deploy_info["tx_hash"]) # declare+deploy assert_transaction_receipt_not_received(NONEXISTENT_TX_HASH) # check code @@ -104,6 +91,7 @@ def test_general_workflow(expected_block_hash): private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) assert_transaction(invoke_tx_hash, "ACCEPTED_ON_L2") + assert_receipt(invoke_tx_hash, "ACCEPTED_ON_L2") value = call( function="get_balance", address=deploy_info["address"], abi_path=ABI_PATH ) @@ -111,35 +99,45 @@ def test_general_workflow(expected_block_hash): # check storage, block and receipt after increase assert_storage(deploy_info["address"], BALANCE_KEY, "0x1e") - assert_block(GENESIS_BLOCK_NUMBER + 2, invoke_tx_hash) - assert_receipt(invoke_tx_hash, "test/expected/invoke_receipt.json") + assert_block(GENESIS_BLOCK_NUMBER + 3, invoke_tx_hash) - # check handling complex input - value = call( - function="sum_point_array", - address=deploy_info["address"], - abi_path=ABI_PATH, - inputs=["2", "10", "20", "30", "40"], + +@devnet_in_background() +def test_salty_deploy(): + """Test deploying with salt""" + + expected_address = ( + "0x6c9b52d3297d731eaea82dbfa4d20424855d498b8594b9442a1d4d5d995a5bd" ) - assert_equal(value, "40 60", "Checking complex input failed!") - - # check deploy when a salt is provided, and use the same contract to test events - for _ in range(2): - assert_salty_deploy( - contract_path=EVENTS_CONTRACT_PATH, - salt="0x99", - inputs=None, - expected_status="ACCEPTED_ON_L2", - expected_address=EXPECTED_SALTY_DEPLOY_ADDRESS, - expected_tx_hash=EXPECTED_SALTY_DEPLOY_HASH, - ) - - salty_invoke_tx_hash = invoke( - calls=[(EXPECTED_SALTY_DEPLOY_ADDRESS, "increase_balance", [10])], - account_address=PREDEPLOYED_ACCOUNT_ADDRESS, - private_key=PREDEPLOYED_ACCOUNT_PRIVATE_KEY, + contract_path = EVENTS_CONTRACT_PATH + inputs = None + salt = "0x99" + + # first deploy (and declare before it) + deploy_info = declare_and_deploy_with_chargeable( + contract_path, inputs=inputs, salt=salt, max_fee=int(1e18) + ) + assert_hex_equal(actual=deploy_info["address"], expected=expected_address) + assert_tx_status(deploy_info["tx_hash"], "ACCEPTED_ON_L2") + + # attempt another deploy - should be rejected since address occupied + repeated_deploy_info = deploy_with_chargeable( + class_hash=deploy_info["class_hash"], + inputs=inputs, + salt=salt, + # different max_fee to induce a different tx_hash + max_fee=int(1e18) + 1, ) + assert_hex_equal(actual=repeated_deploy_info["address"], expected=expected_address) + assert_tx_status(repeated_deploy_info["tx_hash"], "REJECTED") - assert_events(salty_invoke_tx_hash, "test/expected/invoke_receipt_event.json") - _assert_failing_deploy(contract_path=FAILING_CONTRACT_PATH) +@devnet_in_background() +def test_failing_deploy(): + """Test a failing deployment""" + deploy_info = declare_and_deploy_with_chargeable( + FAILING_CONTRACT_PATH, + max_fee=int(1e18), # if not provided, will fail on implicit estimation + ) + assert_tx_status(deploy_info["tx_hash"], "REJECTED") + assert_transaction(deploy_info["tx_hash"], "REJECTED") diff --git a/test/test_l1_l2_mock_messaging.py b/test/test_l1_l2_mock_messaging.py index bd24dc187..67882ab5d 100644 --- a/test/test_l1_l2_mock_messaging.py +++ b/test/test_l1_l2_mock_messaging.py @@ -13,7 +13,7 @@ from starknet_devnet.server import app -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( L1L2_ABI_PATH, @@ -22,19 +22,8 @@ PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) -from .util import ( - assert_tx_status, - call, - deploy, - devnet_in_background, - load_file_content, -) +from .util import assert_tx_status, call, devnet_in_background -DEPLOY_CONTENT = load_file_content("deploy.json") -INVOKE_CONTENT = load_file_content("invoke.json") -CALL_CONTENT = load_file_content("call.json") -INVALID_HASH = "0x58d4d4ed7580a7a98ab608883ec9fe722424ce52c19f2f369eeea301f535914" -INVALID_ADDRESS = "0x123" USER_ID = 1 L1_CONTRACT_ADDRESS = "0xE7F1725E7734CE288F8367E1BB143E90BB3F0512" L2_CONTRACT_ADDRESS = ( @@ -81,7 +70,7 @@ def _post_through_test_client(url: str, data: dict) -> TestResponse: def test_send_message_to_l2_deploy_execute(): """Test POST l1 to l2 deploy contract and execute transaction""" # Deploy L1L2 contract - deploy_info = deploy(contract=L1L2_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(contract=L1L2_CONTRACT_PATH) # Create l1 to l2 mock transaction response = send_message_to_l2( @@ -157,7 +146,7 @@ def test_send_message_to_l2_execute_without_deploy(): @devnet_in_background() def test_send_message_to_l2_with_zero_message_fee(): """Should fail if message fee is zero""" - deploy_info = deploy(L1L2_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(L1L2_CONTRACT_PATH) data = _VALID_MESSAGE_TO_L2_BODY.copy() data["l2_contract_address"] = deploy_info["address"] @@ -171,7 +160,7 @@ def test_send_message_to_l2_with_zero_message_fee(): @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) def test_consume_message_from_l2_deploy_execute(): """Test POST l2 to l1 deploy contract and execute transaction""" - deploy_info = deploy(L1L2_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(L1L2_CONTRACT_PATH) # increase and withdraw balance invoke( @@ -205,7 +194,7 @@ def test_consume_message_from_l2_deploy_execute(): @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) def test_consume_message_from_l2_deploy_execute_without_withdraw(): """Test POST l2 to l1 deploy contract and try to execute transaction without calling withdraw""" - deploy_info = deploy(L1L2_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(L1L2_CONTRACT_PATH) response = consume_message_from_l2( { "l2_contract_address": deploy_info["address"], diff --git a/test/test_max_fee_0.py b/test/test_max_fee_0.py index 3b55102de..307b09f74 100644 --- a/test/test_max_fee_0.py +++ b/test/test_max_fee_0.py @@ -4,7 +4,7 @@ from starkware.starknet.definitions.error_codes import StarknetErrorCode -from .account import declare, invoke +from .account import declare, declare_and_deploy_with_chargeable, invoke from .shared import ( CONTRACT_PATH, PREDEPLOY_ACCOUNT_CLI_ARGS, @@ -15,7 +15,6 @@ ErrorExpector, assert_class_by_hash, assert_tx_status, - deploy, devnet_in_background, ) @@ -24,7 +23,9 @@ def test_invoke_with_max_fee_0(): """Test that invoke transaction with max fee 0 will fail""" initial_balance = 100 - deploy_info = deploy(CONTRACT_PATH, [str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + CONTRACT_PATH, [str(initial_balance)] + ) account_address = PREDEPLOYED_ACCOUNT_ADDRESS private_key = PREDEPLOYED_ACCOUNT_PRIVATE_KEY calls = [(deploy_info["address"], "increase_balance", [10, 20])] @@ -36,7 +37,9 @@ def test_invoke_with_max_fee_0(): def test_invoke_with_max_fee_0_and_allow_max_fee_zero(): """Test that invoke transaction with max fee 0 will succeed if allow flag is set""" initial_balance = 100 - deploy_info = deploy(CONTRACT_PATH, [str(initial_balance)]) + deploy_info = declare_and_deploy_with_chargeable( + CONTRACT_PATH, [str(initial_balance)] + ) account_address = PREDEPLOYED_ACCOUNT_ADDRESS private_key = PREDEPLOYED_ACCOUNT_PRIVATE_KEY calls = [(deploy_info["address"], "increase_balance", [10, 20])] diff --git a/test/test_postman.py b/test/test_postman.py index 44c02115d..f4eaf3128 100644 --- a/test/test_postman.py +++ b/test/test_postman.py @@ -10,7 +10,7 @@ import requests from web3 import Web3 -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .settings import APP_URL, L1_HOST, L1_PORT, L1_URL from .shared import ( L1L2_ABI_PATH, @@ -20,9 +20,9 @@ PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) from .util import ( + assert_hex_equal, assert_tx_status, call, - deploy, devnet_in_background, ensure_server_alive, estimate_message_fee, @@ -82,13 +82,12 @@ def assert_flush_response( assert response["l1_provider"] == expected_l1_provider for i, l1_message in enumerate(response["consumed_messages"]["from_l1"]): - assert ( - l1_message["args"]["from_address"] - == expected_from_l1[i]["args"]["from_address"] + assert_hex_equal( + l1_message["args"]["from_address"], + expected_from_l1[i]["args"]["from_address"], ) - assert ( - l1_message["args"]["to_address"] - == expected_from_l1[i]["args"]["to_address"] + assert_hex_equal( + l1_message["args"]["to_address"], expected_from_l1[i]["args"]["to_address"] ) assert l1_message["args"]["payload"] == [ hex(x) for x in expected_from_l1[i]["args"]["payload"] @@ -114,8 +113,10 @@ def assert_flush_response( assert key in l1_message["args"] for i, l2_message in enumerate(response["consumed_messages"]["from_l2"]): - assert l2_message["from_address"] == expected_from_l2[i]["from_address"].lower() - assert l2_message["to_address"] == expected_from_l2[i]["to_address"].lower() + assert_hex_equal( + l2_message["from_address"], expected_from_l2[i]["from_address"] + ) + assert_hex_equal(l2_message["to_address"], expected_from_l2[i]["to_address"]) assert l2_message["payload"] == [hex(x) for x in expected_from_l2[i]["payload"]] assert ( @@ -172,7 +173,7 @@ def load_messaging_contract(starknet_messaging_contract_address): def _init_l2_contract(l1l2_example_contract_address: str): """Deploys the L1L2Example cairo contract, returns the result of calling 'get_balance'""" - deploy_info = deploy(L1L2_CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(L1L2_CONTRACT_PATH) l2_address = deploy_info["address"] # increase and withdraw balance diff --git a/test/test_restart.py b/test/test_restart.py index 504255d1f..fc5afd6fb 100644 --- a/test/test_restart.py +++ b/test/test_restart.py @@ -5,7 +5,7 @@ import pytest import requests -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( ABI_PATH, @@ -19,7 +19,6 @@ assert_transaction_not_received, assert_tx_status, call, - deploy, devnet_in_background, get_block, ) @@ -38,7 +37,7 @@ def get_state_update(): def deploy_contract(salt=None): """Deploy empty contract with balance of 0""" - return deploy(CONTRACT_PATH, inputs=["0"], salt=salt) + return declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"], salt=salt) @pytest.mark.restart diff --git a/test/test_state_update.py b/test/test_state_update.py index f355757df..d6ce513ce 100644 --- a/test/test_state_update.py +++ b/test/test_state_update.py @@ -11,7 +11,7 @@ ) from starkware.starknet.public.abi import get_selector_from_name -from .account import declare, invoke +from .account import declare, declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( CONTRACT_PATH, @@ -29,10 +29,10 @@ assert_equal, assert_hex_equal, assert_transaction, - deploy, devnet_in_background, get_block, load_contract_class, + mint, ) STORAGE_KEY = hex(get_selector_from_name("storage")) @@ -60,7 +60,7 @@ def deploy_empty_contract(): Deploy storage contract Returns contract address. """ - deploy_dict = deploy(STORAGE_CONTRACT_PATH) + deploy_dict = declare_and_deploy_with_chargeable(STORAGE_CONTRACT_PATH) contract_address = deploy_dict["address"] return contract_address @@ -130,7 +130,11 @@ def test_storage_diff(): @devnet_in_background() def test_block_hash(): """Test block hash in the state update""" - deploy_empty_contract() + dummy_address = "0x1" + dummy_amount = 1 + + # generate first block + mint(address=dummy_address, amount=dummy_amount, lite=False) initial_state_update = get_state_update() first_block = get_block(parse=True) @@ -138,8 +142,8 @@ def test_block_hash(): assert_equal(first_block_hash, initial_state_update["block_hash"]) - # creates new block - deploy_empty_contract() + # generate second block + mint(address=dummy_address, amount=dummy_amount, lite=False) new_state_update = get_state_update() previous_state_update = get_state_update(first_block_hash) @@ -161,11 +165,15 @@ def test_wrong_block_hash(): @devnet_in_background() def test_block_number(): """Test block hash in the state update""" - deploy_empty_contract() + dummy_address = "0x1" + dummy_amount = 1 + + # generate first block + mint(address=dummy_address, amount=dummy_amount, lite=False) initial_state_update = get_state_update() - # creates new block - deploy_empty_contract() + # generate second block + mint(address=dummy_address, amount=dummy_amount, lite=False) new_state_update = get_state_update() first_block_state_update = get_state_update(block_number=GENESIS_BLOCK_NUMBER + 1) @@ -188,7 +196,12 @@ def test_wrong_block_number(): @devnet_in_background() def test_roots(): """Test new root and old root in the state update""" - deploy_empty_contract() + dummy_address = "0x1" + dummy_amount = 1 + + # generate first block + mint(address=dummy_address, amount=dummy_amount, lite=False) + state_update = get_state_update() new_root = state_update["new_root"] @@ -196,8 +209,8 @@ def test_roots(): assert re.match(r"^[a-fA-F0-9]{64}$", new_root) assert state_update["old_root"] is not None - # creates new block - deploy_empty_contract() + # generate second block + mint(address=dummy_address, amount=dummy_amount, lite=False) state_update = get_state_update() old_root = state_update["old_root"] @@ -223,10 +236,10 @@ def test_declaration_and_deployment(): assert diff_after_declare["declared_classes"] == [] # Deploy the deployer - also deploys a contract of the declared class using the deploy syscall - initial_balance_in_constructor = "5" - deployer_deploy_info = deploy( + initial_balance_in_constructor = 5 + deployer_deploy_info = declare_and_deploy_with_chargeable( contract=DEPLOYER_CONTRACT_PATH, - inputs=[contract_class_hash, initial_balance_in_constructor], + inputs=[int(contract_class_hash, 16), initial_balance_in_constructor], ) deployer_class_hash = hex(get_class_hash_at_path(DEPLOYER_CONTRACT_PATH)) deployer_address = deployer_deploy_info["address"] @@ -240,5 +253,6 @@ def test_declaration_and_deployment(): assert_hex_equal(deployed_contract_diff["class_hash"], contract_class_hash) # deployed_contract_diff["address"] is a random value - # deployer expected to be declared - assert diff_after_deploy["old_declared_contracts"] == [deployer_class_hash] + # no declarations in the last block + assert diff_after_deploy["old_declared_contracts"] == [] + assert diff_after_deploy["declared_classes"] == [] diff --git a/test/test_timestamps.py b/test/test_timestamps.py index d83691032..43033514b 100644 --- a/test/test_timestamps.py +++ b/test/test_timestamps.py @@ -9,8 +9,9 @@ from starknet_devnet.block_info_generator import BlockInfo, BlockInfoGenerator from starknet_devnet.general_config import DEFAULT_GENERAL_CONFIG +from .account import declare_and_deploy_with_chargeable from .shared import ARTIFACTS_PATH -from .util import call, deploy, devnet_in_background, get_block, increase_time, set_time +from .util import call, devnet_in_background, get_block, increase_time, set_time TS_CONTRACT_PATH = f"{ARTIFACTS_PATH}/timestamp.cairo/timestamp.json" TS_ABI_PATH = f"{ARTIFACTS_PATH}/timestamp.cairo/timestamp_abi.json" @@ -20,7 +21,7 @@ def deploy_ts_contract(): """Deploys the timestamp contract""" - return deploy(TS_CONTRACT_PATH) + return declare_and_deploy_with_chargeable(TS_CONTRACT_PATH) def get_ts_from_contract(address): diff --git a/test/test_transaction_trace.py b/test/test_transaction_trace.py index bbf55fef5..47c02940d 100644 --- a/test/test_transaction_trace.py +++ b/test/test_transaction_trace.py @@ -4,26 +4,29 @@ import pytest import requests +from starkware.starknet.business_logic.execution.objects import CallType +from starkware.starknet.public.abi import get_selector_from_name +from starkware.starknet.services.api.contract_class.contract_class import EntryPointType from starkware.starknet.services.api.feeder_gateway.response_objects import ( BlockTransactionTraces, + TransactionTrace, ) -from .account import declare, invoke +from starknet_devnet.chargeable_account import ChargeableAccount + +from .account import declare, declare_and_deploy_with_chargeable, invoke from .settings import APP_URL from .shared import ( CONTRACT_PATH, + EXPECTED_FEE_TOKEN_ADDRESS, + EXPECTED_UDC_ADDRESS, GENESIS_BLOCK_NUMBER, NONEXISTENT_TX_HASH, PREDEPLOY_ACCOUNT_CLI_ARGS, PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) -from .util import ( - deploy, - devnet_in_background, - get_transaction_receipt, - load_json_from_path, -) +from .util import devnet_in_background, get_transaction_receipt, load_json_from_path def get_transaction_trace_response(tx_hash=None, server_url=APP_URL): @@ -44,7 +47,7 @@ def deploy_empty_contract(): Deploy sample contract with balance = 0. Returns transaction hash. """ - return deploy(CONTRACT_PATH, inputs=["0"], salt="0x99") + return declare_and_deploy_with_chargeable(CONTRACT_PATH, inputs=["0"], salt="0x99") def assert_function_invocation(function_invocation, expected_path): @@ -57,17 +60,46 @@ def assert_function_invocation(function_invocation, expected_path): @devnet_in_background() def test_deploy_transaction_trace(): """Test deploy transaction trace""" - tx_hash = deploy_empty_contract()["tx_hash"] - res = get_transaction_trace_response(tx_hash) - - assert res.status_code == 200 - - transaction_trace = res.json() - assert transaction_trace["signature"] == [] - assert_function_invocation( - transaction_trace["function_invocation"], - "test/expected/deploy_function_invocation.json", + deploy_info = deploy_empty_contract() + tx_hash = deploy_info["tx_hash"] + + get_trace_resp = get_transaction_trace_response(tx_hash) + assert get_trace_resp.status_code == 200 + transaction_trace = TransactionTrace.load(get_trace_resp.json()) + + # assert invoking account + function_invocation = transaction_trace.function_invocation + assert function_invocation.call_type == CallType.CALL + assert function_invocation.contract_address == ChargeableAccount.ADDRESS + assert function_invocation.entry_point_type == EntryPointType.EXTERNAL + assert function_invocation.selector == get_selector_from_name("__execute__") + internal_calls = function_invocation.internal_calls + assert len(internal_calls) == 1 + + # assert deployment through UDC + assert internal_calls[0].call_type == CallType.CALL + assert internal_calls[0].contract_address == int(EXPECTED_UDC_ADDRESS, 16) + assert internal_calls[0].entry_point_type == EntryPointType.EXTERNAL + assert internal_calls[0].selector == get_selector_from_name("deployContract") + assert len(internal_calls[0].internal_calls) == 1 + + udc_internal_calls = internal_calls[0].internal_calls + + # assert constructor call + assert udc_internal_calls[0].call_type == CallType.CALL + assert udc_internal_calls[0].contract_address == int(deploy_info["address"], 16) + assert udc_internal_calls[0].entry_point_type == EntryPointType.CONSTRUCTOR + assert udc_internal_calls[0].selector == get_selector_from_name("constructor") + assert len(udc_internal_calls[0].internal_calls) == 0 + + # assert fee subtraction + fee_transfer_invocation = transaction_trace.fee_transfer_invocation + assert fee_transfer_invocation.call_type == CallType.CALL + assert fee_transfer_invocation.contract_address == int( + EXPECTED_FEE_TOKEN_ADDRESS, 16 ) + assert fee_transfer_invocation.selector == get_selector_from_name("transfer") + assert fee_transfer_invocation.entry_point_type == EntryPointType.EXTERNAL @pytest.mark.transaction_trace @@ -132,10 +164,9 @@ def test_get_block_traces(): block_hash = tx_receipt["block_hash"] assert_get_block_traces_response({"blockHash": block_hash}, tx_hash) - assert_get_block_traces_response({"blockNumber": GENESIS_BLOCK_NUMBER + 1}, tx_hash) - assert_get_block_traces_response( - {}, tx_hash - ) # default behavior - no params provided + assert_get_block_traces_response({"blockNumber": GENESIS_BLOCK_NUMBER + 2}, tx_hash) + # default behavior - no params provided + assert_get_block_traces_response({}, tx_hash) @pytest.mark.transaction_trace diff --git a/test/test_tx_version.py b/test/test_tx_version.py index 00f084b76..a43636a05 100644 --- a/test/test_tx_version.py +++ b/test/test_tx_version.py @@ -5,14 +5,14 @@ import pytest from starkware.starknet.definitions.constants import TRANSACTION_VERSION -from .account import invoke +from .account import declare_and_deploy_with_chargeable, invoke from .shared import ( ARTIFACTS_PATH, PREDEPLOY_ACCOUNT_CLI_ARGS, PREDEPLOYED_ACCOUNT_ADDRESS, PREDEPLOYED_ACCOUNT_PRIVATE_KEY, ) -from .util import call, deploy, devnet_in_background +from .util import call, devnet_in_background CONTRACT_PATH = f"{ARTIFACTS_PATH}/tx_version.cairo/tx_version.json" ABI_PATH = f"{ARTIFACTS_PATH}/tx_version.cairo/tx_version_abi.json" @@ -22,7 +22,7 @@ @devnet_in_background(*PREDEPLOY_ACCOUNT_CLI_ARGS) def test_transaction_version(): """Check if transaction versions are correct""" - deploy_info = deploy(CONTRACT_PATH) + deploy_info = declare_and_deploy_with_chargeable(CONTRACT_PATH) address = deploy_info["address"] invoke( diff --git a/test/util.py b/test/util.py index b30ba47f5..98b825446 100644 --- a/test/util.py +++ b/test/util.py @@ -12,7 +12,6 @@ import pytest import requests -from starkware.starknet.cli.starknet_cli import get_salt from starkware.starknet.definitions.error_codes import StarknetErrorCode from starkware.starknet.definitions.general_config import StarknetChainId from starkware.starknet.definitions.transaction_type import TransactionType @@ -21,12 +20,13 @@ CompiledClassBase, DeprecatedCompiledClass, ) -from starkware.starknet.services.api.gateway.transaction import Deploy +from starkware.starknet.services.api.feeder_gateway.response_objects import ( + TransactionInfo, +) from starknet_devnet.general_config import DEFAULT_GENERAL_CONFIG from .settings import APP_URL, HOST, PORT -from .shared import SUPPORTED_TX_VERSION class ReturnCodeAssertionError(AssertionError): @@ -128,8 +128,11 @@ def assert_equal(actual, expected, explanation=None): def assert_hex_equal(actual, expected): - """Assert that two hex strings are equal when converted to ints""" - assert int(actual, 16) == int(expected, 16) + """ + Assert that two hex strings are equal when converted to ints. + Converting back to hex to have hex strings in error message in case of failed assertion. + """ + assert hex(int(actual, 16)) == hex(int(expected, 16)) def assert_get_events_response( @@ -197,30 +200,10 @@ def send_tx(transaction: dict, tx_type: TransactionType, gateway_url=APP_URL) -> url=f"{gateway_url}/gateway/add_transaction", json={**transaction, "type": tx_type.name}, ) - assert resp.status_code == 200 + assert resp.status_code == 200, resp.json() return resp.json() -def deploy(contract, inputs=None, salt=None, gateway_url=APP_URL): - """Wrapper around starknet deploy""" - - inputs = inputs or [] - - deploy_tx = Deploy( - contract_address_salt=get_salt(salt), - contract_definition=load_contract_class(contract), - constructor_calldata=[int(value, 0) for value in inputs], - version=SUPPORTED_TX_VERSION, - ).dump() - - resp = send_tx(deploy_tx, TransactionType.DEPLOY, gateway_url) - - return { - "tx_hash": resp["transaction_hash"], - "address": resp["address"], - } - - def estimate_message_fee( from_address: str, function: str, inputs: List[str], to_address: str, abi_path: str ): @@ -251,52 +234,12 @@ def assert_transaction( output = run_starknet( ["get_transaction", "--hash", tx_hash], gateway_url=feeder_gateway_url ) - transaction = json.loads(output.stdout) - assert_equal(transaction["status"], expected_status, transaction) - if expected_signature: - assert_equal(transaction["transaction"]["signature"], expected_signature) - - expected_keys = ["status", "transaction", "transaction_index"] - if expected_status == "REJECTED": - expected_keys.append("transaction_failure_reason") - else: - expected_keys.extend(["block_hash", "block_number"]) - - assert_keys(transaction, expected_keys) - - tx_type = transaction["transaction"]["type"] - - if tx_type == "INVOKE_FUNCTION": - invoke_transaction_keys = [ - "calldata", - "sender_address", - "max_fee", - "signature", - "transaction_hash", - "type", - "nonce", - "version", - ] - assert_keys(transaction["transaction"], invoke_transaction_keys) - elif tx_type == "DEPLOY": - deploy_transaction_keys = [ - "class_hash", - "constructor_calldata", - "contract_address", - "contract_address_salt", - "transaction_hash", - "type", - "version", - ] - assert_keys(transaction["transaction"], deploy_transaction_keys) - else: - raise RuntimeError(f"Unknown tx_type: {tx_type}") + transaction: TransactionInfo = TransactionInfo.loads(output.stdout) + assert_equal(transaction.status.name, expected_status, transaction) -def assert_keys(dictionary, keys): - """Asserts that the dict has the correct keys""" - expected_set = set(keys) - assert dictionary.keys() == expected_set, f"{dictionary.keys()} != {expected_set}" + if expected_signature: + assert_equal(transaction.transaction.signature, expected_signature) def assert_transaction_not_received(tx_hash: str, feeder_gateway_url=APP_URL): @@ -378,7 +321,7 @@ def call( address: str, abi_path: str, inputs=None, - block_number=None, # Starknet CLI defaults to pending + block_number=None, # Starknet CLI defaults to pending - we shouldn't rely on that block_hash=None, feeder_gateway_url=APP_URL, ): @@ -615,17 +558,12 @@ def assert_compiled_class_by_hash_not_present( assert_undeclared_class(resp) -def assert_receipt(tx_hash, expected_path): +def assert_receipt(tx_hash: str, expected_status: str): """Asserts the content of the receipt of tx with tx_hash.""" receipt = get_transaction_receipt(tx_hash) - expected_receipt = load_json_from_path(expected_path) assert_equal(receipt["transaction_hash"], tx_hash) - - for ignorable_key in ["block_hash", "transaction_hash"]: - receipt.pop(ignorable_key) - expected_receipt.pop(ignorable_key) - assert_equal(receipt, expected_receipt) + assert_equal(receipt["status"], expected_status) def assert_receipt_present( @@ -702,18 +640,6 @@ def assert_block(latest_block_number, latest_tx_hash): assert re.match(r"^[a-fA-F0-9]{64}$", latest_block["state_root"]) -def assert_salty_deploy( - contract_path, inputs, salt, expected_status, expected_address, expected_tx_hash -): - """Deploy with salt and assert.""" - - deploy_info = deploy(contract_path, inputs=inputs, salt=salt) - assert_tx_status(deploy_info["tx_hash"], expected_status) - assert_equal( - deploy_info, {"address": expected_address, "tx_hash": expected_tx_hash} - ) - - def load_file_content(file_name: str): """Load content of file located in the same directory as this test file.""" full_file_path = os.path.join(os.path.dirname(__file__), file_name)