]> Git Repo - VerusCoin.git/blob - src/transaction_builder.cpp
Auto merge of #4075 - Eirik0:4059-fix-migration-test, r=Eirik0
[VerusCoin.git] / src / transaction_builder.cpp
1 // Copyright (c) 2018 The Zcash developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or https://www.opensource.org/licenses/mit-license.php .
4
5 #include "transaction_builder.h"
6
7 #include "main.h"
8 #include "pubkey.h"
9 #include "rpc/protocol.h"
10 #include "script/sign.h"
11 #include "utilmoneystr.h"
12
13 #include <boost/variant.hpp>
14 #include <librustzcash.h>
15
16 SpendDescriptionInfo::SpendDescriptionInfo(
17     libzcash::SaplingExpandedSpendingKey expsk,
18     libzcash::SaplingNote note,
19     uint256 anchor,
20     SaplingWitness witness) : expsk(expsk), note(note), anchor(anchor), witness(witness)
21 {
22     librustzcash_sapling_generate_r(alpha.begin());
23 }
24
25 TransactionBuilderResult::TransactionBuilderResult(const CTransaction& tx) : maybeTx(tx) {}
26
27 TransactionBuilderResult::TransactionBuilderResult(const std::string& error) : maybeError(error) {}
28
29 bool TransactionBuilderResult::IsTx() { return maybeTx != boost::none; }
30
31 bool TransactionBuilderResult::IsError() { return maybeError != boost::none; }
32
33 CTransaction TransactionBuilderResult::GetTxOrThrow() {
34     if (maybeTx) {
35         return maybeTx.get();
36     } else {
37         throw JSONRPCError(RPC_WALLET_ERROR, "Failed to build transaction: " + GetError());
38     }
39 }
40
41 std::string TransactionBuilderResult::GetError() {
42     if (maybeError) {
43         return maybeError.get();
44     } else {
45         // This can only happen if isTx() is true in which case we should not call getError()
46         throw std::runtime_error("getError() was called in TransactionBuilderResult, but the result was not initialized as an error.");
47     }
48 }
49
50 TransactionBuilder::TransactionBuilder(
51     const Consensus::Params& consensusParams,
52     int nHeight,
53     int nExpiryDelta,
54     CKeyStore* keystore,
55     ZCJoinSplit* sproutParams,
56     CCoinsViewCache* coinsView,
57     CCriticalSection* cs_coinsView) :
58     consensusParams(consensusParams),
59     nHeight(nHeight),
60     keystore(keystore),
61     sproutParams(sproutParams),
62     coinsView(coinsView),
63     cs_coinsView(cs_coinsView)
64 {
65     mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight, nExpiryDelta);
66 }
67
68 // This exception is thrown in certain scenarios when building JoinSplits fails.
69 struct JSDescException : public std::exception
70 {
71     JSDescException (const std::string msg_) : msg(msg_) {}
72
73     const char* what() { return msg.c_str(); }
74
75 private:
76     std::string msg;
77 };
78
79 void TransactionBuilder::AddSaplingSpend(
80     libzcash::SaplingExpandedSpendingKey expsk,
81     libzcash::SaplingNote note,
82     uint256 anchor,
83     SaplingWitness witness)
84 {
85     // Sanity check: cannot add Sapling spend to pre-Sapling transaction
86     if (mtx.nVersion < SAPLING_TX_VERSION) {
87         throw std::runtime_error("TransactionBuilder cannot add Sapling spend to pre-Sapling transaction");
88     }
89
90     // Consistency check: all anchors must equal the first one
91     if (spends.size() > 0 && spends[0].anchor != anchor) {
92         throw JSONRPCError(RPC_WALLET_ERROR, "Anchor does not match previously-added Sapling spends.");
93     }
94
95     spends.emplace_back(expsk, note, anchor, witness);
96     mtx.valueBalance += note.value();
97 }
98
99 void TransactionBuilder::AddSaplingOutput(
100     uint256 ovk,
101     libzcash::SaplingPaymentAddress to,
102     CAmount value,
103     std::array<unsigned char, ZC_MEMO_SIZE> memo)
104 {
105     // Sanity check: cannot add Sapling output to pre-Sapling transaction
106     if (mtx.nVersion < SAPLING_TX_VERSION) {
107         throw std::runtime_error("TransactionBuilder cannot add Sapling output to pre-Sapling transaction");
108     }
109
110     auto note = libzcash::SaplingNote(to, value);
111     outputs.emplace_back(ovk, note, memo);
112     mtx.valueBalance -= value;
113 }
114
115 void TransactionBuilder::AddSproutInput(
116     libzcash::SproutSpendingKey sk,
117     libzcash::SproutNote note,
118     SproutWitness witness)
119 {
120     if (sproutParams == nullptr) {
121         throw std::runtime_error("Cannot add Sprout inputs to a TransactionBuilder without Sprout params");
122     }
123
124     // Consistency check: all anchors must equal the first one
125     if (!jsInputs.empty()) {
126         if (jsInputs[0].witness.root() != witness.root()) {
127             throw JSONRPCError(RPC_WALLET_ERROR, "Anchor does not match previously-added Sprout spends.");
128         }
129     }
130
131     jsInputs.emplace_back(witness, note, sk);
132 }
133
134 void TransactionBuilder::AddSproutOutput(
135     libzcash::SproutPaymentAddress to,
136     CAmount value,
137     std::array<unsigned char, ZC_MEMO_SIZE> memo)
138 {
139     if (sproutParams == nullptr) {
140         throw std::runtime_error("Cannot add Sprout outputs to a TransactionBuilder without Sprout params");
141     }
142
143     libzcash::JSOutput jsOutput(to, value);
144     jsOutput.memo = memo;
145     jsOutputs.push_back(jsOutput);
146 }
147
148 void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value)
149 {
150     if (keystore == nullptr) {
151         throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
152     }
153
154     mtx.vin.emplace_back(utxo);
155     tIns.emplace_back(scriptPubKey, value);
156 }
157
158 void TransactionBuilder::AddTransparentOutput(CTxDestination& to, CAmount value)
159 {
160     if (!IsValidDestination(to)) {
161         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr.");
162     }
163
164     CScript scriptPubKey = GetScriptForDestination(to);
165     CTxOut out(value, scriptPubKey);
166     mtx.vout.push_back(out);
167 }
168
169 void TransactionBuilder::SetFee(CAmount fee)
170 {
171     this->fee = fee;
172 }
173
174 void TransactionBuilder::SendChangeTo(libzcash::SaplingPaymentAddress changeAddr, uint256 ovk)
175 {
176     saplingChangeAddr = std::make_pair(ovk, changeAddr);
177     sproutChangeAddr = boost::none;
178     tChangeAddr = boost::none;
179 }
180
181 void TransactionBuilder::SendChangeTo(libzcash::SproutPaymentAddress changeAddr)
182 {
183     sproutChangeAddr = changeAddr;
184     saplingChangeAddr = boost::none;
185     tChangeAddr = boost::none;
186 }
187
188 void TransactionBuilder::SendChangeTo(CTxDestination& changeAddr)
189 {
190     if (!IsValidDestination(changeAddr)) {
191         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid change address, not a valid taddr.");
192     }
193
194     tChangeAddr = changeAddr;
195     saplingChangeAddr = boost::none;
196     sproutChangeAddr = boost::none;
197 }
198
199 TransactionBuilderResult TransactionBuilder::Build()
200 {
201     //
202     // Consistency checks
203     //
204
205     // Valid change
206     CAmount change = mtx.valueBalance - fee;
207     for (auto jsInput : jsInputs) {
208         change += jsInput.note.value();
209     }
210     for (auto jsOutput : jsOutputs) {
211         change -= jsOutput.value;
212     }
213     for (auto tIn : tIns) {
214         change += tIn.value;
215     }
216     for (auto tOut : mtx.vout) {
217         change -= tOut.nValue;
218     }
219     if (change < 0) {
220         return TransactionBuilderResult("Change cannot be negative");
221     }
222
223     //
224     // Change output
225     //
226
227     if (change > 0) {
228         // Send change to the specified change address. If no change address
229         // was set, send change to the first Sapling address given as input
230         // if any; otherwise the first Sprout address given as input.
231         // (A t-address can only be used as the change address if explicitly set.)
232         if (saplingChangeAddr) {
233             AddSaplingOutput(saplingChangeAddr->first, saplingChangeAddr->second, change);
234         } else if (sproutChangeAddr) {
235             AddSproutOutput(sproutChangeAddr.get(), change);
236         } else if (tChangeAddr) {
237             // tChangeAddr has already been validated.
238             AddTransparentOutput(tChangeAddr.value(), change);
239         } else if (!spends.empty()) {
240             auto fvk = spends[0].expsk.full_viewing_key();
241             auto note = spends[0].note;
242             libzcash::SaplingPaymentAddress changeAddr(note.d, note.pk_d);
243             AddSaplingOutput(fvk.ovk, changeAddr, change);
244         } else if (!jsInputs.empty()) {
245             auto changeAddr = jsInputs[0].key.address();
246             AddSproutOutput(changeAddr, change);
247         } else {
248             return TransactionBuilderResult("Could not determine change address");
249         }
250     }
251
252     //
253     // Sapling spends and outputs
254     //
255
256     auto ctx = librustzcash_sapling_proving_ctx_init();
257
258     // Create Sapling SpendDescriptions
259     for (auto spend : spends) {
260         auto cm = spend.note.cm();
261         auto nf = spend.note.nullifier(
262             spend.expsk.full_viewing_key(), spend.witness.position());
263         if (!cm || !nf) {
264             librustzcash_sapling_proving_ctx_free(ctx);
265             return TransactionBuilderResult("Spend is invalid");
266         }
267
268         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
269         ss << spend.witness.path();
270         std::vector<unsigned char> witness(ss.begin(), ss.end());
271
272         SpendDescription sdesc;
273         if (!librustzcash_sapling_spend_proof(
274                 ctx,
275                 spend.expsk.full_viewing_key().ak.begin(),
276                 spend.expsk.nsk.begin(),
277                 spend.note.d.data(),
278                 spend.note.r.begin(),
279                 spend.alpha.begin(),
280                 spend.note.value(),
281                 spend.anchor.begin(),
282                 witness.data(),
283                 sdesc.cv.begin(),
284                 sdesc.rk.begin(),
285                 sdesc.zkproof.data())) {
286             librustzcash_sapling_proving_ctx_free(ctx);
287             return TransactionBuilderResult("Spend proof failed");
288         }
289
290         sdesc.anchor = spend.anchor;
291         sdesc.nullifier = *nf;
292         mtx.vShieldedSpend.push_back(sdesc);
293     }
294
295     // Create Sapling OutputDescriptions
296     for (auto output : outputs) {
297         auto cm = output.note.cm();
298         if (!cm) {
299             librustzcash_sapling_proving_ctx_free(ctx);
300             return TransactionBuilderResult("Output is invalid");
301         }
302
303         libzcash::SaplingNotePlaintext notePlaintext(output.note, output.memo);
304
305         auto res = notePlaintext.encrypt(output.note.pk_d);
306         if (!res) {
307             librustzcash_sapling_proving_ctx_free(ctx);
308             return TransactionBuilderResult("Failed to encrypt note");
309         }
310         auto enc = res.get();
311         auto encryptor = enc.second;
312
313         OutputDescription odesc;
314         if (!librustzcash_sapling_output_proof(
315                 ctx,
316                 encryptor.get_esk().begin(),
317                 output.note.d.data(),
318                 output.note.pk_d.begin(),
319                 output.note.r.begin(),
320                 output.note.value(),
321                 odesc.cv.begin(),
322                 odesc.zkproof.begin())) {
323             librustzcash_sapling_proving_ctx_free(ctx);
324             return TransactionBuilderResult("Output proof failed");
325         }
326
327         odesc.cm = *cm;
328         odesc.ephemeralKey = encryptor.get_epk();
329         odesc.encCiphertext = enc.first;
330
331         libzcash::SaplingOutgoingPlaintext outPlaintext(output.note.pk_d, encryptor.get_esk());
332         odesc.outCiphertext = outPlaintext.encrypt(
333             output.ovk,
334             odesc.cv,
335             odesc.cm,
336             encryptor);
337         mtx.vShieldedOutput.push_back(odesc);
338     }
339
340     //
341     // Sprout JoinSplits
342     //
343
344     unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
345     crypto_sign_keypair(mtx.joinSplitPubKey.begin(), joinSplitPrivKey);
346
347     // Create Sprout JSDescriptions
348     if (!jsInputs.empty() || !jsOutputs.empty()) {
349         try {
350             CreateJSDescriptions();
351         } catch (JSDescException e) {
352             librustzcash_sapling_proving_ctx_free(ctx);
353             return TransactionBuilderResult(e.what());
354         } catch (std::runtime_error e) {
355             librustzcash_sapling_proving_ctx_free(ctx);
356             throw e;
357         }
358     }
359
360     //
361     // Signatures
362     //
363
364     auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
365
366     // Empty output script.
367     uint256 dataToBeSigned;
368     CScript scriptCode;
369     try {
370         dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId);
371     } catch (std::logic_error ex) {
372         librustzcash_sapling_proving_ctx_free(ctx);
373         return TransactionBuilderResult("Could not construct signature hash: " + std::string(ex.what()));
374     }
375
376     // Create Sapling spendAuth and binding signatures
377     for (size_t i = 0; i < spends.size(); i++) {
378         librustzcash_sapling_spend_sig(
379             spends[i].expsk.ask.begin(),
380             spends[i].alpha.begin(),
381             dataToBeSigned.begin(),
382             mtx.vShieldedSpend[i].spendAuthSig.data());
383     }
384     librustzcash_sapling_binding_sig(
385         ctx,
386         mtx.valueBalance,
387         dataToBeSigned.begin(),
388         mtx.bindingSig.data());
389
390     librustzcash_sapling_proving_ctx_free(ctx);
391
392     // Create Sprout joinSplitSig
393     if (crypto_sign_detached(
394         mtx.joinSplitSig.data(), NULL,
395         dataToBeSigned.begin(), 32,
396         joinSplitPrivKey) != 0)
397     {
398         return TransactionBuilderResult("Failed to create Sprout joinSplitSig");
399     }
400
401     // Sanity check Sprout joinSplitSig
402     if (crypto_sign_verify_detached(
403         mtx.joinSplitSig.data(),
404         dataToBeSigned.begin(), 32,
405         mtx.joinSplitPubKey.begin()) != 0)
406     {
407         return TransactionBuilderResult("Sprout joinSplitSig sanity check failed");
408     }
409
410     // Transparent signatures
411     CTransaction txNewConst(mtx);
412     for (int nIn = 0; nIn < mtx.vin.size(); nIn++) {
413         auto tIn = tIns[nIn];
414         SignatureData sigdata;
415         bool signSuccess = ProduceSignature(
416             TransactionSignatureCreator(
417                 keystore, &txNewConst, nIn, tIn.value, SIGHASH_ALL),
418             tIn.scriptPubKey, sigdata, consensusBranchId);
419
420         if (!signSuccess) {
421             return TransactionBuilderResult("Failed to sign transaction");
422         } else {
423             UpdateTransaction(mtx, nIn, sigdata);
424         }
425     }
426
427     return TransactionBuilderResult(CTransaction(mtx));
428 }
429
430 void TransactionBuilder::CreateJSDescriptions()
431 {
432     // Copy jsInputs and jsOutputs to more flexible containers
433     std::deque<libzcash::JSInput> jsInputsDeque;
434     for (auto jsInput : jsInputs) {
435         jsInputsDeque.push_back(jsInput);
436     }
437     std::deque<libzcash::JSOutput> jsOutputsDeque;
438     for (auto jsOutput : jsOutputs) {
439         jsOutputsDeque.push_back(jsOutput);
440     }
441
442     // If we have no Sprout shielded inputs, then we do the simpler more-leaky
443     // process where we just create outputs directly. We save the chaining logic,
444     // at the expense of leaking the sums of pairs of output values in vpub_old.
445     if (jsInputs.empty()) {
446         // Create joinsplits, where each output represents a zaddr recipient.
447         while (jsOutputsDeque.size() > 0) {
448             // Default array entries are dummy inputs and outputs
449             std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> vjsin;
450             std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> vjsout;
451             uint64_t vpub_old = 0;
452
453             for (int n = 0; n < ZC_NUM_JS_OUTPUTS && jsOutputsDeque.size() > 0; n++) {
454                 vjsout[n] = jsOutputsDeque.front();
455                 jsOutputsDeque.pop_front();
456
457                 // Funds are removed from the value pool and enter the private pool
458                 vpub_old += vjsout[n].value;
459             }
460
461             std::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
462             std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
463             CreateJSDescription(vpub_old, 0, vjsin, vjsout, inputMap, outputMap);
464         }
465         return;
466     }
467
468     // At this point, we are guaranteed to have at least one input note.
469     // Use address of first input note as the temporary change address.
470     auto changeKey = jsInputsDeque.front().key;
471     auto changeAddress = changeKey.address();
472
473     CAmount jsChange = 0;          // this is updated after each joinsplit
474     int changeOutputIndex = -1;    // this is updated after each joinsplit if jsChange > 0
475     bool vpubOldProcessed = false; // updated when vpub_old for taddr inputs is set in first joinsplit
476     bool vpubNewProcessed = false; // updated when vpub_new for miner fee and taddr outputs is set in last joinsplit
477
478     CAmount valueOut = 0;
479     for (auto jsInput : jsInputs) {
480         valueOut += jsInput.note.value();
481     }
482     for (auto jsOutput : jsOutputs) {
483         valueOut -= jsOutput.value;
484     }
485     CAmount vpubOldTarget = valueOut < 0 ? -valueOut : 0;
486     CAmount vpubNewTarget = valueOut > 0 ? valueOut : 0;
487
488     // Keep track of treestate within this transaction
489     boost::unordered_map<uint256, SproutMerkleTree, CCoinsKeyHasher> intermediates;
490     std::vector<uint256> previousCommitments;
491
492     while (!vpubNewProcessed) {
493         // Default array entries are dummy inputs and outputs
494         std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> vjsin;
495         std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> vjsout;
496         uint64_t vpub_old = 0;
497         uint64_t vpub_new = 0;
498
499         // Set vpub_old in the first joinsplit
500         if (!vpubOldProcessed) {
501             vpub_old += vpubOldTarget; // funds flowing from public pool
502             vpubOldProcessed = true;
503         }
504
505         CAmount jsInputValue = 0;
506         uint256 jsAnchor;
507
508         JSDescription prevJoinSplit;
509
510         // Keep track of previous JoinSplit and its commitments
511         if (mtx.vJoinSplit.size() > 0) {
512             prevJoinSplit = mtx.vJoinSplit.back();
513         }
514
515         // If there is no change, the chain has terminated so we can reset the tracked treestate.
516         if (jsChange == 0 && mtx.vJoinSplit.size() > 0) {
517             intermediates.clear();
518             previousCommitments.clear();
519         }
520
521         //
522         // Consume change as the first input of the JoinSplit.
523         //
524         if (jsChange > 0) {
525             // Update tree state with previous joinsplit
526             SproutMerkleTree tree;
527             {
528                 // assert that coinsView is not null
529                 assert(coinsView);
530                 // We do not check cs_coinView because we do not set this in testing
531                 // assert(cs_coinsView);
532                 LOCK(cs_coinsView);
533                 auto it = intermediates.find(prevJoinSplit.anchor);
534                 if (it != intermediates.end()) {
535                     tree = it->second;
536                 } else if (!coinsView->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) {
537                     throw JSDescException("Could not find previous JoinSplit anchor");
538                 }
539             }
540
541             assert(changeOutputIndex != -1);
542             assert(changeOutputIndex < prevJoinSplit.commitments.size());
543             boost::optional<SproutWitness> changeWitness;
544             int n = 0;
545             for (const uint256& commitment : prevJoinSplit.commitments) {
546                 tree.append(commitment);
547                 previousCommitments.push_back(commitment);
548                 if (!changeWitness && changeOutputIndex == n++) {
549                     changeWitness = tree.witness();
550                 } else if (changeWitness) {
551                     changeWitness.get().append(commitment);
552                 }
553             }
554             assert(changeWitness.has_value());
555             jsAnchor = tree.root();
556             intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries)
557
558             // Decrypt the change note's ciphertext to retrieve some data we need
559             ZCNoteDecryption decryptor(changeKey.receiving_key());
560             auto hSig = prevJoinSplit.h_sig(*sproutParams, mtx.joinSplitPubKey);
561             try {
562                 auto plaintext = libzcash::SproutNotePlaintext::decrypt(
563                     decryptor,
564                     prevJoinSplit.ciphertexts[changeOutputIndex],
565                     prevJoinSplit.ephemeralKey,
566                     hSig,
567                     (unsigned char)changeOutputIndex);
568
569                 auto note = plaintext.note(changeAddress);
570                 vjsin[0] = libzcash::JSInput(changeWitness.get(), note, changeKey);
571
572                 jsInputValue += plaintext.value();
573
574                 LogPrint("zrpcunsafe", "spending change (amount=%s)\n", FormatMoney(plaintext.value()));
575
576             } catch (const std::exception& e) {
577                 throw JSDescException("Error decrypting output note of previous JoinSplit");
578             }
579         }
580
581         //
582         // Consume spendable non-change notes
583         //
584         for (int n = (jsChange > 0) ? 1 : 0; n < ZC_NUM_JS_INPUTS && jsInputsDeque.size() > 0; n++) {
585             auto jsInput = jsInputsDeque.front();
586             jsInputsDeque.pop_front();
587
588             // Add history of previous commitments to witness
589             if (jsChange > 0) {
590                 for (const uint256& commitment : previousCommitments) {
591                     jsInput.witness.append(commitment);
592                 }
593                 if (jsAnchor != jsInput.witness.root()) {
594                     throw JSDescException("Witness for spendable note does not have same anchor as change input");
595                 }
596             }
597
598             // The jsAnchor is null if this JoinSplit is at the start of a new chain
599             if (jsAnchor.IsNull()) {
600                 jsAnchor = jsInput.witness.root();
601             }
602
603             jsInputValue += jsInput.note.value();
604             vjsin[n] = jsInput;
605         }
606
607         // Find recipient to transfer funds to
608         libzcash::JSOutput recipient;
609         if (jsOutputsDeque.size() > 0) {
610             recipient = jsOutputsDeque.front();
611             jsOutputsDeque.pop_front();
612         }
613         // `recipient` is now either a valid recipient, or a dummy output with value = 0
614
615         // Reset change
616         jsChange = 0;
617         CAmount outAmount = recipient.value;
618
619         // Set vpub_new in the last joinsplit (when there are no more notes to spend or zaddr outputs to satisfy)
620         if (jsOutputsDeque.empty() && jsInputsDeque.empty()) {
621             assert(!vpubNewProcessed);
622             if (jsInputValue < vpubNewTarget) {
623                 throw JSDescException(strprintf("Insufficient funds for vpub_new %s", FormatMoney(vpubNewTarget)));
624             }
625             outAmount += vpubNewTarget;
626             vpub_new += vpubNewTarget; // funds flowing back to public pool
627             vpubNewProcessed = true;
628             jsChange = jsInputValue - outAmount;
629             assert(jsChange >= 0);
630         } else {
631             // This is not the last joinsplit, so compute change and any amount still due to the recipient
632             if (jsInputValue > outAmount) {
633                 jsChange = jsInputValue - outAmount;
634             } else if (outAmount > jsInputValue) {
635                 // Any amount due is owed to the recipient.  Let the miners fee get paid first.
636                 CAmount due = outAmount - jsInputValue;
637                 libzcash::JSOutput recipientDue(recipient.addr, due);
638                 recipientDue.memo = recipient.memo;
639                 jsOutputsDeque.push_front(recipientDue);
640
641                 // reduce the amount being sent right now to the value of all inputs
642                 recipient.value = jsInputValue;
643             }
644         }
645
646         // create output for recipient
647         assert(ZC_NUM_JS_OUTPUTS == 2); // If this changes, the logic here will need to be adjusted
648         vjsout[0] = recipient;
649
650         // create output for any change
651         if (jsChange > 0) {
652             vjsout[1] = libzcash::JSOutput(changeAddress, jsChange);
653
654             LogPrint("zrpcunsafe", "generating note for change (amount=%s)\n", FormatMoney(jsChange));
655         }
656
657         std::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
658         std::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
659         CreateJSDescription(vpub_old, vpub_new, vjsin, vjsout, inputMap, outputMap);
660
661         if (jsChange > 0) {
662             changeOutputIndex = -1;
663             for (size_t i = 0; i < outputMap.size(); i++) {
664                 if (outputMap[i] == 1) {
665                     changeOutputIndex = i;
666                 }
667             }
668             assert(changeOutputIndex != -1);
669         }
670     }
671 }
672
673 void TransactionBuilder::CreateJSDescription(
674     uint64_t vpub_old,
675     uint64_t vpub_new,
676     std::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> vjsin,
677     std::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> vjsout,
678     std::array<size_t, ZC_NUM_JS_INPUTS>& inputMap,
679     std::array<size_t, ZC_NUM_JS_OUTPUTS>& outputMap)
680 {
681     LogPrint("zrpcunsafe", "CreateJSDescription: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n",
682         mtx.vJoinSplit.size(),
683         FormatMoney(vpub_old), FormatMoney(vpub_new),
684         FormatMoney(vjsin[0].note.value()), FormatMoney(vjsin[1].note.value()),
685         FormatMoney(vjsout[0].value), FormatMoney(vjsout[1].value));
686
687     uint256 esk; // payment disclosure - secret
688
689     // Generate the proof, this can take over a minute.
690     JSDescription jsdesc = JSDescription::Randomized(
691             mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION),
692             *sproutParams,
693             mtx.joinSplitPubKey,
694             vjsin[0].witness.root(),
695             vjsin,
696             vjsout,
697             inputMap,
698             outputMap,
699             vpub_old,
700             vpub_new,
701             true, //!this->testmode,
702             &esk); // parameter expects pointer to esk, so pass in address
703
704     {
705         auto verifier = libzcash::ProofVerifier::Strict();
706         if (!jsdesc.Verify(*sproutParams, verifier, mtx.joinSplitPubKey)) {
707             throw std::runtime_error("error verifying joinsplit");
708         }
709     }
710
711     mtx.vJoinSplit.push_back(jsdesc);
712
713     // TODO: Sprout payment disclosure
714 }
This page took 0.06348 seconds and 4 git commands to generate.