Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for voting with scripts #245

Merged
merged 1 commit into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cardano_clusterlib/clusterlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from cardano_clusterlib.structs import OptionalMint
from cardano_clusterlib.structs import OptionalScriptCerts
from cardano_clusterlib.structs import OptionalScriptTxIn
from cardano_clusterlib.structs import OptionalScriptVotes
from cardano_clusterlib.structs import OptionalScriptWithdrawals
from cardano_clusterlib.structs import OptionalTxOuts
from cardano_clusterlib.structs import OptionalUTXOData
Expand All @@ -48,6 +49,7 @@
from cardano_clusterlib.structs import PoolParamsTop
from cardano_clusterlib.structs import PoolUser
from cardano_clusterlib.structs import ScriptTxIn
from cardano_clusterlib.structs import ScriptVote
from cardano_clusterlib.structs import ScriptWithdrawal
from cardano_clusterlib.structs import StakeAddrInfo
from cardano_clusterlib.structs import TxFiles
Expand Down
7 changes: 7 additions & 0 deletions cardano_clusterlib/conway_gov_action_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ def _get_cc_members_args(
str(cc_member.cold_vkey_hash),
]
)
elif cc_member.cold_script_hash:
cc_members_args.extend(
[
f"--{arg_action}-cc-cold-script-hash",
str(cc_member.cold_script_hash),
]
)
else:
msg = f"Either {arg_action} cold verification key or its hash must be set."
raise AssertionError(msg)
Expand Down
28 changes: 18 additions & 10 deletions cardano_clusterlib/conway_gov_vote_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def create_committee(
cc_hot_vkey: str = "",
cc_hot_vkey_file: tp.Optional[itp.FileType] = None,
cc_hot_key_hash: str = "",
cc_hot_script_hash: str = "",
anchor_url: str = "",
anchor_data_hash: str = "",
destination_dir: itp.FileType = ".",
Expand All @@ -92,13 +93,15 @@ def create_committee(
)

if cc_hot_vkey:
key_args = ["--cc-hot-verification-key", cc_hot_vkey]
cred_args = ["--cc-hot-verification-key", cc_hot_vkey]
elif cc_hot_vkey_file:
key_args = ["--cc-hot-verification-key-file", str(cc_hot_vkey_file)]
cred_args = ["--cc-hot-verification-key-file", str(cc_hot_vkey_file)]
elif cc_hot_key_hash:
key_args = ["--cc-hot-key-hash", cc_hot_key_hash]
cred_args = ["--cc-hot-key-hash", cc_hot_key_hash]
elif cc_hot_script_hash:
cred_args = ["--cc-hot-script-hash", cc_hot_script_hash]
else:
msg = "No CC key was specified."
msg = "No CC key or script hash was specified."
raise AssertionError(msg)

self._clusterlib_obj.cli(
Expand All @@ -107,7 +110,7 @@ def create_committee(
"create",
*vote_args,
*gov_action_args,
*key_args,
*cred_args,
*anchor_args,
"--out-file",
str(out_file),
Expand All @@ -123,6 +126,7 @@ def create_committee(
cc_hot_vkey=cc_hot_vkey,
cc_hot_vkey_file=helpers._maybe_path(cc_hot_vkey_file),
cc_hot_key_hash=cc_hot_key_hash,
cc_hot_script_hash=cc_hot_script_hash,
anchor_url=anchor_url,
anchor_data_hash=anchor_data_hash,
)
Expand All @@ -137,6 +141,7 @@ def create_drep(
drep_vkey: str = "",
drep_vkey_file: tp.Optional[itp.FileType] = None,
drep_key_hash: str = "",
drep_script_hash: str = "",
anchor_url: str = "",
anchor_data_hash: str = "",
destination_dir: itp.FileType = ".",
Expand All @@ -154,13 +159,15 @@ def create_drep(
)

if drep_vkey:
key_args = ["--drep-verification-key", drep_vkey]
cred_args = ["--drep-verification-key", drep_vkey]
elif drep_vkey_file:
key_args = ["--drep-verification-key-file", str(drep_vkey_file)]
cred_args = ["--drep-verification-key-file", str(drep_vkey_file)]
elif drep_key_hash:
key_args = ["--drep-key-hash", drep_key_hash]
cred_args = ["--drep-key-hash", drep_key_hash]
elif drep_script_hash:
cred_args = ["--drep-script-hash", drep_script_hash]
else:
msg = "No DRep key was specified."
msg = "No DRep key or script hash was specified."
raise AssertionError(msg)

self._clusterlib_obj.cli(
Expand All @@ -169,7 +176,7 @@ def create_drep(
"create",
*vote_args,
*gov_action_args,
*key_args,
*cred_args,
*anchor_args,
"--out-file",
str(out_file),
Expand All @@ -185,6 +192,7 @@ def create_drep(
drep_vkey=drep_vkey,
drep_vkey_file=helpers._maybe_path(drep_vkey_file),
drep_key_hash=drep_key_hash,
drep_script_hash=drep_script_hash,
anchor_url=anchor_url,
anchor_data_hash=anchor_data_hash,
)
Expand Down
20 changes: 20 additions & 0 deletions cardano_clusterlib/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ class ComplexCert:
redeemer_value: str = ""


@dataclasses.dataclass(frozen=True, order=True)
class ScriptVote:
"""Data structure for voting that are combined with scripts."""

vote_file: itp.FileType = ""
script_file: itp.FileType = ""
# values below needed only when working with Plutus
collaterals: OptionalUTXOData = ()
execution_units: tp.Optional[tp.Tuple[int, int]] = None
redeemer_file: itp.FileType = ""
redeemer_cbor_file: itp.FileType = ""
redeemer_value: str = ""


@dataclasses.dataclass(frozen=True, order=True)
class Mint:
txouts: tp.List[TxOut]
Expand All @@ -161,6 +175,8 @@ class Mint:
OptionalScriptWithdrawals = tp.Union[tp.List[ScriptWithdrawal], tp.Tuple[()]]
# list of `Mint`s, empty list, or empty tuple
OptionalMint = tp.Union[tp.List[Mint], tp.Tuple[()]]
# list of `ScriptVote`s, empty list, or empty tuple
OptionalScriptVotes = tp.Union[tp.List[ScriptVote], tp.Tuple[()]]


@dataclasses.dataclass(frozen=True, order=True)
Expand Down Expand Up @@ -206,6 +222,7 @@ class TxRawOutput:
era: str = "" # Era used for the transaction
script_txins: OptionalScriptTxIn = () # Tx inputs that are combined with scripts
script_withdrawals: OptionalScriptWithdrawals = () # Withdrawals that are combined with scripts
script_votes: OptionalScriptVotes = () # Votes that are combined with scripts
complex_certs: OptionalScriptCerts = () # Certificates that are combined with scripts
mint: OptionalMint = () # Minting data (Tx outputs, script, etc.)
invalid_hereafter: tp.Optional[int] = None # Validity interval upper bound
Expand Down Expand Up @@ -287,6 +304,7 @@ class CCMember:
cold_skey: str = ""
cold_skey_file: itp.FileType = ""
cold_skey_hash: str = ""
cold_script_hash: str = ""
hot_vkey: str = ""
hot_vkey_file: itp.FileType = ""
hot_vkey_hash: str = ""
Expand All @@ -304,6 +322,7 @@ class VoteCC:
cc_hot_vkey: str = ""
cc_hot_vkey_file: tp.Optional[pl.Path] = None
cc_hot_key_hash: str = ""
cc_hot_script_hash: str = ""
anchor_url: str = ""
anchor_data_hash: str = ""

Expand All @@ -317,6 +336,7 @@ class VoteDrep:
drep_vkey: str = ""
drep_vkey_file: tp.Optional[pl.Path] = None
drep_key_hash: str = ""
drep_script_hash: str = ""
anchor_url: str = ""
anchor_data_hash: str = ""

Expand Down
19 changes: 19 additions & 0 deletions cardano_clusterlib/transaction_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def build_raw_tx_bare(
ttl: tp.Optional[int] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
script_valid: bool = True,
Expand Down Expand Up @@ -195,6 +196,7 @@ def build_raw_tx_bare(
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
script_valid: A bool indicating that the script is valid (True by default).
Expand Down Expand Up @@ -256,6 +258,7 @@ def build_raw_tx_bare(
mint=mint,
complex_certs=complex_certs,
script_withdrawals=script_withdrawals,
script_votes=script_votes,
for_build=False,
)

Expand Down Expand Up @@ -321,6 +324,7 @@ def build_raw_tx_bare(
era=self._clusterlib_obj.command_era or self._clusterlib_obj.tx_era,
script_txins=script_txins,
script_withdrawals=script_withdrawals,
script_votes=script_votes,
complex_certs=complex_certs,
mint=mint,
invalid_hereafter=invalid_hereafter or ttl,
Expand Down Expand Up @@ -360,6 +364,7 @@ def build_raw_tx(
ttl: tp.Optional[int] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
deposit: tp.Optional[int] = None,
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
Expand Down Expand Up @@ -395,6 +400,7 @@ def build_raw_tx(
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
deposit: A deposit amount needed by the transaction (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
Expand Down Expand Up @@ -453,6 +459,7 @@ def build_raw_tx(
required_signer_hashes=required_signer_hashes,
withdrawals=collected_data.withdrawals,
script_withdrawals=collected_data.script_withdrawals,
script_votes=script_votes,
invalid_hereafter=invalid_hereafter or ttl,
invalid_before=invalid_before,
join_txouts=join_txouts,
Expand Down Expand Up @@ -530,6 +537,7 @@ def calculate_tx_fee(
ttl: tp.Optional[int] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
deposit: tp.Optional[int] = None,
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
Expand Down Expand Up @@ -566,6 +574,7 @@ def calculate_tx_fee(
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
deposit: A deposit amount needed by the transaction (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
Expand Down Expand Up @@ -608,6 +617,7 @@ def calculate_tx_fee(
fee=self.min_fee,
withdrawals=withdrawals,
script_withdrawals=script_withdrawals,
script_votes=script_votes,
invalid_hereafter=invalid_hereafter or ttl,
invalid_before=invalid_before,
deposit=deposit,
Expand Down Expand Up @@ -735,6 +745,7 @@ def build_tx( # noqa: C901
required_signer_hashes: tp.Optional[tp.List[str]] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
deposit: tp.Optional[int] = None,
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
Expand Down Expand Up @@ -774,6 +785,7 @@ def build_tx( # noqa: C901
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
deposit: A deposit amount needed by the transaction (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
Expand Down Expand Up @@ -866,6 +878,7 @@ def build_tx( # noqa: C901
mint=mint,
complex_certs=complex_certs,
script_withdrawals=collected_data.script_withdrawals,
script_votes=script_votes,
for_build=True,
)

Expand Down Expand Up @@ -931,6 +944,7 @@ def build_tx( # noqa: C901
era=self._clusterlib_obj.command_era or self._clusterlib_obj.tx_era,
script_txins=script_txins,
script_withdrawals=collected_data.script_withdrawals,
script_votes=script_votes,
complex_certs=complex_certs,
mint=mint,
invalid_hereafter=invalid_hereafter,
Expand Down Expand Up @@ -1159,6 +1173,7 @@ def send_tx(
ttl: tp.Optional[int] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
deposit: tp.Optional[int] = None,
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
Expand Down Expand Up @@ -1203,6 +1218,7 @@ def send_tx(
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
deposit: A deposit amount needed by the transaction (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
Expand Down Expand Up @@ -1274,6 +1290,7 @@ def send_tx(
required_signer_hashes=required_signer_hashes,
withdrawals=withdrawals,
script_withdrawals=script_withdrawals,
script_votes=script_votes,
deposit=deposit,
invalid_hereafter=invalid_hereafter or ttl,
invalid_before=invalid_before,
Expand Down Expand Up @@ -1387,6 +1404,7 @@ def calculate_plutus_script_cost(
required_signer_hashes: tp.Optional[tp.List[str]] = None,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
script_votes: structs.OptionalScriptVotes = (),
deposit: tp.Optional[int] = None,
invalid_hereafter: tp.Optional[int] = None,
invalid_before: tp.Optional[int] = None,
Expand Down Expand Up @@ -1425,6 +1443,7 @@ def calculate_plutus_script_cost(
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
data (optional).
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
deposit: A deposit amount needed by the transaction (optional).
invalid_hereafter: A last block when the transaction is still valid (optional).
invalid_before: A first block when the transaction is valid (optional).
Expand Down
35 changes: 35 additions & 0 deletions cardano_clusterlib/txtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,7 @@ def _get_script_args( # noqa: C901
mint: structs.OptionalMint,
complex_certs: structs.OptionalScriptCerts,
script_withdrawals: structs.OptionalScriptWithdrawals,
script_votes: structs.OptionalScriptVotes,
for_build: bool = True,
) -> tp.List[str]:
# pylint: disable=too-many-statements,too-many-branches
Expand Down Expand Up @@ -1195,6 +1196,40 @@ def _get_script_args( # noqa: C901
["--withdrawal-reference-tx-in-redeemer-value", str(wrec.redeemer_value)]
)

# voting
for vrec in script_votes:
vrec_collaterals = {f"{c.utxo_hash}#{c.utxo_ix}" for c in vrec.collaterals}
collaterals_all.update(vrec_collaterals)
grouped_args.extend(
[
"--vote-file",
str(vrec.vote_file),
]
)

if vrec.script_file:
grouped_args.extend(
[
"--vote-script-file",
str(vrec.script_file),
]
)

if not for_build and vrec.execution_units:
grouped_args.extend(
[
"--vote-execution-units",
f"({vrec.execution_units[0]},{vrec.execution_units[1]})",
]
)

if vrec.redeemer_file:
grouped_args.extend(["--vote-redeemer-file", str(vrec.redeemer_file)])
if vrec.redeemer_cbor_file:
grouped_args.extend(["--vote-redeemer-cbor-file", str(vrec.redeemer_cbor_file)])
if vrec.redeemer_value:
grouped_args.extend(["--vote-redeemer-value", str(vrec.redeemer_value)])

# add unique collaterals
grouped_args.extend(
[
Expand Down
Loading