diff --git a/cardano_node_tests/tests/tests_conway/test_committee.py b/cardano_node_tests/tests/tests_conway/test_committee.py new file mode 100644 index 000000000..a5bc9910f --- /dev/null +++ b/cardano_node_tests/tests/tests_conway/test_committee.py @@ -0,0 +1,148 @@ +"""Tests for Conway governance Constitutional Committee functionality.""" +import logging +import pathlib as pl + +import allure +import pytest +from cardano_clusterlib import clusterlib + +from cardano_node_tests.cluster_management import cluster_management +from cardano_node_tests.tests import common +from cardano_node_tests.utils import clusterlib_utils +from cardano_node_tests.utils import helpers +from cardano_node_tests.utils import submit_utils +from cardano_node_tests.utils.versions import VERSIONS + +LOGGER = logging.getLogger(__name__) +DATA_DIR = pl.Path(__file__).parent / "data" + +pytestmark = pytest.mark.skipif( + VERSIONS.transaction_era < VERSIONS.CONWAY, + reason="runs only with Tx era >= Conway", +) + + +class TestCommittee: + """Tests for Constitutional Committee.""" + + @pytest.fixture + def payment_addr( + self, + cluster_manager: cluster_management.ClusterManager, + cluster: clusterlib.ClusterLib, + ) -> clusterlib.AddressRecord: + """Create new payment address.""" + addr = clusterlib_utils.create_payment_addr_records( + f"chain_tx_addr_ci{cluster_manager.cluster_instance_num}", + cluster_obj=cluster, + )[0] + + # Fund source address + clusterlib_utils.fund_from_faucet( + addr, + cluster_obj=cluster, + faucet_data=cluster_manager.cache.addrs_data["user1"], + ) + + return addr + + @allure.link(helpers.get_vcs_link()) + @submit_utils.PARAM_SUBMIT_METHOD + @common.PARAM_USE_BUILD_CMD + def test_register_and_resign_committee( + self, + cluster: clusterlib.ClusterLib, + payment_addr: clusterlib.AddressRecord, + use_build_cmd: bool, + submit_method: str, + ): + """Test Constitutional Committee Member registration and resignation. + + * register CC Member + * check that CC Member was registered + * resign from CC Member position + * check that CC Member resigned + """ + temp_template = common.get_test_id(cluster) + + # Register CC Member + + reg_cc = clusterlib_utils.register_committee( + cluster_obj=cluster, + name_template=temp_template, + payment_addr=payment_addr, + submit_method=submit_method, + use_build_cmd=use_build_cmd, + ) + + reg_out_utxos = cluster.g_query.get_utxo(tx_raw_output=reg_cc.tx_output) + assert ( + clusterlib.filter_utxos(utxos=reg_out_utxos, address=payment_addr.address)[0].amount + == clusterlib.calculate_utxos_balance(reg_cc.tx_output.txins) - reg_cc.tx_output.fee + ), f"Incorrect balance for source address `{payment_addr.address}`" + + reg_committee_state = cluster.g_conway_governance.query.committee_state() + member_key = "keyHash-" + reg_cc.key_hash + assert ( + reg_committee_state["committee"][member_key]["hotCredsAuthStatus"]["tag"] + == "MemberAuthorized" + ), "CC Memebr was not registered" + + # Resignation of CC Member + + res_cert = cluster.g_conway_governance.committee.gen_cold_key_resignation_cert( + key_name=temp_template, + cold_vkey_file=reg_cc.cold_key_pair.vkey_file, + resignation_metadata_url="http://www.cc-resign.com", + resignation_metadata_hash="5d372dca1a4cc90d7d16d966c48270e33e3aa0abcb0e78f0d5ca7ff330d2245d", + ) + + tx_files_res = clusterlib.TxFiles( + certificate_files=[res_cert], + signing_key_files=[payment_addr.skey_file, reg_cc.cold_key_pair.skey_file], + ) + + if use_build_cmd: + tx_output_res = cluster.g_transaction.build_tx( + src_address=payment_addr.address, + tx_name=temp_template, + tx_files=tx_files_res, + witness_override=len(tx_files_res.signing_key_files), + ) + else: + fee_res = cluster.g_transaction.calculate_tx_fee( + src_address=payment_addr.address, + tx_name=temp_template, + tx_files=tx_files_res, + witness_count_add=len(tx_files_res.signing_key_files), + ) + tx_output_res = cluster.g_transaction.build_raw_tx( + src_address=payment_addr.address, + tx_name=temp_template, + tx_files=tx_files_res, + fee=fee_res, + ) + + tx_signed_res = cluster.g_transaction.sign_tx( + tx_body_file=tx_output_res.out_file, + signing_key_files=tx_files_res.signing_key_files, + tx_name=temp_template, + ) + submit_utils.submit_tx( + submit_method=submit_method, + cluster_obj=cluster, + tx_file=tx_signed_res, + txins=tx_output_res.txins, + ) + + res_committee_state = cluster.g_conway_governance.query.committee_state() + assert ( + res_committee_state["committee"][member_key]["hotCredsAuthStatus"]["tag"] + == "MemberResigned" + ), "CC Memebr not resigned" + + res_out_utxos = cluster.g_query.get_utxo(tx_raw_output=reg_cc.tx_output) + assert ( + clusterlib.filter_utxos(utxos=res_out_utxos, address=payment_addr.address)[0].amount + == clusterlib.calculate_utxos_balance(tx_output_res.txins) - tx_output_res.fee + ), f"Incorrect balance for source address `{payment_addr.address}`" diff --git a/cardano_node_tests/utils/clusterlib_utils.py b/cardano_node_tests/utils/clusterlib_utils.py index 43a38b305..bf6f0f548 100644 --- a/cardano_node_tests/utils/clusterlib_utils.py +++ b/cardano_node_tests/utils/clusterlib_utils.py @@ -49,6 +49,14 @@ class DRepRegistration(tp.NamedTuple): deposit: int +class CommitteeRegistration(tp.NamedTuple): + registration_cert: pl.Path + cold_key_pair: clusterlib.KeyPair + hot_key_pair: clusterlib.KeyPair + tx_output: clusterlib.TxRawOutput + key_hash: str + + def get_pool_state( cluster_obj: clusterlib.ClusterLib, pool_id: str, @@ -1377,3 +1385,74 @@ def register_drep( drep_id=drep_id, deposit=deposit_amt, ) + + +def register_committee( + cluster_obj: clusterlib.ClusterLib, + name_template: str, + payment_addr: clusterlib.AddressRecord, + submit_method: str = submit_utils.SubmitMethods.CLI, + use_build_cmd: bool = False, +) -> CommitteeRegistration: + """Register Constitutional Committee Member.""" + committee_cold_keys = cluster_obj.g_conway_governance.committee.gen_cold_key_pair( + key_name=name_template + ) + committee_hot_keys = cluster_obj.g_conway_governance.committee.gen_hot_key_pair( + key_name=name_template + ) + reg_cert = cluster_obj.g_conway_governance.committee.gen_hot_key_auth_cert( + key_name=name_template, + cold_vkey_file=committee_cold_keys.vkey_file, + hot_key_file=committee_hot_keys.vkey_file, + ) + + tx_files = clusterlib.TxFiles( + certificate_files=[reg_cert], + signing_key_files=[payment_addr.skey_file, committee_cold_keys.skey_file], + ) + + if use_build_cmd: + tx_output = cluster_obj.g_transaction.build_tx( + src_address=payment_addr.address, + tx_name=name_template, + tx_files=tx_files, + witness_override=len(tx_files.signing_key_files), + ) + else: + fee = cluster_obj.g_transaction.calculate_tx_fee( + src_address=payment_addr.address, + tx_name=name_template, + tx_files=tx_files, + witness_count_add=len(tx_files.signing_key_files), + ) + tx_output = cluster_obj.g_transaction.build_raw_tx( + src_address=payment_addr.address, + tx_name=name_template, + tx_files=tx_files, + fee=fee, + ) + + tx_signed = cluster_obj.g_transaction.sign_tx( + tx_body_file=tx_output.out_file, + signing_key_files=tx_files.signing_key_files, + tx_name=name_template, + ) + submit_utils.submit_tx( + submit_method=submit_method, + cluster_obj=cluster_obj, + tx_file=tx_signed, + txins=tx_output.txins, + ) + + key_hash = cluster_obj.g_conway_governance.committee.get_key_hash( + vkey_file=committee_cold_keys.vkey_file, + ) + + return CommitteeRegistration( + registration_cert=reg_cert, + cold_key_pair=committee_cold_keys, + hot_key_pair=committee_cold_keys, + tx_output=tx_output, + key_hash=key_hash, + )