@@ -343,7 +343,7 @@ def build_raw_tx_bare( # noqa: C901
343343 complex_proposals = complex_proposals ,
344344 script_withdrawals = script_withdrawals ,
345345 script_votes = script_votes ,
346- for_build = False ,
346+ with_execution_units = True ,
347347 )
348348
349349 grouped_args_str = " " .join (grouped_args )
@@ -954,11 +954,9 @@ def build_tx( # noqa: C901
954954 complex_proposals = complex_proposals ,
955955 script_withdrawals = collected_data .script_withdrawals ,
956956 script_votes = script_votes ,
957- for_build = True ,
957+ with_execution_units = False ,
958958 )
959959
960- misc_args .extend (["--change-address" , change_address ])
961-
962960 if witness_override is not None :
963961 misc_args .extend (["--witness-override" , str (witness_override )])
964962
@@ -994,12 +992,14 @@ def build_tx( # noqa: C901
994992 * helpers ._prepend_flag ("--metadata-cbor-file" , tx_files .metadata_cbor_files ),
995993 * helpers ._prepend_flag ("--withdrawal" , withdrawal_strings ),
996994 * txtools ._get_return_collateral_txout_args (txouts = return_collateral_txouts ),
995+ "--change-address" ,
996+ change_address ,
997997 * misc_args ,
998998 * self ._clusterlib_obj .magic_args ,
999999 * self ._clusterlib_obj .socket_args ,
10001000 ]
1001- stdout = self ._clusterlib_obj .cli (cli_args ). stdout . strip ( )
1002- stdout_dec = stdout .decode ("utf-8" ) if stdout else ""
1001+ out = self ._clusterlib_obj .cli (cli_args )
1002+ stdout_dec = out . stdout .strip (). decode ("utf-8" ) if out . stdout else ""
10031003
10041004 # Check for the presence of fee information. No fee information was provided in older
10051005 # versions of the `build` command.
@@ -1008,6 +1008,292 @@ def build_tx( # noqa: C901
10081008 estimated_fee = int (stdout_dec .split ()[- 2 ])
10091009 elif "transaction fee" in stdout_dec :
10101010 estimated_fee = int (stdout_dec .split ()[- 1 ])
1011+ else :
1012+ fee_str = self .view_tx_dict (tx_body_file = out_file ).get ("fee" ) or ""
1013+ if fee_str .endswith ("Lovelace" ):
1014+ estimated_fee = int (fee_str .split ()[- 2 ])
1015+
1016+ return structs .TxRawOutput (
1017+ txins = list (collected_data .txins ),
1018+ txouts = processed_txouts ,
1019+ txouts_count = txouts_count ,
1020+ tx_files = tx_files ,
1021+ out_file = out_file ,
1022+ fee = estimated_fee ,
1023+ build_args = cli_args ,
1024+ era = self ._clusterlib_obj .era_in_use ,
1025+ script_txins = script_txins ,
1026+ script_withdrawals = collected_data .script_withdrawals ,
1027+ script_votes = script_votes ,
1028+ complex_certs = complex_certs ,
1029+ complex_proposals = complex_proposals ,
1030+ mint = mint ,
1031+ invalid_hereafter = invalid_hereafter ,
1032+ invalid_before = invalid_before ,
1033+ treasury_donation = treasury_donation ,
1034+ withdrawals = collected_data .withdrawals ,
1035+ change_address = change_address or src_address ,
1036+ return_collateral_txouts = return_collateral_txouts ,
1037+ total_collateral_amount = total_collateral_amount ,
1038+ readonly_reference_txins = readonly_reference_txins ,
1039+ script_valid = script_valid ,
1040+ required_signers = required_signers ,
1041+ required_signer_hashes = required_signer_hashes ,
1042+ combined_reference_txins = txtools ._get_reference_txins (
1043+ readonly_reference_txins = readonly_reference_txins ,
1044+ script_txins = script_txins ,
1045+ mint = mint ,
1046+ complex_certs = complex_certs ,
1047+ script_withdrawals = script_withdrawals ,
1048+ ),
1049+ )
1050+
1051+ def build_estimate_tx ( # noqa: C901
1052+ self ,
1053+ src_address : str ,
1054+ tx_name : str ,
1055+ txins : structs .OptionalUTXOData = (),
1056+ txouts : structs .OptionalTxOuts = (),
1057+ readonly_reference_txins : structs .OptionalUTXOData = (),
1058+ script_txins : structs .OptionalScriptTxIn = (),
1059+ return_collateral_txouts : structs .OptionalTxOuts = (),
1060+ total_collateral_amount : int | None = None ,
1061+ mint : structs .OptionalMint = (),
1062+ tx_files : structs .TxFiles | None = None ,
1063+ complex_certs : structs .OptionalScriptCerts = (),
1064+ complex_proposals : structs .OptionalScriptProposals = (),
1065+ change_address : str = "" ,
1066+ fee_buffer : int | None = None ,
1067+ required_signers : itp .OptionalFiles = (),
1068+ required_signer_hashes : tp .Optional [list [str ]] = None ,
1069+ withdrawals : structs .OptionalTxOuts = (),
1070+ script_withdrawals : structs .OptionalScriptWithdrawals = (),
1071+ script_votes : structs .OptionalScriptVotes = (),
1072+ deposit : int | None = None ,
1073+ current_treasury_value : int | None = None ,
1074+ treasury_donation : int | None = None ,
1075+ invalid_hereafter : int | None = None ,
1076+ invalid_before : int | None = None ,
1077+ script_valid : bool = True ,
1078+ src_addr_utxos : list [structs .UTXOData ] | None = None ,
1079+ witness_count_add : int = 0 ,
1080+ byron_witness_count : int = 0 ,
1081+ reference_script_size : int = 0 ,
1082+ join_txouts : bool = True ,
1083+ destination_dir : itp .FileType = "." ,
1084+ skip_asset_balancing : bool = True ,
1085+ ) -> structs .TxRawOutput :
1086+ """Build a balanced transaction without access to a live node.
1087+
1088+ Args:
1089+ src_address: An address used for fee and inputs (if inputs not specified by `txins`).
1090+ tx_name: A name of the transaction.
1091+ txins: An iterable of `structs.UTXOData`, specifying input UTxOs (optional).
1092+ txouts: A list (iterable) of `TxOuts`, specifying transaction outputs (optional).
1093+ readonly_reference_txins: An iterable of `structs.UTXOData`, specifying input
1094+ UTxOs to be referenced and used as readonly (optional).
1095+ script_txins: An iterable of `ScriptTxIn`, specifying input script UTxOs (optional).
1096+ return_collateral_txouts: A list (iterable) of `TxOuts`, specifying transaction outputs
1097+ for excess collateral (optional).
1098+ total_collateral_amount: An integer indicating the total amount of collateral
1099+ (optional).
1100+ mint: An iterable of `Mint`, specifying script minting data (optional).
1101+ tx_files: A `structs.TxFiles` data container containing files needed for the transaction
1102+ (optional).
1103+ complex_certs: An iterable of `ComplexCert`, specifying certificates script data
1104+ (optional).
1105+ complex_proposals: An iterable of `ComplexProposal`, specifying proposals script data
1106+ (optional).
1107+ change_address: A string with address where ADA in excess of the transaction fee
1108+ will go to (`src_address` by default).
1109+ fee_buffer: A buffer for fee amount (optional).
1110+ required_signers: An iterable of filepaths of the signing keys whose signatures
1111+ are required (optional).
1112+ required_signer_hashes: A list of hashes of the signing keys whose signatures
1113+ are required (optional).
1114+ withdrawals: A list (iterable) of `TxOuts`, specifying reward withdrawals (optional).
1115+ script_withdrawals: An iterable of `ScriptWithdrawal`, specifying withdrawal script
1116+ data (optional).
1117+ script_votes: An iterable of `ScriptVote`, specifying vote script data (optional).
1118+ deposit: A deposit amount needed by the transaction (optional).
1119+ current_treasury_value: The current treasury value (optional).
1120+ treasury_donation: A donation to the treasury to perform (optional).
1121+ invalid_hereafter: A last block when the transaction is still valid (optional).
1122+ invalid_before: A first block when the transaction is valid (optional).
1123+ script_valid: A bool indicating that the script is valid (True by default).
1124+ src_addr_utxos: A list of UTxOs for the source address (optional).
1125+ witness_count_add: A number of witnesses to add - workaround to make the fee
1126+ calculation more precise.
1127+ byron_witness_count: A number of Byron witnesses (optional).
1128+ reference_script_size: A size in bytes of transaction reference scripts (optional).
1129+ join_txouts: A bool indicating whether to aggregate transaction outputs
1130+ by payment address (True by default).
1131+ destination_dir: A path to directory for storing artifacts (optional).
1132+ skip_asset_balancing: A bool indicating if assets balancing should be skipped.
1133+
1134+ Returns:
1135+ structs.TxRawOutput: A data container with transaction output details.
1136+ """
1137+ max_txout = [o for o in txouts if o .amount == - 1 and o .coin in ("" , consts .DEFAULT_COIN )]
1138+ if max_txout :
1139+ if change_address :
1140+ msg = "Cannot use '-1' amount and change address at the same time."
1141+ raise AssertionError (msg )
1142+ change_address = max_txout [0 ].address
1143+ else :
1144+ change_address = change_address or src_address
1145+
1146+ if (treasury_donation is not None ) != (current_treasury_value is not None ):
1147+ msg = (
1148+ "Both `treasury_donation` and `current_treasury_value` must be specified together."
1149+ )
1150+ raise AssertionError (msg )
1151+
1152+ tx_files = tx_files or structs .TxFiles ()
1153+ if tx_files .certificate_files and complex_certs :
1154+ LOGGER .warning (
1155+ "Mixing `tx_files.certificate_files` and `complex_certs`, "
1156+ "certs may come in unexpected order."
1157+ )
1158+
1159+ if tx_files .proposal_files and complex_proposals :
1160+ LOGGER .warning (
1161+ "Mixing `tx_files.proposal_files` and `complex_proposals`, "
1162+ "proposals may come in unexpected order."
1163+ )
1164+
1165+ destination_dir = pl .Path (destination_dir ).expanduser ()
1166+
1167+ out_file = destination_dir / f"{ tx_name } _tx.body"
1168+ clusterlib_helpers ._check_files_exist (out_file , clusterlib_obj = self ._clusterlib_obj )
1169+
1170+ collected_data = txtools .collect_data_for_build (
1171+ clusterlib_obj = self ._clusterlib_obj ,
1172+ src_address = src_address ,
1173+ txins = txins ,
1174+ txouts = txouts ,
1175+ script_txins = script_txins ,
1176+ mint = mint ,
1177+ tx_files = tx_files ,
1178+ complex_certs = complex_certs ,
1179+ complex_proposals = complex_proposals ,
1180+ fee = fee_buffer or 0 ,
1181+ withdrawals = withdrawals ,
1182+ script_withdrawals = script_withdrawals ,
1183+ deposit = deposit ,
1184+ treasury_donation = treasury_donation ,
1185+ src_addr_utxos = src_addr_utxos ,
1186+ skip_asset_balancing = skip_asset_balancing ,
1187+ )
1188+
1189+ required_signer_hashes = required_signer_hashes or []
1190+
1191+ txout_args , processed_txouts , txouts_count = txtools ._process_txouts (
1192+ txouts = collected_data .txouts , join_txouts = join_txouts
1193+ )
1194+
1195+ txin_strings = txtools ._get_txin_strings (
1196+ txins = collected_data .txins , script_txins = script_txins
1197+ )
1198+
1199+ withdrawal_strings = [f"{ x .address } +{ x .amount } " for x in collected_data .withdrawals ]
1200+
1201+ mint_txouts = list (itertools .chain .from_iterable (m .txouts for m in mint ))
1202+
1203+ script_txins_records = list (itertools .chain .from_iterable (r .txins for r in script_txins ))
1204+ combined_txins = [
1205+ * collected_data .txins ,
1206+ * script_txins_records ,
1207+ ]
1208+ total_utxo_value = txtools .calculate_utxos_balance (utxos = combined_txins )
1209+
1210+ estimate_args = [
1211+ "--shelley-key-witnesses" ,
1212+ str (len (tx_files .signing_key_files ) + witness_count_add ),
1213+ "--byron-key-witnesses" ,
1214+ str (byron_witness_count ),
1215+ "--reference-script-size" ,
1216+ str (reference_script_size ),
1217+ "--total-utxo-value" ,
1218+ str (total_utxo_value ),
1219+ ]
1220+
1221+ misc_args = []
1222+
1223+ if invalid_before is not None :
1224+ misc_args .extend (["--invalid-before" , str (invalid_before )])
1225+ if invalid_hereafter is not None :
1226+ misc_args .extend (["--invalid-hereafter" , str (invalid_hereafter )])
1227+
1228+ if treasury_donation is not None :
1229+ misc_args .extend (["--treasury-donation" , str (treasury_donation )])
1230+
1231+ if not script_valid :
1232+ misc_args .append ("--script-invalid" )
1233+
1234+ # There's allowed just single `--mint` argument, let's aggregate all the outputs
1235+ mint_records = [f"{ m .amount } { m .coin } " for m in mint_txouts ]
1236+ misc_args .extend (["--mint" , "+" .join (mint_records )] if mint_records else [])
1237+
1238+ for txin in readonly_reference_txins :
1239+ misc_args .extend (["--read-only-tx-in-reference" , f"{ txin .utxo_hash } #{ txin .utxo_ix } " ])
1240+
1241+ grouped_args = txtools ._get_script_args (
1242+ script_txins = script_txins ,
1243+ mint = mint ,
1244+ complex_certs = complex_certs ,
1245+ complex_proposals = complex_proposals ,
1246+ script_withdrawals = collected_data .script_withdrawals ,
1247+ script_votes = script_votes ,
1248+ with_execution_units = True ,
1249+ )
1250+
1251+ if total_collateral_amount :
1252+ misc_args .extend (["--tx-total-collateral" , str (total_collateral_amount )])
1253+
1254+ if tx_files .metadata_json_files and tx_files .metadata_json_detailed_schema :
1255+ misc_args .append ("--json-metadata-detailed-schema" )
1256+
1257+ self ._clusterlib_obj .create_pparams_file ()
1258+
1259+ cli_args = [
1260+ "transaction" ,
1261+ "build-estimate" ,
1262+ "--out-file" ,
1263+ str (out_file ),
1264+ * estimate_args ,
1265+ * grouped_args ,
1266+ * helpers ._prepend_flag ("--tx-in" , txin_strings ),
1267+ * txout_args ,
1268+ * helpers ._prepend_flag ("--required-signer" , required_signers ),
1269+ * helpers ._prepend_flag ("--required-signer-hash" , required_signer_hashes ),
1270+ * helpers ._prepend_flag ("--certificate-file" , tx_files .certificate_files ),
1271+ * helpers ._prepend_flag ("--proposal-file" , tx_files .proposal_files ),
1272+ * helpers ._prepend_flag ("--vote-file" , tx_files .vote_files ),
1273+ * helpers ._prepend_flag ("--auxiliary-script-file" , tx_files .auxiliary_script_files ),
1274+ * helpers ._prepend_flag ("--metadata-json-file" , tx_files .metadata_json_files ),
1275+ * helpers ._prepend_flag ("--metadata-cbor-file" , tx_files .metadata_cbor_files ),
1276+ * helpers ._prepend_flag ("--withdrawal" , withdrawal_strings ),
1277+ * txtools ._get_return_collateral_txout_args (txouts = return_collateral_txouts ),
1278+ "--change-address" ,
1279+ change_address ,
1280+ "--protocol-params-file" ,
1281+ str (self ._clusterlib_obj .pparams_file ),
1282+ * misc_args ,
1283+ * self ._clusterlib_obj .socket_args ,
1284+ ]
1285+ out = self ._clusterlib_obj .cli (cli_args )
1286+ stdout_dec = out .stdout .strip ().decode ("utf-8" ) if out .stdout else ""
1287+
1288+ # Check for the presence of fee information. No fee information was provided in older
1289+ # versions of the `build-estimate` command. Try to get the fee information from the
1290+ # `transaction view` command if not available from the `build-estimate`.
1291+ estimated_fee = - 1
1292+ fee_str = stdout_dec
1293+ if not fee_str .endswith ("Lovelace" ):
1294+ fee_str = self .view_tx_dict (tx_body_file = out_file ).get ("fee" ) or ""
1295+ if fee_str .endswith ("Lovelace" ):
1296+ estimated_fee = int (fee_str .split ()[- 2 ])
10111297
10121298 return structs .TxRawOutput (
10131299 txins = list (collected_data .txins ),
@@ -1192,7 +1478,10 @@ def submit_tx_bare(self, tx_file: itp.FileType) -> str:
11921478 return txhash
11931479
11941480 def submit_tx (
1195- self , tx_file : itp .FileType , txins : list [structs .UTXOData ], wait_blocks : int | None = None
1481+ self ,
1482+ tx_file : itp .FileType ,
1483+ txins : list [structs .UTXOData ],
1484+ wait_blocks : int | None = None ,
11961485 ) -> str :
11971486 """Submit a transaction, resubmit if the transaction didn't make it to the chain.
11981487
0 commit comments