Skip to content

Commit 09d3b6f

Browse files
committed
Update txbuilder to only add signatures and validity when building smart
transactions
1 parent 3fe6ed4 commit 09d3b6f

File tree

2 files changed

+71
-80
lines changed

2 files changed

+71
-80
lines changed

pycardano/txbuilder.py

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -869,8 +869,9 @@ def build(
869869
change_address: Optional[Address] = None,
870870
merge_change: Optional[bool] = False,
871871
collateral_change_address: Optional[Address] = None,
872-
auto_validity: Optional[bool] = True,
873-
auto_required_signers: Optional[bool] = True,
872+
auto_validity_start_offset: Optional[int] = None,
873+
auto_ttl_offset: Optional[int] = None,
874+
auto_required_signers: Optional[bool] = None,
874875
) -> TransactionBody:
875876
"""Build a transaction body from all constraints set through the builder.
876877
@@ -880,33 +881,40 @@ def build(
880881
merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount
881882
will be directly added to that transaction output, instead of being added as a separate output.
882883
collateral_change_address (Optional[Address]): Address to which collateral changes will be returned.
883-
auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a
884-
reasonable value
884+
auto_validity_start_offset (Optional[int]): Automatically set the validity start interval of the transaction
885+
to the current slot number + the given offset (default -1000).
886+
A manually set validity start will always take precedence.
887+
auto_ttl_offset (Optional[int]): Automatically set the validity end interval (ttl) of the transaction
888+
to the current slot number + the given offset (default 10_000).
889+
A manually set ttl will always take precedence.
885890
auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs
886-
to required signatories
891+
to required signatories (default only for Smart Contract transactions).
892+
Manually set required signers will always take precedence.
887893
888894
Returns:
889895
TransactionBody: A transaction body.
890896
"""
891897
self._ensure_no_input_exclusion_conflict()
892898

893-
if auto_validity:
894-
# Automatically set the validity range to a tight value around transaction creation
899+
# only automatically set the validity interval and required signers if scripts are involved
900+
is_smart = bool(self.scripts)
901+
902+
# Automatically set the validity range to a tight value around transaction creation
903+
if (
904+
is_smart or auto_validity_start_offset is not None
905+
) and self.validity_start is None:
895906
last_slot = self.context.last_block_slot
896-
if self.validity_start is None:
897-
self.validity_start = max(0, last_slot - 1000)
898-
if self.ttl is None:
899-
self.ttl = last_slot + 10000
907+
# If None is provided, the default value is -1000
908+
if auto_validity_start_offset is None:
909+
auto_validity_start_offset = -1000
910+
self.validity_start = max(0, last_slot + auto_validity_start_offset)
900911

901-
if auto_required_signers:
902-
# collect all signatories from explicitly defined transaction inputs and collateral inputs
903-
required_signers = set(
904-
i.output.address.payment_part
905-
for i in self.inputs + self.collaterals
906-
if not isinstance(i.output.address.payment_part, ScriptHash)
907-
and i.output.address.payment_part is not None
908-
)
909-
self.required_signers = list(required_signers)
912+
if (is_smart or auto_ttl_offset is not None) and self.ttl is None:
913+
last_slot = self.context.last_block_slot
914+
# If None is provided, the default value is 10_000
915+
if auto_ttl_offset is None:
916+
auto_ttl_offset = 10_000
917+
self.ttl = max(0, last_slot + auto_ttl_offset)
910918

