def deregister_stake_addr(cluster_obj: clusterlib.ClusterLib, pool_user: clusterlib.PoolUser, name_template: str) -> clusterlib.TxRawOutput: """Deregister stake address.""" # files for deregistering stake address stake_addr_dereg_cert = cluster_obj.gen_stake_addr_deregistration_cert( addr_name=f"{name_template}_addr0_dereg", stake_vkey_file=pool_user.stake.vkey_file) tx_files_deregister = clusterlib.TxFiles( certificate_files=[stake_addr_dereg_cert], signing_key_files=[ pool_user.payment.skey_file, pool_user.stake.skey_file ], ) # withdraw rewards to payment address withdraw_reward(cluster_obj=cluster_obj, pool_user=pool_user, name_template=name_template) tx_raw_output = cluster_obj.send_tx( src_address=pool_user.payment.address, tx_name=f"{name_template}_dereg_stake_addr", tx_files=tx_files_deregister, ) cluster_obj.wait_for_new_block(new_blocks=2) return tx_raw_output
def test_no_kes_period_arg( self, cluster: clusterlib.ClusterLib, cluster_manager: parallel_run.ClusterManager, temp_dir: Path, ): """Try to generate new operational certificate without specifying the `--kes-period`. Expect failure. """ pool_name = "node-pool2" pool_rec = cluster_manager.cache.addrs_data[pool_name] temp_template = helpers.get_func_name() out_file = temp_dir / f"{temp_template}_shouldnt_exist.opcert" # try to generate new operational certificate without specifying the `--kes-period` with pytest.raises(clusterlib.CLIError) as excinfo: cluster.cli( [ "node", "issue-op-cert", "--kes-verification-key-file", str(pool_rec["kes_key_pair"].vkey_file), "--cold-signing-key-file", str(pool_rec["cold_key_pair"].skey_file), "--operational-certificate-issue-counter", str(pool_rec["cold_key_pair"].counter_file), "--out-file", str(out_file), ] ) assert "Missing: --kes-period NATURAL" in str(excinfo.value) assert not out_file.exists(), "New operational certificate was generated"
def check_epoch_length(cluster_obj: clusterlib.ClusterLib) -> None: cluster_obj.wait_for_new_epoch() epoch_no = cluster_obj.get_last_block_epoch() time.sleep((cluster_obj.slot_length * cluster_obj.epoch_length) - 5) assert epoch_no == cluster_obj.get_last_block_epoch() time.sleep(5) assert epoch_no + 1 == cluster_obj.get_last_block_epoch()
def test_addr_deregistration_fees( self, cluster: clusterlib.ClusterLib, pool_users: List[clusterlib.PoolUser], addr_fee: Tuple[int, int], ): """Test stake address deregistration fees.""" no_of_addr, expected_fee = addr_fee temp_template = f"{helpers.get_func_name()}_{no_of_addr}" src_address = pool_users[0].payment.address selected_users = pool_users[:no_of_addr] stake_addr_dereg_certs = [ cluster.gen_stake_addr_deregistration_cert( addr_name=f"{temp_template}_addr{i}", stake_vkey_file=p.stake.vkey_file) for i, p in enumerate(selected_users) ] # create TX data tx_files = clusterlib.TxFiles( certificate_files=[*stake_addr_dereg_certs], signing_key_files=[ *[p.payment.skey_file for p in selected_users], *[p.stake.skey_file for p in selected_users], ], ) # calculate TX fee tx_fee = cluster.calculate_tx_fee(src_address=src_address, tx_name=temp_template, tx_files=tx_files) assert tx_fee == expected_fee, "Expected fee doesn't match the actual fee"
def test_negative_fee( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord], fee: int, ): """Try to send a transaction with negative fee (property-based test). Expect failure. """ temp_template = f"{helpers.get_func_name()}_{clusterlib_utils.get_timestamped_rand_str()}" src_address = payment_addrs[0].address dst_address = payment_addrs[1].address destinations = [clusterlib.TxOut(address=dst_address, amount=10)] tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file]) with pytest.raises(clusterlib.CLIError) as excinfo: cluster.send_funds( src_address=src_address, destinations=destinations, tx_name=temp_template, tx_files=tx_files, fee=fee, ) assert "option --fee: cannot parse value" in str(excinfo.value)
def wait_for_stake_distribution(cluster_obj: clusterlib.ClusterLib) -> dict: """Wait to 3rd epoch (if necessary) and return stake distribution info.""" last_block_epoch = cluster_obj.get_last_block_epoch() if last_block_epoch < 3: new_epochs = 3 - last_block_epoch LOGGER.info( f"Waiting {new_epochs} epoch(s) to get stake distribution.") cluster_obj.wait_for_new_epoch(new_epochs) return cluster_obj.get_stake_distribution()
def _create_pool_certificates( self, cluster_obj: clusterlib.ClusterLib, pool_owners: List[clusterlib.PoolUser], temp_template: str, pool_data: clusterlib.PoolData, ) -> Tuple[str, clusterlib.TxFiles]: """Create certificates for registering a stake pool, delegating stake address.""" # create node VRF key pair node_vrf = cluster_obj.gen_vrf_key_pair(node_name=pool_data.pool_name) # create node cold key pair and counter node_cold = cluster_obj.gen_cold_key_pair_and_counter( node_name=pool_data.pool_name) # create stake address registration certs stake_addr_reg_cert_files = [ cluster_obj.gen_stake_addr_registration_cert( addr_name=f"{temp_template}_addr{i}", stake_vkey_file=p.stake.vkey_file) for i, p in enumerate(pool_owners) ] # create stake address delegation cert stake_addr_deleg_cert_files = [ cluster_obj.gen_stake_addr_delegation_cert( addr_name=f"{temp_template}_addr{i}", stake_vkey_file=p.stake.vkey_file, cold_vkey_file=node_cold.vkey_file, ) for i, p in enumerate(pool_owners) ] # create stake pool registration cert pool_reg_cert_file = cluster_obj.gen_pool_registration_cert( pool_data=pool_data, vrf_vkey_file=node_vrf.vkey_file, cold_vkey_file=node_cold.vkey_file, owner_stake_vkey_files=[p.stake.vkey_file for p in pool_owners], ) src_address = pool_owners[0].payment.address # register and delegate stake address, create and register pool tx_files = clusterlib.TxFiles( certificate_files=[ pool_reg_cert_file, *stake_addr_reg_cert_files, *stake_addr_deleg_cert_files, ], signing_key_files=[ *[p.payment.skey_file for p in pool_owners], *[p.stake.skey_file for p in pool_owners], node_cold.skey_file, ], ) return src_address, tx_files
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_addr = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address num_of_skeys = random.randrange(required, skeys_len) multisig_tx( cluster_obj=cluster, temp_template=temp_template, src_address=payment_addrs[0].address, dst_address=script_addr, 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_addr, 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 save_ledger_state( cluster_obj: clusterlib.ClusterLib, name_template: str, destination_dir: FileType = ".", ) -> Path: """Save ledger state.""" name_template = name_template or get_timestamped_rand_str(0) json_file = Path(destination_dir) / f"{name_template}_ledger_state.json" cluster_obj.query_cli( ["ledger-state", *cluster_obj.era_arg, "--out-file", str(json_file)]) return json_file
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_tip()["slotNo"] - 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_addr = 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_addr, 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_addr, 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_normal_tx_from_script_addr( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Try to send funds from script address using TX signed with skeys. Sending funds from script address is expected to fail when not using witness files. """ 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.ANY, payment_vkey_files=payment_vkey_files, ) # create script address script_addr = 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_addr, amount=300_000, multisig_script=multisig_script, payment_skey_files=[payment_skey_files[0]], ) # send funds from script address destinations_from = [ clusterlib.TxOut(address=payment_addrs[0].address, amount=1000) ] tx_files_from = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file]) # cannot send the TX without signing it using witness files with pytest.raises(clusterlib.CLIError) as excinfo: cluster.send_funds( src_address=script_addr, tx_name=temp_template, destinations=destinations_from, tx_files=tx_files_from, ) assert "MissingScriptWitnessesUTXOW" in str(excinfo.value)
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_addr = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # send funds to script address num_of_skeys = random.randrange(required, skeys_len) multisig_tx( cluster_obj=cluster, temp_template=f"{temp_template}_to", src_address=payment_addrs[0].address, dst_address=script_addr, 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_addr, 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_pool_registration_fees( self, cluster: clusterlib.ClusterLib, temp_dir: Path, pool_users: List[clusterlib.PoolUser], addr_fee: Tuple[int, int], ): """Test pool registration fees.""" no_of_addr, expected_fee = addr_fee rand_str = clusterlib.get_rand_str(4) temp_template = f"{helpers.get_func_name()}_{rand_str}_{no_of_addr}" pool_name = f"pool_{rand_str}" pool_metadata = { "name": pool_name, "description": "Shelley QA E2E test Test", "ticker": "QA1", "homepage": "www.test1.com", } pool_metadata_file = helpers.write_json( temp_dir / f"{pool_name}_registration_metadata.json", pool_metadata) pool_data = clusterlib.PoolData( pool_name=pool_name, pool_pledge=1000, pool_cost=15, pool_margin=0.2, pool_metadata_url="https://www.where_metadata_file_is_located.com", pool_metadata_hash=cluster.gen_pool_metadata_hash( pool_metadata_file), ) # create pool owners selected_owners = pool_users[:no_of_addr] # create certificates src_address, tx_files = self._create_pool_certificates( cluster_obj=cluster, pool_owners=selected_owners, temp_template=temp_template, pool_data=pool_data, ) # calculate TX fee tx_fee = cluster.calculate_tx_fee(src_address=src_address, tx_name=temp_template, tx_files=tx_files) assert tx_fee == expected_fee, "Expected fee doesn't match the actual fee"
def load_registered_pool_data(cluster_obj: clusterlib.ClusterLib, pool_name: str, pool_id: str) -> clusterlib.PoolData: """Load data of existing registered pool.""" if pool_id.startswith("pool"): pool_id = helpers.decode_bech32(pool_id) pool_state: dict = cluster_obj.get_registered_stake_pools_ledger_state( ).get(pool_id) or {} metadata = pool_state.get("metadata") or {} # TODO: extend to handle more relays records relays_list = pool_state.get("relays") or [] relay = relays_list[0] if relays_list else {} relay = relay.get("single host address") or {} pool_data = clusterlib.PoolData( pool_name=pool_name, pool_pledge=pool_state["pledge"], pool_cost=pool_state["cost"], pool_margin=pool_state["margin"], pool_metadata_url=metadata.get("url") or "", pool_metadata_hash=metadata.get("hash") or "", pool_relay_ipv4=relay.get("IPv4") or "", pool_relay_port=relay.get("port") or 0, ) return pool_data
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_tip()["slotNo"] + 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_addr = 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_addr, 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_addr, 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_tip()["slotNo"] + 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_addr = 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_addr, 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_addr, 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 update_params( cluster_obj: clusterlib.ClusterLib, src_addr_record: clusterlib.AddressRecord, update_proposals: List[UpdateProposal], ) -> None: """Update params using update proposal.""" _cli_args = [(u.arg, str(u.value)) for u in update_proposals] cli_args = list(itertools.chain.from_iterable(_cli_args)) with helpers.FileLockIfXdist( f"{helpers.TEST_TEMP_DIR}/update_params.lock"): LOGGER.info("Waiting for new epoch to submit proposal.") cluster_obj.wait_for_new_epoch() cluster_obj.submit_update_proposal( cli_args=cli_args, src_address=src_addr_record.address, src_skey_file=src_addr_record.skey_file, tx_name=get_timestamped_rand_str(), ) LOGGER.info(f"Update Proposal submitted ({cli_args})") cluster_obj.wait_for_new_epoch() protocol_params = cluster_obj.get_protocol_params() for u in update_proposals: # TODO: handle nested dictionaries if not u.name: continue updated_value = protocol_params[u.name] if str(updated_value) != str(u.value): raise AssertionError( f"Cluster update proposal failed! Param value for {u.name}: {updated_value}.\n" f"Expected: {u.value}\n" f"Tip: {cluster_obj.get_tip()}")
def test_tx_script_invalid(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Build transaction with invalid auxiliary script. Expect failure. """ temp_template = helpers.get_func_name() tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file], script_files=[self.JSON_METADATA_FILE], # not valid script file ) with pytest.raises(clusterlib.CLIError) as excinfo: cluster.send_tx(src_address=payment_addrs[0].address, tx_name=temp_template, tx_files=tx_files) assert 'Error in $: key "type" not found' in str(excinfo.value)
def test_multisig_all(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Send funds to and from script address using the *all* 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] # 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_addr = 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_addr, 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_addr, dst_address=payment_addrs[0].address, amount=1000, multisig_script=multisig_script, payment_skey_files=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 _from_to_transactions( self, cluster_obj: clusterlib.ClusterLib, tx_name: str, pool_users: List[clusterlib.PoolUser], from_num: int, to_num: int, amount_expected: Tuple[int, int], ): """Check fees for 1 tx from `from_num` payment addresses to `to_num` payment addresses.""" amount, expected_fee = amount_expected src_address = pool_users[0].payment.address # addr1..addr<from_num+1> from_addr_recs = [p.payment for p in pool_users[1:from_num + 1]] # addr<from_num+1>..addr<from_num+to_num+1> dst_addresses = [ pool_users[i].payment.address for i in range(from_num + 1, from_num + to_num + 1) ] # create TX data _txins = [cluster_obj.get_utxo(r.address) for r in from_addr_recs] # flatten the list of lists that is _txins txins = list(itertools.chain.from_iterable(_txins)) txouts = [ clusterlib.TxOut(address=addr, amount=amount) for addr in dst_addresses ] tx_files = clusterlib.TxFiles( signing_key_files=[r.skey_file for r in from_addr_recs]) # calculate TX fee tx_fee = cluster_obj.calculate_tx_fee(src_address=src_address, tx_name=tx_name, txins=txins, txouts=txouts, tx_files=tx_files) assert tx_fee == expected_fee, "Expected fee doesn't match the actual fee"
def return_funds_to_faucet( *src_addrs: clusterlib.AddressRecord, cluster_obj: clusterlib.ClusterLib, faucet_addr: str, amount: int = -1, tx_name: Optional[str] = None, destination_dir: FileType = ".", ) -> None: """Send `amount` from all `src_addrs` to `faucet_addr`. The amount of "-1" means all available funds. """ tx_name = tx_name or get_timestamped_rand_str() tx_name = f"{tx_name}_return_funds" with helpers.FileLockIfXdist( f"{helpers.TEST_TEMP_DIR}/{faucet_addr}.lock"): try: logging.disable(logging.ERROR) for src in src_addrs: fund_dst = [ clusterlib.TxOut(address=faucet_addr, amount=amount) ] fund_tx_files = clusterlib.TxFiles( signing_key_files=[src.skey_file]) # try to return funds; don't mind if there's not enough funds for fees etc. try: cluster_obj.send_funds( src_address=src.address, destinations=fund_dst, tx_name=tx_name, tx_files=fund_tx_files, destination_dir=destination_dir, ) cluster_obj.wait_for_new_block(new_blocks=2) except Exception: pass finally: logging.disable(logging.NOTSET)
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_addr = cluster.gen_script_addr(addr_name=temp_template, script_file=multisig_script) # check script address length assert len(script_addr) == len(payment_addrs[0].address)
def create_stake_addr_records( *names: str, cluster_obj: clusterlib.ClusterLib, destination_dir: FileType = ".", ) -> List[clusterlib.AddressRecord]: """Create new stake address(es).""" addrs = [ cluster_obj.gen_stake_addr_and_keys(name=name, destination_dir=destination_dir) for name in names ] LOGGER.debug(f"Created {len(addrs)} stake address(es)") return addrs
def test_smaller_fee( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord], fee_change: float, ): """Try to send a transaction with smaller-than-expected fee. Expect failure. """ temp_template = f"{helpers.get_func_name()}_{fee_change}" src_address = payment_addrs[0].address dst_address = payment_addrs[1].address destinations = [clusterlib.TxOut(address=dst_address, amount=10)] tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file]) fee = 0.0 if fee_change: fee = (cluster.calculate_tx_fee( src_address=src_address, tx_name=temp_template, txouts=destinations, tx_files=tx_files, ) / fee_change) with pytest.raises(clusterlib.CLIError) as excinfo: cluster.send_funds( src_address=src_address, destinations=destinations, tx_name=temp_template, tx_files=tx_files, fee=int(fee), ) assert "FeeTooSmallUTxO" 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_addr = 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_addr) # send funds to script address destinations = [clusterlib.TxOut(address=script_addr, 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_addr) == dst_init_balance + amount ), f"Incorrect balance for destination address `{script_addr}`"
def create_payment_addr_records( *names: str, cluster_obj: clusterlib.ClusterLib, stake_vkey_file: Optional[FileType] = None, destination_dir: FileType = ".", ) -> List[clusterlib.AddressRecord]: """Create new payment address(es).""" addrs = [ cluster_obj.gen_payment_addr_and_keys( name=name, stake_vkey_file=stake_vkey_file, destination_dir=destination_dir, ) for name in names ] LOGGER.debug(f"Created {len(addrs)} payment address(es)") return addrs
def withdraw_reward( cluster_obj: clusterlib.ClusterLib, pool_user: clusterlib.PoolUser, name_template: str, dst_addr_record: Optional[clusterlib.AddressRecord] = None, ) -> None: """Withdraw rewards to payment address.""" dst_addr_record = dst_addr_record or pool_user.payment dst_address = dst_addr_record.address src_init_balance = cluster_obj.get_address_balance(dst_address) tx_files_withdrawal = clusterlib.TxFiles(signing_key_files=[ dst_addr_record.skey_file, pool_user.stake.skey_file ], ) this_epoch = cluster_obj.get_last_block_epoch() tx_raw_withdrawal_output = cluster_obj.send_tx( src_address=dst_address, tx_name=f"{name_template}_reward_withdrawal", tx_files=tx_files_withdrawal, withdrawals=[ clusterlib.TxOut(address=pool_user.stake.address, amount=-1) ], ) cluster_obj.wait_for_new_block(new_blocks=2) if this_epoch != cluster_obj.get_last_block_epoch(): LOGGER.warning( "New epoch during rewards withdrawal! Reward account may not be empty." ) else: # check that reward is 0 assert (cluster_obj.get_stake_addr_info( pool_user.stake.address).reward_account_balance == 0 ), "Not all rewards were transfered" # check that rewards were transfered src_reward_balance = cluster_obj.get_address_balance(dst_address) assert (src_reward_balance == src_init_balance - tx_raw_withdrawal_output.fee + tx_raw_withdrawal_output.withdrawals[0].amount # type: ignore ), f"Incorrect balance for destination address `{dst_address}`"
def test_expected_or_higher_fee( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord], fee_add: int, ): """Send a transaction with fee that is same or higher than expected.""" temp_template = f"{helpers.get_func_name()}_{fee_add}" amount = 100 src_address = payment_addrs[0].address dst_address = payment_addrs[1].address src_init_balance = cluster.get_address_balance(src_address) dst_init_balance = cluster.get_address_balance(dst_address) destinations = [clusterlib.TxOut(address=dst_address, amount=amount)] tx_files = clusterlib.TxFiles( signing_key_files=[payment_addrs[0].skey_file]) fee = (cluster.calculate_tx_fee( src_address=src_address, tx_name=temp_template, txouts=destinations, tx_files=tx_files, ) + fee_add) tx_raw_output = cluster.send_funds( src_address=src_address, destinations=destinations, tx_name=temp_template, tx_files=tx_files, fee=fee, ) cluster.wait_for_new_block(new_blocks=2) assert tx_raw_output.fee == fee, "The actual fee doesn't match the specified fee" assert (cluster.get_address_balance(src_address) == src_init_balance - tx_raw_output.fee - len(destinations) * amount ), f"Incorrect balance for source address `{src_address}`" assert (cluster.get_address_balance(dst_address) == dst_init_balance + amount ), f"Incorrect balance for destination address `{dst_address}`"
def test_pool_deregistration_fees( self, cluster: clusterlib.ClusterLib, temp_dir: Path, pool_users: List[clusterlib.PoolUser], addr_fee: Tuple[int, int], ): """Test pool deregistration fees.""" no_of_addr, expected_fee = addr_fee rand_str = clusterlib.get_rand_str(4) temp_template = f"{helpers.get_func_name()}_{rand_str}_{no_of_addr}" src_address = pool_users[0].payment.address pool_name = f"pool_{rand_str}" pool_metadata = { "name": pool_name, "description": "Shelley QA E2E test Test", "ticker": "QA1", "homepage": "www.test1.com", } pool_metadata_file = helpers.write_json( temp_dir / f"{pool_name}_registration_metadata.json", pool_metadata) pool_data = clusterlib.PoolData( pool_name=pool_name, pool_pledge=222, pool_cost=123, pool_margin=0.512, pool_metadata_url="https://www.where_metadata_file_is_located.com", pool_metadata_hash=cluster.gen_pool_metadata_hash( pool_metadata_file), ) # create pool owners selected_owners = pool_users[:no_of_addr] # create node cold key pair and counter node_cold = cluster.gen_cold_key_pair_and_counter( node_name=pool_data.pool_name) # create deregistration certificate pool_dereg_cert_file = cluster.gen_pool_deregistration_cert( pool_name=pool_data.pool_name, cold_vkey_file=node_cold.vkey_file, epoch=cluster.get_last_block_epoch() + 1, ) # submit the pool deregistration certificate through a tx tx_files = clusterlib.TxFiles( certificate_files=[pool_dereg_cert_file], signing_key_files=[ *[p.payment.skey_file for p in selected_owners], *[p.stake.skey_file for p in selected_owners], node_cold.skey_file, ], ) # calculate TX fee tx_fee = cluster.calculate_tx_fee(src_address=src_address, tx_name=temp_template, tx_files=tx_files) assert tx_fee == expected_fee, "Expected fee doesn't match the actual fee"