def pool_user( self, cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> clusterlib.PoolUser: """Create pool user.""" with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore created_user = clusterlib_utils.create_pool_users( cluster_obj=cluster, name_template= f"test_mir_certs_ci{cluster_manager.cluster_instance}", no_of_addr=1, )[0] fixture_cache.value = created_user # fund source addresses clusterlib_utils.fund_from_faucet( created_user, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return created_user
def payment_addrs( self, cluster_manager: parallel_run.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create new payment addresses.""" data_key = id(TestTimeLocking) cached_value = cluster_manager.cache.test_data.get(data_key) if cached_value: return cached_value # type: ignore addrs = clusterlib_utils.create_payment_addr_records( *[ f"multi_addr_time_locking_ci{cluster_manager.cluster_instance}_{i}" for i in range(20) ], cluster_obj=cluster, ) cluster_manager.cache.test_data[data_key] = addrs # fund source addresses clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=20_000_000, ) return addrs
def payment_addrs( self, cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create 2 new payment addresses.""" with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore addrs = clusterlib_utils.create_payment_addr_records( f"addr_test_fee_ci{cluster_manager.cluster_instance}_0", f"addr_test_fee_ci{cluster_manager.cluster_instance}_1", cluster_obj=cluster, ) fixture_cache.value = addrs # fund source addresses clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return addrs
def pool_users( cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.PoolUser]: """Create pool users.""" with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore created_users = clusterlib_utils.create_pool_users( cluster_obj=cluster, name_template= f"test_delegation_pool_user_ci{cluster_manager.cluster_instance_num}", no_of_addr=2, ) fixture_cache.value = created_users # fund source addresses clusterlib_utils.fund_from_faucet( created_users[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return created_users
def payment_addr( self, cluster_manager: cluster_management.ClusterManager, cluster_update_proposal: clusterlib.ClusterLib, ) -> clusterlib.AddressRecord: """Create new payment address.""" cluster = cluster_update_proposal with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore addr = clusterlib_utils.create_payment_addr_records( f"addr_test_update_proposal_ci{cluster_manager.cluster_instance_num}_0", cluster_obj=cluster, )[0] fixture_cache.value = addr # fund source addresses clusterlib_utils.fund_from_faucet( addr, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return addr
def pool_users( self, cluster_manager: parallel_run.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.PoolUser]: """Create pool users.""" data_key = id(TestExpectedFees) cached_value = cluster_manager.cache.test_data.get(data_key) if cached_value: return cached_value # type: ignore created_users = clusterlib_utils.create_pool_users( cluster_obj=cluster, name_template= f"test_expected_fees_ci{cluster_manager.cluster_instance}", no_of_addr=201, ) cluster_manager.cache.test_data[data_key] = created_users # fund source addresses clusterlib_utils.fund_from_faucet( *created_users[:10], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return created_users
def payment_addrs( self, cluster_manager: parallel_run.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create 2 new payment addresses.""" data_key = id(TestFee) cached_value = cluster_manager.cache.test_data.get(data_key) if cached_value: return cached_value # type: ignore addrs = clusterlib_utils.create_payment_addr_records( f"addr_test_fee_ci{cluster_manager.cluster_instance}_0", f"addr_test_fee_ci{cluster_manager.cluster_instance}_1", cluster_obj=cluster, ) cluster_manager.cache.test_data[data_key] = addrs # fund source addresses clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return addrs
def payment_addrs( self, cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create 2 new payment addresses.""" if cluster.use_cddl: pytest.skip("runs only when `cluster.use_cddl == False`") with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore addrs = clusterlib_utils.create_payment_addr_records( f"addr_shelley_cddl_ci{cluster_manager.cluster_instance_num}_0", f"addr_shelley_cddl_ci{cluster_manager.cluster_instance_num}_1", cluster_obj=cluster, ) fixture_cache.value = addrs # fund source addresses clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return addrs
def payment_addr( self, cluster_manager: parallel_run.ClusterManager, cluster_update_proposal: clusterlib.ClusterLib, ) -> clusterlib.AddressRecord: """Create new payment address.""" data_key = id(TestBasic) cached_value = cluster_manager.cache.test_data.get(data_key) if cached_value: return cached_value # type: ignore cluster = cluster_update_proposal addr = clusterlib_utils.create_payment_addr_records( f"addr_test_basic_update_proposal_ci{cluster_manager.cluster_instance}_0", cluster_obj=cluster, )[0] cluster_manager.cache.test_data[data_key] = addr # fund source addresses clusterlib_utils.fund_from_faucet( addr, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) return addr
def issuers_addrs( cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create new issuers addresses.""" with cluster_manager.cache_fixture() as fixture_cache: if fixture_cache.value: return fixture_cache.value # type: ignore addrs = clusterlib_utils.create_payment_addr_records( *[ f"token_minting_ci{cluster_manager.cluster_instance}_{i}" for i in range(3) ], cluster_obj=cluster, ) fixture_cache.value = addrs # fund source addresses clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=900_000_000, ) return addrs
def pool_user( cluster_manager: cluster_management.ClusterManager, cluster_lock_42stake: Tuple[clusterlib.ClusterLib, str], ) -> delegation.PoolUserScript: """Create pool user.""" cluster, *__ = cluster_lock_42stake test_id = common.get_test_id(cluster) script_stake_address = cluster.gen_stake_addr( addr_name=f"{test_id}_pool_user", stake_script_file=plutus_common.STAKE_GUESS_42_PLUTUS_V1, ) payment_addr_rec = cluster.gen_payment_addr_and_keys( name=f"{test_id}_pool_user", stake_script_file=plutus_common.STAKE_GUESS_42_PLUTUS_V1, ) pool_user = delegation.PoolUserScript( payment=payment_addr_rec, stake=delegation.AddressRecordScript( address=script_stake_address, script_file=plutus_common.STAKE_GUESS_42_PLUTUS_V1, ), ) # fund source addresses clusterlib_utils.fund_from_faucet( payment_addr_rec, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=10_000_000_000, ) return pool_user
def create_addrs_data( self, cluster_obj: clusterlib.ClusterLib, destination_dir: FileType = ".") -> Dict[str, Dict[str, Any]]: """Create addresses and their keys for usage in tests.""" destination_dir = Path(destination_dir).expanduser() destination_dir.mkdir(parents=True, exist_ok=True) cluster_env = get_cluster_env() instance_num = cluster_env.instance_num # create new addresses new_addrs_data: Dict[str, Dict[str, Any]] = {} for addr_name in self.test_addr_records: addr_name_instance = f"{addr_name}_ci{instance_num}" payment = cluster_obj.gen_payment_addr_and_keys( name=addr_name_instance, destination_dir=destination_dir, ) new_addrs_data[addr_name] = { "payment": payment, } # create records for existing byron addresses byron_addrs_data: Dict[str, Dict[str, Any]] = {} byron_dir = get_cluster_env().state_dir / "byron" for b in range(len(list(byron_dir.glob("*.skey")))): byron_addr = { "payment": clusterlib.AddressRecord( address=clusterlib.read_address_from_file( byron_dir / f"address-00{b}-converted"), vkey_file=byron_dir / f"payment-keys.00{b}-converted.vkey", skey_file=byron_dir / f"payment-keys.00{b}-converted.skey", ) } byron_addrs_data[f"byron00{b}"] = byron_addr # fund new addresses from byron address LOGGER.debug("Funding created addresses.") to_fund = [d["payment"] for d in new_addrs_data.values()] clusterlib_utils.fund_from_faucet( *to_fund, cluster_obj=cluster_obj, faucet_data=byron_addrs_data["byron000"], amount=100_000_000_000_000, destination_dir=destination_dir, force=True, ) addrs_data = {**new_addrs_data, **byron_addrs_data} return addrs_data
def payment_addrs( cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib, ) -> List[clusterlib.AddressRecord]: """Create new payment addresses.""" test_id = common.get_test_id(cluster) addrs = clusterlib_utils.create_payment_addr_records( *[f"{test_id}_payment_addr_{i}" for i in range(2)], cluster_obj=cluster, ) # fund source address clusterlib_utils.fund_from_faucet( addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=3_000_000_000, ) return addrs
def test_deregister( self, cluster_manager: cluster_management.ClusterManager, cluster_and_pool: Tuple[clusterlib.ClusterLib, str], ): """Deregister stake address. * create two payment addresses that share single stake address * register and delegate the stake address to pool * attempt to deregister the stake address - deregistration is expected to fail because there are rewards in the stake address * withdraw rewards to payment address and deregister stake address * check that the key deposit was returned and rewards withdrawn * check that the stake address is no longer delegated * (optional) check records in db-sync """ cluster, pool_id = cluster_and_pool temp_template = common.get_test_id(cluster) # create two payment addresses that share single stake address (just to test that # delegation works as expected even under such circumstances) stake_addr_rec = clusterlib_utils.create_stake_addr_records( f"{temp_template}_addr0", cluster_obj=cluster)[0] payment_addr_recs = clusterlib_utils.create_payment_addr_records( f"{temp_template}_addr0", f"{temp_template}_addr1", cluster_obj=cluster, stake_vkey_file=stake_addr_rec.vkey_file, ) # fund payment address clusterlib_utils.fund_from_faucet( *payment_addr_recs, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], ) pool_user = clusterlib.PoolUser(payment=payment_addr_recs[1], stake=stake_addr_rec) clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-20) init_epoch = cluster.get_epoch() # submit registration certificate and delegate to pool delegation_out = delegation.delegate_stake_addr( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, temp_template=temp_template, pool_user=pool_user, pool_id=pool_id, ) assert ( cluster.get_epoch() == init_epoch ), "Delegation took longer than expected and would affect other checks" tx_db_deleg = dbsync_utils.check_tx( cluster_obj=cluster, tx_raw_output=delegation_out.tx_raw_output) if tx_db_deleg: # check in db-sync that both payment addresses share single stake address assert (dbsync_utils.get_utxo( address=payment_addr_recs[0].address).stake_address == stake_addr_rec.address) assert (dbsync_utils.get_utxo( address=payment_addr_recs[1].address).stake_address == stake_addr_rec.address) delegation.db_check_delegation( pool_user=delegation_out.pool_user, db_record=tx_db_deleg, deleg_epoch=init_epoch, pool_id=delegation_out.pool_id, ) src_address = delegation_out.pool_user.payment.address LOGGER.info("Waiting 4 epochs for first reward.") cluster.wait_for_new_epoch(new_epochs=4, padding_seconds=10) if not cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance: pytest.skip( f"User of pool '{pool_id}' hasn't received any rewards, cannot continue." ) # make sure we have enough time to finish deregistration in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) # files for deregistering stake address stake_addr_dereg_cert = cluster.gen_stake_addr_deregistration_cert( addr_name=f"{temp_template}_addr0", stake_vkey_file=delegation_out.pool_user.stake.vkey_file, ) tx_files_deregister = clusterlib.TxFiles( certificate_files=[stake_addr_dereg_cert], signing_key_files=[ delegation_out.pool_user.payment.skey_file, delegation_out.pool_user.stake.skey_file, ], ) # attempt to deregister the stake address - deregistration is expected to fail # because there are rewards in the stake address with pytest.raises(clusterlib.CLIError) as excinfo: cluster.send_tx( src_address=src_address, tx_name=f"{temp_template}_dereg_fail", tx_files=tx_files_deregister, ) assert "StakeKeyNonZeroAccountBalanceDELEG" in str(excinfo.value) src_payment_balance = cluster.get_address_balance(src_address) reward_balance = cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance # withdraw rewards to payment address, deregister stake address tx_raw_deregister_output = cluster.send_tx( src_address=src_address, tx_name=f"{temp_template}_dereg_withdraw", tx_files=tx_files_deregister, withdrawals=[ clusterlib.TxOut( address=delegation_out.pool_user.stake.address, amount=-1) ], ) # check that the key deposit was returned and rewards withdrawn assert ( cluster.get_address_balance(src_address) == src_payment_balance - tx_raw_deregister_output.fee + reward_balance + cluster.get_address_deposit() ), f"Incorrect balance for source address `{src_address}`" # check that the stake address is no longer delegated stake_addr_info = cluster.get_stake_addr_info( delegation_out.pool_user.stake.address) assert (not stake_addr_info.delegation ), f"Stake address is still delegated: {stake_addr_info}" tx_db_dereg = dbsync_utils.check_tx( cluster_obj=cluster, tx_raw_output=tx_raw_deregister_output) if tx_db_dereg: assert delegation_out.pool_user.stake.address in tx_db_dereg.stake_deregistration assert ( cluster.get_address_balance(src_address) == dbsync_utils.get_utxo(address=src_address).amount_sum ), f"Unexpected balance for source address `{src_address}` in db-sync"
def test_oversaturated( # noqa: C901 self, cluster_manager: cluster_management.ClusterManager, cluster_lock_pools: clusterlib.ClusterLib, ): """Check diminished rewards when stake pool is oversaturated. The stake pool continues to operate normally and those who delegate to that pool receive rewards, but the rewards are proportionally lower than those received from stake pool that is not oversaturated. * register and delegate stake address in "init epoch", for all available pools * in "init epoch" + 2, saturate all available pools (block distribution remains balanced among pools) * in "init epoch" + 3, oversaturate one pool * in "init epoch" + 5, for all available pools, withdraw rewards and transfer funds from delegated addresses so pools are no longer (over)saturated * while doing the steps above, collect rewards data for 9 epochs * compare proportionality of rewards in epochs where pools were non-saturated, saturated and oversaturated """ # pylint: disable=too-many-statements,too-many-locals,too-many-branches epoch_saturate = 2 epoch_oversaturate = 4 epoch_withdrawal = 6 cluster = cluster_lock_pools temp_template = common.get_test_id(cluster) initial_balance = 1_000_000_000 faucet_rec = cluster_manager.cache.addrs_data["byron000"] pool_records: Dict[int, PoolRecord] = {} # make sure we have enough time to finish the delegation in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) init_epoch = cluster.get_epoch() # submit registration certificates and delegate to pools for idx, res in enumerate( [ cluster_management.Resources.POOL1, cluster_management.Resources.POOL2, cluster_management.Resources.POOL3, ], start=1, ): pool_addrs_data = cluster_manager.cache.addrs_data[res] reward_addr = clusterlib.PoolUser( payment=pool_addrs_data["payment"], stake=pool_addrs_data["reward"]) pool_id = delegation.get_pool_id( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, pool_name=res, ) pool_id_dec = helpers.decode_bech32(bech32=pool_id) delegation_out = delegation.delegate_stake_addr( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, temp_template=f"{temp_template}_pool{idx}", pool_id=pool_id, amount=initial_balance, ) pool_records[idx] = PoolRecord( name=res, id=pool_id, id_dec=pool_id_dec, reward_addr=reward_addr, delegation_out=delegation_out, user_rewards=[], owner_rewards=[], blocks_minted={}, saturation_amounts={}, ) # record initial reward balance for each pool for pool_rec in pool_records.values(): user_payment_balance = cluster.get_address_balance( pool_rec.delegation_out.pool_user.payment.address) owner_payment_balance = cluster.get_address_balance( pool_rec.reward_addr.payment.address) pool_rec.user_rewards.append( RewardRecord( epoch_no=init_epoch, reward_total=0, reward_per_epoch=0, stake_total=user_payment_balance, )) pool_rec.owner_rewards.append( RewardRecord( epoch_no=init_epoch, reward_total=cluster.get_stake_addr_info( pool_rec.reward_addr.stake.address). reward_account_balance, reward_per_epoch=0, stake_total=owner_payment_balance, )) assert ( cluster.get_epoch() == init_epoch ), "Delegation took longer than expected and would affect other checks" LOGGER.info("Checking rewards for 10 epochs.") for __ in range(10): # wait for new epoch if cluster.get_epoch( ) == pool_records[2].owner_rewards[-1].epoch_no: cluster.wait_for_new_epoch() # sleep till the end of epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=-50, stop=-40, force_epoch=True) this_epoch = cluster.get_epoch() ledger_state = clusterlib_utils.get_ledger_state( cluster_obj=cluster) clusterlib_utils.save_ledger_state( cluster_obj=cluster, state_name=f"{temp_template}_{this_epoch}", ledger_state=ledger_state, ) for pool_rec in pool_records.values(): # reward balance in previous epoch prev_user_reward = pool_rec.user_rewards[-1].reward_total prev_owner_reward = pool_rec.owner_rewards[-1].reward_total pool_rec.blocks_minted[this_epoch - 1] = (ledger_state["blocksBefore"].get( pool_rec.id_dec) or 0) # current reward balance user_reward = cluster.get_stake_addr_info( pool_rec.delegation_out.pool_user.stake.address ).reward_account_balance owner_reward = cluster.get_stake_addr_info( pool_rec.reward_addr.stake.address).reward_account_balance # total reward amounts received this epoch owner_reward_epoch = owner_reward - prev_owner_reward # We cannot compare with previous rewards in epochs where # `this_epoch >= init_epoch + epoch_withdrawal`. # There's a withdrawal of rewards at the end of these epochs. if this_epoch > init_epoch + epoch_withdrawal: user_reward_epoch = user_reward else: user_reward_epoch = user_reward - prev_user_reward # store collected rewards info user_payment_balance = cluster.get_address_balance( pool_rec.delegation_out.pool_user.payment.address) owner_payment_balance = cluster.get_address_balance( pool_rec.reward_addr.payment.address) pool_rec.user_rewards.append( RewardRecord( epoch_no=this_epoch, reward_total=user_reward, reward_per_epoch=user_reward_epoch, stake_total=user_payment_balance + user_reward, )) pool_rec.owner_rewards.append( RewardRecord( epoch_no=this_epoch, reward_total=owner_reward, reward_per_epoch=owner_reward_epoch, stake_total=owner_payment_balance, )) pool_rec.saturation_amounts[ this_epoch] = _get_saturation_threshold( cluster_obj=cluster, ledger_state=ledger_state, pool_id=pool_rec.id) # fund the delegated addresses - saturate all pools if this_epoch == init_epoch + epoch_saturate: clusterlib_utils.fund_from_faucet( *[ p.delegation_out.pool_user.payment for p in pool_records.values() ], cluster_obj=cluster, faucet_data=faucet_rec, amount=[ p.saturation_amounts[this_epoch] - 100_000_000_000 for p in pool_records.values() ], tx_name=f"{temp_template}_saturate_pools_ep{this_epoch}", force=True, ) with cluster_manager.restart_on_failure(): # Fund the address delegated to "pool2" to oversaturate the pool. # New stake amount will be current (saturated) stake * 2. if this_epoch == init_epoch + epoch_oversaturate: assert (pool_records[2].saturation_amounts[this_epoch] > 0), "Pool is already saturated" current_stake = int( cluster.get_stake_snapshot( pool_records[2].id)["poolStakeMark"]) overstaturate_amount = current_stake * 2 saturation_threshold = pool_records[2].saturation_amounts[ this_epoch] assert overstaturate_amount > saturation_threshold, ( f"{overstaturate_amount} Lovelace is not enough to oversature the pool " f"({saturation_threshold} is needed)") clusterlib_utils.fund_from_faucet( pool_records[2].delegation_out.pool_user.payment, cluster_obj=cluster, faucet_data=faucet_rec, amount=overstaturate_amount, tx_name=f"{temp_template}_oversaturate_pool2", force=True, ) # wait 4 epochs for first rewards if this_epoch >= init_epoch + 4: assert (owner_reward > prev_owner_reward ), "New reward was not received by pool owner" # transfer funds back to faucet so the pools are no longer (over)saturated # and staked amount is +- same as the `initial_balance` if this_epoch >= init_epoch + epoch_withdrawal: _withdraw_rewards( *[ p.delegation_out.pool_user for p in pool_records.values() ], cluster_obj=cluster, tx_name=f"{temp_template}_ep{this_epoch}", ) return_to_addrs = [] return_amounts = [] for idx, pool_rec in pool_records.items(): deleg_payment_balance = cluster.get_address_balance( pool_rec.delegation_out.pool_user.payment.address) if deleg_payment_balance > initial_balance + 10_000_000: return_to_addrs.append( pool_rec.delegation_out.pool_user.payment) return_amounts.append(deleg_payment_balance - initial_balance) clusterlib_utils.return_funds_to_faucet( *return_to_addrs, cluster_obj=cluster, faucet_addr=faucet_rec["payment"].address, amount=return_amounts, tx_name=f"{temp_template}_ep{this_epoch}", ) for return_addr in return_to_addrs: deleg_payment_balance = cluster.get_address_balance( return_addr.address) assert ( deleg_payment_balance <= initial_balance ), "Unexpected funds in payment address '{return_addr}'" assert ( cluster.get_epoch() == this_epoch ), "Failed to finish actions in single epoch, it would affect other checks" pool1_user_rewards_per_block = _get_reward_per_block(pool_records[1]) pool2_user_rewards_per_block = _get_reward_per_block(pool_records[2]) pool3_user_rewards_per_block = _get_reward_per_block(pool_records[3]) pool1_owner_rewards_per_block = _get_reward_per_block( pool_records[1], owner_rewards=True) pool2_owner_rewards_per_block = _get_reward_per_block( pool_records[2], owner_rewards=True) pool3_owner_rewards_per_block = _get_reward_per_block( pool_records[3], owner_rewards=True) oversaturated_epoch = max( e for e, r in pool_records[2].saturation_amounts.items() if r < 0) saturated_epoch = oversaturated_epoch - 2 nonsaturated_epoch = oversaturated_epoch - 4 try: # check that rewards per block per stake for "pool2" in the epoch where the pool is # oversaturated is lower than in epochs where pools are not oversaturated assert (pool1_user_rewards_per_block[nonsaturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) assert (pool2_user_rewards_per_block[nonsaturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) assert (pool3_user_rewards_per_block[nonsaturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) assert (pool1_user_rewards_per_block[saturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) assert (pool2_user_rewards_per_block[saturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) assert (pool3_user_rewards_per_block[saturated_epoch] > pool2_user_rewards_per_block[oversaturated_epoch]) # check that oversaturated pool doesn't lead to increased rewards for pool owner # when compared to saturated pool, i.e. total pool margin amount is not increased pool1_rew_fraction_sat = pool1_owner_rewards_per_block[ saturated_epoch] pool2_rew_fraction_sat = pool2_owner_rewards_per_block[ saturated_epoch] pool3_rew_fraction_sat = pool3_owner_rewards_per_block[ saturated_epoch] pool2_rew_fraction_over = pool2_owner_rewards_per_block[ oversaturated_epoch] assert pool2_rew_fraction_sat > pool2_rew_fraction_over or helpers.is_in_interval( pool2_rew_fraction_sat, pool2_rew_fraction_over, frac=0.4, ) assert pool1_rew_fraction_sat > pool2_rew_fraction_over or helpers.is_in_interval( pool1_rew_fraction_sat, pool2_rew_fraction_over, frac=0.4, ) assert pool3_rew_fraction_sat > pool2_rew_fraction_over or helpers.is_in_interval( pool3_rew_fraction_sat, pool2_rew_fraction_over, frac=0.4, ) # Compare rewards in last (non-saturated) epoch to rewards in next-to-last # (saturated / over-saturated) epoch. # This way check that staked amount for each pool was restored to `initial_balance` # and that rewards correspond to the restored amounts. for pool_rec in pool_records.values(): assert (pool_rec.user_rewards[-1].reward_per_epoch * 100 < pool_rec.user_rewards[-2].reward_per_epoch) except Exception: # save debugging data in case of test failure with open(f"{temp_template}_pool_records.pickle", "wb") as out_data: pickle.dump(pool_records, out_data) raise
def test_deregister_reward_addr_retire_pool( # noqa: C901 self, cluster_manager: cluster_management.ClusterManager, cluster_lock_pool2: clusterlib.ClusterLib, ): """Test deregistering reward address and retiring stake pool. The pool deposit is lost when reward address is deregistered before the pool is retired. * wait for first reward for the pool * withdraw pool rewards to payment address * deregister the pool reward address * check that the key deposit was returned * check that pool owner is NOT receiving rewards * deregister stake pool * check that the pool deposit was NOT returned to reward or stake address * return the pool to the original state - reregister the pool, register the reward address, delegate the stake address to the pool * check that pool deposit was needed * check that pool owner is receiving rewards """ # pylint: disable=too-many-statements,too-many-locals __: Any # mypy workaround pool_name = cluster_management.Resources.POOL2 cluster = cluster_lock_pool2 pool_rec = cluster_manager.cache.addrs_data[pool_name] pool_reward = clusterlib.PoolUser(payment=pool_rec["payment"], stake=pool_rec["reward"]) pool_owner = clusterlib.PoolUser(payment=pool_rec["payment"], stake=pool_rec["stake"]) pool_opcert_file: Path = pool_rec["pool_operational_cert"] temp_template = common.get_test_id(cluster) LOGGER.info("Waiting up to 4 full epochs for first reward.") for i in range(5): if i > 0: cluster.wait_for_new_epoch(padding_seconds=10) if cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance: break else: pytest.skip( f"Pool '{pool_name}' hasn't received any rewards, cannot continue." ) # make sure we have enough time to finish reward address deregistration in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) # withdraw pool rewards to payment address cluster.withdraw_reward( stake_addr_record=pool_reward.stake, dst_addr_record=pool_reward.payment, tx_name=temp_template, ) # deregister the pool reward address stake_addr_dereg_cert = cluster.gen_stake_addr_deregistration_cert( addr_name=f"{temp_template}_addr0", stake_vkey_file=pool_reward.stake.vkey_file) tx_files_deregister = clusterlib.TxFiles( certificate_files=[stake_addr_dereg_cert], signing_key_files=[ pool_reward.payment.skey_file, pool_reward.stake.skey_file ], ) src_init_balance = cluster.get_address_balance( pool_reward.payment.address) tx_raw_deregister_output = cluster.send_tx( src_address=pool_reward.payment.address, tx_name=f"{temp_template}_dereg_reward", tx_files=tx_files_deregister, ) with cluster_manager.restart_on_failure(): # check that the key deposit was returned assert ( cluster.get_address_balance( pool_reward.payment.address) == src_init_balance - tx_raw_deregister_output.fee + cluster.get_address_deposit() ), f"Incorrect balance for source address `{pool_reward.payment.address}`" # check that the reward address is no longer delegated assert not cluster.get_stake_addr_info( pool_reward.stake.address), "Stake address still delegated" cluster.wait_for_new_epoch(3) # check that pool owner is NOT receiving rewards assert (cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance == 0 ), "Pool owner received unexpected rewards" # fund pool owner's addresses so balance keeps higher than pool pledge after fees etc. # are deducted clusterlib_utils.fund_from_faucet( pool_owner, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=900_000_000, force=True, ) # make sure we have enough time to finish pool deregistration in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) src_dereg_balance = cluster.get_address_balance( pool_owner.payment.address) stake_acount_balance = cluster.get_stake_addr_info( pool_owner.stake.address).reward_account_balance reward_acount_balance = cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance node_cold = pool_rec["cold_key_pair"] pool_id = cluster.get_stake_pool_id(node_cold.vkey_file) # deregister stake pool depoch = cluster.get_epoch() + 1 __, tx_raw_output = cluster.deregister_stake_pool( pool_owners=[pool_owner], cold_key_pair=node_cold, epoch=depoch, pool_name=pool_name, tx_name=temp_template, ) assert cluster.get_pool_params(pool_id).retiring == depoch # check that the pool was deregistered cluster.wait_for_new_epoch() assert not cluster.get_pool_params( pool_id ).pool_params, f"The pool {pool_id} was not deregistered" # check command kes-period-info case: de-register pool # TODO: the query is currently broken kes_query_currently_broken = False try: kes_period_info = cluster.get_kes_period_info(pool_opcert_file) except clusterlib.CLIError as err: if "currentlyBroken" not in str(err): raise kes_query_currently_broken = True if not kes_query_currently_broken: kes.check_kes_period_info_result( kes_output=kes_period_info, expected_scenario=kes.KesScenarios.ALL_VALID) # check that the balance for source address was correctly updated assert src_dereg_balance - tx_raw_output.fee == cluster.get_address_balance( pool_owner.payment.address) # check that the pool deposit was NOT returned to reward or stake address assert (cluster.get_stake_addr_info( pool_owner.stake.address).reward_account_balance == stake_acount_balance) assert (cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance == reward_acount_balance) # Return the pool to the original state - reregister the pool, register # the reward address, delegate the stake address to the pool. src_updated_balance = cluster.get_address_balance( pool_reward.payment.address) # reregister the pool by resubmitting the pool registration certificate, # delegate stake address to pool again, reregister reward address tx_files = clusterlib.TxFiles( certificate_files=[ pool_rec["reward_addr_registration_cert"], pool_rec["pool_registration_cert"], pool_rec["stake_addr_delegation_cert"], ], signing_key_files=[ pool_rec["payment"].skey_file, pool_rec["stake"].skey_file, pool_rec["reward"].skey_file, node_cold.skey_file, ], ) tx_raw_output = cluster.send_tx( src_address=pool_reward.payment.address, tx_name=f"{temp_template}_rereg_pool", tx_files=tx_files, ) # check command kes-period-info case: re-register pool, check without # waiting to take effect if not kes_query_currently_broken: kes_period_info = cluster.get_kes_period_info(pool_opcert_file) kes.check_kes_period_info_result( kes_output=kes_period_info, expected_scenario=kes.KesScenarios.ALL_VALID) # check that the balance for source address was correctly updated and that the # pool deposit was needed assert ( cluster.get_address_balance( pool_reward.payment.address) == src_updated_balance - tx_raw_output.fee - cluster.get_pool_deposit() - cluster.get_address_deposit() ), f"Incorrect balance for source address `{pool_reward.payment.address}`" LOGGER.info( "Waiting up to 5 epochs for stake pool to be reregistered.") for __ in range(5): cluster.wait_for_new_epoch(padding_seconds=10) if pool_id in cluster.get_stake_distribution(): break else: raise AssertionError( f"Stake pool `{pool_id}` not registered even after 5 epochs." ) # check command kes-period-info case: re-register pool if not kes_query_currently_broken: kes_period_info = cluster.get_kes_period_info(pool_opcert_file) kes.check_kes_period_info_result( kes_output=kes_period_info, expected_scenario=kes.KesScenarios.ALL_VALID) # wait before checking delegation and rewards cluster.wait_for_new_epoch(3, padding_seconds=30) # check that the stake address was delegated stake_addr_info = cluster.get_stake_addr_info( pool_owner.stake.address) assert ( stake_addr_info.delegation ), f"Stake address was not delegated yet: {stake_addr_info}" assert pool_id == stake_addr_info.delegation, "Stake address delegated to wrong pool" # check that pool owner is receiving rewards assert cluster.get_stake_addr_info( pool_reward.stake.address ).reward_account_balance, "New reward was not received by pool reward address" # check that pledge is still met after the owner address was used to pay for Txs pool_data = clusterlib_utils.load_registered_pool_data( cluster_obj=cluster, pool_name=pool_name, pool_id=pool_id) owner_payment_balance = cluster.get_address_balance( pool_owner.payment.address) assert (owner_payment_balance >= pool_data.pool_pledge ), f"Pledge is not met for pool '{pool_name}'!"
def test_no_reward_deregistered_reward_addr( self, cluster_manager: cluster_management.ClusterManager, cluster_lock_pool2: clusterlib.ClusterLib, ): """Check that the reward address is not receiving rewards when deregistered. The stake pool continues to operate normally and those who delegate to that pool receive rewards. * delegate stake address * wait for first reward * withdraw pool rewards to payment address * deregister the pool reward address * check that the key deposit was returned * check that pool owner is NOT receiving rewards * check that new rewards are received by those delegating to the pool * return the pool to the original state - reregister reward address * check that pool owner is receiving rewards """ pool_name = cluster_management.Resources.POOL2 cluster = cluster_lock_pool2 pool_rec = cluster_manager.cache.addrs_data[pool_name] pool_reward = clusterlib.PoolUser(payment=pool_rec["payment"], stake=pool_rec["reward"]) temp_template = common.get_test_id(cluster) pool_id = delegation.get_pool_id( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, pool_name=pool_name) clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-20) init_epoch = cluster.get_epoch() # submit registration certificate and delegate to pool delegation_out = delegation.delegate_stake_addr( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, temp_template=temp_template, pool_id=pool_id, ) assert ( cluster.get_epoch() == init_epoch ), "Delegation took longer than expected and would affect other checks" LOGGER.info("Waiting 4 epochs for first reward.") cluster.wait_for_new_epoch(new_epochs=4, padding_seconds=10) if not cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance: pytest.skip( f"User of pool '{pool_name}' hasn't received any rewards, cannot continue." ) # make sure we have enough time to finish deregistration in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) # withdraw pool rewards to payment address # use `transaction build` if possible if (VERSIONS.transaction_era >= VERSIONS.ALONZO and VERSIONS.transaction_era == VERSIONS.cluster_era): clusterlib_utils.withdraw_reward_w_build( cluster_obj=cluster, stake_addr_record=pool_reward.stake, dst_addr_record=pool_reward.payment, tx_name=temp_template, ) else: cluster.withdraw_reward( stake_addr_record=pool_reward.stake, dst_addr_record=pool_reward.payment, tx_name=temp_template, ) # deregister the pool reward address stake_addr_dereg_cert = cluster.gen_stake_addr_deregistration_cert( addr_name=f"{temp_template}_addr0", stake_vkey_file=pool_reward.stake.vkey_file) tx_files_deregister = clusterlib.TxFiles( certificate_files=[stake_addr_dereg_cert], signing_key_files=[ pool_reward.payment.skey_file, pool_reward.stake.skey_file ], ) src_init_balance = cluster.get_address_balance( pool_reward.payment.address) tx_raw_deregister_output = cluster.send_tx( src_address=pool_reward.payment.address, tx_name=f"{temp_template}_dereg_reward", tx_files=tx_files_deregister, ) with cluster_manager.restart_on_failure(): # check that the key deposit was returned assert ( cluster.get_address_balance( pool_reward.payment.address) == src_init_balance - tx_raw_deregister_output.fee + cluster.get_address_deposit() ), f"Incorrect balance for source address `{pool_reward.payment.address}`" # check that the reward address is no longer delegated assert not cluster.get_stake_addr_info( pool_reward.stake.address), "Stake address still delegated" orig_user_reward = cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance cluster.wait_for_new_epoch(3) # check that pool owner is NOT receiving rewards assert (cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance == 0 ), "Pool owner received unexpected rewards" # check that new rewards are received by those delegating to the pool assert (orig_user_reward < cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "New reward was not received by stake address" # Return the pool to the original state - reregister reward address. # fund pool owner's addresses so balance keeps higher than pool pledge after fees etc. # are deducted clusterlib_utils.fund_from_faucet( pool_reward, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=900_000_000, force=True, ) src_updated_balance = cluster.get_address_balance( pool_reward.payment.address) # reregister reward address tx_files = clusterlib.TxFiles( certificate_files=[ pool_rec["reward_addr_registration_cert"], ], signing_key_files=[ pool_reward.payment.skey_file, pool_reward.stake.skey_file ], ) tx_raw_output = cluster.send_tx( src_address=pool_reward.payment.address, tx_name=f"{temp_template}_rereg_deleg", tx_files=tx_files, ) # check that the balance for source address was correctly updated assert ( cluster.get_address_balance( pool_reward.payment.address) == src_updated_balance - tx_raw_output.fee - cluster.get_address_deposit() ), f"Incorrect balance for source address `{pool_reward.payment.address}`" cluster.wait_for_new_epoch(4, padding_seconds=30) # check that new rewards were received by those delegating to the pool assert (orig_user_reward < cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "New reward was not received by stake address" # check that pool owner is also receiving rewards assert (cluster.get_stake_addr_info( pool_reward.stake.address).reward_account_balance > 0), "New reward was not received by pool reward address" # check that pledge is still met after the owner address was used to pay for Txs pool_data = clusterlib_utils.load_registered_pool_data( cluster_obj=cluster, pool_name=pool_name, pool_id=pool_id) owner_payment_balance = cluster.get_address_balance( pool_reward.payment.address) assert (owner_payment_balance >= pool_data.pool_pledge ), f"Pledge is not met for pool '{pool_name}'!"
def test_no_reward_unmet_pledge1( self, cluster_manager: cluster_management.ClusterManager, cluster_lock_pool2: clusterlib.ClusterLib, ): """Check that the stake pool is not receiving rewards when pledge is not met. When the pledge is higher than available funds, neither pool owners nor those who delegate to that pool receive rewards. * delegate stake address * wait for first reward * increase the needed pledge amount - update the pool parameters by resubmitting the pool registration certificate - the funds are now lower than what is needed by the stake pool * check that NO new rewards were received by those delegating to the pool * check that pool owner is also NOT receiving rewards * return the pool to the original state - restore pledge settings * check that new rewards were received by those delegating to the pool * check that pool owner is also receiving rewards """ pool_name = cluster_management.Resources.POOL2 cluster = cluster_lock_pool2 pool_rec = cluster_manager.cache.addrs_data[pool_name] pool_owner = clusterlib.PoolUser(payment=pool_rec["payment"], stake=pool_rec["stake"]) temp_template = common.get_test_id(cluster) pool_id = delegation.get_pool_id( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, pool_name=pool_name) clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-20) init_epoch = cluster.get_epoch() # submit registration certificate and delegate to pool delegation_out = delegation.delegate_stake_addr( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, temp_template=temp_template, pool_id=pool_id, ) assert ( cluster.get_epoch() == init_epoch ), "Delegation took longer than expected and would affect other checks" LOGGER.info("Waiting 4 epochs for first reward.") cluster.wait_for_new_epoch(new_epochs=4, padding_seconds=10) if not cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance: pytest.skip( f"User of pool '{pool_name}' hasn't received any rewards, cannot continue." ) # make sure we have enough time to finish the pool update in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) # load and update original pool data loaded_data = clusterlib_utils.load_registered_pool_data( cluster_obj=cluster, pool_name=f"changed_{pool_name}", pool_id=pool_id) pool_data_updated = loaded_data._replace( pool_pledge=loaded_data.pool_pledge * 9) # increase the needed pledge amount - update the pool parameters by resubmitting the pool # registration certificate cluster.register_stake_pool( pool_data=pool_data_updated, pool_owners=[pool_owner], vrf_vkey_file=pool_rec["vrf_key_pair"].vkey_file, cold_key_pair=pool_rec["cold_key_pair"], tx_name=f"{temp_template}_update_param", reward_account_vkey_file=pool_rec["reward"].vkey_file, deposit=0, # no additional deposit, the pool is already registered ) cluster.wait_for_new_epoch(4, padding_seconds=30) orig_owner_reward = cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance orig_user_reward = cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance cluster.wait_for_new_epoch(3) with cluster_manager.restart_on_failure(): # check that NO new rewards were received by those delegating to the pool assert (orig_user_reward == cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "Received unexpected rewards" # check that pool owner is also NOT receiving rewards assert (orig_owner_reward == cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance ), "Pool owner received unexpected rewards" # Return the pool to the original state - restore pledge settings. # fund pool owner's addresses so balance keeps higher than pool pledge after fees etc. # are deducted clusterlib_utils.fund_from_faucet( pool_owner, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=900_000_000, force=True, ) # update the pool to original parameters by resubmitting # the pool registration certificate cluster.register_stake_pool( pool_data=loaded_data, pool_owners=[pool_owner], vrf_vkey_file=pool_rec["vrf_key_pair"].vkey_file, cold_key_pair=pool_rec["cold_key_pair"], tx_name=f"{temp_template}_update_to_orig", reward_account_vkey_file=pool_rec["reward"].vkey_file, deposit= 0, # no additional deposit, the pool is already registered ) cluster.wait_for_new_epoch(5, padding_seconds=30) # check that new rewards were received by those delegating to the pool assert (orig_user_reward < cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "New reward was not received by stake address" # check that pool owner is also receiving rewards assert (orig_owner_reward < cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance ), "New reward was not received by pool reward address" # check that pledge is still met after the owner address was used to pay for Txs pool_data = clusterlib_utils.load_registered_pool_data( cluster_obj=cluster, pool_name=pool_name, pool_id=pool_id) owner_payment_balance = cluster.get_address_balance( pool_owner.payment.address) assert (owner_payment_balance >= pool_data.pool_pledge ), f"Pledge is not met for pool '{pool_name}'!"
if not pool_user: stake_addr_rec = clusterlib_utils.create_stake_addr_records( f"{temp_template}_addr0", cluster_obj=cluster_obj)[0] payment_addr_rec = clusterlib_utils.create_payment_addr_records( f"{temp_template}_addr0", cluster_obj=cluster_obj, stake_vkey_file=stake_addr_rec.vkey_file, )[0] pool_user = clusterlib.PoolUser(payment=payment_addr_rec, stake=stake_addr_rec) # fund payment address clusterlib_utils.fund_from_faucet( pool_user.payment, cluster_obj=cluster_obj, faucet_data=addrs_data["user1"], amount=amount, ) # create stake address registration cert if address is not already registered if cluster_obj.get_stake_addr_info(pool_user.stake.address): stake_addr_reg_cert_file = None else: stake_addr_reg_cert_file = cluster_obj.gen_stake_addr_registration_cert( addr_name=f"{temp_template}_addr0", stake_vkey_file=pool_user.stake.vkey_file) # create stake address delegation cert deleg_kwargs: Dict[str, Any] = { "addr_name": f"{temp_template}_addr0", "stake_vkey_file": pool_user.stake.vkey_file,
def setup_test_addrs(cluster_obj: clusterlib.ClusterLib, destination_dir: FileType = ".") -> Path: """Create addresses and their keys for usage in tests.""" destination_dir = Path(destination_dir).expanduser() destination_dir.mkdir(parents=True, exist_ok=True) cluster_env = get_cluster_env() instance_num = cluster_env["instance_num"] addrs = ("user1", ) LOGGER.debug("Creating addresses and keys for tests.") addrs_data: Dict[str, Dict[str, Any]] = {} for addr_name in addrs: addr_name_instance = f"{addr_name}_ci{instance_num}" stake = cluster_obj.gen_stake_addr_and_keys( name=addr_name_instance, destination_dir=destination_dir) payment = cluster_obj.gen_payment_addr_and_keys( name=addr_name_instance, stake_vkey_file=stake.vkey_file, destination_dir=destination_dir, ) stake_addr_registration_cert = cluster_obj.gen_stake_addr_registration_cert( addr_name=addr_name_instance, stake_vkey_file=stake.vkey_file, destination_dir=destination_dir, ) addrs_data[addr_name] = { "payment": payment, "stake": stake, "stake_addr_registration_cert": stake_addr_registration_cert, } LOGGER.debug("Funding created addresses.") if cluster_instances.CLUSTER_ERA == "shelley": # fund from shelley genesis clusterlib_utils.fund_from_genesis( *[d["payment"].address for d in addrs_data.values()], cluster_obj=cluster_obj, amount=6_000_000_000_000, destination_dir=destination_dir, ) else: to_fund = [d["payment"] for d in addrs_data.values()] byron_dir = cluster_env["state_dir"] / "byron" for b in range(3): byron_addr = { "payment": clusterlib.AddressRecord( address=clusterlib.read_address_from_file( byron_dir / f"address-00{b}-converted"), vkey_file=byron_dir / f"payment-keys.00{b}-converted.vkey", skey_file=byron_dir / f"payment-keys.00{b}-converted.skey", ) } addrs_data[f"byron00{b}"] = byron_addr # fund from converted byron address clusterlib_utils.fund_from_faucet( *to_fund, cluster_obj=cluster_obj, faucet_data=addrs_data["byron000"], amount=6_000_000_000_000, destination_dir=destination_dir, force=True, ) pools_data = load_devops_pools_data(cluster_obj) data_file = Path(cluster_env["state_dir"]) / ADDR_DATA with open(data_file, "wb") as out_data: pickle.dump({**addrs_data, **pools_data}, out_data) return data_file
def test_no_reward_unmet_pledge2( self, cluster_manager: cluster_management.ClusterManager, cluster_lock_pool2: clusterlib.ClusterLib, ): """Check that the stake pool is not receiving rewards when pledge is not met. When the pledge is higher than available funds, neither pool owners nor those who delegate to that pool receive rewards. * delegate stake address * wait for first reward * withdraw part of the pledge - the funds are lower than what is needed by the stake pool * check that NO new rewards were received by those delegating to the pool * check that pool owner is also NOT receiving rewards * return the pool to the original state - restore pledge funds * check that new rewards were received by those delegating to the pool * check that pool owner is also receiving rewards """ pool_name = cluster_management.Resources.POOL2 cluster = cluster_lock_pool2 pool_rec = cluster_manager.cache.addrs_data[pool_name] pool_owner = clusterlib.PoolUser(payment=pool_rec["payment"], stake=pool_rec["stake"]) temp_template = common.get_test_id(cluster) pool_id = delegation.get_pool_id( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, pool_name=pool_name) clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-20) init_epoch = cluster.get_epoch() # submit registration certificate and delegate to pool delegation_out = delegation.delegate_stake_addr( cluster_obj=cluster, addrs_data=cluster_manager.cache.addrs_data, temp_template=temp_template, pool_id=pool_id, ) assert ( cluster.get_epoch() == init_epoch ), "Delegation took longer than expected and would affect other checks" LOGGER.info("Waiting 4 epochs for first reward.") cluster.wait_for_new_epoch(new_epochs=4, padding_seconds=10) if not cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance: pytest.skip( f"User of pool '{pool_name}' hasn't received any rewards, cannot continue." ) # make sure we have enough time to withdraw the pledge in one epoch clusterlib_utils.wait_for_epoch_interval(cluster_obj=cluster, start=5, stop=-40) # load pool data loaded_data = clusterlib_utils.load_registered_pool_data( cluster_obj=cluster, pool_name=f"changed_{pool_name}", pool_id=pool_id) pledge_amount = loaded_data.pool_pledge // 2 # withdraw part of the pledge destinations = [ clusterlib.TxOut(address=delegation_out.pool_user.payment.address, amount=pledge_amount) ] tx_files = clusterlib.TxFiles( signing_key_files=[pool_owner.payment.skey_file]) cluster.send_funds( src_address=pool_owner.payment.address, destinations=destinations, tx_name=f"{temp_template}_withdraw_pledge", tx_files=tx_files, ) assert cluster.get_address_balance( pool_owner.payment.address ) < loaded_data.pool_pledge, ( f"Pledge still high - pledge: {loaded_data.pool_pledge}, " f"funds: {cluster.get_address_balance(pool_owner.payment.address)}" ) cluster.wait_for_new_epoch(4, padding_seconds=30) orig_owner_reward = cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance orig_user_reward = cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance cluster.wait_for_new_epoch(3) with cluster_manager.restart_on_failure(): # check that NO new rewards were received by those delegating to the pool assert (orig_user_reward == cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "Received unexpected rewards" # check that pool owner is also NOT receiving rewards assert (orig_owner_reward == cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance ), "Pool owner received unexpected rewards" # Return the pool to the original state - restore pledge funds. # fund user address so it has enough funds for fees etc. clusterlib_utils.fund_from_faucet( delegation_out.pool_user, cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=900_000_000, force=True, ) # return pledge destinations = [ clusterlib.TxOut(address=pool_owner.payment.address, amount=pledge_amount + 100_000_000) ] tx_files = clusterlib.TxFiles( signing_key_files=[delegation_out.pool_user.payment.skey_file]) cluster.send_funds( src_address=delegation_out.pool_user.payment.address, destinations=destinations, tx_name=f"{temp_template}_return_pledge", tx_files=tx_files, ) assert ( cluster.get_address_balance( pool_owner.payment.address) >= loaded_data.pool_pledge ), (f"Funds still low - pledge: {loaded_data.pool_pledge}, " f"funds: {cluster.get_address_balance(pool_owner.payment.address)}" ) cluster.wait_for_new_epoch(5, padding_seconds=30) # check that new rewards were received by those delegating to the pool assert (orig_user_reward < cluster.get_stake_addr_info( delegation_out.pool_user.stake.address).reward_account_balance ), "New reward was not received by stake address" # check that pool owner is also receiving rewards assert (orig_owner_reward < cluster.get_stake_addr_info( pool_rec["reward"].address).reward_account_balance ), "New reward was not received by pool reward address"
def test_pretty_utxo( self, cluster_manager: cluster_management.ClusterManager, cluster: clusterlib.ClusterLib ): """Check that pretty printed `query utxo` output looks as expected.""" temp_template = common.get_test_id(cluster) amount1 = 2_000_000 amount2 = 2_500_000 # create source and destination payment addresses payment_addrs = clusterlib_utils.create_payment_addr_records( f"{temp_template}_src", f"{temp_template}_dst", cluster_obj=cluster, ) # fund source addresses clusterlib_utils.fund_from_faucet( payment_addrs[0], cluster_obj=cluster, faucet_data=cluster_manager.cache.addrs_data["user1"], amount=amount1 + amount2 + 10_000_000, ) src_address = payment_addrs[0].address dst_address = payment_addrs[1].address txouts = [ clusterlib.TxOut(address=dst_address, amount=amount1), clusterlib.TxOut(address=dst_address, amount=amount2), ] tx_files = clusterlib.TxFiles(signing_key_files=[payment_addrs[0].skey_file]) tx_raw_output = cluster.send_tx( src_address=src_address, tx_name=temp_template, txouts=txouts, tx_files=tx_files, join_txouts=False, ) utxo_out = ( cluster.cli( [ "query", "utxo", "--address", dst_address, *cluster.magic_args, ] ) .stdout.decode("utf-8") .split() ) txid = cluster.get_txid(tx_body_file=tx_raw_output.out_file) expected_out = [ "TxHash", "TxIx", "Amount", "--------------------------------------------------------------------------------" "------", txid, "0", str(amount1), "lovelace", "+", "TxOutDatumNone", txid, "1", str(amount2), "lovelace", "+", "TxOutDatumNone", ] assert utxo_out == expected_out