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 .
5 #include "transaction_builder.h"
9 #include "rpc/protocol.h"
10 #include "script/sign.h"
11 #include "utilmoneystr.h"
13 #include <boost/variant.hpp>
14 #include <librustzcash.h>
16 SpendDescriptionInfo::SpendDescriptionInfo(
17 libzcash::SaplingExpandedSpendingKey expsk,
18 libzcash::SaplingNote note,
20 SaplingWitness witness) : expsk(expsk), note(note), anchor(anchor), witness(witness)
22 librustzcash_sapling_generate_r(alpha.begin());
25 TransactionBuilderResult::TransactionBuilderResult(const CTransaction& tx) : maybeTx(tx) {}
27 TransactionBuilderResult::TransactionBuilderResult(const std::string& error) : maybeError(error) {}
29 bool TransactionBuilderResult::IsTx() { return maybeTx != boost::none; }
31 bool TransactionBuilderResult::IsError() { return maybeError != boost::none; }
33 CTransaction TransactionBuilderResult::GetTxOrThrow() {
37 throw JSONRPCError(RPC_WALLET_ERROR, "Failed to build transaction: " + GetError());
41 std::string TransactionBuilderResult::GetError() {
43 return maybeError.get();
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.");
50 TransactionBuilder::TransactionBuilder(
51 const Consensus::Params& consensusParams,
55 ZCJoinSplit* sproutParams,
56 CCoinsViewCache* coinsView,
57 CCriticalSection* cs_coinsView) :
58 consensusParams(consensusParams),
61 sproutParams(sproutParams),
63 cs_coinsView(cs_coinsView)
65 mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight, nExpiryDelta);
68 // This exception is thrown in certain scenarios when building JoinSplits fails.
69 struct JSDescException : public std::exception
71 JSDescException (const std::string msg_) : msg(msg_) {}
73 const char* what() { return msg.c_str(); }
79 void TransactionBuilder::AddSaplingSpend(
80 libzcash::SaplingExpandedSpendingKey expsk,
81 libzcash::SaplingNote note,
83 SaplingWitness witness)
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");
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.");
95 spends.emplace_back(expsk, note, anchor, witness);
96 mtx.valueBalance += note.value();
99 void TransactionBuilder::AddSaplingOutput(
101 libzcash::SaplingPaymentAddress to,
103 std::array<unsigned char, ZC_MEMO_SIZE> memo)
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");
110 auto note = libzcash::SaplingNote(to, value);
111 outputs.emplace_back(ovk, note, memo);
112 mtx.valueBalance -= value;
115 void TransactionBuilder::AddSproutInput(
116 libzcash::SproutSpendingKey sk,
117 libzcash::SproutNote note,
118 SproutWitness witness)
120 if (sproutParams == nullptr) {
121 throw std::runtime_error("Cannot add Sprout inputs to a TransactionBuilder without Sprout params");
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.");
131 jsInputs.emplace_back(witness, note, sk);
134 void TransactionBuilder::AddSproutOutput(
135 libzcash::SproutPaymentAddress to,
137 std::array<unsigned char, ZC_MEMO_SIZE> memo)
139 if (sproutParams == nullptr) {
140 throw std::runtime_error("Cannot add Sprout outputs to a TransactionBuilder without Sprout params");
143 libzcash::JSOutput jsOutput(to, value);
144 jsOutput.memo = memo;
145 jsOutputs.push_back(jsOutput);
148 void TransactionBuilder::AddTransparentInput(COutPoint utxo, CScript scriptPubKey, CAmount value)
150 if (keystore == nullptr) {
151 throw std::runtime_error("Cannot add transparent inputs to a TransactionBuilder without a keystore");
154 mtx.vin.emplace_back(utxo);
155 tIns.emplace_back(scriptPubKey, value);
158 void TransactionBuilder::AddTransparentOutput(CTxDestination& to, CAmount value)
160 if (!IsValidDestination(to)) {
161 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr.");
164 CScript scriptPubKey = GetScriptForDestination(to);
165 CTxOut out(value, scriptPubKey);
166 mtx.vout.push_back(out);
169 void TransactionBuilder::SetFee(CAmount fee)
174 void TransactionBuilder::SendChangeTo(libzcash::SaplingPaymentAddress changeAddr, uint256 ovk)
176 saplingChangeAddr = std::make_pair(ovk, changeAddr);
177 sproutChangeAddr = boost::none;
178 tChangeAddr = boost::none;
181 void TransactionBuilder::SendChangeTo(libzcash::SproutPaymentAddress changeAddr)
183 sproutChangeAddr = changeAddr;
184 saplingChangeAddr = boost::none;
185 tChangeAddr = boost::none;
188 void TransactionBuilder::SendChangeTo(CTxDestination& changeAddr)
190 if (!IsValidDestination(changeAddr)) {
191 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid change address, not a valid taddr.");
194 tChangeAddr = changeAddr;
195 saplingChangeAddr = boost::none;
196 sproutChangeAddr = boost::none;
199 TransactionBuilderResult TransactionBuilder::Build()
202 // Consistency checks
206 CAmount change = mtx.valueBalance - fee;
207 for (auto jsInput : jsInputs) {
208 change += jsInput.note.value();
210 for (auto jsOutput : jsOutputs) {
211 change -= jsOutput.value;
213 for (auto tIn : tIns) {
216 for (auto tOut : mtx.vout) {
217 change -= tOut.nValue;
220 return TransactionBuilderResult("Change cannot be negative");
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);
248 return TransactionBuilderResult("Could not determine change address");
253 // Sapling spends and outputs
256 auto ctx = librustzcash_sapling_proving_ctx_init();
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());
264 librustzcash_sapling_proving_ctx_free(ctx);
265 return TransactionBuilderResult("Spend is invalid");
268 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
269 ss << spend.witness.path();
270 std::vector<unsigned char> witness(ss.begin(), ss.end());
272 SpendDescription sdesc;
273 if (!librustzcash_sapling_spend_proof(
275 spend.expsk.full_viewing_key().ak.begin(),
276 spend.expsk.nsk.begin(),
278 spend.note.r.begin(),
281 spend.anchor.begin(),
285 sdesc.zkproof.data())) {
286 librustzcash_sapling_proving_ctx_free(ctx);
287 return TransactionBuilderResult("Spend proof failed");
290 sdesc.anchor = spend.anchor;
291 sdesc.nullifier = *nf;
292 mtx.vShieldedSpend.push_back(sdesc);
295 // Create Sapling OutputDescriptions
296 for (auto output : outputs) {
297 auto cm = output.note.cm();
299 librustzcash_sapling_proving_ctx_free(ctx);
300 return TransactionBuilderResult("Output is invalid");
303 libzcash::SaplingNotePlaintext notePlaintext(output.note, output.memo);
305 auto res = notePlaintext.encrypt(output.note.pk_d);
307 librustzcash_sapling_proving_ctx_free(ctx);
308 return TransactionBuilderResult("Failed to encrypt note");
310 auto enc = res.get();
311 auto encryptor = enc.second;
313 OutputDescription odesc;
314 if (!librustzcash_sapling_output_proof(
316 encryptor.get_esk().begin(),
317 output.note.d.data(),
318 output.note.pk_d.begin(),
319 output.note.r.begin(),
322 odesc.zkproof.begin())) {
323 librustzcash_sapling_proving_ctx_free(ctx);
324 return TransactionBuilderResult("Output proof failed");
328 odesc.ephemeralKey = encryptor.get_epk();
329 odesc.encCiphertext = enc.first;
331 libzcash::SaplingOutgoingPlaintext outPlaintext(output.note.pk_d, encryptor.get_esk());
332 odesc.outCiphertext = outPlaintext.encrypt(
337 mtx.vShieldedOutput.push_back(odesc);
344 unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES];
345 crypto_sign_keypair(mtx.joinSplitPubKey.begin(), joinSplitPrivKey);
347 // Create Sprout JSDescriptions
348 if (!jsInputs.empty() || !jsOutputs.empty()) {
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);
364 auto consensusBranchId = CurrentEpochBranchId(nHeight, consensusParams);
366 // Empty output script.
367 uint256 dataToBeSigned;
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()));
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());
384 librustzcash_sapling_binding_sig(
387 dataToBeSigned.begin(),
388 mtx.bindingSig.data());
390 librustzcash_sapling_proving_ctx_free(ctx);
392 // Create Sprout joinSplitSig
393 if (crypto_sign_detached(
394 mtx.joinSplitSig.data(), NULL,
395 dataToBeSigned.begin(), 32,
396 joinSplitPrivKey) != 0)
398 return TransactionBuilderResult("Failed to create Sprout joinSplitSig");
401 // Sanity check Sprout joinSplitSig
402 if (crypto_sign_verify_detached(
403 mtx.joinSplitSig.data(),
404 dataToBeSigned.begin(), 32,
405 mtx.joinSplitPubKey.begin()) != 0)
407 return TransactionBuilderResult("Sprout joinSplitSig sanity check failed");
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);
421 return TransactionBuilderResult("Failed to sign transaction");
423 UpdateTransaction(mtx, nIn, sigdata);
427 return TransactionBuilderResult(CTransaction(mtx));
430 void TransactionBuilder::CreateJSDescriptions()
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);
437 std::deque<libzcash::JSOutput> jsOutputsDeque;
438 for (auto jsOutput : jsOutputs) {
439 jsOutputsDeque.push_back(jsOutput);
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;
453 for (int n = 0; n < ZC_NUM_JS_OUTPUTS && jsOutputsDeque.size() > 0; n++) {
454 vjsout[n] = jsOutputsDeque.front();
455 jsOutputsDeque.pop_front();
457 // Funds are removed from the value pool and enter the private pool
458 vpub_old += vjsout[n].value;
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);
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();
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
478 CAmount valueOut = 0;
479 for (auto jsInput : jsInputs) {
480 valueOut += jsInput.note.value();
482 for (auto jsOutput : jsOutputs) {
483 valueOut -= jsOutput.value;
485 CAmount vpubOldTarget = valueOut < 0 ? -valueOut : 0;
486 CAmount vpubNewTarget = valueOut > 0 ? valueOut : 0;
488 // Keep track of treestate within this transaction
489 boost::unordered_map<uint256, SproutMerkleTree, CCoinsKeyHasher> intermediates;
490 std::vector<uint256> previousCommitments;
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;
499 // Set vpub_old in the first joinsplit
500 if (!vpubOldProcessed) {
501 vpub_old += vpubOldTarget; // funds flowing from public pool
502 vpubOldProcessed = true;
505 CAmount jsInputValue = 0;
508 JSDescription prevJoinSplit;
510 // Keep track of previous JoinSplit and its commitments
511 if (mtx.vJoinSplit.size() > 0) {
512 prevJoinSplit = mtx.vJoinSplit.back();
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();
522 // Consume change as the first input of the JoinSplit.
525 // Update tree state with previous joinsplit
526 SproutMerkleTree tree;
528 // assert that coinsView is not null
530 // We do not check cs_coinView because we do not set this in testing
531 // assert(cs_coinsView);
533 auto it = intermediates.find(prevJoinSplit.anchor);
534 if (it != intermediates.end()) {
536 } else if (!coinsView->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) {
537 throw JSDescException("Could not find previous JoinSplit anchor");
541 assert(changeOutputIndex != -1);
542 assert(changeOutputIndex < prevJoinSplit.commitments.size());
543 boost::optional<SproutWitness> changeWitness;
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);
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)
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);
562 auto plaintext = libzcash::SproutNotePlaintext::decrypt(
564 prevJoinSplit.ciphertexts[changeOutputIndex],
565 prevJoinSplit.ephemeralKey,
567 (unsigned char)changeOutputIndex);
569 auto note = plaintext.note(changeAddress);
570 vjsin[0] = libzcash::JSInput(changeWitness.get(), note, changeKey);
572 jsInputValue += plaintext.value();
574 LogPrint("zrpcunsafe", "spending change (amount=%s)\n", FormatMoney(plaintext.value()));
576 } catch (const std::exception& e) {
577 throw JSDescException("Error decrypting output note of previous JoinSplit");
582 // Consume spendable non-change notes
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();
588 // Add history of previous commitments to witness
590 for (const uint256& commitment : previousCommitments) {
591 jsInput.witness.append(commitment);
593 if (jsAnchor != jsInput.witness.root()) {
594 throw JSDescException("Witness for spendable note does not have same anchor as change input");
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();
603 jsInputValue += jsInput.note.value();
607 // Find recipient to transfer funds to
608 libzcash::JSOutput recipient;
609 if (jsOutputsDeque.size() > 0) {
610 recipient = jsOutputsDeque.front();
611 jsOutputsDeque.pop_front();
613 // `recipient` is now either a valid recipient, or a dummy output with value = 0
617 CAmount outAmount = recipient.value;
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)));
625 outAmount += vpubNewTarget;
626 vpub_new += vpubNewTarget; // funds flowing back to public pool
627 vpubNewProcessed = true;
628 jsChange = jsInputValue - outAmount;
629 assert(jsChange >= 0);
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);
641 // reduce the amount being sent right now to the value of all inputs
642 recipient.value = jsInputValue;
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;
650 // create output for any change
652 vjsout[1] = libzcash::JSOutput(changeAddress, jsChange);
654 LogPrint("zrpcunsafe", "generating note for change (amount=%s)\n", FormatMoney(jsChange));
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);
662 changeOutputIndex = -1;
663 for (size_t i = 0; i < outputMap.size(); i++) {
664 if (outputMap[i] == 1) {
665 changeOutputIndex = i;
668 assert(changeOutputIndex != -1);
673 void TransactionBuilder::CreateJSDescription(
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)
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));
687 uint256 esk; // payment disclosure - secret
689 // Generate the proof, this can take over a minute.
690 JSDescription jsdesc = JSDescription::Randomized(
691 mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION),
694 vjsin[0].witness.root(),
701 true, //!this->testmode,
702 &esk); // parameter expects pointer to esk, so pass in address
705 auto verifier = libzcash::ProofVerifier::Strict();
706 if (!jsdesc.Verify(*sproutParams, verifier, mtx.joinSplitPubKey)) {
707 throw std::runtime_error("error verifying joinsplit");
711 mtx.vJoinSplit.push_back(jsdesc);
713 // TODO: Sprout payment disclosure