def test_delegate_addr_with_wrong_key(
        self,
        cluster_and_pool: Tuple[clusterlib.ClusterLib, str],
        pool_users: List[clusterlib.PoolUser],
        pool_users_disposable: List[clusterlib.PoolUser],
    ):
        """Try to delegate stake address using wrong payment skey.

        Expect failure.
        """
        cluster, pool_id = cluster_and_pool
        temp_template = common.get_test_id(cluster)

        user_registered = pool_users_disposable[0]
        user_payment = pool_users[0].payment

        # create stake address registration cert
        stake_addr_reg_cert_file = cluster.gen_stake_addr_registration_cert(
            addr_name=f"{temp_template}_addr0",
            stake_vkey_file=user_registered.stake.vkey_file)

        # register stake address
        tx_files = clusterlib.TxFiles(
            certificate_files=[stake_addr_reg_cert_file],
            signing_key_files=[user_payment.skey_file],
        )
        cluster.send_tx(src_address=user_payment.address,
                        tx_name=f"{temp_template}_reg",
                        tx_files=tx_files)

        # create stake address delegation cert
        stake_addr_deleg_cert_file = cluster.gen_stake_addr_delegation_cert(
            addr_name=f"{temp_template}_addr0",
            stake_vkey_file=user_registered.stake.vkey_file,
            stake_pool_id=pool_id,
        )

        # delegate stake address, use wrong payment skey
        tx_files = clusterlib.TxFiles(
            certificate_files=[stake_addr_deleg_cert_file],
            signing_key_files=[pool_users[1].payment.skey_file],
        )

        with pytest.raises(clusterlib.CLIError) as excinfo:
            cluster.send_tx(
                src_address=user_payment.address,
                tx_name=f"{temp_template}_deleg",
                tx_files=tx_files,
            )
        assert "MissingVKeyWitnessesUTXOW" in str(excinfo.value)
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
    cluster_obj.withdraw_reward(
        stake_addr_record=pool_user.stake,
        dst_addr_record=pool_user.payment,
        tx_name=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,
    )
    return tx_raw_output
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 helpers.get_timestamped_rand_str()
    tx_name = f"{tx_name}_return_funds"
    with helpers.FileLockIfXdist(f"{helpers.get_basetemp()}/{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,
                    )
                except Exception:
                    pass
        finally:
            logging.disable(logging.NOTSET)
    def test_transfer_to_rewards(self, cluster: clusterlib.ClusterLib,
                                 pool_user: clusterlib.PoolUser):
        """Send funds from the treasury pot to the reserves pot.

        Expected to fail until Alonzo.
        """
        temp_template = helpers.get_func_name()
        amount = 50_000

        mir_cert = cluster.gen_mir_cert_to_rewards(transfer=amount,
                                                   tx_name=temp_template)
        tx_files = clusterlib.TxFiles(
            certificate_files=[mir_cert],
            signing_key_files=[
                pool_user.payment.skey_file,
                *cluster.genesis_keys.delegate_skeys
            ],
        )

        # send the transaction at the beginning of an epoch
        if cluster.time_from_epoch_start() > (cluster.epoch_length_sec // 6):
            cluster.wait_for_new_epoch()

        # fail is expected until Alonzo
        with pytest.raises(clusterlib.CLIError) as excinfo:
            cluster.send_tx(
                src_address=pool_user.payment.address,
                tx_name=temp_template,
                tx_files=tx_files,
            )
        assert "MIRTransferNotCurrentlyAllowed" in str(excinfo.value)
def register_stake_address(cluster_obj: clusterlib.ClusterLib,
                           pool_user: clusterlib.PoolUser,
                           name_template: str) -> clusterlib.TxRawOutput:
    """Register stake address."""
    # files for registering stake address
    addr_reg_cert = cluster_obj.gen_stake_addr_registration_cert(
        addr_name=name_template,
        stake_vkey_file=pool_user.stake.vkey_file,
    )
    tx_files = clusterlib.TxFiles(
        certificate_files=[addr_reg_cert],
        signing_key_files=[
            pool_user.payment.skey_file, pool_user.stake.skey_file
        ],
    )

    tx_raw_output = cluster_obj.send_tx(
        src_address=pool_user.payment.address,
        tx_name=f"{name_template}_reg_stake_addr",
        tx_files=tx_files,
    )

    if not cluster_obj.get_stake_addr_info(pool_user.stake.address):
        raise AssertionError(
            f"The address {pool_user.stake.address} was not registered.")

    return tx_raw_output
    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 helpers.is_in_interval(
            tx_fee, expected_fee), "Expected fee doesn't match the actual fee"
Exemple #7
0
def withdraw_reward(
    cluster_obj: clusterlib.ClusterLib,
    stake_addr_record: clusterlib.AddressRecord,
    dst_addr_record: clusterlib.AddressRecord,
    name_template: str,
) -> None:
    """Withdraw rewards to payment address."""
    dst_address = dst_addr_record.address

    tx_files_withdrawal = clusterlib.TxFiles(signing_key_files=[
        dst_addr_record.skey_file, stake_addr_record.skey_file
    ], )

    LOGGER.info(f"Withdrawing rewards for '{stake_addr_record.address}'")
    try:
        cluster_obj.send_tx(
            src_address=dst_address,
            tx_name=f"rf_{name_template}_reward_withdrawal",
            tx_files=tx_files_withdrawal,
            withdrawals=[
                clusterlib.TxOut(address=stake_addr_record.address, amount=-1)
            ],
        )
    except clusterlib.CLIError:
        return
    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()}_{helpers.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)
