Skip to content

Add more negative scenario functional tests #1228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions test/functional/test_framework/wallet_cli_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from dataclasses import dataclass
from tempfile import NamedTemporaryFile

from typing import Optional, List
from typing import Optional, List, Tuple

ONE_MB = 2**20
READ_TIMEOUT_SEC = 30
Expand Down Expand Up @@ -176,13 +176,12 @@ async def issue_new_token(self,
amount_to_issue: str,
number_of_decimals: int,
metadata_uri: str,
destination_address: str) -> Optional[str]:
output = await self._write_command(f"issuenewtoken {token_ticker} {amount_to_issue} {number_of_decimals} {metadata_uri} {destination_address}\n")
destination_address: str) -> Tuple[Optional[str], Optional[str]]:
output = await self._write_command(f'issuenewtoken "{token_ticker}" "{amount_to_issue}" "{number_of_decimals}" "{metadata_uri}" {destination_address}\n')
if output.startswith("A new token has been issued with ID"):
return output[output.find(':')+2:]
return output[output.find(':')+2:], None

self.log.error(f"err: {output}")
return None
return None, output

async def issue_new_nft(self,
destination_address: str,
Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_delegations.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 50_000_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 50_000 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)
self.log.debug(f"Encoded transaction {tx_id}: {encoded_tx}")
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_get_address_usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.mintlayer import (MLT_COIN, make_tx, reward_input, tx_input)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController
Expand Down Expand Up @@ -98,7 +98,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 1_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 10 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_nfts.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.mintlayer import (make_tx, reward_input, tx_input, MLT_COIN)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController
Expand Down Expand Up @@ -90,7 +90,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 100_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 1000 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

Expand Down
7 changes: 5 additions & 2 deletions test/functional/wallet_recover_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.mintlayer import (make_tx, reward_input, tx_input, MLT_COIN)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import DEFAULT_ACCOUNT_INDEX, WalletCliController
Expand Down Expand Up @@ -77,6 +77,9 @@ async def async_test(self):

# new wallet
async with WalletCliController(node, self.config, self.log) as wallet:
invalid_mnemonic = "asd asd dwa"
assert "Invalid mnemonic:" in await wallet.recover_wallet(invalid_mnemonic)

await wallet.create_wallet()

# check it is on genesis
Expand All @@ -93,7 +96,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 1_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 10 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

Expand Down
22 changes: 21 additions & 1 deletion test/functional/wallet_select_utxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController
from test_framework.wallet_cli_controller import UtxoOutpoint, WalletCliController

import asyncio
import sys
Expand Down Expand Up @@ -124,6 +124,15 @@ def make_output(pub_key_bytes):
assert len(utxos) == num_utxos

address = await wallet.new_address()

# try to select one and send more than it has it should fail
selected_utxos = utxos[:1]
output = await wallet.send_to_address(address, 11, selected_utxos)
assert "Controller error: Wallet error: Coin selection error: Not enough funds" in output
# check that we didn't spent any utxos
assert utxos == await wallet.list_utxos()

# select the first 3 and check that they will be spent
selected_utxos = utxos[:3]
not_selected_utxos = utxos[3:]
await wallet.send_to_address(address, 1, selected_utxos)
Expand All @@ -146,6 +155,17 @@ def make_output(pub_key_bytes):
# check not-selected utxos are still present
assert all(not_selected_utxo in new_utxos for not_selected_utxo in not_selected_utxos)

# try to select already spent utxo
assert "Selected UTXO is already consumed" in await wallet.send_to_address(address, 11, selected_utxos)

# try to select unknown utxo
unknown_utxo_id = "0" * len(selected_utxos[0].id)
unknown_utxo = UtxoOutpoint(unknown_utxo_id, 1)
assert "Cannot find UTXO" in await wallet.send_to_address(address, 11, [unknown_utxo])

# check that we didn't spent any utxos
assert new_utxos == await wallet.list_utxos()



if __name__ == '__main__':
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_submit_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.mintlayer import (make_tx, reward_input, tx_input, MLT_COIN)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController
Expand Down Expand Up @@ -89,7 +89,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 1_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 10 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

