def test_policy_before_future( self, cluster: clusterlib.ClusterLib, issuers_addrs: List[clusterlib.AddressRecord]): """Test that it's NOT possible to mint tokens. The "before" slot is in the future and the given range is invalid. """ temp_template = helpers.get_func_name() rand = clusterlib.get_rand_str(4) amount = 5 token_mint_addr = issuers_addrs[0] payment_vkey_files = [p.vkey_file for p in issuers_addrs] before_slot = cluster.get_slot_no() + 10_000 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files[1:], slot=before_slot, slot_type_arg=clusterlib.MultiSlotTypeArgs.BEFORE, ) policyid = cluster.get_policyid(multisig_script) tokens_to_mint = [] for tnum in range(5): asset_name = f"couttscoin{rand}{tnum}" token = f"{policyid}.{asset_name}" assert not cluster.get_utxo(token_mint_addr.address, coins=[ token ]), "The token already exists" tokens_to_mint.append( clusterlib_utils.TokenRecord( token=token, asset_name=asset_name, amount=amount, issuers_addrs=issuers_addrs, token_mint_addr=token_mint_addr, script=multisig_script, )) # token minting - invalid range, slot is in the future with pytest.raises(clusterlib.CLIError) as excinfo: _mint_or_burn_witness( cluster_obj=cluster, new_tokens=tokens_to_mint, temp_template=f"{temp_template}_mint", invalid_before=1, invalid_hereafter=before_slot + 1, ) assert "ScriptWitnessNotValidatingUTXOW" in str(excinfo.value) for t in tokens_to_mint: token_utxo = cluster.get_utxo(token_mint_addr.address, coins=[t.token]) assert not token_utxo, "The token was minted unexpectedly"
def test_address_info_script(self, cluster: clusterlib.ClusterLib): """Check script address info.""" temp_template = helpers.get_func_name() # create payment address payment_rec = cluster.gen_payment_addr_and_keys( name=temp_template, ) # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=[payment_rec.vkey_file], slot=100, slot_type_arg=clusterlib.MultiSlotTypeArgs.AFTER, ) # create script address address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) addr_info = cluster.address_info(address=address) assert addr_info.address == address assert addr_info.era == "shelley" assert addr_info.encoding == "bech32" assert addr_info.type == "payment"
def test_after_past(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Check that it's NOT possible to spend from the script address. The "after" slot is in the past. """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] after_slot = cluster.get_slot_no() - 1 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files, slot=after_slot, slot_type_arg=clusterlib.MultiSlotTypeArgs.AFTER, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_address, amount=500_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address - valid slot, # invalid range - `invalid_hereafter` is in the past with pytest.raises(clusterlib.CLIError) as excinfo: multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from", src_address=script_address, dst_address=payment_addrs[0].address, amount=10, multisig_script=multisig_script, payment_skey_files=payment_skey_files, invalid_before=1, invalid_hereafter=after_slot, script_is_src=True, ) assert "ScriptWitnessNotValidatingUTXOW" in str(excinfo.value)
def test_multisig_atleast_low_num_of_skeys( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Try to send funds from script address using the *atLeast* script. Num of skeys < required. Expect failure. """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] skeys_len = len(payment_skey_files) required = skeys_len - 4 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.AT_LEAST, payment_vkey_files=payment_vkey_files, required=required, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=temp_template, src_address=payment_addrs[0].address, dst_address=script_address, amount=300_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address, use lower number of skeys then required for num_of_skeys in range(required): with pytest.raises(clusterlib.CLIError) as excinfo: multisig_tx( cluster_obj=cluster, temp_template=temp_template, src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=random.sample(payment_skey_files, k=num_of_skeys), script_is_src=True, ) assert "ScriptWitnessNotValidatingUTXOW" in str(excinfo.value)
def test_normal_tx_to_script_addr( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send funds to script address using TX signed with skeys (not using witness files).""" temp_template = helpers.get_func_name() src_address = payment_addrs[0].address amount = 1000 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=[p.vkey_file for p in payment_addrs], ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # record initial balances src_init_balance = cluster.get_address_balance(src_address) dst_init_balance = cluster.get_address_balance(script_address) # send funds to script address destinations = [ clusterlib.TxOut(address=script_address, amount=amount) ] tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file]) tx_raw_output = cluster.send_funds( src_address=src_address, tx_name=temp_template, destinations=destinations, tx_files=tx_files, ) cluster.wait_for_new_block(new_blocks=2) # check final balances assert ( cluster.get_address_balance(src_address) == src_init_balance - tx_raw_output.fee - amount), f"Incorrect balance for source address `{src_address}`" assert ( cluster.get_address_balance(script_address) == dst_init_balance + amount ), f"Incorrect balance for destination address `{script_address}`"
def test_multisig_atleast(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send funds to and from script address using the *atLeast* script.""" temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] skeys_len = len(payment_skey_files) required = skeys_len - 4 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.AT_LEAST, payment_vkey_files=payment_vkey_files, required=required, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_address, amount=2_000_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address for i in range(5): num_of_skeys = random.randrange(required, skeys_len) multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from_{i}", src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=random.sample(payment_skey_files, k=num_of_skeys), script_is_src=True, )
def test_script_before(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Check that it is possible to spend from script address before given slot.""" temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] before_slot = cluster.get_slot_no() + 10_000 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files, slot=before_slot, slot_type_arg=clusterlib.MultiSlotTypeArgs.BEFORE, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_address, amount=2_000_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from", src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=payment_skey_files, invalid_before=100, invalid_hereafter=cluster.get_slot_no() + 1000, script_is_src=True, )
def test_multisig_any_unlisted_skey( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Try to send funds from script address using the *any* script with unlisted skey. Expect failure. """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs[:-1]] payment_skey_files = [p.skey_file for p in payment_addrs] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ANY, payment_vkey_files=payment_vkey_files, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=temp_template, src_address=payment_addrs[0].address, dst_address=script_address, amount=300_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address, use skey that is not listed in the script with pytest.raises(clusterlib.CLIError) as excinfo: multisig_tx( cluster_obj=cluster, temp_template=temp_template, src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[-1]], script_is_src=True, ) assert "ScriptWitnessNotValidatingUTXOW" in str(excinfo.value)
def test_multisig_no_required_atleast( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send funds from script address using the *atLeast* script with no required witnesses.""" temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.AT_LEAST, payment_vkey_files=payment_vkey_files, required=0, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_address, amount=2_000_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from", src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=[], script_is_src=True, )
def test_tx_script_metadata_cbor( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send transaction with auxiliary script and metadata CBOR. Check that the auxiliary script is present in the TX body. """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.AT_LEAST, payment_vkey_files=payment_vkey_files, required=2, slot=1000, slot_type_arg=clusterlib.MultiSlotTypeArgs.BEFORE, ) tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file], metadata_cbor_files=[self.CBOR_METADATA_FILE], script_files=[multisig_script], ) tx_raw_output = cluster.send_tx(src_address=payment_addrs[0].address, tx_name=temp_template, tx_files=tx_files) cluster.wait_for_new_block(new_blocks=2) assert tx_raw_output.fee, "Transaction had no fee" with open(tx_raw_output.out_file) as body_fp: tx_body_json = json.load(body_fp) cbor_body = bytes.fromhex(tx_body_json["cborHex"]) cbor_body_metadata = cbor2.loads(cbor_body)[1] cbor_body_script = cbor_body_metadata[1] assert cbor_body_script, "Auxiliary script not present"
def multisig_script_policyid( cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, issuers_addrs: List[clusterlib.AddressRecord], ) -> Tuple[Path, str]: """Return multisig script and it's PolicyId.""" with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore temp_template = "test_native_tokens_multisig" payment_vkey_files = [p.vkey_file for p in issuers_addrs] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files[1:], ) policyid = cluster.get_policyid(multisig_script) return multisig_script, policyid
def test_script_addr_length(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Check that script address length is the same as lenght of other addresses. There was an issue that script address was 32 bytes instead of 28 bytes. """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # check script address length assert len(script_address) == len(payment_addrs[0].address)
def test_valid_policy_before( self, cluster: clusterlib.ClusterLib, issuers_addrs: List[clusterlib.AddressRecord]): """Test minting and burning tokens before given slot.""" expected_fee = 351093 temp_template = helpers.get_func_name() rand = clusterlib.get_rand_str(4) amount = 5 token_mint_addr = issuers_addrs[0] payment_vkey_files = [p.vkey_file for p in issuers_addrs] before_slot = cluster.get_slot_no() + 10_000 # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files[1:], slot=before_slot, slot_type_arg=clusterlib.MultiSlotTypeArgs.BEFORE, ) policyid = cluster.get_policyid(multisig_script) tokens_to_mint = [] for tnum in range(5): asset_name = f"couttscoin{rand}{tnum}" token = f"{policyid}.{asset_name}" assert not cluster.get_utxo(token_mint_addr.address, coins=[ token ]), "The token already exists" tokens_to_mint.append( clusterlib_utils.TokenRecord( token=token, asset_name=asset_name, amount=amount, issuers_addrs=issuers_addrs, token_mint_addr=token_mint_addr, script=multisig_script, )) # token minting tx_out_mint = _mint_or_burn_witness( cluster_obj=cluster, new_tokens=tokens_to_mint, temp_template=f"{temp_template}_mint", invalid_before=100, invalid_hereafter=cluster.get_slot_no() + 1000, ) for t in tokens_to_mint: token_utxo = cluster.get_utxo(token_mint_addr.address, coins=[t.token]) assert token_utxo and token_utxo[ 0].amount == amount, "The token was not minted" # token burning tokens_to_burn = [t._replace(amount=-amount) for t in tokens_to_mint] tx_out_burn = _mint_or_burn_witness( cluster_obj=cluster, new_tokens=tokens_to_burn, temp_template=f"{temp_template}_burn", invalid_before=100, invalid_hereafter=cluster.get_slot_no() + 1000, ) for t in tokens_to_burn: token_utxo = cluster.get_utxo(token_mint_addr.address, coins=[t.token]) assert not token_utxo, "The token was not burnt" # check expected fees assert helpers.is_in_interval( tx_out_mint.fee, expected_fee, frac=0.15) and helpers.is_in_interval( tx_out_burn.fee, expected_fee, frac=0.15), "TX fee doesn't fit the expected interval"
def test_minting_and_partial_burning( self, cluster: clusterlib.ClusterLib, issuers_addrs: List[clusterlib.AddressRecord]): """Test minting and partial burning of tokens.""" expected_fee = 201141 temp_template = helpers.get_func_name() asset_name = f"couttscoin{clusterlib.get_rand_str(4)}" amount = 50 payment_vkey_files = [p.vkey_file for p in issuers_addrs] token_mint_addr = issuers_addrs[0] # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ALL, payment_vkey_files=payment_vkey_files[1:], ) policyid = cluster.get_policyid(multisig_script) token = f"{policyid}.{asset_name}" assert not cluster.get_utxo(token_mint_addr.address, coins=[token]), "The token already exists" token_mint = clusterlib_utils.TokenRecord( token=token, asset_name=asset_name, amount=amount, issuers_addrs=issuers_addrs, token_mint_addr=token_mint_addr, script=multisig_script, ) # token minting tx_out_mint = _mint_or_burn_witness( cluster_obj=cluster, new_tokens=[token_mint], temp_template=f"{temp_template}_mint", ) token_utxo = cluster.get_utxo(token_mint_addr.address, coins=[token]) assert token_utxo and token_utxo[ 0].amount == amount, "The token was not minted" # token burning burn_amount = amount - 10 token_burn = token_mint._replace(amount=-burn_amount) _mint_or_burn_witness( cluster_obj=cluster, new_tokens=[token_burn], temp_template=f"{temp_template}_burn", ) token_utxo = cluster.get_utxo(token_mint_addr.address, coins=[token]) assert (token_utxo and token_utxo[0].amount == amount - burn_amount), "The token was not burned" # burn the rest of tokens final_burn = token_mint._replace(amount=-10) _mint_or_burn_witness( cluster_obj=cluster, new_tokens=[final_burn], temp_template=f"{temp_template}_burn", ) # check expected fee assert helpers.is_in_interval( tx_out_mint.fee, expected_fee, frac=0.15), "TX fee doesn't fit the expected interval"
def test_multisig_any(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send funds using the *any* script. * send funds to script address * send funds from script address using single witness * send funds from script address using multiple witnesses """ temp_template = helpers.get_func_name() payment_vkey_files = [p.vkey_file for p in payment_addrs] payment_skey_files = [p.skey_file for p in payment_addrs] skeys_len = len(payment_skey_files) # create multisig script multisig_script = cluster.build_multisig_script( script_name=temp_template, script_type_arg=clusterlib.MultiSigTypeArgs.ANY, payment_vkey_files=payment_vkey_files, ) # create script address script_address = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_address, amount=5_000_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address using single witness for i in range(5): multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from_single_{i}", src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=[ payment_skey_files[random.randrange(0, skeys_len)] ], script_is_src=True, ) # send funds from script address using multiple witnesses for i in range(5): num_of_skeys = random.randrange(2, skeys_len) multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_from_multi_{i}", src_address=script_address, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=random.sample(payment_skey_files, k=num_of_skeys), script_is_src=True, )