@@ -209,66 +209,31 @@ void TransactionBuilder::SendChangeTo(CTxDestination& changeAddr)
209209 saplingChangeAddr = nullopt ;
210210}
211211
212- TransactionBuilderResult TransactionBuilder::Build ()
212+ TransactionBuilderResult TransactionBuilder::ProveAndSign ()
213213{
214214 //
215- // Consistency checks
215+ // Sapling spend descriptions
216216 //
217- // Valid fee
218- if (fee < 0 ) {
219- return TransactionBuilderResult (" Fee cannot be negative" );
220- }
221-
222- // Valid change
223- CAmount change = mtx.sapData ->valueBalance - fee;
224- for (auto & tIn : tIns) {
225- change += tIn.value ;
226- }
227- for (auto & tOut : mtx.vout ) {
228- change -= tOut.nValue ;
229- }
230- if (change < 0 ) {
231- return TransactionBuilderResult (" Change cannot be negative" );
232- }
217+ if (!spends.empty () || !outputs.empty ()) {
233218
234- //
235- // Change output
236- //
219+ auto ctx = librustzcash_sapling_proving_ctx_init ();
237220
238- if (change > 0 ) {
239- // If we get here and the change is dust, add it to the fee
240- CAmount dustThreshold = (spends.empty () && outputs.empty ()) ? GetDustThreshold (minRelayTxFee) :
241- GetShieldedDustThreshold (minRelayTxFee);
242- if (change > dustThreshold) {
243- // Send change to the specified change address. If no change address
244- // was set, send change to the first Sapling address given as input
245- // (A t-address can only be used as the change address if explicitly set.)
246- if (saplingChangeAddr) {
247- AddSaplingOutput (saplingChangeAddr->first , saplingChangeAddr->second , change);
248- } else if (tChangeAddr) {
249- // tChangeAddr has already been validated.
250- AddTransparentOutput (*tChangeAddr, change);
251- } else if (!spends.empty ()) {
252- auto fvk = spends[0 ].expsk .full_viewing_key ();
253- auto note = spends[0 ].note ;
254- libzcash::SaplingPaymentAddress changeAddr (note.d , note.pk_d );
255- AddSaplingOutput (fvk.ovk , changeAddr, change);
256- } else {
257- return TransactionBuilderResult (" Could not determine change address" );
221+ // Create Sapling OutputDescriptions
222+ for (auto output : outputs) {
223+ // Check this out here as well to provide better logging.
224+ if (!output.note .cmu ()) {
225+ librustzcash_sapling_proving_ctx_free (ctx);
226+ return TransactionBuilderResult (" Output is invalid" );
258227 }
259- } else {
260- // Not used after, but update for consistency
261- fee += change;
262- change = 0 ;
263- }
264- }
265228
266- //
267- // Sapling spends and outputs
268- //
269- if (!spends.empty () || !outputs.empty ()) {
229+ auto odesc = output.Build (ctx);
230+ if (!odesc) {
231+ librustzcash_sapling_proving_ctx_free (ctx);
232+ return TransactionBuilderResult (" Failed to create output description" );
233+ }
270234
271- auto ctx = librustzcash_sapling_proving_ctx_init ();
235+ mtx.sapData ->vShieldedOutput .push_back (odesc.get ());
236+ }
272237
273238 // Create Sapling SpendDescriptions
274239 for (auto spend : spends) {
@@ -307,23 +272,6 @@ TransactionBuilderResult TransactionBuilder::Build()
307272 mtx.sapData ->vShieldedSpend .push_back (sdesc);
308273 }
309274
310- // Create Sapling OutputDescriptions
311- for (auto output : outputs) {
312- // Check this out here as well to provide better logging.
313- if (!output.note .cmu ()) {
314- librustzcash_sapling_proving_ctx_free (ctx);
315- return TransactionBuilderResult (" Output is invalid" );
316- }
317-
318- auto odesc = output.Build (ctx);
319- if (!odesc) {
320- librustzcash_sapling_proving_ctx_free (ctx);
321- return TransactionBuilderResult (" Failed to create output description" );
322- }
323-
324- mtx.sapData ->vShieldedOutput .push_back (odesc.get ());
325- }
326-
327275 //
328276 // Signatures
329277 //
@@ -375,3 +323,60 @@ TransactionBuilderResult TransactionBuilder::Build()
375323
376324 return TransactionBuilderResult (CTransaction (mtx));
377325}
326+
327+ TransactionBuilderResult TransactionBuilder::Build ()
328+ {
329+ //
330+ // Consistency checks
331+ //
332+ // Valid fee
333+ if (fee < 0 ) {
334+ return TransactionBuilderResult (" Fee cannot be negative" );
335+ }
336+
337+ // Valid change
338+ CAmount change = mtx.sapData ->valueBalance - fee;
339+ for (auto & tIn : tIns) {
340+ change += tIn.value ;
341+ }
342+ for (auto & tOut : mtx.vout ) {
343+ change -= tOut.nValue ;
344+ }
345+ if (change < 0 ) {
346+ return TransactionBuilderResult (" Change cannot be negative" );
347+ }
348+
349+ //
350+ // Change output
351+ //
352+
353+ if (change > 0 ) {
354+ // If we get here and the change is dust, add it to the fee
355+ CAmount dustThreshold = (spends.empty () && outputs.empty ()) ? GetDustThreshold (minRelayTxFee) :
356+ GetShieldedDustThreshold (minRelayTxFee);
357+ if (change > dustThreshold) {
358+ // Send change to the specified change address. If no change address
359+ // was set, send change to the first Sapling address given as input
360+ // (A t-address can only be used as the change address if explicitly set.)
361+ if (saplingChangeAddr) {
362+ AddSaplingOutput (saplingChangeAddr->first , saplingChangeAddr->second , change);
363+ } else if (tChangeAddr) {
364+ // tChangeAddr has already been validated.
365+ AddTransparentOutput (*tChangeAddr, change);
366+ } else if (!spends.empty ()) {
367+ auto fvk = spends[0 ].expsk .full_viewing_key ();
368+ auto note = spends[0 ].note ;
369+ libzcash::SaplingPaymentAddress changeAddr (note.d , note.pk_d );
370+ AddSaplingOutput (fvk.ovk , changeAddr, change);
371+ } else {
372+ return TransactionBuilderResult (" Could not determine change address" );
373+ }
374+ } else {
375+ // Not used after, but update for consistency
376+ fee += change;
377+ change = 0 ;
378+ }
379+ }
380+
381+ return ProveAndSign ();
382+ }
0 commit comments