Expand Down
41 changes: 37 additions & 4 deletions test/functional/wallet_tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"""

from test_framework.test_framework import BitcoinTestFramework
from test_framework.mintlayer import (make_tx, reward_input, tx_input)
from test_framework.mintlayer import (make_tx, reward_input, tx_input, MLT_COIN)
from test_framework.util import assert_raises_rpc_error
from test_framework.mintlayer import mintlayer_hash, block_input_data_obj
from test_framework.wallet_cli_controller import WalletCliController
Expand Down Expand Up @@ -90,7 +90,7 @@ async def async_test(self):

# Submit a valid transaction
output = {
'Transfer': [ { 'Coin': 100_000_000_000_000 }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
'Transfer': [ { 'Coin': 101 * MLT_COIN }, { 'PublicKey': {'key': {'Secp256k1Schnorr' : {'pubkey_data': pub_key_bytes}}} } ],
}
encoded_tx, tx_id = make_tx([reward_input(tip_id)], [output], 0)

Expand All @@ -108,11 +108,38 @@ async def async_test(self):
assert await wallet.get_best_block_height() == '1'
assert await wallet.get_best_block() == block_id

assert "Coins amount: 1000" in await wallet.get_balance()
assert "Coins amount: 101" in await wallet.get_balance()

address = await wallet.new_address()
token_id = await wallet.issue_new_token("XXX", "10000", 2, "http://uri", address)

# invalid ticker
# > max len
token_id, err = await wallet.issue_new_token("asdddd", "10000", 2, "http://uri", address)
assert token_id is None
assert err is not None
assert "Invalid ticker length" in err
# non alphanumeric
token_id, err = await wallet.issue_new_token("asd#", "10000", 2, "http://uri", address)
assert token_id is None
assert err is not None
assert "Invalid character in token ticker" in err

# invalid url
token_id, err = await wallet.issue_new_token("XXX", "10000", 2, "123 123", address)
assert token_id is None
assert err is not None
assert "Incorrect metadata URI" in err

# invalid num decimals
token_id, err = await wallet.issue_new_token("XXX", "10000", 99, "http://uri", address)
assert token_id is None
assert err is not None
assert "Too many decimals" in err

# issue a valid token
token_id, err = await wallet.issue_new_token("XXX", "10000", 2, "http://uri", address)
assert token_id is not None
assert err is None
self.log.info(f"new token id: {token_id}")

self.generate_block()
Expand All @@ -135,6 +162,12 @@ async def async_test(self):
# check the new balance
assert f"{token_id} amount: 9989.99" in await wallet.get_balance()

# try to issue a new token, should fail with not enough coins
token_id, err = await wallet.issue_new_token("XXX", "10000", 2, "http://uri", address)
assert token_id is None
assert err is not None
assert "Not enough funds" in err

if __name__ == '__main__':
WalletTokens().main()

Expand Down
2 changes: 1 addition & 1 deletion wallet/wallet-cli-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ rust-version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chainstate = { path = "../../chainstate" }
common = { path = "../../common" }
consensus = { path = "../../consensus" }
crypto = { path = "../../crypto" }
Expand Down Expand Up @@ -36,7 +37,6 @@ prettytable-rs = "0.10"

[dev-dependencies]
blockprod = { path = "../../blockprod" }
chainstate = { path = "../../chainstate" }
chainstate-storage = { path = "../../chainstate/storage" }
crypto = { path = "../../crypto" }
mempool = { path = "../../mempool" }
Expand Down
18 changes: 15 additions & 3 deletions wallet/wallet-cli-lib/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod helper_types;

use std::{path::PathBuf, str::FromStr, sync::Arc};

use chainstate::TokenIssuanceError;
use clap::Parser;
use common::{
address::Address,
Expand All @@ -29,10 +30,13 @@ use common::{
use crypto::key::{hdkd::u31::U31, PublicKey};
use p2p_types::{bannable_address::BannableAddress, ip_or_socket_address::IpOrSocketAddress};
use serialization::{hex::HexEncode, hex_encoded::HexEncoded};
use wallet::{account::Currency, version::get_version, wallet_events::WalletEventsNoOp};
use utils::ensure;
use wallet::{
account::Currency, version::get_version, wallet_events::WalletEventsNoOp, WalletError,
};
use wallet_controller::{
read::ReadOnlyController, synced_controller::SyncedController, NodeInterface, NodeRpcClient,
PeerId, DEFAULT_ACCOUNT_INDEX,
read::ReadOnlyController, synced_controller::SyncedController, ControllerError, NodeInterface,
NodeRpcClient, PeerId, DEFAULT_ACCOUNT_INDEX,
};

use crate::{errors::WalletCliError, CliController};
Expand Down Expand Up @@ -474,6 +478,7 @@ impl CommandHandler {
.await
.map_err(WalletCliError::Controller)
}

fn get_readonly_controller(
&mut self,
) -> Result<ReadOnlyController<'_, NodeRpcClient>, WalletCliError> {
Expand Down Expand Up @@ -784,6 +789,13 @@ impl CommandHandler {
metadata_uri,
destination_address,
} => {
ensure!(
number_of_decimals <= chain_config.token_max_dec_count(),
WalletCliError::Controller(ControllerError::WalletError(
WalletError::TokenIssuance(TokenIssuanceError::IssueErrorTooManyDecimals),
))
);

let amount_to_issue = parse_token_amount(number_of_decimals, &amount_to_issue)?;
let destination_address = parse_address(chain_config, &destination_address)?;

Expand Down