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