]> Git Repo - VerusCoin.git/blob - src/wallet/asyncrpcoperation_sendmany.cpp
Auto merge of #2213 - daira:2211.release-1.0.8, r=daira
[VerusCoin.git] / src / wallet / asyncrpcoperation_sendmany.cpp
1 // Copyright (c) 2016 The Zcash developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include "asyncrpcoperation_sendmany.h"
6 #include "asyncrpcqueue.h"
7 #include "amount.h"
8 #include "core_io.h"
9 #include "init.h"
10 #include "main.h"
11 #include "net.h"
12 #include "netbase.h"
13 #include "rpcserver.h"
14 #include "timedata.h"
15 #include "util.h"
16 #include "utilmoneystr.h"
17 #include "wallet.h"
18 #include "walletdb.h"
19 #include "script/interpreter.h"
20 #include "utiltime.h"
21 #include "rpcprotocol.h"
22 #include "zcash/IncrementalMerkleTree.hpp"
23 #include "sodium.h"
24 #include "miner.h"
25
26 #include <iostream>
27 #include <chrono>
28 #include <thread>
29 #include <string>
30
31 using namespace libzcash;
32
33 int find_output(UniValue obj, int n) {
34     UniValue outputMapValue = find_value(obj, "outputmap");
35     if (!outputMapValue.isArray()) {
36         throw JSONRPCError(RPC_WALLET_ERROR, "Missing outputmap for JoinSplit operation");
37     }
38
39     UniValue outputMap = outputMapValue.get_array();
40     assert(outputMap.size() == ZC_NUM_JS_OUTPUTS);
41     for (size_t i = 0; i < outputMap.size(); i++) {
42         if (outputMap[i].get_int() == n) {
43             return i;
44         }
45     }
46
47     throw std::logic_error("n is not present in outputmap");
48 }
49
50 AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
51         std::string fromAddress,
52         std::vector<SendManyRecipient> tOutputs,
53         std::vector<SendManyRecipient> zOutputs,
54         int minDepth,
55         CAmount fee,
56         UniValue contextInfo) :
57         fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo)
58 {
59     assert(fee_ >= 0);
60
61     if (minDepth < 0) {
62         throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative");
63     }
64     
65     if (fromAddress.size() == 0) {
66         throw JSONRPCError(RPC_INVALID_PARAMETER, "From address parameter missing");
67     }
68     
69     if (tOutputs.size() == 0 && zOutputs.size() == 0) {
70         throw JSONRPCError(RPC_INVALID_PARAMETER, "No recipients");
71     }
72     
73     fromtaddr_ = CBitcoinAddress(fromAddress);
74     isfromtaddr_ = fromtaddr_.IsValid();
75     isfromzaddr_ = false;
76
77     if (!isfromtaddr_) {
78         CZCPaymentAddress address(fromAddress);
79         try {
80             PaymentAddress addr = address.Get();
81
82             // We don't need to lock on the wallet as spending key related methods are thread-safe
83             SpendingKey key;
84             if (!pwalletMain->GetSpendingKey(addr, key)) {
85                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, no spending key found for zaddr");
86             }
87             
88             isfromzaddr_ = true;
89             frompaymentaddress_ = addr;
90             spendingkey_ = key;
91         } catch (const std::runtime_error& e) {
92             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("runtime error: ") + e.what());
93         }
94     }
95
96     // Log the context info i.e. the call parameters to z_sendmany
97     if (LogAcceptCategory("zrpcunsafe")) {
98         LogPrint("zrpcunsafe", "%s: z_sendmany initialized (params=%s)\n", getId(), contextInfo.write());
99     } else {
100         LogPrint("zrpc", "%s: z_sendmany initialized\n", getId());
101     }
102 }
103
104 AsyncRPCOperation_sendmany::~AsyncRPCOperation_sendmany() {
105 }
106
107 void AsyncRPCOperation_sendmany::main() {
108     if (isCancelled())
109         return;
110
111     set_state(OperationStatus::EXECUTING);
112     start_execution_clock();
113
114     bool success = false;
115
116 #ifdef ENABLE_MINING
117   #ifdef ENABLE_WALLET
118     GenerateBitcoins(false, NULL, 0);
119   #else
120     GenerateBitcoins(false, 0);
121   #endif
122 #endif
123
124     try {
125         success = main_impl();
126     } catch (const UniValue& objError) {
127         int code = find_value(objError, "code").get_int();
128         std::string message = find_value(objError, "message").get_str();
129         set_error_code(code);
130         set_error_message(message);
131     } catch (const runtime_error& e) {
132         set_error_code(-1);
133         set_error_message("runtime error: " + string(e.what()));
134     } catch (const logic_error& e) {
135         set_error_code(-1);
136         set_error_message("logic error: " + string(e.what()));
137     } catch (const exception& e) {
138         set_error_code(-1);
139         set_error_message("general exception: " + string(e.what()));
140     } catch (...) {
141         set_error_code(-2);
142         set_error_message("unknown error");
143     }
144
145 #ifdef ENABLE_MINING
146   #ifdef ENABLE_WALLET
147     GenerateBitcoins(GetBoolArg("-gen",false), pwalletMain, GetArg("-genproclimit", 1));
148   #else
149     GenerateBitcoins(GetBoolArg("-gen",false), GetArg("-genproclimit", 1));
150   #endif
151 #endif
152
153     stop_execution_clock();
154
155     if (success) {
156         set_state(OperationStatus::SUCCESS);
157     } else {
158         set_state(OperationStatus::FAILED);
159     }
160
161     std::string s = strprintf("%s: z_sendmany finished (status=%s", getId(), getStateAsString());
162     if (success) {
163         s += strprintf(", txid=%s)\n", tx_.GetHash().ToString());
164     } else {
165         s += strprintf(", error=%s)\n", getErrorMessage());
166     }
167     LogPrintf("%s",s);
168 }
169
170 // Notes:
171 // 1. #1159 Currently there is no limit set on the number of joinsplits, so size of tx could be invalid.
172 // 2. #1360 Note selection is not optimal
173 // 3. #1277 Spendable notes are not locked, so an operation running in parallel could also try to use them
174 bool AsyncRPCOperation_sendmany::main_impl() {
175
176     assert(isfromtaddr_ != isfromzaddr_);
177
178     bool isSingleZaddrOutput = (t_outputs_.size()==0 && z_outputs_.size()==1);
179     bool isMultipleZaddrOutput = (t_outputs_.size()==0 && z_outputs_.size()>=1);
180     bool isPureTaddrOnlyTx = (isfromtaddr_ && z_outputs_.size() == 0);
181     CAmount minersFee = fee_;
182
183     // When spending coinbase utxos, you can only specify a single zaddr as the change must go somewhere
184     // and if there are multiple zaddrs, we don't know where to send it.
185     if (isfromtaddr_) {
186         if (isSingleZaddrOutput) {
187             bool b = find_utxos(true);
188             if (!b) {
189                 throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no UTXOs found for taddr from address.");
190             }
191         } else {
192             bool b = find_utxos(false);
193             if (!b) {
194                 if (isMultipleZaddrOutput) {
195                     throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend. Coinbase UTXOs can only be sent to a single zaddr recipient.");
196                 } else {
197                     throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Could not find any non-coinbase UTXOs to spend.");
198                 }
199             }
200         }        
201     }
202     
203     if (isfromzaddr_ && !find_unspent_notes()) {
204         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address.");
205     }
206     
207     CAmount t_inputs_total = 0;
208     for (SendManyInputUTXO & t : t_inputs_) {
209         t_inputs_total += std::get<2>(t);
210     }
211
212     CAmount z_inputs_total = 0;
213     for (SendManyInputJSOP & t : z_inputs_) {
214         z_inputs_total += std::get<2>(t);
215     }
216
217     CAmount t_outputs_total = 0;
218     for (SendManyRecipient & t : t_outputs_) {
219         t_outputs_total += std::get<1>(t);
220     }
221
222     CAmount z_outputs_total = 0;
223     for (SendManyRecipient & t : z_outputs_) {
224         z_outputs_total += std::get<1>(t);
225     }
226
227     CAmount sendAmount = z_outputs_total + t_outputs_total;
228     CAmount targetAmount = sendAmount + minersFee;
229
230     assert(!isfromtaddr_ || z_inputs_total == 0);
231     assert(!isfromzaddr_ || t_inputs_total == 0);
232
233     if (isfromtaddr_ && (t_inputs_total < targetAmount)) {
234         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
235             strprintf("Insufficient transparent funds, have %s, need %s",
236             FormatMoney(t_inputs_total), FormatMoney(targetAmount)));
237     }
238     
239     if (isfromzaddr_ && (z_inputs_total < targetAmount)) {
240         throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
241             strprintf("Insufficient protected funds, have %s, need %s",
242             FormatMoney(z_inputs_total), FormatMoney(targetAmount)));
243     }
244
245     // If from address is a taddr, select UTXOs to spend
246     CAmount selectedUTXOAmount = 0;
247     bool selectedUTXOCoinbase = false;
248     if (isfromtaddr_) {
249         // Get dust threshold
250         CKey secret;
251         secret.MakeNewKey(true);
252         CScript scriptPubKey = GetScriptForDestination(secret.GetPubKey().GetID());
253         CTxOut out(CAmount(1), scriptPubKey);
254         CAmount dustThreshold = out.GetDustThreshold(minRelayTxFee);
255         CAmount dustChange = -1;
256
257         std::vector<SendManyInputUTXO> selectedTInputs;
258         for (SendManyInputUTXO & t : t_inputs_) {
259             bool b = std::get<3>(t);
260             if (b) {
261                 selectedUTXOCoinbase = true;
262             }
263             selectedUTXOAmount += std::get<2>(t);
264             selectedTInputs.push_back(t);
265             if (selectedUTXOAmount >= targetAmount) {
266                 // Select another utxo if there is change less than the dust threshold.
267                 dustChange = selectedUTXOAmount - targetAmount;
268                 if (dustChange == 0 || dustChange >= dustThreshold) {
269                     break;
270                 }
271             }
272         }
273
274         // If there is transparent change, is it valid or is it dust?
275         if (dustChange < dustThreshold && dustChange != 0) {
276             throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS,
277                 strprintf("Insufficient transparent funds, have %s, need %s more to avoid creating invalid change output %s (dust threshold is %s)",
278                 FormatMoney(t_inputs_total), FormatMoney(dustThreshold - dustChange), FormatMoney(dustChange), FormatMoney(dustThreshold)));
279         }
280
281         t_inputs_ = selectedTInputs;
282         t_inputs_total = selectedUTXOAmount;
283
284         // update the transaction with these inputs
285         CMutableTransaction rawTx(tx_);
286         for (SendManyInputUTXO & t : t_inputs_) {
287             uint256 txid = std::get<0>(t);
288             int vout = std::get<1>(t);
289             CAmount amount = std::get<2>(t);
290             CTxIn in(COutPoint(txid, vout));
291             rawTx.vin.push_back(in);
292         }
293         tx_ = CTransaction(rawTx);
294     }
295
296     LogPrint((isfromtaddr_) ? "zrpc" : "zrpcunsafe", "%s: spending %s to send %s with fee %s\n",
297             getId(), FormatMoney(targetAmount), FormatMoney(sendAmount), FormatMoney(minersFee));
298     LogPrint("zrpc", "%s: transparent input: %s (to choose from)\n", getId(), FormatMoney(t_inputs_total));
299     LogPrint("zrpcunsafe", "%s: private input: %s (to choose from)\n", getId(), FormatMoney(z_inputs_total));
300     LogPrint("zrpc", "%s: transparent output: %s\n", getId(), FormatMoney(t_outputs_total));
301     LogPrint("zrpcunsafe", "%s: private output: %s\n", getId(), FormatMoney(z_outputs_total));
302     LogPrint("zrpc", "%s: fee: %s\n", getId(), FormatMoney(minersFee));
303
304     /**
305      * SCENARIO #1
306      * 
307      * taddr -> taddrs
308      * 
309      * There are no zaddrs or joinsplits involved.
310      */
311     if (isPureTaddrOnlyTx) {
312         add_taddr_outputs_to_tx();
313         
314         CAmount funds = selectedUTXOAmount;
315         CAmount fundsSpent = t_outputs_total + minersFee;
316         CAmount change = funds - fundsSpent;
317         
318         if (change > 0) {
319             add_taddr_change_output_to_tx(change);
320
321             LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
322                     getId(),
323                     FormatMoney(change)
324                     );
325         }
326         
327         UniValue obj(UniValue::VOBJ);
328         obj.push_back(Pair("rawtxn", EncodeHexTx(tx_)));
329         sign_send_raw_transaction(obj);
330         return true;
331     }
332     /**
333      * END SCENARIO #1
334      */
335
336     
337     // Prepare raw transaction to handle JoinSplits
338     CMutableTransaction mtx(tx_);
339     mtx.nVersion = 2;
340     crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_);
341     mtx.joinSplitPubKey = joinSplitPubKey_;
342     tx_ = CTransaction(mtx);
343
344     // Copy zinputs and zoutputs to more flexible containers
345     std::deque<SendManyInputJSOP> zInputsDeque;
346     for (auto o : z_inputs_) {
347         zInputsDeque.push_back(o);
348     }
349     std::deque<SendManyRecipient> zOutputsDeque;
350     for (auto o : z_outputs_) {
351         zOutputsDeque.push_back(o);
352     }
353
354     // When spending notes, take a snapshot of note witnesses and anchors as the treestate will
355     // change upon arrival of new blocks which contain joinsplit transactions.  This is likely
356     // to happen as creating a chained joinsplit transaction can take longer than the block interval.
357     if (z_inputs_.size() > 0) {
358         LOCK2(cs_main, pwalletMain->cs_wallet);
359         for (auto t : z_inputs_) {
360             JSOutPoint jso = std::get<0>(t);
361             std::vector<JSOutPoint> vOutPoints = { jso };
362             uint256 inputAnchor;
363             std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
364             pwalletMain->GetNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor);
365             jsopWitnessAnchorMap[ jso.ToString() ] = WitnessAnchorData{ vInputWitnesses[0], inputAnchor };
366         }
367     }
368
369
370     /**
371      * SCENARIO #2
372      * 
373      * taddr -> taddrs
374      *       -> zaddrs
375      * 
376      * Note: Consensus rule states that coinbase utxos can only be sent to a zaddr.
377      *       Local wallet rule does not allow any change when sending coinbase utxos
378      *       since there is currently no way to specify a change address and we don't
379      *       want users accidentally sending excess funds to a recipient.
380      */
381     if (isfromtaddr_) {
382         add_taddr_outputs_to_tx();
383         
384         CAmount funds = selectedUTXOAmount;
385         CAmount fundsSpent = t_outputs_total + minersFee + z_outputs_total;
386         CAmount change = funds - fundsSpent;
387         
388         if (change > 0) {
389             if (selectedUTXOCoinbase) {
390                 assert(isSingleZaddrOutput);
391                 throw JSONRPCError(RPC_WALLET_ERROR, strprintf(
392                     "Change %s not allowed. When protecting coinbase funds, the wallet does not "
393                     "allow any change as there is currently no way to specify a change address "
394                     "in z_sendmany.", FormatMoney(change)));
395             } else {
396                 add_taddr_change_output_to_tx(change);
397                 LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n",
398                         getId(),
399                         FormatMoney(change)
400                         );
401             }
402         }
403
404         // Create joinsplits, where each output represents a zaddr recipient.
405         UniValue obj(UniValue::VOBJ);
406         while (zOutputsDeque.size() > 0) {
407             AsyncJoinSplitInfo info;
408             info.vpub_old = 0;
409             info.vpub_new = 0;
410             int n = 0;
411             while (n++<ZC_NUM_JS_OUTPUTS && zOutputsDeque.size() > 0) {
412                 SendManyRecipient smr = zOutputsDeque.front();
413                 std::string address = std::get<0>(smr);
414                 CAmount value = std::get<1>(smr);
415                 std::string hexMemo = std::get<2>(smr);
416                 zOutputsDeque.pop_front();
417
418                 PaymentAddress pa = CZCPaymentAddress(address).Get();
419                 JSOutput jso = JSOutput(pa, value);
420                 if (hexMemo.size() > 0) {
421                     jso.memo = get_memo_from_hex_string(hexMemo);
422                 }
423                 info.vjsout.push_back(jso);
424                 
425                 // Funds are removed from the value pool and enter the private pool
426                 info.vpub_old += value;
427             }
428             obj = perform_joinsplit(info);
429         }
430         sign_send_raw_transaction(obj);
431         return true;
432     }
433     /**
434      * END SCENARIO #2
435      */   
436  
437     
438     
439     /**
440      * SCENARIO #3
441      * 
442      * zaddr -> taddrs
443      *       -> zaddrs
444      * 
445      * Processing order:
446      * Part 1: taddrs and miners fee
447      * Part 2: zaddrs 
448      */
449     
450     /**
451      * SCENARIO #3
452      * Part 1: Add to the transparent value pool.
453      */
454     UniValue obj(UniValue::VOBJ);
455     CAmount jsChange = 0;   // this is updated after each joinsplit
456     int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0
457     bool minersFeeProcessed = false;
458
459     if (t_outputs_total > 0) {
460         add_taddr_outputs_to_tx();
461         CAmount taddrTargetAmount = t_outputs_total + minersFee;
462         minersFeeProcessed = true;
463         while (zInputsDeque.size() > 0 && taddrTargetAmount > 0) {
464             AsyncJoinSplitInfo info;
465             info.vpub_old = 0;
466             info.vpub_new = 0;
467             std::vector<JSOutPoint> outPoints;
468             int n = 0;
469             while (n++ < ZC_NUM_JS_INPUTS && taddrTargetAmount > 0) {
470                 SendManyInputJSOP o = zInputsDeque.front();
471                 JSOutPoint outPoint = std::get<0>(o);
472                 Note note = std::get<1>(o);
473                 CAmount noteFunds = std::get<2>(o);
474                 zInputsDeque.pop_front();
475
476                 info.notes.push_back(note);
477                 outPoints.push_back(outPoint);
478
479                 int wtxHeight = -1;
480                 int wtxDepth = -1;
481                 {
482                     LOCK2(cs_main, pwalletMain->cs_wallet);
483                     const CWalletTx& wtx = pwalletMain->mapWallet[outPoint.hash];
484                     wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
485                     wtxDepth = wtx.GetDepthInMainChain();
486                 }
487                 LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
488                         getId(),
489                         outPoint.hash.ToString().substr(0, 10),
490                         outPoint.js,
491                         int(outPoint.n), // uint8_t
492                         FormatMoney(noteFunds),
493                         wtxHeight,
494                         wtxDepth
495                         );
496
497                 
498                 // Put value back into the value pool
499                 if (noteFunds >= taddrTargetAmount) {
500                     jsChange = noteFunds - taddrTargetAmount;
501                     info.vpub_new += taddrTargetAmount;
502                 } else {
503                     info.vpub_new += noteFunds;
504                 }
505
506                 taddrTargetAmount -= noteFunds;
507                 if (taddrTargetAmount <= 0) {
508                     break;
509                 }
510             }
511
512             if (jsChange > 0) {
513                 info.vjsout.push_back(JSOutput());
514                 info.vjsout.push_back(JSOutput(frompaymentaddress_, jsChange));
515                 
516                 LogPrint("zrpcunsafe", "%s: generating note for change (amount=%s)\n",
517                         getId(),
518                         FormatMoney(jsChange)
519                         );
520             }
521
522             obj = perform_joinsplit(info, outPoints);
523
524             if (jsChange > 0) {
525                 changeOutputIndex = find_output(obj, 1);
526             }
527         }
528     }
529
530
531     /**
532      * SCENARIO #3
533      * Part 2: Send to zaddrs by chaining JoinSplits together and immediately consuming any change
534      */            
535     if (z_outputs_total>0) {
536
537         // Keep track of treestate within this transaction 
538         boost::unordered_map<uint256, ZCIncrementalMerkleTree, CCoinsKeyHasher> intermediates;
539         std::vector<uint256> previousCommitments;
540         
541         while (zOutputsDeque.size() > 0) {
542             AsyncJoinSplitInfo info;
543             info.vpub_old = 0;
544             info.vpub_new = 0;
545
546             CAmount jsInputValue = 0;
547             uint256 jsAnchor;
548             std::vector<boost::optional<ZCIncrementalWitness>> witnesses;
549
550             JSDescription prevJoinSplit;
551
552             // Keep track of previous JoinSplit and its commitments
553             if (tx_.vjoinsplit.size() > 0) {
554                 prevJoinSplit = tx_.vjoinsplit.back();
555             }
556             
557             // If there is no change, the chain has terminated so we can reset the tracked treestate.
558             if (jsChange==0 && tx_.vjoinsplit.size() > 0) {
559                 intermediates.clear();
560                 previousCommitments.clear();
561             }
562             
563             //
564             // Consume change as the first input of the JoinSplit.
565             //
566             if (jsChange > 0) {
567                 LOCK2(cs_main, pwalletMain->cs_wallet);
568
569                 // Update tree state with previous joinsplit                
570                 ZCIncrementalMerkleTree tree;
571                 auto it = intermediates.find(prevJoinSplit.anchor);
572                 if (it != intermediates.end()) {
573                     tree = it->second;
574                 } else if (!pcoinsTip->GetAnchorAt(prevJoinSplit.anchor, tree)) {
575                     throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor");
576                 }
577                 
578                 assert(changeOutputIndex != -1);
579                 boost::optional<ZCIncrementalWitness> changeWitness;
580                 int n = 0;
581                 for (const uint256& commitment : prevJoinSplit.commitments) {
582                     tree.append(commitment);
583                     previousCommitments.push_back(commitment);
584                     if (!changeWitness && changeOutputIndex == n++) {
585                         changeWitness = tree.witness();
586                     } else if (changeWitness) {
587                         changeWitness.get().append(commitment);
588                     }
589                 }
590                 if (changeWitness) {
591                         witnesses.push_back(changeWitness);
592                 }
593                 jsAnchor = tree.root();
594                 intermediates.insert(std::make_pair(tree.root(), tree));    // chained js are interstitial (found in between block boundaries)
595
596                 // Decrypt the change note's ciphertext to retrieve some data we need
597                 ZCNoteDecryption decryptor(spendingkey_.viewing_key());
598                 auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey);
599                 try {
600                     NotePlaintext plaintext = NotePlaintext::decrypt(
601                             decryptor,
602                             prevJoinSplit.ciphertexts[changeOutputIndex],
603                             prevJoinSplit.ephemeralKey,
604                             hSig,
605                             (unsigned char) changeOutputIndex);
606
607                     Note note = plaintext.note(frompaymentaddress_);
608                     info.notes.push_back(note);
609                     
610                     jsInputValue += plaintext.value;
611                     
612                     LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n",
613                         getId(),
614                         FormatMoney(plaintext.value)
615                         );
616
617                 } catch (const std::exception& e) {
618                     throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what()));
619                 }
620             }
621
622             
623             //
624             // Consume spendable non-change notes
625             //
626             std::vector<Note> vInputNotes;
627             std::vector<JSOutPoint> vOutPoints;
628             std::vector<boost::optional<ZCIncrementalWitness>> vInputWitnesses;
629             uint256 inputAnchor;
630             int numInputsNeeded = (jsChange>0) ? 1 : 0;
631             while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) {
632                 SendManyInputJSOP t = zInputsDeque.front();
633                 JSOutPoint jso = std::get<0>(t);
634                 Note note = std::get<1>(t);
635                 CAmount noteFunds = std::get<2>(t);
636                 zInputsDeque.pop_front();
637
638                 WitnessAnchorData wad = jsopWitnessAnchorMap[ jso.ToString() ];
639                 vInputWitnesses.push_back(wad.witness);
640                 if (inputAnchor.IsNull()) {
641                     inputAnchor = wad.anchor;
642                 } else if (inputAnchor != wad.anchor) {
643                     throw JSONRPCError(RPC_WALLET_ERROR, "Selected input notes do not share the same anchor");
644                 }
645
646                 vOutPoints.push_back(jso);
647                 vInputNotes.push_back(note);
648                 
649                 jsInputValue += noteFunds;
650                 
651                 int wtxHeight = -1;
652                 int wtxDepth = -1;
653                 {
654                     LOCK2(cs_main, pwalletMain->cs_wallet);
655                     const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash];
656                     wtxHeight = mapBlockIndex[wtx.hashBlock]->nHeight;
657                     wtxDepth = wtx.GetDepthInMainChain();
658                 }
659                 LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n",
660                         getId(),
661                         jso.hash.ToString().substr(0, 10),
662                         jso.js,
663                         int(jso.n), // uint8_t
664                         FormatMoney(noteFunds),
665                         wtxHeight,
666                         wtxDepth
667                         );
668             }
669                         
670             // Add history of previous commitments to witness 
671             if (vInputNotes.size() > 0) {
672
673                 if (vInputWitnesses.size()==0) {
674                     throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment");
675                 }
676                 
677                 for (auto & optionalWitness : vInputWitnesses) {
678                     if (!optionalWitness) {
679                         throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null");
680                     }
681                     ZCIncrementalWitness w = *optionalWitness; // could use .get();
682                     if (jsChange > 0) {
683                         for (const uint256& commitment : previousCommitments) {
684                             w.append(commitment);
685                         }
686                         if (jsAnchor != w.root()) {
687                             throw JSONRPCError(RPC_WALLET_ERROR, "Witness for spendable note does not have same anchor as change input");
688                         }
689                     }
690                     witnesses.push_back(w);
691                 }
692
693                 // The jsAnchor is null if this JoinSplit is at the start of a new chain
694                 if (jsAnchor.IsNull()) {                   
695                     jsAnchor = inputAnchor;                   
696                 }
697
698                 // Add spendable notes as inputs
699                 std::copy(vInputNotes.begin(), vInputNotes.end(), std::back_inserter(info.notes));
700             }
701
702             
703             //
704             // Find recipient to transfer funds to
705             //            
706             SendManyRecipient smr = zOutputsDeque.front();
707             std::string address = std::get<0>(smr);
708             CAmount value = std::get<1>(smr);
709             std::string hexMemo = std::get<2>(smr);
710             zOutputsDeque.pop_front();
711
712             // Will we have any change?  Has the miners fee been processed yet?
713             jsChange = 0;
714             CAmount outAmount = value;
715             if (!minersFeeProcessed) {
716                 if (jsInputValue < minersFee) {
717                     throw JSONRPCError(RPC_WALLET_ERROR, "Not enough funds to pay miners fee");
718                 }
719                 outAmount += minersFee;
720             }
721             
722             if (jsInputValue > outAmount) {
723                 jsChange = jsInputValue - outAmount;
724             } else if (outAmount > jsInputValue) {
725                 // Any amount due is owed to the recipient.  Let the miners fee get paid first.
726                 CAmount due = outAmount - jsInputValue;
727                 SendManyRecipient r = SendManyRecipient(address, due, hexMemo);
728                 zOutputsDeque.push_front(r);
729
730                 // reduce the amount being sent right now to the value of all inputs
731                 value = jsInputValue;
732                 if (!minersFeeProcessed) {
733                     value -= minersFee;
734                 }
735             }
736             
737             if (!minersFeeProcessed) {
738                 minersFeeProcessed = true;
739                 info.vpub_new += minersFee; // funds flowing back to public pool
740             }
741             
742             // create output for recipient
743             PaymentAddress pa = CZCPaymentAddress(address).Get();
744             JSOutput jso = JSOutput(pa, value);
745             if (hexMemo.size() > 0) {
746                 jso.memo = get_memo_from_hex_string(hexMemo);
747             }
748             info.vjsout.push_back(jso);
749                         
750             // create output for any change
751             if (jsChange>0) {
752                 info.vjsout.push_back(JSOutput(frompaymentaddress_, jsChange));
753
754                 LogPrint("zrpcunsafe", "%s: generating note for change (amount=%s)\n",
755                         getId(),
756                         FormatMoney(jsChange)
757                         );
758             }
759
760             obj = perform_joinsplit(info, witnesses, jsAnchor);
761
762             if (jsChange > 0) {
763                 changeOutputIndex = find_output(obj, 1);
764             }
765         }
766     }
767
768     sign_send_raw_transaction(obj);
769     return true;
770 }
771
772
773 /**
774  * Sign and send a raw transaction.
775  * Raw transaction as hex string should be in object field "rawtxn"
776  */
777 void AsyncRPCOperation_sendmany::sign_send_raw_transaction(UniValue obj)
778 {   
779     // Sign the raw transaction
780     UniValue rawtxnValue = find_value(obj, "rawtxn");
781     if (rawtxnValue.isNull()) {
782         throw JSONRPCError(RPC_WALLET_ERROR, "Missing hex data for raw transaction");
783     }
784     std::string rawtxn = rawtxnValue.get_str();
785
786     UniValue params = UniValue(UniValue::VARR);
787     params.push_back(rawtxn);
788     UniValue signResultValue = signrawtransaction(params, false);
789     UniValue signResultObject = signResultValue.get_obj();
790     UniValue completeValue = find_value(signResultObject, "complete");
791     bool complete = completeValue.get_bool();
792     if (!complete) {
793         // TODO: #1366 Maybe get "errors" and print array vErrors into a string
794         throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Failed to sign transaction");
795     }
796
797     UniValue hexValue = find_value(signResultObject, "hex");
798     if (hexValue.isNull()) {
799         throw JSONRPCError(RPC_WALLET_ERROR, "Missing hex data for signed transaction");
800     }
801     std::string signedtxn = hexValue.get_str();
802
803     // Send the signed transaction
804     if (!testmode) {
805         params.clear();
806         params.setArray();
807         params.push_back(signedtxn);
808         UniValue sendResultValue = sendrawtransaction(params, false);
809         if (sendResultValue.isNull()) {
810             throw JSONRPCError(RPC_WALLET_ERROR, "Send raw transaction did not return an error or a txid.");
811         }
812
813         std::string txid = sendResultValue.get_str();
814
815         UniValue o(UniValue::VOBJ);
816         o.push_back(Pair("txid", txid));
817         set_result(o);
818     } else {
819         // Test mode does not send the transaction to the network.
820
821         CDataStream stream(ParseHex(signedtxn), SER_NETWORK, PROTOCOL_VERSION);
822         CTransaction tx;
823         stream >> tx;
824
825         UniValue o(UniValue::VOBJ);
826         o.push_back(Pair("test", 1));
827         o.push_back(Pair("txid", tx.GetHash().ToString()));
828         o.push_back(Pair("hex", signedtxn));
829         set_result(o);
830     }
831
832     // Keep the signed transaction so we can hash to the same txid
833     CDataStream stream(ParseHex(signedtxn), SER_NETWORK, PROTOCOL_VERSION);
834     CTransaction tx;
835     stream >> tx;
836     tx_ = tx;
837 }
838
839
840 bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
841     set<CBitcoinAddress> setAddress = {fromtaddr_};
842     vector<COutput> vecOutputs;
843
844     LOCK2(cs_main, pwalletMain->cs_wallet);
845
846     pwalletMain->AvailableCoins(vecOutputs, false, NULL, true, fAcceptCoinbase);
847
848     BOOST_FOREACH(const COutput& out, vecOutputs) {
849         if (out.nDepth < mindepth_) {
850             continue;
851         }
852
853         if (setAddress.size()) {
854             CTxDestination address;
855             if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
856                 continue;
857             }
858
859             if (!setAddress.count(address)) {
860                 continue;
861             }
862         }
863
864         // By default we ignore coinbase outputs
865         bool isCoinbase = out.tx->IsCoinBase();
866         if (isCoinbase && fAcceptCoinbase==false) {
867             continue;
868         }
869         
870         CAmount nValue = out.tx->vout[out.i].nValue;
871         SendManyInputUTXO utxo(out.tx->GetHash(), out.i, nValue, isCoinbase);
872         t_inputs_.push_back(utxo);
873     }
874
875     // sort in ascending order, so smaller utxos appear first
876     std::sort(t_inputs_.begin(), t_inputs_.end(), [](SendManyInputUTXO i, SendManyInputUTXO j) -> bool {
877         return ( std::get<2>(i) < std::get<2>(j));
878     });
879
880     return t_inputs_.size() > 0;
881 }
882
883
884 bool AsyncRPCOperation_sendmany::find_unspent_notes() {
885     std::vector<CNotePlaintextEntry> entries;
886     {
887         LOCK2(cs_main, pwalletMain->cs_wallet);
888         pwalletMain->GetFilteredNotes(entries, fromaddress_, mindepth_);
889     }
890
891     for (CNotePlaintextEntry & entry : entries) {
892         z_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(frompaymentaddress_), CAmount(entry.plaintext.value)));
893         std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end());
894         LogPrint("zrpcunsafe", "%s: found unspent note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n",
895             getId(),
896             entry.jsop.hash.ToString().substr(0, 10),
897             entry.jsop.js,
898             int(entry.jsop.n),  // uint8_t
899             FormatMoney(entry.plaintext.value),
900             HexStr(data).substr(0, 10)
901             );
902     }
903     
904     if (z_inputs_.size() == 0) {
905         return false;
906     }
907
908     // sort in descending order, so big notes appear first
909     std::sort(z_inputs_.begin(), z_inputs_.end(), [](SendManyInputJSOP i, SendManyInputJSOP j) -> bool {
910         return ( std::get<2>(i) > std::get<2>(j));
911     });
912
913     return true;
914 }
915
916 UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info) {
917     std::vector<boost::optional < ZCIncrementalWitness>> witnesses;
918     uint256 anchor;
919     {
920         LOCK2(cs_main, pwalletMain->cs_wallet);
921         anchor = pcoinsTip->GetBestAnchor();    // As there are no inputs, ask the wallet for the best anchor
922     }
923     return perform_joinsplit(info, witnesses, anchor);
924 }
925
926
927 UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info, std::vector<JSOutPoint> & outPoints) {
928     std::vector<boost::optional < ZCIncrementalWitness>> witnesses;
929     uint256 anchor;
930     {
931         LOCK(cs_main);
932         pwalletMain->GetNoteWitnesses(outPoints, witnesses, anchor);
933     }
934     return perform_joinsplit(info, witnesses, anchor);
935 }
936
937 UniValue AsyncRPCOperation_sendmany::perform_joinsplit(
938         AsyncJoinSplitInfo & info,
939         std::vector<boost::optional < ZCIncrementalWitness>> witnesses,
940         uint256 anchor)
941 {
942     if (anchor.IsNull()) {
943         throw std::runtime_error("anchor is null");
944     }
945
946     if (!(witnesses.size() == info.notes.size())) {
947         throw runtime_error("number of notes and witnesses do not match");
948     }
949
950     for (size_t i = 0; i < witnesses.size(); i++) {
951         if (!witnesses[i]) {
952             throw runtime_error("joinsplit input could not be found in tree");
953         }
954         info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], spendingkey_));
955     }
956
957     // Make sure there are two inputs and two outputs
958     while (info.vjsin.size() < ZC_NUM_JS_INPUTS) {
959         info.vjsin.push_back(JSInput());
960     }
961
962     while (info.vjsout.size() < ZC_NUM_JS_OUTPUTS) {
963         info.vjsout.push_back(JSOutput());
964     }
965
966     if (info.vjsout.size() != ZC_NUM_JS_INPUTS || info.vjsin.size() != ZC_NUM_JS_OUTPUTS) {
967         throw runtime_error("unsupported joinsplit input/output counts");
968     }
969
970     CMutableTransaction mtx(tx_);
971
972     LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n",
973             getId(),
974             tx_.vjoinsplit.size(),
975             FormatMoney(info.vpub_old), FormatMoney(info.vpub_new),
976             FormatMoney(info.vjsin[0].note.value), FormatMoney(info.vjsin[1].note.value),
977             FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value)
978             );
979
980     // Generate the proof, this can take over a minute.
981     boost::array<libzcash::JSInput, ZC_NUM_JS_INPUTS> inputs
982             {info.vjsin[0], info.vjsin[1]};
983     boost::array<libzcash::JSOutput, ZC_NUM_JS_OUTPUTS> outputs
984             {info.vjsout[0], info.vjsout[1]};
985     boost::array<size_t, ZC_NUM_JS_INPUTS> inputMap;
986     boost::array<size_t, ZC_NUM_JS_OUTPUTS> outputMap;
987     JSDescription jsdesc = JSDescription::Randomized(
988             *pzcashParams,
989             joinSplitPubKey_,
990             anchor,
991             inputs,
992             outputs,
993             inputMap,
994             outputMap,
995             info.vpub_old,
996             info.vpub_new,
997             !this->testmode);
998
999     {
1000         auto verifier = libzcash::ProofVerifier::Strict();
1001         if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) {
1002             throw std::runtime_error("error verifying joinsplit");
1003         }
1004     }
1005
1006     mtx.vjoinsplit.push_back(jsdesc);
1007
1008     // Empty output script.
1009     CScript scriptCode;
1010     CTransaction signTx(mtx);
1011     uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL);
1012
1013     // Add the signature
1014     if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL,
1015             dataToBeSigned.begin(), 32,
1016             joinSplitPrivKey_
1017             ) == 0))
1018     {
1019         throw std::runtime_error("crypto_sign_detached failed");
1020     }
1021
1022     // Sanity check
1023     if (!(crypto_sign_verify_detached(&mtx.joinSplitSig[0],
1024             dataToBeSigned.begin(), 32,
1025             mtx.joinSplitPubKey.begin()
1026             ) == 0))
1027     {
1028         throw std::runtime_error("crypto_sign_verify_detached failed");
1029     }
1030
1031     CTransaction rawTx(mtx);
1032     tx_ = rawTx;
1033
1034     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
1035     ss << rawTx;
1036
1037     std::string encryptedNote1;
1038     std::string encryptedNote2;
1039     {
1040         CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
1041         ss2 << ((unsigned char) 0x00);
1042         ss2 << jsdesc.ephemeralKey;
1043         ss2 << jsdesc.ciphertexts[0];
1044         ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_);
1045
1046         encryptedNote1 = HexStr(ss2.begin(), ss2.end());
1047     }
1048     {
1049         CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION);
1050         ss2 << ((unsigned char) 0x01);
1051         ss2 << jsdesc.ephemeralKey;
1052         ss2 << jsdesc.ciphertexts[1];
1053         ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_);
1054
1055         encryptedNote2 = HexStr(ss2.begin(), ss2.end());
1056     }
1057
1058     UniValue arrInputMap(UniValue::VARR);
1059     UniValue arrOutputMap(UniValue::VARR);
1060     for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) {
1061         arrInputMap.push_back(inputMap[i]);
1062     }
1063     for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) {
1064         arrOutputMap.push_back(outputMap[i]);
1065     }
1066
1067     UniValue obj(UniValue::VOBJ);
1068     obj.push_back(Pair("encryptednote1", encryptedNote1));
1069     obj.push_back(Pair("encryptednote2", encryptedNote2));
1070     obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end())));
1071     obj.push_back(Pair("inputmap", arrInputMap));
1072     obj.push_back(Pair("outputmap", arrOutputMap));
1073     return obj;
1074 }
1075
1076 void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() {
1077
1078     CMutableTransaction rawTx(tx_);
1079
1080     for (SendManyRecipient & r : t_outputs_) {
1081         std::string outputAddress = std::get<0>(r);
1082         CAmount nAmount = std::get<1>(r);
1083
1084         CBitcoinAddress address(outputAddress);
1085         if (!address.IsValid()) {
1086             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid output address, not a valid taddr.");
1087         }
1088
1089         CScript scriptPubKey = GetScriptForDestination(address.Get());
1090
1091         CTxOut out(nAmount, scriptPubKey);
1092         rawTx.vout.push_back(out);
1093     }
1094
1095     tx_ = CTransaction(rawTx);
1096 }
1097
1098 void AsyncRPCOperation_sendmany::add_taddr_change_output_to_tx(CAmount amount) {
1099
1100     LOCK2(cs_main, pwalletMain->cs_wallet);
1101
1102     EnsureWalletIsUnlocked();
1103     CReserveKey keyChange(pwalletMain);
1104     CPubKey vchPubKey;
1105     bool ret = keyChange.GetReservedKey(vchPubKey);
1106     if (!ret) {
1107         throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Could not generate a taddr to use as a change address"); // should never fail, as we just unlocked
1108     }
1109     CScript scriptPubKey = GetScriptForDestination(vchPubKey.GetID());
1110     CTxOut out(amount, scriptPubKey);
1111
1112     CMutableTransaction rawTx(tx_);
1113     rawTx.vout.push_back(out);
1114     tx_ = CTransaction(rawTx);
1115 }
1116
1117 boost::array<unsigned char, ZC_MEMO_SIZE> AsyncRPCOperation_sendmany::get_memo_from_hex_string(std::string s) {
1118     boost::array<unsigned char, ZC_MEMO_SIZE> memo = {{0x00}};
1119     
1120     std::vector<unsigned char> rawMemo = ParseHex(s.c_str());
1121
1122     // If ParseHex comes across a non-hex char, it will stop but still return results so far.
1123     size_t slen = s.length();
1124     if (slen % 2 !=0 || (slen>0 && rawMemo.size()!=slen/2)) {
1125         throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo must be in hexadecimal format");
1126     }
1127     
1128     if (rawMemo.size() > ZC_MEMO_SIZE) {
1129         throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Memo size of %d is too big, maximum allowed is %d", rawMemo.size(), ZC_MEMO_SIZE));
1130     }
1131     
1132     // copy vector into boost array
1133     int lenMemo = rawMemo.size();
1134     for (int i = 0; i < ZC_MEMO_SIZE && i < lenMemo; i++) {
1135         memo[i] = rawMemo[i];
1136     }
1137     return memo;
1138 }
1139
1140 /**
1141  * Override getStatus() to append the operation's input parameters to the default status object.
1142  */
1143 UniValue AsyncRPCOperation_sendmany::getStatus() const {
1144     UniValue v = AsyncRPCOperation::getStatus();
1145     if (contextinfo_.isNull()) {
1146         return v;
1147     }
1148
1149     UniValue obj = v.get_obj();
1150     obj.push_back(Pair("method", "z_sendmany"));
1151     obj.push_back(Pair("params", contextinfo_ ));
1152     return obj;
1153 }
1154
This page took 0.095624 seconds and 4 git commands to generate.