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

Adds support for proposals with script in transaction group and constitution_script_hash in action group #248

Merged
merged 2 commits into from
Jul 10, 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 @@ -32,13 +32,15 @@
from cardano_clusterlib.structs import CLIOut
from cardano_clusterlib.structs import ColdKeyPair
from cardano_clusterlib.structs import ComplexCert
from cardano_clusterlib.structs import ComplexProposal
from cardano_clusterlib.structs import DataForBuild
from cardano_clusterlib.structs import GenesisKeys
from cardano_clusterlib.structs import KeyPair
from cardano_clusterlib.structs import LeadershipSchedule
from cardano_clusterlib.structs import Mint
from cardano_clusterlib.structs import OptionalMint
from cardano_clusterlib.structs import OptionalScriptCerts
from cardano_clusterlib.structs import OptionalScriptProposals
from cardano_clusterlib.structs import OptionalScriptTxIn
from cardano_clusterlib.structs import OptionalScriptVotes
from cardano_clusterlib.structs import OptionalScriptWithdrawals
Expand Down
8 changes: 8 additions & 0 deletions cardano_clusterlib/conway_gov_action_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ def create_constitution(
anchor_data_hash: str,
constitution_url: str,
constitution_hash: str,
constitution_script_hash: str = "",
deposit_return_stake_vkey: str = "",
deposit_return_stake_vkey_file: tp.Optional[itp.FileType] = None,
deposit_return_stake_key_hash: str = "",
Expand Down Expand Up @@ -170,6 +171,13 @@ def create_constitution(
"--constitution-hash",
str(constitution_hash),
]
if constitution_script_hash:
constitution_anchor_args.extend(
[
"--constitution-script-hash",
str(constitution_script_hash),
]
)

self._clusterlib_obj.cli(
[
Expand Down
21 changes: 21 additions & 0 deletions cardano_clusterlib/structs.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,24 @@ class ComplexCert:
redeemer_value: str = ""


@dataclasses.dataclass(frozen=True, order=True)
class ComplexProposal:
"""Data structure for proposal with optional data for Plutus scripts.

If used for one proposal, it needs to be used for all the other proposals in a given
transaction (instead of `TxFiles.proposal_files`). Otherwise, order of proposals
cannot be guaranteed.
"""

proposal_file: itp.FileType
script_file: itp.FileType = ""
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 ScriptVote:
"""Data structure for voting that are combined with scripts."""
Expand Down Expand Up @@ -171,6 +189,8 @@ class Mint:
OptionalScriptTxIn = tp.Union[tp.List[ScriptTxIn], tp.Tuple[()]]
# list of `ComplexCert`s, empty list, or empty tuple
OptionalScriptCerts = tp.Union[tp.List[ComplexCert], tp.Tuple[()]]
# list of `ComplexProposal`s, empty list, or empty tuple
OptionalScriptProposals = tp.Union[tp.List[ComplexProposal], tp.Tuple[()]]
# list of `ScriptWithdrawal`s, empty list, or empty tuple
OptionalScriptWithdrawals = tp.Union[tp.List[ScriptWithdrawal], tp.Tuple[()]]
# list of `Mint`s, empty list, or empty tuple
Expand Down Expand Up @@ -224,6 +244,7 @@ class TxRawOutput:
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
complex_proposals: OptionalScriptProposals = () # Proposals that are combined with scripts
mint: OptionalMint = () # Minting data (Tx outputs, script, etc.)
invalid_hereafter: tp.Optional[int] = None # Validity interval upper bound
invalid_before: tp.Optional[int] = None # Validity interval lower bound
Expand Down
41 changes: 40 additions & 1 deletion cardano_clusterlib/transaction_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def get_tx_deposit(self, tx_files: structs.TxFiles) -> int:

return deposit

def build_raw_tx_bare(
def build_raw_tx_bare( # noqa: C901
self,
out_file: itp.FileType,
txouts: tp.List[structs.TxOut],
Expand All @@ -158,6 +158,7 @@ def build_raw_tx_bare(
total_collateral_amount: tp.Optional[int] = None,
mint: structs.OptionalMint = (),
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
required_signers: itp.OptionalFiles = (),
required_signer_hashes: tp.Optional[tp.List[str]] = None,
ttl: tp.Optional[int] = None,
Expand Down Expand Up @@ -187,6 +188,8 @@ def build_raw_tx_bare(
mint: An iterable of `Mint`, specifying script minting data (optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposal script data
(optional).
required_signers: An iterable of filepaths of the signing keys whose signatures
are required (optional).
required_signer_hashes: A list of hashes of the signing keys whose signatures
Expand All @@ -213,6 +216,12 @@ def build_raw_tx_bare(
"certs may come in unexpected order."
)

if tx_files.proposal_files and complex_proposals:
LOGGER.warning(
"Mixing `tx_files.proposal_files` and `complex_proposals`, "
"proposals may come in unexpected order."
)

out_file = pl.Path(out_file)

withdrawals, script_withdrawals, __ = txtools._get_withdrawals(
Expand Down Expand Up @@ -257,6 +266,7 @@ def build_raw_tx_bare(
script_txins=script_txins,
mint=mint,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
script_withdrawals=script_withdrawals,
script_votes=script_votes,
for_build=False,
Expand Down Expand Up @@ -326,6 +336,7 @@ def build_raw_tx_bare(
script_withdrawals=script_withdrawals,
script_votes=script_votes,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
mint=mint,
invalid_hereafter=invalid_hereafter or ttl,
invalid_before=invalid_before,
Expand Down Expand Up @@ -358,6 +369,7 @@ def build_raw_tx(
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
fee: int = 0,
required_signers: itp.OptionalFiles = (),
required_signer_hashes: tp.Optional[tp.List[str]] = None,
Expand Down Expand Up @@ -390,6 +402,8 @@ def build_raw_tx(
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposals script data
(optional).
fee: A fee amount (optional).
required_signers: An iterable of filepaths of the signing keys whose signatures
are required (optional).
Expand Down Expand Up @@ -427,6 +441,7 @@ def build_raw_tx(
mint=mint,
tx_files=tx_files,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
fee=fee,
withdrawals=withdrawals,
script_withdrawals=script_withdrawals,
Expand Down Expand Up @@ -455,6 +470,7 @@ def build_raw_tx(
total_collateral_amount=total_collateral_amount,
mint=mint,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
required_signers=required_signers,
required_signer_hashes=required_signer_hashes,
withdrawals=collected_data.withdrawals,
Expand Down Expand Up @@ -532,6 +548,7 @@ def calculate_tx_fee(
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
required_signers: itp.OptionalFiles = (),
required_signer_hashes: tp.Optional[tp.List[str]] = None,
ttl: tp.Optional[int] = None,
Expand Down Expand Up @@ -565,6 +582,8 @@ def calculate_tx_fee(
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposal script data
(optional).
required_signers: An iterable of filepaths of the signing keys whose signatures
are required (optional).
required_signer_hashes: A list of hashes of the signing keys whose signatures
Expand Down Expand Up @@ -612,6 +631,7 @@ def calculate_tx_fee(
mint=mint,
tx_files=tx_files,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
required_signers=required_signers,
required_signer_hashes=required_signer_hashes,
fee=self.min_fee,
Expand Down Expand Up @@ -739,6 +759,7 @@ def build_tx( # noqa: C901
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
change_address: str = "",
fee_buffer: tp.Optional[int] = None,
required_signers: itp.OptionalFiles = (),
Expand Down Expand Up @@ -775,6 +796,8 @@ def build_tx( # noqa: C901
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposal script data
(optional).
change_address: A string with address where ADA in excess of the transaction fee
will go to (`src_address` by default).
fee_buffer: A buffer for fee amount (optional).
Expand Down Expand Up @@ -819,6 +842,11 @@ def build_tx( # noqa: C901
"Mixing `tx_files.certificate_files` and `complex_certs`, "
"certs may come in unexpected order."
)
if tx_files.proposal_files and complex_proposals:
LOGGER.warning(
"Mixing `tx_files.proposal_files` and `complex_proposals`, "
"proposals may come in unexpected order."
)

destination_dir = pl.Path(destination_dir).expanduser()

Expand All @@ -834,6 +862,7 @@ def build_tx( # noqa: C901
mint=mint,
tx_files=tx_files,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
fee=fee_buffer or 0,
withdrawals=withdrawals,
script_withdrawals=script_withdrawals,
Expand Down Expand Up @@ -877,6 +906,7 @@ def build_tx( # noqa: C901
script_txins=script_txins,
mint=mint,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
script_withdrawals=collected_data.script_withdrawals,
script_votes=script_votes,
for_build=True,
Expand Down Expand Up @@ -946,6 +976,7 @@ def build_tx( # noqa: C901
script_withdrawals=collected_data.script_withdrawals,
script_votes=script_votes,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
mint=mint,
invalid_hereafter=invalid_hereafter,
invalid_before=invalid_before,
Expand Down Expand Up @@ -1167,6 +1198,7 @@ def send_tx(
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
fee: tp.Optional[int] = None,
required_signers: itp.OptionalFiles = (),
required_signer_hashes: tp.Optional[tp.List[str]] = None,
Expand Down Expand Up @@ -1208,6 +1240,8 @@ def send_tx(
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposal script data
(optional).
fee: A fee amount (optional).
required_signers: An iterable of filepaths of the signing keys whose signatures
are required (optional).
Expand Down Expand Up @@ -1258,6 +1292,7 @@ def send_tx(
mint=mint,
tx_files=tx_files,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
required_signers=required_signers,
required_signer_hashes=required_signer_hashes,
withdrawals=withdrawals,
Expand Down Expand Up @@ -1285,6 +1320,7 @@ def send_tx(
mint=mint,
tx_files=tx_files,
complex_certs=complex_certs,
complex_proposals=complex_proposals,
fee=fee,
required_signers=required_signers,
required_signer_hashes=required_signer_hashes,
Expand Down Expand Up @@ -1398,6 +1434,7 @@ def calculate_plutus_script_cost(
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
change_address: str = "",
fee_buffer: tp.Optional[int] = None,
required_signers: itp.OptionalFiles = (),
Expand Down Expand Up @@ -1433,6 +1470,8 @@ def calculate_plutus_script_cost(
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposal script data
(optional).
change_address: A string with address where ADA in excess of the transaction fee
will go to (`src_address` by default).
fee_buffer: A buffer for fee amount (optional).
Expand Down
42 changes: 42 additions & 0 deletions cardano_clusterlib/txtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ def collect_data_for_build(
mint: structs.OptionalMint = (),
tx_files: tp.Optional[structs.TxFiles] = None,
complex_certs: structs.OptionalScriptCerts = (),
complex_proposals: structs.OptionalScriptProposals = (),
fee: int = 0,
withdrawals: structs.OptionalTxOuts = (),
script_withdrawals: structs.OptionalScriptWithdrawals = (),
Expand All @@ -631,6 +632,8 @@ def collect_data_for_build(
(optional).
complex_certs: An iterable of `ComplexCert`, specifying certificates script data
(optional).
complex_proposals: An iterable of `ComplexProposal`, specifying proposals script data
(optional).
fee: A fee amount (optional).
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
Expand Down Expand Up @@ -672,6 +675,10 @@ def collect_data_for_build(
*tx_files.certificate_files,
*[c.certificate_file for c in complex_certs],
],
proposal_files=[
*tx_files.proposal_files,
*[p.proposal_file for p in complex_proposals],
],
)
txins_copy, txouts_copy = _get_tx_ins_outs(
clusterlib_obj=clusterlib_obj,
Expand Down Expand Up @@ -868,6 +875,7 @@ def _get_script_args( # noqa: C901
script_txins: structs.OptionalScriptTxIn,
mint: structs.OptionalMint,
complex_certs: structs.OptionalScriptCerts,
complex_proposals: structs.OptionalScriptProposals,
script_withdrawals: structs.OptionalScriptWithdrawals,
script_votes: structs.OptionalScriptVotes,
for_build: bool = True,
Expand Down Expand Up @@ -1122,6 +1130,40 @@ def _get_script_args( # noqa: C901
["--certificate-reference-tx-in-redeemer-value", str(crec.redeemer_value)]
)

# proposals
for prec in complex_proposals:
prec_collaterals = {f"{c.utxo_hash}#{c.utxo_ix}" for c in prec.collaterals}
collaterals_all.update(prec_collaterals)
grouped_args.extend(
[
"--proposal-file",
str(prec.proposal_file),
]
)

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

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

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

# withdrawals
for wrec in script_withdrawals:
wrec_collaterals = {f"{c.utxo_hash}#{c.utxo_ix}" for c in wrec.collaterals}
Expand Down
Loading