911919
selected_utxos = []
912920
selected_amount = Value()
@@ -1039,6 +1047,18 @@ def build(
10391047

10401048
self.inputs[:] = selected_utxos[:]
10411049

1050+
# Automatically set the required signers for smart transactions
1051+
if (
1052+
is_smart or auto_required_signers is not None
1053+
) and self.required_signers is None:
1054+
# Collect all signatories from explicitly defined transaction inputs and collateral inputs
1055+
required_signers = set(
1056+
i.output.address.payment_part
1057+
for i in self.inputs + self.collaterals
1058+
if isinstance(i.output.address.payment_part, VerificationKeyHash)
1059+
)
1060+
self.required_signers = list(required_signers)
1061+
10421062
self._set_redeemer_index()
10431063

10441064
self._set_collateral_return(collateral_change_address or change_address)
@@ -1190,8 +1210,9 @@ def build_and_sign(
11901210
change_address: Optional[Address] = None,
11911211
merge_change: Optional[bool] = False,
11921212
collateral_change_address: Optional[Address] = None,
1193-
auto_validity: Optional[bool] = True,
1194-
auto_required_signers: Optional[bool] = True,
1213+
auto_validity_start_offset: Optional[int] = None,
1214+
auto_ttl_offset: Optional[int] = None,
1215+
auto_required_signers: Optional[bool] = None,
11951216
) -> Transaction:
11961217
"""Build a transaction body from all constraints set through the builder and sign the transaction with
11971218
provided signing keys.
@@ -1204,10 +1225,15 @@ def build_and_sign(
12041225
merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount
12051226
will be directly added to that transaction output, instead of being added as a separate output.
12061227
collateral_change_address (Optional[Address]): Address to which collateral changes will be returned.
1207-
auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to
1208-
a reasonable value
1228+
auto_validity_start_offset (Optional[int]): Automatically set the validity start interval of the transaction
1229+
to the current slot number + the given offset (default -1000).
1230+
A manually set validity start will always take precedence.
1231+
auto_ttl_offset (Optional[int]): Automatically set the validity end interval (ttl) of the transaction
1232+
to the current slot number + the given offset (default 10_000).
1233+
A manually set ttl will always take precedence.
12091234
auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs
1210-
to required signatories
1235+
to required signatories (default only for Smart Contract transactions).
1236+
Manually set required signers will always take precedence.
12111237
12121238
Returns:
12131239
Transaction: A signed transaction.
@@ -1217,7 +1243,8 @@ def build_and_sign(
12171243
change_address=change_address,
12181244
merge_change=merge_change,
12191245
collateral_change_address=collateral_change_address,
1220-
auto_validity=auto_validity,
1246+
auto_validity_start_offset=auto_validity_start_offset,
1247+
auto_ttl_offset=auto_ttl_offset,
12211248
auto_required_signers=auto_required_signers,
12221249
)
12231250
witness_set = self.build_witness_set()

test/pycardano/test_txbuilder.py

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ def test_tx_builder(chain_context):
5959
TransactionOutput.from_primitive([sender, 500000])
6060
)
6161

62-
tx_body = tx_builder.build(
63-
change_address=sender_address, auto_validity=False, auto_required_signers=False
64-
)
62+
tx_body = tx_builder.build(change_address=sender_address)
6563

6664
expected = {
6765
0: [[b"11111111111111111111111111111111", 0]],
@@ -102,9 +100,7 @@ def test_tx_builder_with_certain_input(chain_context):
102100
TransactionOutput.from_primitive([sender, 500000])
103101
)
104102

105-
tx_body = tx_builder.build(
106-
change_address=sender_address, auto_validity=False, auto_required_signers=False
107-
)
103+
tx_body = tx_builder.build(change_address=sender_address)
108104

109105
expected = {
110106
0: [[b"22222222222222222222222222222222", 1]],
@@ -140,9 +136,7 @@ def test_tx_builder_multi_asset(chain_context):
140136
)
141137
)
142138

143-
tx_body = tx_builder.build(
144-
change_address=sender_address, auto_validity=False, auto_required_signers=False
145-
)
139+
tx_body = tx_builder.build(change_address=sender_address)
146140

147141
expected = {
148142
0: [
@@ -186,8 +180,6 @@ def test_tx_builder_raises_utxo_selection(chain_context):
186180
with pytest.raises(UTxOSelectionException) as e:
187181
tx_body = tx_builder.build(
188182
change_address=sender_address,
189-
auto_validity=False,
190-
auto_required_signers=False,
191183
)
192184

193185
# The unfulfilled amount includes requested (991000000) and estimated fees (161277)
@@ -224,9 +216,7 @@ def test_tx_small_utxo_precise_fee(chain_context):
224216

225217
# This will not fail as we replace max fee constraint with more precise fee calculation
226218
# And remainder is greater than minimum ada required for change
227-
tx_body = tx_builder.build(
228-
change_address=sender_address, auto_validity=False, auto_required_signers=False
229-
)
219+
tx_body = tx_builder.build(change_address=sender_address)
230220

231221
expect = {
232222
0: [
@@ -278,9 +268,7 @@ def test_tx_small_utxo_balance_pass(chain_context):
278268

279269
# Balance is smaller than minimum ada required in change
280270
# Additional UTxOs are selected from the input address
281-
tx_body = tx_builder.build(
282-
change_address=sender_address, auto_validity=False, auto_required_signers=False
283-
)
271+
tx_body = tx_builder.build(change_address=sender_address)
284272

285273
expected = {
286274
0: [
@@ -315,7 +303,7 @@ def test_tx_builder_mint_multi_asset(chain_context):
315303

316304
tx_builder = TransactionBuilder(chain_context)
317305
sender = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x"
318-
sender_address = Address.from_primitive(sender)
306+
sender_address: Address = Address.from_primitive(sender)
319307

320308
# Add sender address as input
321309
mint = {policy_id.payload: {b"Token1": 1}}
@@ -326,9 +314,7 @@ def test_tx_builder_mint_multi_asset(chain_context):
326314
tx_builder.native_scripts = [script]
327315
tx_builder.ttl = 123456789
328316

329-
tx_body = tx_builder.build(
330-
change_address=sender_address, auto_validity=False, auto_required_signers=False
331-
)
317+
tx_body = tx_builder.build(change_address=sender_address)
332318

333319
expected = {
334320
0: [
@@ -344,14 +330,16 @@ def test_tx_builder_mint_multi_asset(chain_context):
344330
[
345331
sender_address.to_primitive(),
346332
[
347-
5811267,
333+
5809683,
348334
{b"1111111111111111111111111111": {b"Token1": 1, b"Token2": 2}},
349335
],
350336
],
351337
],
352-
2: 188733,
338+
2: 190317,
353339
3: 123456789,
340+
8: 1000,
354341
9: mint,
342+
14: [sender_address.payment_part.to_primitive()],
355343
}
356344

357345
assert expected == tx_body.to_primitive()
@@ -370,9 +358,7 @@ def test_tx_add_change_split_nfts(chain_context):
370358
TransactionOutput.from_primitive([sender, 7000000])
371359
)
372360

373-
tx_body = tx_builder.build(
374-
change_address=sender_address, auto_validity=False, auto_required_signers=False
375-
)
361+
tx_body = tx_builder.build(change_address=sender_address)
376362

377363
expected = {
378364
0: [
@@ -804,9 +790,7 @@ def test_excluded_input(chain_context):
804790

805791
tx_builder.excluded_inputs.append(chain_context.utxos(sender)[0])
806792

807-
tx_body = tx_builder.build(
808-
change_address=sender_address, auto_validity=False, auto_required_signers=False
809-
)
793+
tx_body = tx_builder.build(change_address=sender_address)
810794

811795
expected = {
812796
0: [[b"22222222222222222222222222222222", 1]],
@@ -839,9 +823,7 @@ def test_build_and_sign(chain_context):
839823
TransactionOutput.from_primitive([sender, 500000])
840824
)
841825

842-
tx_body = tx_builder1.build(
843-
change_address=sender_address, auto_validity=False, auto_required_signers=False
844-
)
826+
tx_body = tx_builder1.build(change_address=sender_address)
845827

846828
tx_builder2 = TransactionBuilder(
847829
chain_context, [RandomImproveMultiAsset([0, 0, 0, 0, 0])]
@@ -852,8 +834,6 @@ def test_build_and_sign(chain_context):
852834
tx = tx_builder2.build_and_sign(
853835
[SK],
854836
change_address=sender_address,
855-
auto_validity=False,
856-
auto_required_signers=False,
857837
)
858838

859839
assert tx.transaction_witness_set.vkey_witnesses == [
@@ -910,7 +890,7 @@ def test_tx_builder_exact_fee_no_change(chain_context):
910890

911891
tx_builder.add_output(TransactionOutput.from_primitive([sender, 5000000]))
912892

913-
tx_body = tx_builder.build(auto_validity=False, auto_required_signers=False)
893+
tx_body = tx_builder.build()
914894

915895
tx_builder = TransactionBuilder(chain_context)
916896

@@ -924,9 +904,7 @@ def test_tx_builder_exact_fee_no_change(chain_context):
924904
TransactionOutput.from_primitive([sender, input_amount - tx_body.fee])
925905
)
926906

927-
tx = tx_builder.build_and_sign(
928-
[SK], auto_validity=False, auto_required_signers=False
929-
)
907+
tx = tx_builder.build_and_sign([SK])
930908

931909
expected = {
932910
0: [[b"11111111111111111111111111111111", 3]],
@@ -962,9 +940,7 @@ def test_tx_builder_certificates(chain_context):
962940

963941
tx_builder.certificates = [stake_registration, stake_delegation]
964942

965-
tx_body = tx_builder.build(
966-
change_address=sender_address, auto_validity=False, auto_required_signers=False
967-
)
943+
tx_body = tx_builder.build(change_address=sender_address)
968944

969945
expected = {
970946
0: [[b"11111111111111111111111111111111", 0]],
@@ -1001,9 +977,7 @@ def test_tx_builder_withdrawal(chain_context):
1001977
withdrawals = Withdrawals({bytes(stake_address): 10000})
1002978
tx_builder.withdrawals = withdrawals
1003979

1004-
tx_body = tx_builder.build(
1005-
change_address=sender_address, auto_validity=False, auto_required_signers=False
1006-
)
980+
tx_body = tx_builder.build(change_address=sender_address)
1007981

1008982
expected = {
1009983
0: [[b"11111111111111111111111111111111", 0]],
@@ -1038,8 +1012,6 @@ def test_tx_builder_no_output(chain_context):
10381012
tx_body = tx_builder.build(
10391013
change_address=sender_address,
10401014
merge_change=True,
1041-
auto_validity=False,
1042-
auto_required_signers=False,
10431015
)
10441016

10451017
expected = {
@@ -1070,8 +1042,6 @@ def test_tx_builder_merge_change_to_output(chain_context):
10701042
tx_body = tx_builder.build(
10711043
change_address=sender_address,
10721044
merge_change=True,
1073-
auto_validity=False,
1074-
auto_required_signers=False,
10751045
)
10761046

10771047
expected = {
@@ -1106,8 +1076,6 @@ def test_tx_builder_merge_change_to_output_2(chain_context):
11061076
tx_body = tx_builder.build(
11071077
change_address=sender_address,
11081078
merge_change=True,
1109-
auto_validity=False,
1110-
auto_required_signers=False,
11111079
)
11121080

11131081
expected = {
@@ -1140,8 +1108,6 @@ def test_tx_builder_merge_change_to_zero_amount_output(chain_context):
11401108
tx_body = tx_builder.build(
11411109
change_address=sender_address,
11421110
merge_change=True,
1143-
auto_validity=False,
1144-
auto_required_signers=False,
11451111
)
11461112

11471113
expected = {
@@ -1172,8 +1138,6 @@ def test_tx_builder_merge_change_smaller_than_min_utxo(chain_context):
11721138
tx_body = tx_builder.build(
11731139
change_address=sender_address,
11741140
merge_change=True,
1175-
auto_validity=False,
1176-
auto_required_signers=False,
11771141
)
11781142

11791143
expected = {

0 commit comments

Comments
 (0)