Skip to content

Commit

Permalink
Merge pull request #2412 from mkoura/add_hardfork_test
Browse files Browse the repository at this point in the history
Add hardfork governance test
  • Loading branch information
mkoura committed May 8, 2024
2 parents 200fd51 + 15927e9 commit 21b3f3d
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 8 deletions.
3 changes: 3 additions & 0 deletions cardano_node_tests/tests/reqs_conway.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def __r(id: str) -> requirements.Req:
cip031b = __r("CIP031b")
cip031c_01 = __r("intCIP031c-01") # anchor
cip031c_02 = __r("intCIP031c-02") # script hash
cip031d = __r("CIP031d")
cip031e = __r("CIP031e")
cip031f = __r("CIP031f")
cip032en = __r("intCIP032en") # enacted
Expand All @@ -66,6 +67,7 @@ def __r(id: str) -> requirements.Req:
cip040 = __r("CIP040")
cip041 = __r("CIP041")
cip042 = __r("CIP042")
cip043_01 = __r("intCIP043-01")
cip044 = __r("CIP044")
cip045 = __r("CIP045")
cip046 = __r("CIP046")
Expand Down Expand Up @@ -136,6 +138,7 @@ def __r(id: str) -> requirements.Req:
cli016 = __r("CLI016")
cli017 = __r("CLI017")
cli018 = __r("CLI018")
cli019 = __r("CLI019")
cli020 = __r("CLI020")
cli021 = __r("CLI021")
cli022 = __r("CLI022")
Expand Down
281 changes: 281 additions & 0 deletions cardano_node_tests/tests/tests_conway/test_hardfork.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
"""Tests for Conway hard-fork."""

import logging

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.tests import reqs_conway as reqc
from cardano_node_tests.tests.tests_conway import conway_common
from cardano_node_tests.utils import clusterlib_utils
from cardano_node_tests.utils import governance_setup
from cardano_node_tests.utils import governance_utils
from cardano_node_tests.utils import helpers
from cardano_node_tests.utils.versions import VERSIONS

LOGGER = logging.getLogger(__name__)

pytestmark = pytest.mark.skipif(
VERSIONS.transaction_era < VERSIONS.CONWAY,
reason="runs only with Tx era >= Conway",
)


@pytest.fixture
def pool_user_lg(
cluster_manager: cluster_management.ClusterManager,
cluster_lock_governance: governance_setup.GovClusterT,
) -> clusterlib.PoolUser:
"""Create a pool user for "lock governance"."""
cluster, __ = cluster_lock_governance
key = helpers.get_current_line_str()
return conway_common.get_pool_user(
cluster_manager=cluster_manager, cluster_obj=cluster, caching_key=key
)


class TestHardfork:
"""Tests for hard-fork."""

@pytest.fixture(scope="class")
def skip_hf_command(self):
if not clusterlib_utils.cli_has("action create-hardfork"):
pytest.skip("The `cardano-cli action create-hardfork` command is not available.")

@pytest.fixture
def skip_hf_version(
self,
cluster_lock_governance: governance_setup.GovClusterT,
):
cluster, __ = cluster_lock_governance
pv = cluster.g_conway_governance.query.gov_state()["currentPParams"]["protocolVersion"][
"major"
]
if pv != 9:
pytest.skip("The major protocol version needs to be 9.")

@allure.link(helpers.get_vcs_link())
@pytest.mark.long
def test_hardfork(
self,
skip_hf_command: None, # noqa: ARG002
skip_hf_version: None, # noqa: ARG002
cluster_manager: cluster_management.ClusterManager,
cluster_lock_governance: governance_setup.GovClusterT,
pool_user_lg: clusterlib.PoolUser,
):
"""Test hardfork action.
* create a "hardfork" action
* check that DReps cannot vote during the bootstrap period
* vote to disapprove the action
* vote to approve the action
* check that the action is ratified
* try to disapprove the ratified action, this shouldn't have any effect
* check that the action is enacted
* check that it's not possible to vote on enacted action
"""
cluster, governance_data = cluster_lock_governance
temp_template = common.get_test_id(cluster)

init_return_account_balance = cluster.g_query.get_stake_addr_info(
pool_user_lg.stake.address
).reward_account_balance

# Create an action
deposit_amt = cluster.conway_genesis["govActionDeposit"]
anchor_url = "http://www.hardfork.com"
anchor_data_hash = "5d372dca1a4cc90d7d16d966c48270e33e3aa0abcb0e78f0d5ca7ff330d2245d"
prev_action_rec = governance_utils.get_prev_action(
action_type=governance_utils.PrevGovActionIds.HARDFORK,
gov_state=cluster.g_conway_governance.query.gov_state(),
)

_url = helpers.get_vcs_link()
[
r.start(url=_url)
for r in (reqc.cli019, reqc.cip031a_07, reqc.cip031d, reqc.cip038_07, reqc.cip054_07)
]

