Skip to content

Commit f574128

Browse files
authored
Merge pull request #245 from mkoura/script_votes
Add support for voting with scripts
2 parents e1b0285 + 070ed6c commit f574128

File tree

6 files changed

+101
-10
lines changed

6 files changed

+101
-10
lines changed

cardano_clusterlib/clusterlib.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from cardano_clusterlib.structs import OptionalMint
4141
from cardano_clusterlib.structs import OptionalScriptCerts
4242
from cardano_clusterlib.structs import OptionalScriptTxIn
43+
from cardano_clusterlib.structs import OptionalScriptVotes
4344
from cardano_clusterlib.structs import OptionalScriptWithdrawals
4445
from cardano_clusterlib.structs import OptionalTxOuts
4546
from cardano_clusterlib.structs import OptionalUTXOData
@@ -48,6 +49,7 @@
4849
from cardano_clusterlib.structs import PoolParamsTop
4950
from cardano_clusterlib.structs import PoolUser
5051
from cardano_clusterlib.structs import ScriptTxIn
52+
from cardano_clusterlib.structs import ScriptVote
5153
from cardano_clusterlib.structs import ScriptWithdrawal
5254
from cardano_clusterlib.structs import StakeAddrInfo
5355
from cardano_clusterlib.structs import TxFiles

cardano_clusterlib/conway_gov_action_group.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ def _get_cc_members_args(
7777
str(cc_member.cold_vkey_hash),
7878
]
7979
)
80+
elif cc_member.cold_script_hash:
81+
cc_members_args.extend(
82+
[
83+
f"--{arg_action}-cc-cold-script-hash",
84+
str(cc_member.cold_script_hash),
85+
]
86+
)
8087
else:
8188
msg = f"Either {arg_action} cold verification key or its hash must be set."
8289
raise AssertionError(msg)

