From 5e01f2918f81e30c94007c783ddb52800916bdc4 Mon Sep 17 00:00:00 2001 From: Andrew Nikitin Date: Thu, 27 Jan 2022 18:29:17 +0300 Subject: [PATCH] Merge pull request #270 from cheqd/DEV-720 Get rid of circle dependencies from vdrtools --- .github/workflows/node-ci.yml | 38 +- .../{query_did_2.sh => query_did_via_rest.sh} | 0 tests/e2e/helpers.py | 180 +++---- tests/e2e/test_cosmos.py | 7 +- tests/e2e/test_identity.py | 492 ++++++++---------- x/cheqd/keeper/msg_server_did.go | 2 +- 6 files changed, 299 insertions(+), 420 deletions(-) rename tests/cli/tests/{query_did_2.sh => query_did_via_rest.sh} (100%) diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index 767fc64d4..6b9f49a62 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -233,7 +233,7 @@ jobs: journalctl -u service-name.service --no-pager run-cosmos-tests-using-cli: - name: Run cosmos tests using CLI + name: Run cosmos and identity tests using CLI runs-on: ubuntu-20.04 needs: [build-node-image, build-binary] steps: @@ -267,47 +267,19 @@ jobs: working-directory: ./tests/e2e run: | pip3 install -r requirements.txt >> /dev/null - pip3 install --force-reinstall 'git+https://gitlab.com/evernym/verity/vdr-tools.git@cheqd-node-0.3.1#egg=vdr-tools&subdirectory=wrappers/python' -U cp -R ${NODE_CONFIGS_BASE}/client/.cheqdnode /home/runner/ sudo chmod -R 777 /home/runner - - name: Run tests + - name: Run cosmos-related tests run: | export OP0_ADDRESS=$(cheqd-noded keys list --keyring-backend "test" | sed -nr 's/.*address: (.*?).*/\1/p' | sed -n 1p | sed 's/\r//g') export OP1_ADDRESS=$(cheqd-noded keys list --keyring-backend "test" | sed -nr 's/.*address: (.*?).*/\1/p' | sed -n 2p | sed 's/\r//g') pytest -v -rP tests/e2e/test_cosmos.py - run-identity-tests-using-vdr: - name: Run identity tests using VDR - runs-on: ubuntu-20.04 - needs: build-testnet-image - steps: - - uses: actions/checkout@v2 - - - name: Download testnet image - uses: actions/download-artifact@v2 - with: - name: cheqd-testnet-image.tar - - - name: Load testnet image - run: docker load -i cheqd-testnet-image.tar - - - name: Run test net container - run: | - docker run -d --rm -p "26657:26657" cheqd-testnet - bash tests/networks/tools/wait-for-chain.sh - - - name: Set up test environment - working-directory: ./tests/e2e + - name: Run identity-related tests run: | - sudo cp libindy.so /usr/lib/libindy.so - pip3 install -r requirements.txt >> /dev/null - pip3 install --force-reinstall 'git+https://gitlab.com/evernym/verity/vdr-tools.git@cheqd-node-0.3.1#egg=vdr-tools&subdirectory=wrappers/python' -U - - - name: Run tests - run: | - export OP0_ADDRESS="" - export OP1_ADDRESS="" + export OP0_ADDRESS=$(cheqd-noded keys list --keyring-backend "test" | sed -nr 's/.*address: (.*?).*/\1/p' | sed -n 1p | sed 's/\r//g') + export OP1_ADDRESS=$(cheqd-noded keys list --keyring-backend "test" | sed -nr 's/.*address: (.*?).*/\1/p' | sed -n 2p | sed 's/\r//g') pytest -v -rP tests/e2e/test_identity.py run-identity-tests-using-cli: diff --git a/tests/cli/tests/query_did_2.sh b/tests/cli/tests/query_did_via_rest.sh similarity index 100% rename from tests/cli/tests/query_did_2.sh rename to tests/cli/tests/query_did_via_rest.sh diff --git a/tests/e2e/helpers.py b/tests/e2e/helpers.py index 4794d1b14..5bc3a2986 100644 --- a/tests/e2e/helpers.py +++ b/tests/e2e/helpers.py @@ -1,3 +1,4 @@ +import copy import sys import os import pexpect @@ -7,13 +8,9 @@ import json import time -from vdrtools import wallet -from vdrtools import cheqd_keys, cheqd_pool, cheqd_ledger -from vdrtools.error import CommonInvalidStructure - IMPLICIT_TIMEOUT = 30 ENCODING = "utf-8" -READ_BUFFER = 6000 +READ_BUFFER = 60000 TEST_NET_NETWORK = "cheqd-testnet-2" LOCAL_NET_NETWORK = "cheqd" @@ -25,13 +22,14 @@ TEST_NET_DESTINATION_HTTP = f"{TEST_NET_NODE_HTTP} --chain-id 'cheqd-testnet-2'" LOCAL_NET_DESTINATION = f"{LOCAL_NET_NODE_TCP} --chain-id 'cheqd'" LOCAL_NET_DESTINATION_HTTP = f"{LOCAL_NET_NODE_HTTP} --chain-id 'cheqd'" +GAS_AMOUNT = 90000 # 70000 throws `out of gas` sometimes +GAS_PRICE = 25 TEST_NET_FEES = "--fees 5000000ncheq" TEST_NET_GAS_X_GAS_PRICES = "--gas 90000 --gas-prices 25ncheq" YES_FLAG = "-y" KEYRING_BACKEND_TEST = "--keyring-backend test" DENOM = "ncheq" -GAS_AMOUNT = 90000 # 70000 throws `out of gas` sometimes -GAS_PRICE = 25 + TEST_NET_GAS_X_GAS_PRICES_INT = GAS_AMOUNT * GAS_PRICE MAX_GAS_MAGIC_NUMBER = 1.3 @@ -45,6 +43,10 @@ LOCAL_RECEIVER_ADDRESS = os.environ["OP1_ADDRESS"] CODE_0 = "\"code\":0" +CODE_5 = "\"code\":5" +CODE_11 = "\"code\":11" +CODE_1203 = "\"code\":1203" +CODE_1100 = "\"code\":1100" CODE_0_DIGIT = 0 @@ -53,9 +55,18 @@ def random_string(length): def run(command_base, command, params, expected_output): + # ToDo: Make it more clear. + # Quick hack for getting passing timouted transactions + timeout_str = "Error(.*?)timed out waiting for tx to be included in a block" cli = pexpect.spawn(f"{command_base} {command} {params}", encoding=ENCODING, timeout=IMPLICIT_TIMEOUT, maxread=READ_BUFFER) cli.logfile = sys.stdout - cli.expect(expected_output) + try: + cli.expect(expected_output) + except pexpect.exceptions.EOF as err: + if re.search(timeout_str, cli.before): + get_balance(LOCAL_SENDER_ADDRESS, LOCAL_NET_DESTINATION) + return cli + raise err return cli @@ -72,13 +83,16 @@ def get_balance(address, network_destination): return balance -async def get_balance_vdr(pool_alias, address): - request = await cheqd_ledger.bank.build_query_balance(address, DENOM) - res = await cheqd_pool.abci_query(pool_alias, request) - res = await cheqd_ledger.bank.parse_query_balance_resp(res) - sender_balance = json.loads(res)["balance"]["amount"] +def json_loads(s_to_load: str) -> dict: + s = copy.copy(s_to_load) + s = s.replace("\\", "") + s = s.replace("\"[", "[") + s = s.replace("]\"", "]") + return json.loads(s) + - return sender_balance +def get_gas_extimation(s_to_search: str) -> int: + return int(re.findall(r"\d+", s_to_search)[0]) def send_with_note(note): @@ -93,71 +107,6 @@ def send_with_note(note): return tx_hash, note -async def send_tx_helper(pool_alias, wallet_handle, key_alias, public_key, sender_address, msg, memo): - account_number, sequence_number = await get_base_account_number_and_sequence(pool_alias, sender_address) - timeout_height = await get_timeout_height(pool_alias) - test_tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, GAS_AMOUNT, GAS_AMOUNT*GAS_PRICE, DENOM, sender_address, timeout_height, memo - ) - request = await cheqd_ledger.tx.build_query_simulate(test_tx) - response = await cheqd_pool.abci_query(pool_alias, request) - response = await cheqd_ledger.tx.parse_query_simulate_resp(response) - gas_estimation = json.loads(response)["gas_info"]["gas_used"] - fees = int(gas_estimation*MAX_GAS_MAGIC_NUMBER*GAS_PRICE) - prod_tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, int(gas_estimation*MAX_GAS_MAGIC_NUMBER), fees, DENOM, SENDER_ADDRESS, timeout_height, memo - ) - tx_signed = await cheqd_ledger.auth.sign_tx(wallet_handle, key_alias, prod_tx) - res = json.loads(await cheqd_pool.broadcast_tx_commit(pool_alias, tx_signed)) - tx_hash = res["hash"] - - return res, tx_hash, fees - - -async def send_tx_helper_alt(pool_alias, wallet_handle, key_alias, public_key, sender_address, msg, memo): - account_number, sequence_number = await get_base_account_number_and_sequence(pool_alias, sender_address) - timeout_height = await get_timeout_height(pool_alias) - tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, GAS_AMOUNT, GAS_AMOUNT*GAS_PRICE, DENOM, sender_address, timeout_height, memo - ) - tx_signed = await cheqd_ledger.auth.sign_tx(wallet_handle, key_alias, tx) - res = json.loads(await cheqd_pool.broadcast_tx_commit(pool_alias, tx_signed)) - tx_hash = res["hash"] - - return res, tx_hash - - -async def get_tx_helper(pool_alias, tx_hash): - request = await cheqd_ledger.tx.build_query_get_tx_by_hash(tx_hash) - res = await cheqd_pool.abci_query(pool_alias, request) - res = json.loads(await cheqd_ledger.tx.parse_query_get_tx_by_hash_resp(res)) - - return res - - -async def create_did_helper(pool_alias, wallet_handle, key_alias, public_key, sender_address, fqdid, vk, memo): - req = await cheqd_ledger.cheqd.build_msg_create_did(fqdid, vk) - signed_req = await cheqd_ledger.cheqd.sign_msg_write_request(wallet_handle, fqdid, bytes(req)) - res, _, _ = await send_tx_helper(pool_alias, wallet_handle, key_alias, public_key, sender_address, bytes(signed_req), memo) - - return res - - -async def query_did_helper(pool_alias, fqdid): - req = await cheqd_ledger.cheqd.build_query_get_did(fqdid) - res = await cheqd_pool.abci_query(pool_alias, req) - - return res - - -async def update_did_helper(pool_alias, wallet_handle, key_alias, public_key, sender_address, fqdid, new_vk, version_id, memo): - req = await cheqd_ledger.cheqd.build_msg_update_did(fqdid, new_vk, version_id) - signed_req = await cheqd_ledger.cheqd.sign_msg_write_request(wallet_handle, fqdid, bytes(req)) - res, _, _ = await send_tx_helper(pool_alias, wallet_handle, key_alias, public_key, sender_address, bytes(signed_req), memo) - - return res - - def set_up_operator(): name = random_string(10) cli = run("cheqd-noded keys", "add", f"{name} {KEYRING_BACKEND_TEST}", r"mnemonic: \"\"") @@ -170,35 +119,44 @@ def set_up_operator(): return name, address, pubkey -async def wallet_helper(wallet_id=None, wallet_key="", wallet_key_derivation_method="ARGON2I_INT"): - if not wallet_id: - wallet_id = random_string(25) - wallet_config = json.dumps({"id": wallet_id}) - wallet_credentials = json.dumps({"key": wallet_key, "key_derivation_method": wallet_key_derivation_method}) - await wallet.create_wallet(wallet_config, wallet_credentials) - wallet_handle = await wallet.open_wallet(wallet_config, wallet_credentials) - - return wallet_handle, wallet_config, wallet_credentials - - -async def get_base_account_number_and_sequence(pool_alias, account_id): - req = await cheqd_ledger.auth.build_query_account(account_id) - resp = await cheqd_pool.abci_query(pool_alias, req) - resp = await cheqd_ledger.auth.parse_query_account_resp(resp) - account = json.loads(resp)["account"] - base_account = account["value"] - account_number = base_account["account_number"] - account_sequence = base_account["sequence"] - - return account_number, account_sequence - - -async def get_timeout_height(pool_alias): - TIMEOUT = 50 - try: - info = await cheqd_pool.abci_info(pool_alias) - info = json.loads(info) - current_height = info["response"]["last_block_height"] - return int(current_height) + TIMEOUT - except CommonInvalidStructure: - return 150 +def build_create_did_msg(did: str, + key_id: str, + ver_pub_multibase_58: str) -> str: + return f'{{ "id": "{did}", \ + "verification_method": [{{ \ + "id": "{key_id}", \ + "type": "Ed25519VerificationKey2020", \ + "controller": "{did}", \ + "public_key_multibase": "{ver_pub_multibase_58}" \ + }}], \ + "authentication": [ \ + "{key_id}" \ + ] \ + }} \ ' + + +def build_update_did_msg(did: str, + key_id: str, + ver_pub_multibase_58: str, + version_id: str) -> dict: + return json.loads(f'{{ "id": "{did}", \ + "version_id": "{version_id}", \ + "verification_method": [{{ \ + "id": "{key_id}", \ + "type": "Ed25519VerificationKey2020", \ + "controller": "{did}", \ + "public_key_multibase": "{ver_pub_multibase_58}" \ + }}], \ + "authentication": [ \ + "{key_id}" \ + ] \ + }}') + + +def generate_ed25519_key() -> dict: + cli = run( + "cheqd-noded debug", + "ed25519 random", + "", + "") + return json_loads(cli.read()) diff --git a/tests/e2e/test_cosmos.py b/tests/e2e/test_cosmos.py index c352de617..38545bec7 100644 --- a/tests/e2e/test_cosmos.py +++ b/tests/e2e/test_cosmos.py @@ -3,13 +3,12 @@ import re import time import getpass -from hypothesis import settings, given, strategies, Phase, Verbosity -from string import digits, ascii_letters +from hypothesis import settings, given, strategies +from string import ascii_letters from helpers import run, run_interaction, get_balance, send_with_note, set_up_operator, random_string, \ - TEST_NET_NETWORK, TEST_NET_NODE_TCP, TEST_NET_NODE_HTTP, TEST_NET_DESTINATION, TEST_NET_DESTINATION_HTTP, \ LOCAL_NET_NETWORK, LOCAL_NET_NODE_TCP, LOCAL_NET_NODE_HTTP, LOCAL_NET_DESTINATION, LOCAL_NET_DESTINATION_HTTP, \ TEST_NET_FEES, TEST_NET_GAS_X_GAS_PRICES, YES_FLAG, IMPLICIT_TIMEOUT, \ - LOCAL_SENDER_ADDRESS, LOCAL_RECEIVER_ADDRESS,CODE_0, TEST_NET_GAS_X_GAS_PRICES_INT, KEYRING_BACKEND_TEST + LOCAL_SENDER_ADDRESS, LOCAL_RECEIVER_ADDRESS, CODE_0, TEST_NET_GAS_X_GAS_PRICES_INT, KEYRING_BACKEND_TEST @pytest.mark.parametrize( diff --git a/tests/e2e/test_identity.py b/tests/e2e/test_identity.py index 2bb600de2..2e234239b 100644 --- a/tests/e2e/test_identity.py +++ b/tests/e2e/test_identity.py @@ -1,282 +1,232 @@ -import pytest import json -import logging -import time -from hypothesis import settings, given, strategies, Phase, Verbosity -from string import digits, ascii_letters - -from vdrtools import wallet, did -from vdrtools import cheqd_keys, cheqd_pool, cheqd_ledger -from vdrtools.error import CommonInvalidStructure, PoolLedgerConfigAlreadyExistsError -from helpers import create_did_helper, query_did_helper, random_string, update_did_helper, wallet_helper, get_base_account_number_and_sequence, get_timeout_height, get_balance_vdr, send_tx_helper, send_tx_helper_alt, get_tx_helper, \ - SENDER_ADDRESS, SENDER_MNEMONIC, RECEIVER_ADDRESS, LOCAL_NET_NETWORK, TEST_NET_GAS_X_GAS_PRICES_INT, GAS_AMOUNT, GAS_PRICE, DENOM, IMPLICIT_TIMEOUT, CODE_0_DIGIT, MAX_GAS_MAGIC_NUMBER - -# logger = logging.getLogger(__name__) -# logging.basicConfig(level=logging.DEBUG) +import pytest -KEY_ALIAS = "operator0" -DEFAULT_AMOUNT = 1000 -DEFAULT_MEMO = "test_memo" -MAX_GAS_MAGIC_NUMBER_NEGATIVE = 1.2 -LOCAL_POOL_HTTP = "http://localhost:26657" -FQ_PREFIX = "did:cheqd:testnet:" -MAX_GAS = 0 -MAX_COIN_AMOUNT = 0 +from helpers import run, LOCAL_SENDER_ADDRESS, LOCAL_RECEIVER_ADDRESS, LOCAL_NET_DESTINATION, GAS_PRICE, YES_FLAG, \ + KEYRING_BACKEND_TEST, get_gas_extimation, CODE_0, TEST_NET_GAS_X_GAS_PRICES, generate_ed25519_key, random_string, \ + build_create_did_msg, json_loads, build_update_did_msg, CODE_1100, CODE_1203, get_balance, GAS_AMOUNT, CODE_5, \ + CODE_11 @pytest.mark.parametrize("magic_number_positive", [1.3, 2, 3, 10]) @pytest.mark.parametrize("transfer_amount", ["1", "20002", "3000003", "9000000009"]) -@pytest.mark.asyncio -async def test_gas_estimation_positive(magic_number_positive, transfer_amount): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - msg = await cheqd_ledger.bank.build_msg_send( - SENDER_ADDRESS, RECEIVER_ADDRESS, transfer_amount, DENOM - ) - account_number, sequence_number = await get_base_account_number_and_sequence(pool_alias, SENDER_ADDRESS) - timeout_height = await get_timeout_height(pool_alias) - test_tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, MAX_GAS, MAX_COIN_AMOUNT, DENOM, SENDER_ADDRESS, timeout_height, DEFAULT_MEMO - ) - request = await cheqd_ledger.tx.build_query_simulate(test_tx) - response = await cheqd_pool.abci_query(pool_alias, request) - response = await cheqd_ledger.tx.parse_query_simulate_resp(response) - gas_estimation = json.loads(response)["gas_info"]["gas_used"] - prod_tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, int(gas_estimation*magic_number_positive), int(gas_estimation*magic_number_positive*GAS_PRICE), DENOM, SENDER_ADDRESS, timeout_height, DEFAULT_MEMO - ) - prod_tx_signed = await cheqd_ledger.auth.sign_tx(wallet_handle, KEY_ALIAS, prod_tx) - positive_res = await cheqd_pool.broadcast_tx_commit(pool_alias, prod_tx_signed) - assert json.loads(positive_res)["check_tx"]["code"] == CODE_0_DIGIT - - -@pytest.mark.parametrize("magic_number_negative", [1.2, 1, 0.5, 0.1]) +def test_gas_estimation_positive(magic_number_positive, transfer_amount): + # Get the gas_wanted value and use it as gas_estimation + cli = run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} {transfer_amount}ncheq {LOCAL_NET_DESTINATION} --gas auto --gas-prices {GAS_PRICE}ncheq --gas-adjustment {magic_number_positive} {YES_FLAG} {KEYRING_BACKEND_TEST}", + r"") + # Previous command returns the string, like: + # gas estimate: 123456 + # at the beginning and it will be caught by this function + gas_estimation = get_gas_extimation(str(cli.read())) + + gas = int(gas_estimation * magic_number_positive) + # Send the same request for checking that gas was calculated in a right way + # The main difference between previous run is that `--gas` parameter is set with particular value + run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} {transfer_amount}ncheq {LOCAL_NET_DESTINATION} --gas {gas} --gas-prices {GAS_PRICE}ncheq --gas-adjustment {magic_number_positive} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_0}(.*?)\"value\":\"{transfer_amount}ncheq\"") + + +@pytest.mark.parametrize("magic_number_negative", [1, 0.5, 0.1]) @pytest.mark.parametrize("transfer_amount", ["1", "20002", "3000003", "9000000009"]) -@pytest.mark.asyncio -async def test_gas_estimation_negative(magic_number_negative, transfer_amount): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - msg = await cheqd_ledger.bank.build_msg_send( - SENDER_ADDRESS, RECEIVER_ADDRESS, transfer_amount, DENOM - ) - account_number, sequence_number = await get_base_account_number_and_sequence(pool_alias, SENDER_ADDRESS) - timeout_height = await get_timeout_height(pool_alias) - test_tx = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, MAX_GAS, MAX_COIN_AMOUNT, DENOM, SENDER_ADDRESS, timeout_height, DEFAULT_MEMO - ) - request = await cheqd_ledger.tx.build_query_simulate(test_tx) - response = await cheqd_pool.abci_query(pool_alias, request) - response = await cheqd_ledger.tx.parse_query_simulate_resp(response) - gas_estimation = json.loads(response)["gas_info"]["gas_used"] - prod_tx_negative = await cheqd_ledger.auth.build_tx( - pool_alias, public_key, msg, account_number, sequence_number, int(gas_estimation*magic_number_negative), int(gas_estimation*magic_number_negative*GAS_PRICE), DENOM, SENDER_ADDRESS, timeout_height, DEFAULT_MEMO - ) - prod_tx_negative_signed = await cheqd_ledger.auth.sign_tx(wallet_handle, KEY_ALIAS, prod_tx_negative) - with pytest.raises(CommonInvalidStructure): - await cheqd_pool.broadcast_tx_commit(pool_alias, prod_tx_negative_signed) - - -@pytest.mark.parametrize("transfer_amount", [1, 2, 999, 1001, 9876543210, 1000000000000]) # TODO: hypothesis -@pytest.mark.asyncio -async def test_token_transfer_positive(transfer_amount): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - sender_balance = await get_balance_vdr(pool_alias, SENDER_ADDRESS) - receiver_balance = await get_balance_vdr(pool_alias, RECEIVER_ADDRESS) - - msg = await cheqd_ledger.bank.build_msg_send( - SENDER_ADDRESS, RECEIVER_ADDRESS, str(transfer_amount), DENOM - ) - res, _, fees = await send_tx_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, msg, DEFAULT_MEMO) - assert res["check_tx"]["code"] == CODE_0_DIGIT - - new_sender_balance = await get_balance_vdr(pool_alias, SENDER_ADDRESS) - new_receiver_balance = await get_balance_vdr(pool_alias, RECEIVER_ADDRESS) - - assert int(new_sender_balance) == (int(sender_balance) - transfer_amount - fees) - assert int(new_receiver_balance) == (int(receiver_balance) + transfer_amount) +def test_gas_estimation_negative(magic_number_negative, transfer_amount): + # Get the gas_wanted value and use it as gas_estimation + cli = run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} {transfer_amount}ncheq {LOCAL_NET_DESTINATION} --gas auto --gas-prices {GAS_PRICE}ncheq --gas-adjustment {magic_number_negative} {YES_FLAG} {KEYRING_BACKEND_TEST}", + r"") + + # Previous command returns the string, like: + # gas estimate: 123456 + # at the beginning and it will be caught by this function + gas_estimation = get_gas_extimation(str(cli.read())) + + gas = int(gas_estimation * magic_number_negative) + # Send the same request for checking that gas was calculated in a right way + # The main difference between previous run is that `--gas` parameter is set with particular value + run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} {transfer_amount}ncheq {LOCAL_NET_DESTINATION} --gas {gas} --gas-prices {GAS_PRICE}ncheq --gas-adjustment {magic_number_negative} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_11}(.*?)\"raw_log\":\"out of gas in location") @pytest.mark.parametrize("transfer_amount", [1111111111111111111111, 55555555555555555555555, 999999999999999999999999, 10000000000000000000000000000]) # TODO: hypothesis -@pytest.mark.asyncio -async def test_token_transfer_negative(transfer_amount): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - sender_balance = await get_balance_vdr(pool_alias, SENDER_ADDRESS) - receiver_balance = await get_balance_vdr(pool_alias, RECEIVER_ADDRESS) - - msg = await cheqd_ledger.bank.build_msg_send( - SENDER_ADDRESS, RECEIVER_ADDRESS, str(transfer_amount), DENOM - ) - with pytest.raises(CommonInvalidStructure): - await send_tx_helper_alt(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, msg, DEFAULT_MEMO) - - new_sender_balance = await get_balance_vdr(pool_alias, SENDER_ADDRESS) - new_receiver_balance = await get_balance_vdr(pool_alias, RECEIVER_ADDRESS) - - assert int(new_sender_balance) == (int(sender_balance) - TEST_NET_GAS_X_GAS_PRICES_INT) # fees spent - assert int(new_receiver_balance) == (int(receiver_balance)) # not changed - - -@pytest.mark.parametrize("note", ["a", "1", "test_memo_test", "123qwe$%^&", "______________________________"]) # TODO: hypothesis -@pytest.mark.asyncio -async def test_memo(note): # intermittent failures here due to `Internal error: timed out waiting for tx to be included in a block` - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - msg = await cheqd_ledger.bank.build_msg_send( - SENDER_ADDRESS, RECEIVER_ADDRESS, str(DEFAULT_AMOUNT), DENOM - ) - res, tx_hash, _ = await send_tx_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, msg, note) - assert res["check_tx"]["code"] == CODE_0_DIGIT - - try: - res = await get_tx_helper(pool_alias, tx_hash) - assert res["tx"]["body"]["memo"] == note - except TypeError: - time.sleep(IMPLICIT_TIMEOUT) - res = await get_tx_helper(pool_alias, tx_hash) - assert res["tx"]["body"]["memo"] == note - - - -@pytest.mark.asyncio -async def test_did_positive(): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - # create - _did, vk = await did.create_and_store_my_did(wallet_handle, '{}') - fqdid = FQ_PREFIX + _did - - res = await create_did_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, fqdid, vk, DEFAULT_MEMO) - assert res["check_tx"]["code"] == CODE_0_DIGIT - assert res["deliver_tx"]["code"] == CODE_0_DIGIT - parsed_res = json.loads(await cheqd_ledger.cheqd.parse_msg_create_did(json.dumps(res))) - assert parsed_res["id"] == fqdid - - # query - res = await query_did_helper(pool_alias, fqdid) - parsed_res = json.loads(await cheqd_ledger.cheqd.parse_query_get_did_resp(res)) - version_id = parsed_res["metadata"]["version_id"] - assert parsed_res["did"]["id"] == fqdid - assert parsed_res["did"]["verification_method"][0]["public_key_multibase"] == f"z{vk}" - - # update - new_vk = await did.replace_keys_start(wallet_handle, _did, '{}') - - res = await update_did_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, fqdid, new_vk, version_id, DEFAULT_MEMO) - assert res["check_tx"]["code"] == CODE_0_DIGIT - assert res["deliver_tx"]["code"] == CODE_0_DIGIT - parsed_res = json.loads(await cheqd_ledger.cheqd.parse_msg_update_did(json.dumps(res))) - assert parsed_res["id"] == fqdid - - await did.replace_keys_apply(wallet_handle, _did) - - # query - res = await query_did_helper(pool_alias, fqdid) - parsed_res = json.loads(await cheqd_ledger.cheqd.parse_query_get_did_resp(res)) - new_version_id = parsed_res["metadata"]["version_id"] - assert version_id != new_version_id - assert parsed_res["did"]["id"] == fqdid - assert parsed_res["did"]["verification_method"][0]["public_key_multibase"] == f"z{new_vk}" # new vk - - -@pytest.mark.parametrize("version_id", ["test", "12345", "+M/qoYGJqKE1mwRFSINHIW9cKNGcskTGqPww2kk9aes="]) -@pytest.mark.asyncio -async def test_did_update_wrong_version(version_id): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - # create - _did, vk = await did.create_and_store_my_did(wallet_handle, '{}') - fqdid = FQ_PREFIX + _did - - await create_did_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, fqdid, vk, DEFAULT_MEMO) - - # update - new_vk = await did.replace_keys_start(wallet_handle, _did, '{}') - await did.replace_keys_apply(wallet_handle, _did) - - req = await cheqd_ledger.cheqd.build_msg_update_did(fqdid, new_vk, version_id) - signed_req = await cheqd_ledger.cheqd.sign_msg_write_request(wallet_handle, fqdid, bytes(req)) - with pytest.raises(CommonInvalidStructure): - await send_tx_helper_alt(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, bytes(signed_req), DEFAULT_MEMO) - - -@pytest.mark.asyncio -async def test_did_update_wrong_vk(): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - public_key = json.loads( - await cheqd_keys.add_from_mnemonic(wallet_handle, KEY_ALIAS, SENDER_MNEMONIC, "") - )["pub_key"] - - # create - _did, vk = await did.create_and_store_my_did(wallet_handle, '{}') - fqdid = FQ_PREFIX + _did - - await create_did_helper(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, fqdid, vk, DEFAULT_MEMO) - - # query - res = await query_did_helper(pool_alias, fqdid) - parsed_res = json.loads(await cheqd_ledger.cheqd.parse_query_get_did_resp(res)) - version_id = parsed_res["metadata"]["version_id"] - - # update - _new_did, new_vk = await did.create_and_store_my_did(wallet_handle, '{}') - fq_new_did = FQ_PREFIX + _new_did - - req = await cheqd_ledger.cheqd.build_msg_update_did(fqdid, new_vk, version_id) # new vk - signed_req = await cheqd_ledger.cheqd.sign_msg_write_request(wallet_handle, fq_new_did, bytes(req)) # new signature - with pytest.raises(CommonInvalidStructure): - await send_tx_helper_alt(pool_alias, wallet_handle, KEY_ALIAS, public_key, SENDER_ADDRESS, bytes(signed_req), DEFAULT_MEMO) - - -@pytest.mark.asyncio -async def test_did_query_non_existent(): - pool_alias = random_string(5) - await cheqd_pool.add(pool_alias, LOCAL_POOL_HTTP, LOCAL_NET_NETWORK) - wallet_handle, _, _ = await wallet_helper() - - _did, _ = await did.create_and_store_my_did(wallet_handle, '{}') - fqdid = FQ_PREFIX + _did - - # query - res = await query_did_helper(pool_alias, fqdid) - with pytest.raises(CommonInvalidStructure): - await cheqd_ledger.cheqd.parse_query_get_did_resp(res) +def test_token_transfer_negative(transfer_amount): + # Get balances before sending tx + sender_balance = int(get_balance(LOCAL_SENDER_ADDRESS, LOCAL_NET_DESTINATION)) + receiver_balance = int(get_balance(LOCAL_RECEIVER_ADDRESS, LOCAL_NET_DESTINATION)) + + # Send token transfer + cli = run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} {transfer_amount}ncheq {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_5}(.*?)\"raw_log\":\"(.*?) is smaller than {transfer_amount}ncheq: insufficient funds") + + # Get balances after + sender_balance_after = int(get_balance(LOCAL_SENDER_ADDRESS, LOCAL_NET_DESTINATION)) + receiver_balance_after = int(get_balance(LOCAL_RECEIVER_ADDRESS, LOCAL_NET_DESTINATION)) + + # Compare them ad make sure that only fee amount from sender was burned + assert sender_balance - sender_balance_after == GAS_AMOUNT * GAS_PRICE + assert receiver_balance - receiver_balance_after == 0 + + +@pytest.mark.parametrize("note", ["a", "1", "test_memo_test", "123qwe$%^", "______________________________"]) # TODO: hypothesis +def test_transfer_memo(note): + # Send token transaction with memo set up + cli = run( + "cheqd-noded tx", + "bank send", + f"{LOCAL_SENDER_ADDRESS} {LOCAL_RECEIVER_ADDRESS} 1ncheq {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST} --note {note}", + fr"") + + # Get transaction hash + result_str = cli.read() + tx_hash = json_loads(result_str)["txhash"] + + # Get transaction from the pool by hash + cli = run( + "cheqd-noded query", + "tx", + fr"{tx_hash} --output json", + "") + + # Get memo from + memo_json = json_loads(cli.read()) + + # Compare it with what was sent + assert note == memo_json["tx"]["body"]["memo"] + + +def test_did_query_non_existent(): + did = fr"did:cheqd:testnet:AbCdEfGh" + + # Try to get did + run( + "cheqd-noded query", + "cheqd did", + fr"{did}", + fr"Error: rpc error: code = InvalidArgument desc = not found: invalid request") + + +def test_did_wrong_version_update(): + did = fr"did:cheqd:testnet:{random_string(5)}" + key_id = fr"{did}#key1" + + # Generate ed25519 key + ed25519_key = generate_ed25519_key() + pub_key_base_64 = ed25519_key["pub_key_base_64"] + priv_key_base_64 = ed25519_key["priv_key_base_64"] + + # Get multibase58 represantation + cli = run( + "cheqd-noded debug", + "encoding base64-multibase58", + fr"{pub_key_base_64}", + "") + + ver_pub_multibase_58 = cli.read().strip() + + # Send request to create a DID + msg_create_did = build_create_did_msg(did, + key_id, + ver_pub_multibase_58) + + run( + "cheqd-noded tx", + "cheqd create-did", + f" '{msg_create_did}' {key_id} --from {LOCAL_SENDER_ADDRESS} --ver-key {priv_key_base_64} {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_0}") + + # Get the created DID for getting version_id + cli = run( + "cheqd-noded query", + "cheqd did", + fr"{did} --output json", + "") + + did_json = json_loads(cli.read()) + version_id_orig = did_json["metadata"]["version_id"] + + # Change version_id to the wrong one + wrong_version_id = version_id_orig + "abc" + + # Prepare and send update did message for getting an error + msg_update_did = build_update_did_msg(did, + key_id, + ver_pub_multibase_58, + wrong_version_id) + msg_update_did["capability_delegation"] = [key_id] + + # here we are expecting an 1203 error about wrong version_id + run( + "cheqd-noded tx", + "cheqd update-did", + f" '{json.dumps(msg_update_did)}' {key_id} --from {LOCAL_SENDER_ADDRESS} --ver-key {priv_key_base_64} {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_1203}(.*?)\"raw_log\":\"(.*?)Expected(.*?)unexpected DID version") + + +def test_did_wrong_verkey_update(): + did = fr"did:cheqd:testnet:{random_string(5)}" + key_id = fr"{did}#key1" + + # Generate ed25519 key + ed25519_key = generate_ed25519_key() + pub_key_base_64 = ed25519_key["pub_key_base_64"] + priv_key_base_64 = ed25519_key["priv_key_base_64"] + + # Get multibase58 represantation + cli = run( + "cheqd-noded debug", + "encoding base64-multibase58", + fr"{pub_key_base_64}", + "") + + ver_pub_multibase_58 = cli.read().strip() + + # Send request to create a DID + msg_create_did = build_create_did_msg(did, + key_id, + ver_pub_multibase_58) + + run( + "cheqd-noded tx", + "cheqd create-did", + f" '{msg_create_did}' {key_id} --from {LOCAL_SENDER_ADDRESS} --ver-key {priv_key_base_64} {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_0}") + + # Get the created DID for getting version_id + cli = run( + "cheqd-noded query", + "cheqd did", + fr"{did} --output json", + "") + + did_json = json_loads(cli.read()) + version_id = did_json["metadata"]["version_id"] + + # Prepare and send update did message for getting an error + msg_update_did = build_update_did_msg(did, + key_id, + ver_pub_multibase_58 + "abc", + version_id) + + msg_update_did["capability_delegation"] = [key_id] + + # Create another ed25519 key for using the new one for signing + new_priv_key_base_64 = generate_ed25519_key()["priv_key_base_64"] + + # here we are expecting an 1203 error about wrong version_id + run( + "cheqd-noded tx", + "cheqd update-did", + f" '{json.dumps(msg_update_did)}' {key_id} --from {LOCAL_SENDER_ADDRESS} --ver-key {new_priv_key_base_64} {LOCAL_NET_DESTINATION} {TEST_NET_GAS_X_GAS_PRICES} {YES_FLAG} {KEYRING_BACKEND_TEST}", + fr"{CODE_1100}(.*?)\"raw_log\":\"(.*?)invalid signature detected") \ No newline at end of file diff --git a/x/cheqd/keeper/msg_server_did.go b/x/cheqd/keeper/msg_server_did.go index 543460205..7b6673f06 100644 --- a/x/cheqd/keeper/msg_server_did.go +++ b/x/cheqd/keeper/msg_server_did.go @@ -92,7 +92,7 @@ func (k msgServer) UpdateDid(goCtx context.Context, msg *types.MsgUpdateDid) (*t // replay protection if oldStateValue.Metadata.VersionId != didMsg.VersionId { - errMsg := fmt.Sprintf("Ecpected %s with version %s. Got version %s", didMsg.Id, oldStateValue.Metadata.VersionId, didMsg.VersionId) + errMsg := fmt.Sprintf("Expected %s with version %s. Got version %s", didMsg.Id, oldStateValue.Metadata.VersionId, didMsg.VersionId) return nil, sdkerrors.Wrap(types.ErrUnexpectedDidVersion, errMsg) }