hardfork_action = cluster.g_conway_governance.action.create_hardfork(
action_name=temp_template,
deposit_amt=deposit_amt,
anchor_url=anchor_url,
anchor_data_hash=anchor_data_hash,
protocol_major_version=10,
protocol_minor_version=0,
prev_action_txid=prev_action_rec.txid,
prev_action_ix=prev_action_rec.ix,
deposit_return_stake_vkey_file=pool_user_lg.stake.vkey_file,
)
[r.success() for r in (reqc.cip031a_07, reqc.cip031d, reqc.cip054_07)]

tx_files_action = clusterlib.TxFiles(
proposal_files=[hardfork_action.action_file],
signing_key_files=[
pool_user_lg.payment.skey_file,
],
)

# Make sure we have enough time to submit the proposal and the votes in one epoch
clusterlib_utils.wait_for_epoch_interval(
cluster_obj=cluster, start=1, stop=common.EPOCH_STOP_SEC_BUFFER - 20
)

tx_output_action = clusterlib_utils.build_and_submit_tx(
cluster_obj=cluster,
name_template=f"{temp_template}_action",
src_address=pool_user_lg.payment.address,
use_build_cmd=True,
tx_files=tx_files_action,
)

out_utxos_action = cluster.g_query.get_utxo(tx_raw_output=tx_output_action)
assert (
clusterlib.filter_utxos(utxos=out_utxos_action, address=pool_user_lg.payment.address)[
0
].amount
== clusterlib.calculate_utxos_balance(tx_output_action.txins)
- tx_output_action.fee
- deposit_amt
), f"Incorrect balance for source address `{pool_user_lg.payment.address}`"

action_txid = cluster.g_transaction.get_txid(tx_body_file=tx_output_action.out_file)
action_gov_state = cluster.g_conway_governance.query.gov_state()
_cur_epoch = cluster.g_query.get_epoch()
conway_common.save_gov_state(
gov_state=action_gov_state, name_template=f"{temp_template}_action_{_cur_epoch}"
)
prop_action = governance_utils.lookup_proposal(
gov_state=action_gov_state, action_txid=action_txid
)
assert prop_action, "Hardfork action not found"
assert (
prop_action["proposalProcedure"]["govAction"]["tag"]
== governance_utils.ActionTags.HARDFORK_INIT.value
), "Incorrect action tag"

action_ix = prop_action["actionId"]["govActionIx"]

# Check that DReps cannot vote
with pytest.raises(clusterlib.CLIError) as excinfo:
conway_common.cast_vote(
cluster_obj=cluster,
governance_data=governance_data,
name_template=f"{temp_template}_no",
payment_addr=pool_user_lg.payment,
action_txid=action_txid,
action_ix=action_ix,
approve_cc=False,
approve_drep=False,
approve_spo=False,
)
err_str = str(excinfo.value)
assert "(DisallowedVotesDuringBootstrap ((DRepVoter" in err_str, err_str

# Vote & disapprove the action
reqc.cip043_01.start(url=helpers.get_vcs_link())
conway_common.cast_vote(
cluster_obj=cluster,
governance_data=governance_data,
name_template=f"{temp_template}_no",
payment_addr=pool_user_lg.payment,
action_txid=action_txid,
action_ix=action_ix,
approve_cc=False,
approve_spo=False,
)
reqc.cli019.success()

# Vote & approve the action
voted_votes = conway_common.cast_vote(
cluster_obj=cluster,
governance_data=governance_data,
name_template=f"{temp_template}_yes",
payment_addr=pool_user_lg.payment,
action_txid=action_txid,
action_ix=action_ix,
approve_cc=True,
approve_spo=True,
)

# Testnet will be using an unexpected protocol version, respin is needed
cluster_manager.set_needs_respin()

# Check ratification
_cur_epoch = cluster.wait_for_new_epoch(padding_seconds=5)
rat_gov_state = cluster.g_conway_governance.query.gov_state()
conway_common.save_gov_state(
gov_state=rat_gov_state, name_template=f"{temp_template}_rat_{_cur_epoch}"
)
rat_action = governance_utils.lookup_ratified_actions(
gov_state=rat_gov_state, action_txid=action_txid
)
assert rat_action, "Action not found in ratified actions"
reqc.cip043_01.success()

# Disapprove ratified action, the voting shouldn't have any effect
conway_common.cast_vote(
cluster_obj=cluster,
governance_data=governance_data,
name_template=f"{temp_template}_after_ratification",
payment_addr=pool_user_lg.payment,
action_txid=action_txid,
action_ix=action_ix,
approve_cc=False,
approve_spo=False,
)

assert rat_gov_state["nextRatifyState"]["ratificationDelayed"], "Ratification not delayed"
reqc.cip038_07.success()