Exemple #9
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(address=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 helpers.is_in_interval(
            tx_fee, expected_fee
        ), "Expected fee doesn't match the actual fee"
Exemple #10
0
    def test_transfer_no_ada(
        self,
        cluster: clusterlib.ClusterLib,
        payment_addrs: List[clusterlib.AddressRecord],
        new_token: clusterlib_utils.TokenRecord,
    ):
        """Try to create an UTxO with just native tokens, no ADA. Expect failure."""
        temp_template = helpers.get_func_name()
        amount = 10

        src_address = new_token.token_mint_addr.address
        dst_address = payment_addrs[2].address

        destinations = [
            clusterlib.TxOut(address=dst_address,
                             amount=amount,
                             coin=new_token.token)
        ]
        tx_files = clusterlib.TxFiles(
            signing_key_files=[new_token.token_mint_addr.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,
            )
        assert "OutputTooSmallUTxO" in str(excinfo.value)
    def registered_user(
        self,
        cluster_manager: cluster_management.ClusterManager,
        cluster: clusterlib.ClusterLib,
        pool_user: clusterlib.PoolUser,
    ) -> clusterlib.PoolUser:
        """Register pool user's stake address."""
        with cluster_manager.cache_fixture() as fixture_cache:
            if fixture_cache.value:
                return fixture_cache.value  # type: ignore
            fixture_cache.value = pool_user

        temp_template = f"test_mir_certs_ci{cluster_manager.cluster_instance}"

        addr_reg_cert = cluster.gen_stake_addr_registration_cert(
            addr_name=temp_template,
            stake_vkey_file=pool_user.stake.vkey_file,
        )
        tx_files = clusterlib.TxFiles(
            certificate_files=[addr_reg_cert],
            signing_key_files=[
                pool_user.payment.skey_file, pool_user.stake.skey_file
            ],
        )
        cluster.send_tx(src_address=pool_user.payment.address,
                        tx_name=f"{temp_template}_reg",
                        tx_files=tx_files)
        assert cluster.get_stake_addr_info(
            pool_user.stake.address
        ), f"The address {pool_user.stake.address} was not registered"

        return pool_user
Exemple #12
0
    def test_transfer_tokens(
        self,
        cluster: clusterlib.ClusterLib,
        payment_addrs: List[clusterlib.AddressRecord],
        new_token: clusterlib_utils.TokenRecord,
        amount: int,
    ):
        """Test sending tokens to payment address.

        * send tokens from 1 source address to 1 destination address
        * check expected token balances for both source and destination addresses
        * check fees in Lovelace
        """
        temp_template = f"{helpers.get_func_name()}_{amount}"
        amount_lovelace = 10

        src_address = new_token.token_mint_addr.address
        dst_address = payment_addrs[2].address

        src_init_balance = cluster.get_address_balance(src_address)
        src_init_balance_token = cluster.get_address_balance(
            src_address, coin=new_token.token)
        dst_init_balance_token = cluster.get_address_balance(
            dst_address, coin=new_token.token)

        destinations = [
            clusterlib.TxOut(address=dst_address,
                             amount=amount,
                             coin=new_token.token),
            clusterlib.TxOut(address=dst_address, amount=amount_lovelace),
        ]
        tx_files = clusterlib.TxFiles(
            signing_key_files=[new_token.token_mint_addr.skey_file])

        tx_raw_output = cluster.send_funds(
            src_address=src_address,
            destinations=destinations,
            tx_name=temp_template,
            tx_files=tx_files,
        )
        cluster.wait_for_new_block(new_blocks=2)

        assert (
            cluster.get_address_balance(
                src_address,
                coin=new_token.token) == src_init_balance_token - amount
        ), f"Incorrect token balance for source address `{src_address}`"

        assert (
            cluster.get_address_balance(src_address) == src_init_balance -
            tx_raw_output.fee - amount_lovelace
        ), f"Incorrect Lovelace balance for source address `{src_address}`"

        assert (
            cluster.get_address_balance(
                dst_address,
                coin=new_token.token) == dst_init_balance_token + amount
        ), f"Incorrect token balance for destination address `{dst_address}`"
    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
Exemple #14
0
def mint_or_burn_sign(
    cluster_obj: clusterlib.ClusterLib,
    new_tokens: List[TokenRecord],
    temp_template: str,
) -> clusterlib.TxRawOutput:
    """Mint or burn tokens, depending on the `amount` value. Sign using skeys.

    Positive `amount` value means minting, negative means burning.
    """
    _issuers_addrs = [n.issuers_addrs for n in new_tokens]
    issuers_addrs = list(itertools.chain.from_iterable(_issuers_addrs))
    issuers_skey_files = [p.skey_file for p in issuers_addrs]
    token_mint_addr_skey_files = [
        t.token_mint_addr.skey_file for t in new_tokens
    ]
    src_address = new_tokens[0].token_mint_addr.address

    tx_files = clusterlib.TxFiles(
        signing_key_files=[*issuers_skey_files, *token_mint_addr_skey_files])

    # build and sign a transaction
    ttl = cluster_obj.calculate_tx_ttl()
    fee = cluster_obj.calculate_tx_fee(
        src_address=src_address,
        tx_name=temp_template,
        tx_files=tx_files,
        ttl=ttl,
        # TODO: workaround for https://github.com/input-output-hk/cardano-node/issues/1892
        witness_count_add=len(issuers_skey_files) * 2,
    )
    tx_raw_output = cluster_obj.build_raw_tx(
        src_address=src_address,
        tx_name=temp_template,
        tx_files=tx_files,
        fee=fee,
        ttl=ttl,
        mint=[
            clusterlib.TxOut(address=n.token_mint_addr.address,
                             amount=n.amount,
                             coin=n.token) for n in new_tokens
        ],
    )
    out_file_signed = cluster_obj.sign_tx(
        tx_body_file=tx_raw_output.out_file,
        signing_key_files=tx_files.signing_key_files,
        tx_name=temp_template,
        script_files=[n.script for n in new_tokens],
    )

    # submit signed transaction
    cluster_obj.submit_tx(out_file_signed)
    cluster_obj.wait_for_new_block(new_blocks=2)

    return tx_raw_output
    def test_delegate_unknown_addr(
        self,
        cluster_and_pool: Tuple[clusterlib.ClusterLib, str],
        pool_users: List[clusterlib.PoolUser],
        pool_users_disposable: List[clusterlib.PoolUser],
        use_build_cmd: bool,
    ):
        """Try to delegate unknown stake address.

        Expect failure.
        """
        cluster, pool_id = cluster_and_pool
        temp_template = f"{common.get_test_id(cluster)}_{use_build_cmd}"

        user_registered = pool_users_disposable[0]
        user_payment = pool_users[0].payment

        # create stake address delegation cert
        stake_addr_deleg_cert_file = cluster.gen_stake_addr_delegation_cert(
            addr_name=f"{temp_template}_addr0",
            stake_vkey_file=user_registered.stake.vkey_file,
            stake_pool_id=pool_id,
        )

        # delegate unknown stake address
        tx_files = clusterlib.TxFiles(
            certificate_files=[stake_addr_deleg_cert_file],
            signing_key_files=[
                user_payment.skey_file, user_registered.stake.skey_file
            ],
        )

        with pytest.raises(clusterlib.CLIError) as excinfo:
            if use_build_cmd:
                tx_raw_output = cluster.build_tx(
                    src_address=user_payment.address,
                    tx_name=f"{temp_template}_deleg_unknown",
                    tx_files=tx_files,
                    fee_buffer=2_000_000,
                    witness_override=len(tx_files.signing_key_files),
                )
                tx_signed = cluster.sign_tx(
                    tx_body_file=tx_raw_output.out_file,
                    signing_key_files=tx_files.signing_key_files,
                    tx_name=f"{temp_template}_deleg_unknown",
                )
                cluster.submit_tx(tx_file=tx_signed, txins=tx_raw_output.txins)
            else:
                cluster.send_tx(
                    src_address=user_payment.address,
                    tx_name=f"{temp_template}_deleg_unknown",
                    tx_files=tx_files,
                )
        assert "StakeDelegationImpossibleDELEG" in str(excinfo.value)
Exemple #16
0
def _fund_issuer(
    cluster_obj: clusterlib.ClusterLib,
    temp_template: str,
    payment_addr: clusterlib.AddressRecord,
    issuer_addr: clusterlib.AddressRecord,
    amount: int,
    collateral_amount: int,
) -> Tuple[List[clusterlib.UTXOData], List[clusterlib.UTXOData],
           clusterlib.TxRawOutput]:
    """Fund the token issuer."""
    issuer_init_balance = cluster_obj.get_address_balance(issuer_addr.address)

    tx_files = clusterlib.TxFiles(signing_key_files=[payment_addr.skey_file], )
    txouts = [
        clusterlib.TxOut(
            address=issuer_addr.address,
            amount=amount,
        ),
        clusterlib.TxOut(address=issuer_addr.address,
                         amount=collateral_amount),
    ]
    tx_output = cluster_obj.build_tx(
        src_address=payment_addr.address,
        tx_name=f"{temp_template}_step1",
        tx_files=tx_files,
        txouts=txouts,
        fee_buffer=2_000_000,
        # don't join 'change' and 'collateral' txouts, we need separate UTxOs
        join_txouts=False,
    )
    tx_signed = cluster_obj.sign_tx(
        tx_body_file=tx_output.out_file,
        signing_key_files=tx_files.signing_key_files,
        tx_name=f"{temp_template}_step1",
    )
    cluster_obj.submit_tx(tx_file=tx_signed, txins=tx_output.txins)

    issuer_balance = cluster_obj.get_address_balance(issuer_addr.address)
    assert (
        issuer_balance == issuer_init_balance + amount + collateral_amount
    ), f"Incorrect balance for token issuer address `{issuer_addr.address}`"

    txid = cluster_obj.get_txid(tx_body_file=tx_output.out_file)
    mint_utxos = cluster_obj.get_utxo(txin=f"{txid}#1")
    collateral_utxos = [
        clusterlib.UTXOData(utxo_hash=txid,
                            utxo_ix=2,
                            amount=collateral_amount,
                            address=issuer_addr.address)
    ]

    return mint_utxos, collateral_utxos, tx_output
Exemple #17
0
    def test_exceed_pay_stake_addr_from(
        self,
        cluster_pots: clusterlib.ClusterLib,
        registered_users: List[clusterlib.PoolUser],
        fund_src: str,
    ):
        """Try to send more funds than available from the reserves or treasury pot to stake address.

        Expect failure.

        * generate an MIR certificate
        * submit a TX with the MIR certificate
        * check that submitting the transaction fails with an expected error
        """
        temp_template = f"{common.get_test_id(cluster_pots)}_{fund_src}"
        cluster = cluster_pots
        amount = 30_000_000_000_000_000
        registered_user = registered_users[0]

        init_balance = cluster.get_address_balance(
            registered_user.payment.address)

        mir_cert = cluster.gen_mir_cert_stake_addr(
            stake_addr=registered_user.stake.address,
            reward=amount,
            tx_name=temp_template,
            use_treasury=fund_src == self.TREASURY,
        )
        tx_files = clusterlib.TxFiles(
            certificate_files=[mir_cert],
            signing_key_files=[
                registered_user.payment.skey_file,
                *cluster.genesis_keys.delegate_skeys,
            ],
        )

        # send the transaction at the beginning of an epoch
        if cluster.time_from_epoch_start() > (cluster.epoch_length_sec // 6):
            cluster.wait_for_new_epoch()

        with pytest.raises(clusterlib.CLIError) as excinfo:
            cluster.send_tx(
                src_address=registered_user.payment.address,
                tx_name=temp_template,
                tx_files=tx_files,
            )
        assert "InsufficientForInstantaneousRewardsDELEG" in str(excinfo.value)

        assert (
            cluster.get_address_balance(
                registered_user.payment.address) == init_balance
        ), f"Incorrect balance for source address `{registered_user.payment.address}`"
    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}`"
Exemple #19
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"{common.get_test_id(cluster)}_{fee_add}"
        amount = 2_000_000

        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,
        )

        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_deregister_not_registered_addr(
        self,
        cluster: clusterlib.ClusterLib,
        pool_users: List[clusterlib.PoolUser],
        pool_users_disposable: List[clusterlib.PoolUser],
        use_build_cmd: bool,
    ):
        """Deregister not registered stake address."""
        temp_template = f"{common.get_test_id(cluster)}_{use_build_cmd}"

        user_registered = pool_users_disposable[0]
        user_payment = pool_users[0].payment

        # files for deregistering stake address
        stake_addr_dereg_cert = cluster.gen_stake_addr_deregistration_cert(
            addr_name=f"{temp_template}_addr0",
            stake_vkey_file=user_registered.stake.vkey_file)
        tx_files = clusterlib.TxFiles(
            certificate_files=[stake_addr_dereg_cert],
            signing_key_files=[
                user_payment.skey_file, user_registered.stake.skey_file
            ],
        )

        with pytest.raises(clusterlib.CLIError) as excinfo:
            if use_build_cmd:
                tx_raw_output = cluster.build_tx(
                    src_address=user_payment.address,
                    tx_name=f"{temp_template}_dereg_fail",
                    tx_files=tx_files,
                    fee_buffer=2_000_000,
                    witness_override=len(tx_files.signing_key_files),
                )
                tx_signed = cluster.sign_tx(
                    tx_body_file=tx_raw_output.out_file,
                    signing_key_files=tx_files.signing_key_files,
                    tx_name=f"{temp_template}_dereg_fail",
                )
                cluster.submit_tx(tx_file=tx_signed, txins=tx_raw_output.txins)
            else:
                cluster.send_tx(
                    src_address=user_payment.address,
                    tx_name=f"{temp_template}_dereg_fail",
                    tx_files=tx_files,
                )
        assert "StakeKeyNotRegisteredDELEG" in str(excinfo.value)
def update_params_build(
    cluster_obj: clusterlib.ClusterLib,
    src_addr_record: clusterlib.AddressRecord,
    update_proposals: List[UpdateProposal],
) -> None:
    """Update params using update proposal.

    Uses `cardano-cli transaction build` command for building the transactions.
    """
    if not update_proposals:
        return

    _cli_args = [(u.arg, str(u.value)) for u in update_proposals]
    cli_args = list(itertools.chain.from_iterable(_cli_args))
    temp_template = helpers.get_timestamped_rand_str()

    # assumption is update proposals are submitted near beginning of epoch
    epoch = cluster_obj.get_epoch()

    out_file = cluster_obj.gen_update_proposal(
        cli_args=cli_args,
        epoch=epoch,
        tx_name=temp_template,
    )
    tx_files = clusterlib.TxFiles(
        proposal_files=[out_file],
        signing_key_files=[
            *cluster_obj.genesis_keys.delegate_skeys,
            Path(src_addr_record.skey_file),
        ],
    )
    tx_output = cluster_obj.build_tx(
        src_address=src_addr_record.address,
        tx_name=f"{temp_template}_submit_proposal",
        tx_files=tx_files,
        fee_buffer=2000_000,
    )
    tx_signed = cluster_obj.sign_tx(
        tx_body_file=tx_output.out_file,
        signing_key_files=tx_files.signing_key_files,
        tx_name=f"{temp_template}_submit_proposal",
    )
    cluster_obj.submit_tx(tx_file=tx_signed, txins=tx_output.txins)

    LOGGER.info(f"Update Proposal submitted ({cli_args})")
    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)
Exemple #23
0
    def test_shelley_cddl(self, cluster: clusterlib.ClusterLib,
                          payment_addrs: List[clusterlib.AddressRecord]):
        """Check expected failure when Shelley Tx is used with CDDL format."""
        temp_template = common.get_test_id(cluster)

        src_address = payment_addrs[0].address
        dst_address = payment_addrs[1].address

        # amount value -1 means all available funds
        destinations = [clusterlib.TxOut(address=dst_address, amount=-1)]
        tx_files = clusterlib.TxFiles(
            signing_key_files=[payment_addrs[1].skey_file])

        fee = cluster.calculate_tx_fee(
            src_address=src_address,
            tx_name=temp_template,
            txouts=destinations,
            tx_files=tx_files,
        )

        orig_cddl_value = cluster.use_cddl
        try:
            cluster.use_cddl = True
            tx_raw_output = cluster.build_raw_tx(
                src_address=src_address,
                tx_name=temp_template,
                txouts=destinations,
                tx_files=tx_files,
                fee=fee,
            )
        finally:
            cluster.use_cddl = orig_cddl_value

        with pytest.raises(clusterlib.CLIError) as excinfo:
            cluster.sign_tx(
                tx_body_file=tx_raw_output.out_file,
                signing_key_files=tx_files.signing_key_files,
                tx_name=temp_template,
            )
        if "TextEnvelope error" in str(excinfo.value):
            pytest.xfail("TextEnvelope error")
        else:
            pytest.fail(f"Unexpected error:\n{excinfo.value}")
    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"
Exemple #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"{common.get_test_id(cluster)}_{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 return_funds_to_faucet(
    cluster_obj: clusterlib.ClusterLib,
    src_addr: clusterlib.AddressRecord,
    faucet_address: str,
    tx_name: str,
) -> None:
    """Send funds from `src_addr` to `faucet_address`."""
    tx_name = f"rf_{tx_name}_return_funds"
    # the amount of "-1" means all available funds.
    fund_dst = [clusterlib.TxOut(address=faucet_address, amount=-1)]
    fund_tx_files = clusterlib.TxFiles(signing_key_files=[src_addr.skey_file])

    txins = cluster_obj.get_utxo(address=src_addr.address,
                                 coins=[clusterlib.DEFAULT_COIN])
    utxos_balance = functools.reduce(lambda x, y: x + y.amount, txins, 0)

    # skip if there no (or too little) Lovelace
    if utxos_balance < 1000_000:
        return

    # if the balance is too low, add a faucet UTxO so there's enough funds for fee
    # and the total amount is higher than min ADA value
    if utxos_balance < 3000_000:
        faucet_utxos = cluster_obj.get_utxo(address=faucet_address,
                                            coins=[clusterlib.DEFAULT_COIN])
        futxo = random.choice(faucet_utxos)
        txins.append(futxo)

    LOGGER.info(f"Returning funds from '{src_addr.address}'")
    # try to return funds; don't mind if there's not enough funds for fees etc.
    with contextlib.suppress(clusterlib.CLIError):
        cluster_obj.send_tx(
            src_address=src_addr.address,
            tx_name=tx_name,
            txins=txins,
            txouts=fund_dst,
            tx_files=fund_tx_files,
            verify_tx=False,
        )
Exemple #27
0
    def _mint_tx(
        self,
        cluster_obj: clusterlib.ClusterLib,
        new_tokens: List[clusterlib_utils.TokenRecord],
        temp_template: str,
    ) -> Path:
        """Return signed TX for minting new token. Sign using skeys."""
        _issuers_addrs = [n.issuers_addrs for n in new_tokens]
        issuers_addrs = list(itertools.chain.from_iterable(_issuers_addrs))
        issuers_skey_files = [p.skey_file for p in issuers_addrs]
        token_mint_addr_skey_files = [
            t.token_mint_addr.skey_file for t in new_tokens
        ]
        src_address = new_tokens[0].token_mint_addr.address

        tx_files = clusterlib.TxFiles(signing_key_files=[
            *issuers_skey_files, *token_mint_addr_skey_files
        ])

        # build and sign a transaction
        tx_raw_output = cluster_obj.build_raw_tx(
            src_address=src_address,
            tx_name=temp_template,
            tx_files=tx_files,
            fee=100_000,
            mint=[
                clusterlib.TxOut(address=n.token_mint_addr.address,
                                 amount=n.amount,
                                 coin=n.token) for n in new_tokens
            ],
        )
        out_file_signed = cluster_obj.sign_tx(
            tx_body_file=tx_raw_output.out_file,
            signing_key_files=tx_files.signing_key_files,
            tx_name=temp_template,
            script_files=[n.script for n in new_tokens],
        )

        return out_file_signed
def return_funds_to_faucet(
    *src_addrs: clusterlib.AddressRecord,
    cluster_obj: clusterlib.ClusterLib,
    faucet_addr: str,
    amount: Union[int, List[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 helpers.get_timestamped_rand_str()
    tx_name = f"{tx_name}_return_funds"
    if isinstance(amount, int):
        amount = [amount] * len(src_addrs)

    with locking.FileLockIfXdist(
            f"{temptools.get_basetemp()}/{faucet_addr}.lock"):
        try:
            logging.disable(logging.ERROR)
            for addr, amount_rec in zip(src_addrs, amount):
                fund_dst = [
                    clusterlib.TxOut(address=faucet_addr, amount=amount_rec)
                ]
                fund_tx_files = clusterlib.TxFiles(
                    signing_key_files=[addr.skey_file])
                # try to return funds; don't mind if there's not enough funds for fees etc.
                with contextlib.suppress(Exception):
                    cluster_obj.send_funds(
                        src_address=addr.address,
                        destinations=fund_dst,
                        tx_name=tx_name,
                        tx_files=fund_tx_files,
                        destination_dir=destination_dir,
                    )
        finally:
            logging.disable(logging.NOTSET)
Exemple #29
0
def _withdraw_rewards(
    *pool_users: clusterlib.PoolUser,
    cluster_obj: clusterlib.ClusterLib,
    tx_name: str,
) -> clusterlib.TxRawOutput:
    """Withdraw rewards from multiple stake addresses to corresponding payment addresses."""
    src_addr = pool_users[0].payment

    tx_files_withdrawal = clusterlib.TxFiles(signing_key_files=[
        src_addr.skey_file, *[p.stake.skey_file for p in pool_users]
    ], )

    tx_raw_withdrawal_output = cluster_obj.send_tx(
        src_address=src_addr.address,
        tx_name=f"{tx_name}_reward_withdrawals",
        tx_files=tx_files_withdrawal,
        withdrawals=[
            clusterlib.TxOut(address=p.stake.address, amount=-1)
            for p in pool_users
        ],
    )

    return tx_raw_withdrawal_output
def return_funds_to_faucet(
    cluster_obj: clusterlib.ClusterLib,
    src_addr: clusterlib.AddressRecord,
    faucet_addr: str,
    tx_name: str,
) -> None:
    """Send funds from `src_addr` to `faucet_addr`."""
    tx_name = f"rf_{tx_name}_return_funds"
    # the amount of "-1" means all available funds.
    fund_dst = [clusterlib.TxOut(address=faucet_addr, amount=-1)]
    fund_tx_files = clusterlib.TxFiles(signing_key_files=[src_addr.skey_file])

    LOGGER.info(f"Returning funds from '{src_addr.address}'")
    # try to return funds; don't mind if there's not enough funds for fees etc.
    try:
        cluster_obj.send_funds(
            src_address=src_addr.address,
            destinations=fund_dst,
            tx_name=tx_name,
            tx_files=fund_tx_files,
        )
    except clusterlib.CLIError:
        pass