Beispiel #1
0
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"
Beispiel #3
0
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()
Beispiel #4
0
    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"
Beispiel #5
0
    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)
Beispiel #6
0
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()
Beispiel #7
0
    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
Beispiel #8
0
    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)
Beispiel #9
0
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
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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,
            )
Beispiel #13
0
    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"
Beispiel #14
0
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
Beispiel #15
0
    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,
        )
Beispiel #16
0
    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)
Beispiel #17
0
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()}")
Beispiel #18
0
    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)
Beispiel #19
0
    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,
        )
Beispiel #20
0
    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"
Beispiel #21
0
    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"
Beispiel #22
0
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)
Beispiel #23
0
    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)
Beispiel #24
0
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
Beispiel #25
0
    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)
Beispiel #26
0
    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}`"
Beispiel #27
0
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
Beispiel #28
0
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}`"
Beispiel #29
0
    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}`"
Beispiel #30
0
    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"