# Check enactment
_cur_epoch = cluster.wait_for_new_epoch(padding_seconds=5)
enact_gov_state = cluster.g_conway_governance.query.gov_state()
conway_common.save_gov_state(
gov_state=enact_gov_state, name_template=f"{temp_template}_enact_{_cur_epoch}"
)
assert (
enact_gov_state["currentPParams"]["protocolVersion"]["major"] == 10
), "Incorrect major version"

enact_prev_action_rec = governance_utils.get_prev_action(
action_type=governance_utils.PrevGovActionIds.HARDFORK,
gov_state=enact_gov_state,
)
assert enact_prev_action_rec.txid == action_txid, "Incorrect previous action Txid"
assert enact_prev_action_rec.ix == action_ix, "Incorrect previous action index"

enact_deposit_returned = cluster.g_query.get_stake_addr_info(
pool_user_lg.stake.address
).reward_account_balance

assert (
enact_deposit_returned == init_return_account_balance + deposit_amt
), "Incorrect return account balance"

# Try to vote on enacted action
with pytest.raises(clusterlib.CLIError) as excinfo:
conway_common.cast_vote(
cluster_obj=cluster,
governance_data=governance_data,
name_template=f"{temp_template}_enacted",
payment_addr=pool_user_lg.payment,
action_txid=action_txid,
action_ix=action_ix,
approve_drep=False,
approve_spo=False,
)
err_str = str(excinfo.value)
assert "(GovActionsDoNotExist" in err_str, err_str

# Check action view
governance_utils.check_action_view(cluster_obj=cluster, action_data=hardfork_action)

# Check vote view
if voted_votes.cc:
governance_utils.check_vote_view(cluster_obj=cluster, vote_data=voted_votes.cc[0])
governance_utils.check_vote_view(cluster_obj=cluster, vote_data=voted_votes.spo[0])
15 changes: 14 additions & 1 deletion cardano_node_tests/utils/governance_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@

ActionsAllT = tp.Union[ # pylint: disable=invalid-name
clusterlib.ActionConstitution,
clusterlib.ActionHardfork,
clusterlib.ActionInfo,
clusterlib.ActionNoConfidence,
clusterlib.ActionPParamsUpdate,
clusterlib.ActionUpdateCommittee,
clusterlib.ActionTreasuryWithdrawal,
clusterlib.ActionUpdateCommittee,
]

VotesAllT = tp.Union[ # pylint: disable=invalid-name
Expand Down Expand Up @@ -76,6 +77,7 @@ class ActionTags(enum.Enum):
TREASURY_WITHDRAWALS = "TreasuryWithdrawals"
INFO_ACTION = "InfoAction"
NO_CONFIDENCE = "NoConfidence"
HARDFORK_INIT = "HardForkInitiation"


def get_drep_cred_name(drep_id: str) -> str:
Expand Down Expand Up @@ -376,6 +378,17 @@ def _get_cvkey_hash(member: clusterlib.CCMember) -> str:
else None,
"tag": ActionTags.NO_CONFIDENCE.value,
}
elif isinstance(action_data, clusterlib.ActionHardfork):
gov_action = {
"contents": [
None, # TODO 8.11: what is this?
{
"major": action_data.protocol_major_version,
"minor": action_data.protocol_minor_version,
},
],
"tag": ActionTags.HARDFORK_INIT.value,
}
else:
msg = f"Not implemented for action `{action_data}`"
raise NotImplementedError(msg)
Expand Down
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ packages = [{include = "cardano_node_tests"}]
[tool.poetry.dependencies]
python = ">=3.9,<4.0"
allure-pytest = "^2.13.2"
cardano-clusterlib = "^0.6.0a17"
cardano-clusterlib = "^0.6.0a18"
cbor2 = "^5.4.6"
filelock = "^3.12.2"
hypothesis = "^6.82.6"
Expand Down
2 changes: 1 addition & 1 deletion requirements_freeze.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ allure-pytest==2.13.5 ; python_version >= "3.9" and python_version < "4.0"
allure-python-commons==2.13.5 ; python_version >= "3.9" and python_version < "4.0"
annotated-types==0.6.0 ; python_version >= "3.9" and python_version < "4.0"
attrs==23.2.0 ; python_version >= "3.9" and python_version < "4.0"
cardano-clusterlib==0.6.0a17 ; python_version >= "3.9" and python_version < "4.0"
cardano-clusterlib==0.6.0a18 ; python_version >= "3.9" and python_version < "4.0"
cbor2==5.6.3 ; python_version >= "3.9" and python_version < "4.0"
certifi==2024.2.2 ; python_version >= "3.9" and python_version < "4.0"
cffi==1.16.0 ; python_version >= "3.9" and python_version < "4.0"
Expand Down

0 comments on commit 21b3f3d

Please sign in to comment.