cardano_clusterlib/conway_gov_vote_group.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def create_committee(
7575
cc_hot_vkey: str = "",
7676
cc_hot_vkey_file: tp.Optional[itp.FileType] = None,
7777
cc_hot_key_hash: str = "",
78+
cc_hot_script_hash: str = "",
7879
anchor_url: str = "",
7980
anchor_data_hash: str = "",
8081
destination_dir: itp.FileType = ".",
@@ -92,13 +93,15 @@ def create_committee(
9293
)
9394

9495
if cc_hot_vkey:
95-
key_args = ["--cc-hot-verification-key", cc_hot_vkey]
96+
cred_args = ["--cc-hot-verification-key", cc_hot_vkey]
9697
elif cc_hot_vkey_file:
97-
key_args = ["--cc-hot-verification-key-file", str(cc_hot_vkey_file)]
98+
cred_args = ["--cc-hot-verification-key-file", str(cc_hot_vkey_file)]
9899
elif cc_hot_key_hash:
99-
key_args = ["--cc-hot-key-hash", cc_hot_key_hash]
100+
cred_args = ["--cc-hot-key-hash", cc_hot_key_hash]
101+
elif cc_hot_script_hash:
102+
cred_args = ["--cc-hot-script-hash", cc_hot_script_hash]
100103
else:
101-
msg = "No CC key was specified."
104+
msg = "No CC key or script hash was specified."
102105
raise AssertionError(msg)
103106

104107
self._clusterlib_obj.cli(
@@ -107,7 +110,7 @@ def create_committee(
107110
"create",
108111
*vote_args,
109112
*gov_action_args,
110-
*key_args,
113+
*cred_args,
111114
*anchor_args,
112115
"--out-file",
113116
str(out_file),
@@ -123,6 +126,7 @@ def create_committee(
123126
cc_hot_vkey=cc_hot_vkey,
124127
cc_hot_vkey_file=helpers._maybe_path(cc_hot_vkey_file),
125128
cc_hot_key_hash=cc_hot_key_hash,
129+
cc_hot_script_hash=cc_hot_script_hash,
126130
anchor_url=anchor_url,
127131
anchor_data_hash=anchor_data_hash,
128132
)
@@ -137,6 +141,7 @@ def create_drep(
137141
drep_vkey: str = "",
138142
drep_vkey_file: tp.Optional[itp.FileType] = None,
139143
drep_key_hash: str = "",
144+
drep_script_hash: str = "",
140145
anchor_url: str = "",
141146
anchor_data_hash: str = "",
142147
destination_dir: itp.FileType = ".",
@@ -154,13 +159,15 @@ def create_drep(
154159
)
155160

156161
if drep_vkey:
157-
key_args = ["--drep-verification-key", drep_vkey]
162+
cred_args = ["--drep-verification-key", drep_vkey]
158163
elif drep_vkey_file:
159-
key_args = ["--drep-verification-key-file", str(drep_vkey_file)]
164+
cred_args = ["--drep-verification-key-file", str(drep_vkey_file)]
160165
elif drep_key_hash:
161-
key_args = ["--drep-key-hash", drep_key_hash]
166+
cred_args = ["--drep-key-hash", drep_key_hash]
167+
elif drep_script_hash:
168+
cred_args = ["--drep-script-hash", drep_script_hash]
162169
else:
163-
msg = "No DRep key was specified."
170+
msg = "No DRep key or script hash was specified."
164171
raise AssertionError(msg)
165172

166173
self._clusterlib_obj.cli(
@@ -169,7 +176,7 @@ def create_drep(
169176
"create",
170177
*vote_args,
171178
*gov_action_args,
172-
*key_args,
179+
*cred_args,
173180
*anchor_args,
174181
"--out-file",
175182
str(out_file),
@@ -185,6 +192,7 @@ def create_drep(
185192
drep_vkey=drep_vkey,
186193
drep_vkey_file=helpers._maybe_path(drep_vkey_file),
187194
drep_key_hash=drep_key_hash,
195+
drep_script_hash=drep_script_hash,
188196
anchor_url=anchor_url,
189197
anchor_data_hash=anchor_data_hash,
190198
)

cardano_clusterlib/structs.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ class ComplexCert:
138138
redeemer_value: str = ""
139139

140140

141+
@dataclasses.dataclass(frozen=True, order=True)
142+
class ScriptVote:
143+
"""Data structure for voting that are combined with scripts."""
144+
145+
vote_file: itp.FileType = ""
146+
script_file: itp.FileType = ""
147+
# values below needed only when working with Plutus
148+
collaterals: OptionalUTXOData = ()
149+
execution_units: tp.Optional[tp.Tuple[int, int]] = None
150+
redeemer_file: itp.FileType = ""
151+
redeemer_cbor_file: itp.FileType = ""
152+
redeemer_value: str = ""
153+
154+
141155
@dataclasses.dataclass(frozen=True, order=True)
142156
class Mint:
143157
txouts: tp.List[TxOut]
@@ -161,6 +175,8 @@ class Mint:
161175
OptionalScriptWithdrawals = tp.Union[tp.List[ScriptWithdrawal], tp.Tuple[()]]
162176
# list of `Mint`s, empty list, or empty tuple
163177
OptionalMint = tp.Union[tp.List[Mint], tp.Tuple[()]]
178+
# list of `ScriptVote`s, empty list, or empty tuple
179+
OptionalScriptVotes = tp.Union[tp.List[ScriptVote], tp.Tuple[()]]
164180

165181

166182
@dataclasses.dataclass(frozen=True, order=True)
@@ -206,6 +222,7 @@ class TxRawOutput:
206222
era: str = "" # Era used for the transaction
207223
script_txins: OptionalScriptTxIn = () # Tx inputs that are combined with scripts
208224
script_withdrawals: OptionalScriptWithdrawals = () # Withdrawals that are combined with scripts
225+
script_votes: OptionalScriptVotes = () # Votes that are combined with scripts
209226
complex_certs: OptionalScriptCerts = () # Certificates that are combined with scripts
210227
mint: OptionalMint = () # Minting data (Tx outputs, script, etc.)
211228
invalid_hereafter: tp.Optional[int] = None # Validity interval upper bound
@@ -287,6 +304,7 @@ class CCMember:
287304
cold_skey: str = ""
288305
cold_skey_file: itp.FileType = ""
289306
cold_skey_hash: str = ""
307+
cold_script_hash: str = ""
290308
hot_vkey: str = ""
291309
hot_vkey_file: itp.FileType = ""
292310
hot_vkey_hash: str = ""
@@ -304,6 +322,7 @@ class VoteCC:
304322
cc_hot_vkey: str = ""
305323
cc_hot_vkey_file: tp.Optional[pl.Path] = None
306324
cc_hot_key_hash: str = ""
325+
cc_hot_script_hash: str = ""
307326
anchor_url: str = ""
308327
anchor_data_hash: str = ""
309328

@@ -317,6 +336,7 @@ class VoteDrep:
317336
drep_vkey: str = ""
318337
drep_vkey_file: tp.Optional[pl.Path] = None
319338
drep_key_hash: str = ""
339+
drep_script_hash: str = ""
320340
anchor_url: str = ""
321341
anchor_data_hash: str = ""
322342

cardano_clusterlib/transaction_group.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def build_raw_tx_bare(
163163
ttl: tp.Optional[int] = None,
164164
withdrawals: structs.OptionalTxOuts = (),
165165
script_withdrawals: structs.OptionalScriptWithdrawals = (),
166+
script_votes: structs.OptionalScriptVotes = (),
166167
invalid_hereafter: tp.Optional[int] = None,
167168
invalid_before: tp.Optional[int] = None,
168169
script_valid: bool = True,
@@ -195,6 +196,7 @@ def build_raw_tx_bare(
195196
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
196197
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
197198
data (optional).
199+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
198200
invalid_hereafter: A last block when the transaction is still valid (optional).
199201
invalid_before: A first block when the transaction is valid (optional).
200202
script_valid: A bool indicating that the script is valid (True by default).
@@ -256,6 +258,7 @@ def build_raw_tx_bare(
256258
mint=mint,
257259
complex_certs=complex_certs,
258260
script_withdrawals=script_withdrawals,
261+
script_votes=script_votes,
259262
for_build=False,
260263
)
261264

@@ -321,6 +324,7 @@ def build_raw_tx_bare(
321324
era=self._clusterlib_obj.command_era or self._clusterlib_obj.tx_era,
322325
script_txins=script_txins,
323326
script_withdrawals=script_withdrawals,
327+
script_votes=script_votes,
324328
complex_certs=complex_certs,
325329
mint=mint,
326330
invalid_hereafter=invalid_hereafter or ttl,
@@ -360,6 +364,7 @@ def build_raw_tx(
360364
ttl: tp.Optional[int] = None,
361365
withdrawals: structs.OptionalTxOuts = (),
362366
script_withdrawals: structs.OptionalScriptWithdrawals = (),
367+
script_votes: structs.OptionalScriptVotes = (),
363368
deposit: tp.Optional[int] = None,
364369
invalid_hereafter: tp.Optional[int] = None,
365370
invalid_before: tp.Optional[int] = None,
@@ -395,6 +400,7 @@ def build_raw_tx(
395400
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
396401
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
397402
data (optional).
403+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
398404
deposit: A deposit amount needed by the transaction (optional).
399405
invalid_hereafter: A last block when the transaction is still valid (optional).
400406
invalid_before: A first block when the transaction is valid (optional).
@@ -453,6 +459,7 @@ def build_raw_tx(
453459
required_signer_hashes=required_signer_hashes,
454460
withdrawals=collected_data.withdrawals,
455461
script_withdrawals=collected_data.script_withdrawals,
462+
script_votes=script_votes,
456463
invalid_hereafter=invalid_hereafter or ttl,
457464
invalid_before=invalid_before,
458465
join_txouts=join_txouts,
@@ -530,6 +537,7 @@ def calculate_tx_fee(
530537
ttl: tp.Optional[int] = None,
531538
withdrawals: structs.OptionalTxOuts = (),
532539
script_withdrawals: structs.OptionalScriptWithdrawals = (),
540+
script_votes: structs.OptionalScriptVotes = (),
533541
deposit: tp.Optional[int] = None,
534542
invalid_hereafter: tp.Optional[int] = None,
535543
invalid_before: tp.Optional[int] = None,
@@ -566,6 +574,7 @@ def calculate_tx_fee(
566574
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
567575
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
568576
data (optional).
577+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
569578
deposit: A deposit amount needed by the transaction (optional).
570579
invalid_hereafter: A last block when the transaction is still valid (optional).
571580
invalid_before: A first block when the transaction is valid (optional).
@@ -608,6 +617,7 @@ def calculate_tx_fee(
608617
fee=self.min_fee,
609618
withdrawals=withdrawals,
610619
script_withdrawals=script_withdrawals,
620+
script_votes=script_votes,
611621
invalid_hereafter=invalid_hereafter or ttl,
612622
invalid_before=invalid_before,
613623
deposit=deposit,
@@ -735,6 +745,7 @@ def build_tx( # noqa: C901
735745
required_signer_hashes: tp.Optional[tp.List[str]] = None,
736746
withdrawals: structs.OptionalTxOuts = (),
737747
script_withdrawals: structs.OptionalScriptWithdrawals = (),
748+
script_votes: structs.OptionalScriptVotes = (),
738749
deposit: tp.Optional[int] = None,
739750
invalid_hereafter: tp.Optional[int] = None,
740751
invalid_before: tp.Optional[int] = None,
@@ -774,6 +785,7 @@ def build_tx( # noqa: C901
774785
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
775786
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
776787
data (optional).
788+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
777789
deposit: A deposit amount needed by the transaction (optional).
778790
invalid_hereafter: A last block when the transaction is still valid (optional).
779791
invalid_before: A first block when the transaction is valid (optional).
@@ -866,6 +878,7 @@ def build_tx( # noqa: C901
866878
mint=mint,
867879
complex_certs=complex_certs,
868880
script_withdrawals=collected_data.script_withdrawals,
881+
script_votes=script_votes,
869882
for_build=True,
870883
)
871884

@@ -931,6 +944,7 @@ def build_tx( # noqa: C901
931944
era=self._clusterlib_obj.command_era or self._clusterlib_obj.tx_era,
932945
script_txins=script_txins,
933946
script_withdrawals=collected_data.script_withdrawals,
947+
script_votes=script_votes,
934948
complex_certs=complex_certs,
935949
mint=mint,
936950
invalid_hereafter=invalid_hereafter,
@@ -1159,6 +1173,7 @@ def send_tx(
11591173
ttl: tp.Optional[int] = None,
11601174
withdrawals: structs.OptionalTxOuts = (),
11611175
script_withdrawals: structs.OptionalScriptWithdrawals = (),
1176+
script_votes: structs.OptionalScriptVotes = (),
11621177
deposit: tp.Optional[int] = None,
11631178
invalid_hereafter: tp.Optional[int] = None,
11641179
invalid_before: tp.Optional[int] = None,
@@ -1203,6 +1218,7 @@ def send_tx(
12031218
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
12041219
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
12051220
data (optional).
1221+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
12061222
deposit: A deposit amount needed by the transaction (optional).
12071223
invalid_hereafter: A last block when the transaction is still valid (optional).
12081224
invalid_before: A first block when the transaction is valid (optional).
@@ -1274,6 +1290,7 @@ def send_tx(
12741290
required_signer_hashes=required_signer_hashes,
12751291
withdrawals=withdrawals,
12761292
script_withdrawals=script_withdrawals,
1293+
script_votes=script_votes,
12771294
deposit=deposit,
12781295
invalid_hereafter=invalid_hereafter or ttl,
12791296
invalid_before=invalid_before,
@@ -1387,6 +1404,7 @@ def calculate_plutus_script_cost(
13871404
required_signer_hashes: tp.Optional[tp.List[str]] = None,
13881405
withdrawals: structs.OptionalTxOuts = (),
13891406
script_withdrawals: structs.OptionalScriptWithdrawals = (),
1407+
script_votes: structs.OptionalScriptVotes = (),
13901408
deposit: tp.Optional[int] = None,
13911409
invalid_hereafter: tp.Optional[int] = None,
13921410
invalid_before: tp.Optional[int] = None,
@@ -1425,6 +1443,7 @@ def calculate_plutus_script_cost(
14251443
withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
14261444
script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
14271445
data (optional).
1446+
script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
14281447
deposit: A deposit amount needed by the transaction (optional).
14291448
invalid_hereafter: A last block when the transaction is still valid (optional).
14301449
invalid_before: A first block when the transaction is valid (optional).

cardano_clusterlib/txtools.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,7 @@ def _get_script_args( # noqa: C901
869869
mint: structs.OptionalMint,
870870
complex_certs: structs.OptionalScriptCerts,
871871
script_withdrawals: structs.OptionalScriptWithdrawals,
872+
script_votes: structs.OptionalScriptVotes,
872873
for_build: bool = True,
873874
) -> tp.List[str]:
874875
# pylint: disable=too-many-statements,too-many-branches
@@ -1195,6 +1196,40 @@ def _get_script_args( # noqa: C901
11951196
["--withdrawal-reference-tx-in-redeemer-value", str(wrec.redeemer_value)]
11961197
)
11971198

1199+
# voting
1200+
for vrec in script_votes:
1201+
vrec_collaterals = {f"{c.utxo_hash}#{c.utxo_ix}" for c in vrec.collaterals}
1202+
collaterals_all.update(vrec_collaterals)
1203+
grouped_args.extend(
1204+
[
1205+
"--vote-file",
1206+
str(vrec.vote_file),
1207+
]
1208+
)
1209+
1210+
if vrec.script_file:
1211+
grouped_args.extend(
1212+
[
1213+
"--vote-script-file",
1214+
str(vrec.script_file),
1215+
]
1216+
)
1217+
1218+
if not for_build and vrec.execution_units:
1219+
grouped_args.extend(
1220+
[
1221+
"--vote-execution-units",
1222+
f"({vrec.execution_units[0]},{vrec.execution_units[1]})",
1223+
]
1224+
)
1225+
1226+
if vrec.redeemer_file:
1227+
grouped_args.extend(["--vote-redeemer-file", str(vrec.redeemer_file)])
1228+
if vrec.redeemer_cbor_file:
1229+
grouped_args.extend(["--vote-redeemer-cbor-file", str(vrec.redeemer_cbor_file)])
1230+
if vrec.redeemer_value:
1231+
grouped_args.extend(["--vote-redeemer-value", str(vrec.redeemer_value)])
1232+
11981233
# add unique collaterals
11991234
grouped_args.extend(
12001235
[

0 commit comments

Comments
 (0)