]> Git Repo - VerusCoin.git/blame - src/test/rpc_wallet_tests.cpp
Add Sapling support to z_importkey
[VerusCoin.git] / src / test / rpc_wallet_tests.cpp
CommitLineData
3fc68461 1// Copyright (c) 2013-2014 The Bitcoin Core developers
78253fcb 2// Distributed under the MIT software license, see the accompanying
3fc68461
WL
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
4519a766
DC
5#include "rpc/server.h"
6#include "rpc/client.h"
5094f8d4 7
93bd00a0 8#include "key_io.h"
8a893c94 9#include "main.h"
50c72f23 10#include "wallet/wallet.h"
5094f8d4 11
51598b26
PW
12#include "test/test_bitcoin.h"
13
60f762a5
S
14#include "zcash/Address.hpp"
15
b922924d
S
16#include "asyncrpcqueue.h"
17#include "asyncrpcoperation.h"
6e9c7629 18#include "wallet/asyncrpcoperation_mergetoaddress.h"
b922924d 19#include "wallet/asyncrpcoperation_sendmany.h"
06c19063
S
20#include "wallet/asyncrpcoperation_shieldcoinbase.h"
21
7b79275e 22#include "init.h"
b922924d 23
a6bbb26e 24#include <array>
b922924d
S
25#include <chrono>
26#include <thread>
27
60f762a5
S
28#include <fstream>
29#include <unordered_set>
30
5094f8d4
WL
31#include <boost/algorithm/string.hpp>
32#include <boost/test/unit_test.hpp>
60f762a5 33#include <boost/format.hpp>
6be367ea 34#include <boost/filesystem.hpp>
5094f8d4 35
a10a6e2a 36#include <univalue.h>
d014114d 37
5094f8d4 38using namespace std;
5094f8d4 39
851f58f9 40extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
d014114d 41extern UniValue CallRPC(string args);
5094f8d4 42
fd67424c
GA
43extern CWallet* pwalletMain;
44
0d37ae3a 45bool find_error(const UniValue& objError, const std::string& expected) {
da5e7e51
S
46 return find_value(objError, "message").get_str().find(expected) != string::npos;
47}
48
bf69507c 49static UniValue ValueFromString(const std::string &str)
50{
51 UniValue value;
52 BOOST_CHECK(value.setNumStr(str));
53 return value;
54}
55
51598b26 56BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup)
5094f8d4
WL
57
58BOOST_AUTO_TEST_CASE(rpc_addmultisig)
59{
fd67424c
GA
60 LOCK(pwalletMain->cs_wallet);
61
5094f8d4
WL
62 rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
63
64 // old, 65-byte-long:
65 const char address1Hex[] = "0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8";
66 // new, compressed:
67 const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
68
d014114d 69 UniValue v;
b6be3e88 70 CTxDestination address;
5094f8d4 71 BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
b6be3e88
JG
72 address = DecodeDestination(v.get_str());
73 BOOST_CHECK(IsValidDestination(address) && boost::get<CScriptID>(&address) != nullptr);
5094f8d4
WL
74
75 BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex, address2Hex), false));
b6be3e88
JG
76 address = DecodeDestination(v.get_str());
77 BOOST_CHECK(IsValidDestination(address) && boost::get<CScriptID>(&address) != nullptr);
5094f8d4
WL
78
79 BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(2, address1Hex, address2Hex), false));
b6be3e88
JG
80 address = DecodeDestination(v.get_str());
81 BOOST_CHECK(IsValidDestination(address) && boost::get<CScriptID>(&address) != nullptr);
5094f8d4
WL
82
83 BOOST_CHECK_THROW(addmultisig(createArgs(0), false), runtime_error);
84 BOOST_CHECK_THROW(addmultisig(createArgs(1), false), runtime_error);
85 BOOST_CHECK_THROW(addmultisig(createArgs(2, address1Hex), false), runtime_error);
86
87 BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error);
88 BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error);
89
bc470c43 90 string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing
5094f8d4
WL
91 BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error);
92
bc470c43 93 string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing
5094f8d4
WL
94 BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error);
95}
96
97BOOST_AUTO_TEST_CASE(rpc_wallet)
98{
99 // Test RPC calls for various wallet statistics
d014114d 100 UniValue r;
5094f8d4 101
ed671005 102 LOCK2(cs_main, pwalletMain->cs_wallet);
fd67424c 103
75ebced4 104 CPubKey demoPubkey = pwalletMain->GenerateNewKey();
b6be3e88 105 CTxDestination demoAddress(CTxDestination(demoPubkey.GetID()));
d014114d 106 UniValue retValue;
b6f100cf 107 string strAccount = "";
bc470c43
ES
108 string strPurpose = "receive";
109 BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
110 CWalletDB walletdb(pwalletMain->strWalletFile);
111 CAccount account;
112 account.vchPubKey = demoPubkey;
113 pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
114 walletdb.WriteAccount(strAccount, account);
115 });
75ebced4 116
31d6390f 117 CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
b6be3e88 118 CTxDestination setaccountDemoAddress(CTxDestination(setaccountDemoPubkey.GetID()));
bc470c43
ES
119
120 /*********************************
121 * setaccount
122 *********************************/
b6be3e88 123 BOOST_CHECK_NO_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " \"\""));
b6f100cf 124 /* Accounts are disabled */
b6be3e88 125 BOOST_CHECK_THROW(CallRPC("setaccount " + EncodeDestination(setaccountDemoAddress) + " nullaccount"), runtime_error);
ee64b5e7
JG
126 /* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV is not owned by the test wallet. */
127 BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV nullaccount"), runtime_error);
bc470c43 128 BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error);
ee64b5e7
JG
129 /* t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg (34 chars) is an illegal address (should be 35 chars) */
130 BOOST_CHECK_THROW(CallRPC("setaccount t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg nullaccount"), runtime_error);
75ebced4 131
7c5dd603
EF
132
133 /*********************************
134 * getbalance
135 *********************************/
136 BOOST_CHECK_NO_THROW(CallRPC("getbalance"));
b6be3e88 137 BOOST_CHECK_THROW(CallRPC("getbalance " + EncodeDestination(demoAddress)), runtime_error);
7c5dd603 138
75ebced4
AM
139 /*********************************
140 * listunspent
141 *********************************/
5094f8d4
WL
142 BOOST_CHECK_NO_THROW(CallRPC("listunspent"));
143 BOOST_CHECK_THROW(CallRPC("listunspent string"), runtime_error);
144 BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error);
145 BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error);
146 BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error);
bc470c43 147 BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []"));
5094f8d4
WL
148 BOOST_CHECK(r.get_array().empty());
149
75ebced4 150 /*********************************
bc470c43
ES
151 * listreceivedbyaddress
152 *********************************/
5094f8d4
WL
153 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress"));
154 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0"));
155 BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error);
156 BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 not_bool"), runtime_error);
157 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0 true"));
158 BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error);
159
75ebced4 160 /*********************************
bc470c43
ES
161 * listreceivedbyaccount
162 *********************************/
5094f8d4
WL
163 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount"));
164 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0"));
165 BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error);
166 BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 not_bool"), runtime_error);
167 BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0 true"));
168 BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error);
75ebced4 169
7c5dd603
EF
170 /*********************************
171 * listsinceblock
172 *********************************/
173 BOOST_CHECK_NO_THROW(CallRPC("listsinceblock"));
174
175 /*********************************
176 * listtransactions
177 *********************************/
178 BOOST_CHECK_NO_THROW(CallRPC("listtransactions"));
b6be3e88
JG
179 BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress)));
180 BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20"));
181 BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " 20 0"));
182 BOOST_CHECK_THROW(CallRPC("listtransactions " + EncodeDestination(demoAddress) + " not_int"), runtime_error);
7c5dd603
EF
183
184 /*********************************
185 * listlockunspent
186 *********************************/
187 BOOST_CHECK_NO_THROW(CallRPC("listlockunspent"));
188
189 /*********************************
190 * listaccounts
191 *********************************/
192 BOOST_CHECK_NO_THROW(CallRPC("listaccounts"));
193
194 /*********************************
195 * listaddressgroupings
196 *********************************/
197 BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings"));
198
75ebced4 199 /*********************************
bc470c43
ES
200 * getrawchangeaddress
201 *********************************/
75ebced4
AM
202 BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress"));
203
204 /*********************************
bc470c43
ES
205 * getnewaddress
206 *********************************/
75ebced4 207 BOOST_CHECK_NO_THROW(CallRPC("getnewaddress"));
b6f100cf
JG
208 BOOST_CHECK_NO_THROW(CallRPC("getnewaddress \"\""));
209 /* Accounts are deprecated */
210 BOOST_CHECK_THROW(CallRPC("getnewaddress getnewaddress_demoaccount"), runtime_error);
75ebced4
AM
211
212 /*********************************
bc470c43
ES
213 * getaccountaddress
214 *********************************/
75ebced4 215 BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\""));
b6f100cf
JG
216 /* Accounts are deprecated */
217 BOOST_CHECK_THROW(CallRPC("getaccountaddress accountThatDoesntExists"), runtime_error);
bc470c43 218 BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount));
b6be3e88 219 BOOST_CHECK(DecodeDestination(retValue.get_str()) == demoAddress);
75ebced4 220
bc470c43
ES
221 /*********************************
222 * getaccount
223 *********************************/
224 BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error);
b6be3e88 225 BOOST_CHECK_NO_THROW(CallRPC("getaccount " + EncodeDestination(demoAddress)));
bc470c43
ES
226
227 /*********************************
228 * signmessage + verifymessage
229 *********************************/
b6be3e88 230 BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + EncodeDestination(demoAddress) + " mymessage"));
bc470c43
ES
231 BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error);
232 /* Should throw error because this address is not loaded in the wallet */
ee64b5e7 233 BOOST_CHECK_THROW(CallRPC("signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage"), runtime_error);
bc470c43
ES
234
235 /* missing arguments */
b6be3e88
JG
236 BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress)), runtime_error);
237 BOOST_CHECK_THROW(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str()), runtime_error);
bc470c43 238 /* Illegal address */
ee64b5e7 239 BOOST_CHECK_THROW(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue.get_str() + " mymessage"), runtime_error);
bc470c43 240 /* wrong address */
ee64b5e7 241 BOOST_CHECK(CallRPC("verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue.get_str() + " mymessage").get_bool() == false);
bc470c43 242 /* Correct address and signature but wrong message */
b6be3e88 243 BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " wrongmessage").get_bool() == false);
bc470c43 244 /* Correct address, message and signature*/
b6be3e88 245 BOOST_CHECK(CallRPC("verifymessage " + EncodeDestination(demoAddress) + " " + retValue.get_str() + " mymessage").get_bool() == true);
bc470c43
ES
246
247 /*********************************
248 * getaddressesbyaccount
249 *********************************/
250 BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
251 BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
851f58f9 252 UniValue arr = retValue.get_array();
b6f100cf
JG
253 BOOST_CHECK_EQUAL(4, arr.size());
254 bool notFound = true;
0d37ae3a 255 for (auto a : arr.getValues()) {
b6be3e88 256 notFound &= DecodeDestination(a.get_str()) != demoAddress;
b6f100cf
JG
257 }
258 BOOST_CHECK(!notFound);
5d50130b 259
3d8013a0
MC
260 /*********************************
261 * fundrawtransaction
262 *********************************/
263 BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
264 BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
265
5d50130b
S
266 /*
267 * getblocksubsidy
268 */
269 BOOST_CHECK_THROW(CallRPC("getblocksubsidy too many args"), runtime_error);
270 BOOST_CHECK_THROW(CallRPC("getblocksubsidy -1"), runtime_error);
271 BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 50000"));
0d37ae3a
JG
272 UniValue obj = retValue.get_obj();
273 BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 10.0);
274 BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 2.5);
5d50130b
S
275 BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 1000000"));
276 obj = retValue.get_obj();
0d37ae3a
JG
277 BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 6.25);
278 BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
5d50130b
S
279 BOOST_CHECK_NO_THROW(retValue = CallRPC("getblocksubsidy 2000000"));
280 obj = retValue.get_obj();
0d37ae3a
JG
281 BOOST_CHECK_EQUAL(find_value(obj, "miner").get_real(), 3.125);
282 BOOST_CHECK_EQUAL(find_value(obj, "founders").get_real(), 0.0);
7d3b1528
S
283
284 /*
285 * getblock
286 */
287 BOOST_CHECK_THROW(CallRPC("getblock too many args"), runtime_error);
288 BOOST_CHECK_THROW(CallRPC("getblock -1"), runtime_error);
289 BOOST_CHECK_THROW(CallRPC("getblock 2147483647"), runtime_error); // allowed, but > height of active chain tip
290 BOOST_CHECK_THROW(CallRPC("getblock 2147483648"), runtime_error); // not allowed, > int32 used for nHeight
291 BOOST_CHECK_THROW(CallRPC("getblock 100badchars"), runtime_error);
292 BOOST_CHECK_NO_THROW(CallRPC("getblock 0"));
9bd8f092
S
293 BOOST_CHECK_NO_THROW(CallRPC("getblock 0 0"));
294 BOOST_CHECK_NO_THROW(CallRPC("getblock 0 1"));
295 BOOST_CHECK_NO_THROW(CallRPC("getblock 0 2"));
296 BOOST_CHECK_THROW(CallRPC("getblock 0 -1"), runtime_error); // bad verbosity
297 BOOST_CHECK_THROW(CallRPC("getblock 0 3"), runtime_error); // bad verbosity
5094f8d4
WL
298}
299
e883ffef
S
300BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
301{
302 SelectParams(CBaseChainParams::TESTNET);
303
304 LOCK(pwalletMain->cs_wallet);
305
06c19063 306
e883ffef
S
307 BOOST_CHECK_THROW(CallRPC("z_getbalance too many args"), runtime_error);
308 BOOST_CHECK_THROW(CallRPC("z_getbalance invalidaddress"), runtime_error);
ee64b5e7
JG
309 BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab"));
310 BOOST_CHECK_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
311 BOOST_CHECK_NO_THROW(CallRPC("z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab 0"));
e883ffef 312 BOOST_CHECK_THROW(CallRPC("z_getbalance tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
06c19063
S
313
314
e883ffef
S
315 BOOST_CHECK_THROW(CallRPC("z_gettotalbalance too manyargs"), runtime_error);
316 BOOST_CHECK_THROW(CallRPC("z_gettotalbalance -1"), runtime_error);
317 BOOST_CHECK_NO_THROW(CallRPC("z_gettotalbalance 0"));
06c19063
S
318
319
e883ffef
S
320 BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress too many args"), runtime_error);
321 // negative minconf not allowed
ee64b5e7 322 BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1"), runtime_error);
e883ffef 323 // invalid zaddr, taddr not allowed
ee64b5e7 324 BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab 0"), runtime_error);
e883ffef
S
325 // don't have the spending key
326 BOOST_CHECK_THROW(CallRPC("z_listreceivedbyaddress tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), runtime_error);
327}
328
4e16a724
S
329/**
330 * This test covers RPC command z_validateaddress
331 */
332BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
333{
334 SelectParams(CBaseChainParams::MAIN);
335
336 LOCK2(cs_main, pwalletMain->cs_wallet);
337
0d37ae3a 338 UniValue retValue;
4e16a724
S
339
340 // Check number of args
341 BOOST_CHECK_THROW(CallRPC("z_validateaddress"), runtime_error);
342 BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error);
343
344 // Wallet should be empty
e5eab182 345 std::set<libzcash::SproutPaymentAddress> addrs;
4e16a724
S
346 pwalletMain->GetPaymentAddresses(addrs);
347 BOOST_CHECK(addrs.size()==0);
348
349 // This address is not valid, it belongs to another network
350 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztaaga95QAPyp1kSQ1hD2kguCpzyMHjxWZqaYDEkzbvo7uYQYAw2S8X4Kx98AvhhofMtQL8PAXKHuZsmhRcanavKRKmdCzk"));
0d37ae3a 351 UniValue resultObj = retValue.get_obj();
4e16a724
S
352 bool b = find_value(resultObj, "isvalid").get_bool();
353 BOOST_CHECK_EQUAL(b, false);
354
355 // This address is valid, but the spending key is not in this wallet
356 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcfA19SDAKRYHLoRDoShcoz4nPohqWxuHcqg8WAxsiB2jFrrs6k7oSvst3UZvMYqpMNSRBkxBsnyjjngX5L55FxMzLKach8"));
357 resultObj = retValue.get_obj();
358 b = find_value(resultObj, "isvalid").get_bool();
359 BOOST_CHECK_EQUAL(b, true);
bea87915 360 BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
4e16a724
S
361 b = find_value(resultObj, "ismine").get_bool();
362 BOOST_CHECK_EQUAL(b, false);
363
364 // Let's import a spending key to the wallet and validate its payment address
365 BOOST_CHECK_NO_THROW(CallRPC("z_importkey SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT"));
366 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL"));
367 resultObj = retValue.get_obj();
368 b = find_value(resultObj, "isvalid").get_bool();
369 BOOST_CHECK_EQUAL(b, true);
bea87915 370 BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout");
4e16a724
S
371 b = find_value(resultObj, "ismine").get_bool();
372 BOOST_CHECK_EQUAL(b, true);
373 BOOST_CHECK_EQUAL(find_value(resultObj, "payingkey").get_str(), "f5bb3c888ccc9831e3f6ba06e7528e26a312eec3acc1823be8918b6a3a5e20ad");
374 BOOST_CHECK_EQUAL(find_value(resultObj, "transmissionkey").get_str(), "7a58c7132446564e6b810cf895c20537b3528357dc00150a8e201f491efa9c1a");
bea87915
JG
375
376 // This Sapling address is not valid, it belongs to another network
377 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztestsapling1knww2nyjc62njkard0jmx7hlsj6twxmxwprn7anvrv4dc2zxanl3nemc0qx2hvplxmd2uau8gyw"));
378 resultObj = retValue.get_obj();
379 b = find_value(resultObj, "isvalid").get_bool();
380 BOOST_CHECK_EQUAL(b, false);
381
382 // This Sapling address is valid, but the spending key is not in this wallet
383 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9slya"));
384 resultObj = retValue.get_obj();
385 b = find_value(resultObj, "isvalid").get_bool();
386 BOOST_CHECK_EQUAL(b, true);
387 BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sapling");
388 b = find_value(resultObj, "ismine").get_bool();
389 BOOST_CHECK_EQUAL(b, false);
390 BOOST_CHECK_EQUAL(find_value(resultObj, "diversifier").get_str(), "1787997c30e94f050c634d");
391 BOOST_CHECK_EQUAL(find_value(resultObj, "diversifiedtransmissionkey").get_str(), "34ed1f60f5db5763beee1ddbb37dd5f7e541d4d4fbdcc09fbfcc6b8e949bbe9d");
4e16a724
S
392}
393
60f762a5
S
394/*
395 * This test covers RPC command z_exportwallet
396 */
397BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
398{
399 LOCK2(cs_main, pwalletMain->cs_wallet);
4e16a724 400
4b2e5571 401 // wallet should be empty
e5eab182 402 std::set<libzcash::SproutPaymentAddress> addrs;
60f762a5
S
403 pwalletMain->GetPaymentAddresses(addrs);
404 BOOST_CHECK(addrs.size()==0);
405
406 // wallet should have one key
e5eab182
JG
407 auto address = pwalletMain->GenerateNewZKey();
408 BOOST_CHECK(IsValidPaymentAddress(address));
409 BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
410 auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
60f762a5
S
411 pwalletMain->GetPaymentAddresses(addrs);
412 BOOST_CHECK(addrs.size()==1);
06c19063 413
9064d73b
S
414 // Set up paths
415 boost::filesystem::path tmppath = boost::filesystem::temp_directory_path();
416 boost::filesystem::path tmpfilename = boost::filesystem::unique_path("%%%%%%%%");
417 boost::filesystem::path exportfilepath = tmppath / tmpfilename;
418
419 // export will fail since exportdir is not set
420 BOOST_CHECK_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()), runtime_error);
421
422 // set exportdir
423 mapArgs["-exportdir"] = tmppath.native();
424
425 // run some tests
60f762a5 426 BOOST_CHECK_THROW(CallRPC("z_exportwallet"), runtime_error);
e346a0b3
S
427
428 BOOST_CHECK_THROW(CallRPC("z_exportwallet toomany args"), runtime_error);
429
9064d73b
S
430 BOOST_CHECK_THROW(CallRPC(string("z_exportwallet invalid!*/_chars.txt")), runtime_error);
431
432 BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string()));
60f762a5 433
60f762a5 434
e5eab182 435 libzcash::SproutSpendingKey key;
60f762a5
S
436 BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key));
437
80ed13d5 438 std::string s1 = EncodePaymentAddress(addr);
472f75bc 439 std::string s2 = EncodeSpendingKey(key);
06c19063 440
60f762a5
S
441 // There's no way to really delete a private key so we will read in the
442 // exported wallet file and search for the spending key and payment address.
06c19063 443
60f762a5
S
444 EnsureWalletIsUnlocked();
445
446 ifstream file;
9064d73b 447 file.open(exportfilepath.string().c_str(), std::ios::in | std::ios::ate);
60f762a5
S
448 BOOST_CHECK(file.is_open());
449 bool fVerified = false;
450 int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
451 file.seekg(0, file.beg);
452 while (file.good()) {
453 std::string line;
454 std::getline(file, line);
455 if (line.empty() || line[0] == '#')
456 continue;
457 if (line.find(s1) != std::string::npos && line.find(s2) != std::string::npos) {
458 fVerified = true;
459 break;
460 }
461 }
462 BOOST_CHECK(fVerified);
463}
464
465
466/*
467 * This test covers RPC command z_importwallet
468 */
469BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
470{
471 LOCK2(cs_main, pwalletMain->cs_wallet);
06c19063 472
60f762a5
S
473 // error if no args
474 BOOST_CHECK_THROW(CallRPC("z_importwallet"), runtime_error);
475
e346a0b3
S
476 // error if too many args
477 BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error);
478
60f762a5 479 // create a random key locally
e5eab182 480 auto testSpendingKey = libzcash::SproutSpendingKey::random();
60f762a5 481 auto testPaymentAddress = testSpendingKey.address();
80ed13d5 482 std::string testAddr = EncodePaymentAddress(testPaymentAddress);
472f75bc 483 std::string testKey = EncodeSpendingKey(testSpendingKey);
06c19063 484
60f762a5
S
485 // create test data using the random key
486 std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
487 "# * Created on 2016-08-12T21:55:36Z\n"
488 "# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n"
489 "# mined on 2009-01-03T18:15:05Z\n"
490 "\n"
491 "# Zkeys\n"
492 "\n"
493 "%s 2016-08-12T21:55:36Z # zaddr=%s\n"
494 "\n"
495 "\n# End of dump";
06c19063 496
60f762a5
S
497 boost::format formatobject(format_str);
498 std::string testWalletDump = (formatobject % testKey % testAddr).str();
06c19063 499
60f762a5
S
500 // write test data to file
501 boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
502 boost::filesystem::unique_path();
503 const std::string path = temp.native();
504 std::ofstream file(path);
505 file << testWalletDump;
506 file << std::flush;
507
508 // wallet should currently be empty
e5eab182 509 std::set<libzcash::SproutPaymentAddress> addrs;
60f762a5
S
510 pwalletMain->GetPaymentAddresses(addrs);
511 BOOST_CHECK(addrs.size()==0);
06c19063 512
60f762a5
S
513 // import test data from file into wallet
514 BOOST_CHECK_NO_THROW(CallRPC(string("z_importwallet ") + path));
06c19063 515
60f762a5
S
516 // wallet should now have one zkey
517 pwalletMain->GetPaymentAddresses(addrs);
518 BOOST_CHECK(addrs.size()==1);
06c19063 519
60f762a5 520 // check that we have the spending key for the address
e5eab182
JG
521 auto address = DecodePaymentAddress(testAddr);
522 BOOST_CHECK(IsValidPaymentAddress(address));
523 BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
524 auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
60f762a5 525 BOOST_CHECK(pwalletMain->HaveSpendingKey(addr));
06c19063 526
4b2e5571 527 // Verify the spending key is the same as the test data
e5eab182 528 libzcash::SproutSpendingKey k;
60f762a5 529 BOOST_CHECK(pwalletMain->GetSpendingKey(addr, k));
472f75bc 530 BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k));
60f762a5
S
531}
532
533
534/*
4b2e5571 535 * This test covers RPC commands z_listaddresses, z_importkey, z_exportkey
60f762a5
S
536 */
537BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
538{
539 LOCK2(cs_main, pwalletMain->cs_wallet);
0d37ae3a 540 UniValue retValue;
60f762a5
S
541 int n1 = 1000; // number of times to import/export
542 int n2 = 1000; // number of addresses to create and list
06c19063 543
60f762a5 544 // error if no args
06c19063
S
545 BOOST_CHECK_THROW(CallRPC("z_importkey"), runtime_error);
546 BOOST_CHECK_THROW(CallRPC("z_exportkey"), runtime_error);
60f762a5 547
e346a0b3 548 // error if too many args
a31ba7a0 549 BOOST_CHECK_THROW(CallRPC("z_importkey way too many args"), runtime_error);
e346a0b3
S
550 BOOST_CHECK_THROW(CallRPC("z_exportkey toomany args"), runtime_error);
551
33589401 552 // error if invalid args
e5eab182 553 auto sk = libzcash::SproutSpendingKey::random();
472f75bc 554 std::string prefix = std::string("z_importkey ") + EncodeSpendingKey(sk) + " yes ";
33589401
JG
555 BOOST_CHECK_THROW(CallRPC(prefix + "-1"), runtime_error);
556 BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), runtime_error); // allowed, but > height of active chain tip
557 BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), runtime_error); // not allowed, > int32 used for nHeight
558 BOOST_CHECK_THROW(CallRPC(prefix + "100badchars"), runtime_error);
559
60f762a5 560 // wallet should currently be empty
e5eab182 561 std::set<libzcash::SproutPaymentAddress> addrs;
60f762a5
S
562 pwalletMain->GetPaymentAddresses(addrs);
563 BOOST_CHECK(addrs.size()==0);
564
565 // verify import and export key
566 for (int i = 0; i < n1; i++) {
567 // create a random key locally
e5eab182 568 auto testSpendingKey = libzcash::SproutSpendingKey::random();
60f762a5 569 auto testPaymentAddress = testSpendingKey.address();
80ed13d5 570 std::string testAddr = EncodePaymentAddress(testPaymentAddress);
472f75bc 571 std::string testKey = EncodeSpendingKey(testSpendingKey);
60f762a5
S
572 BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
573 BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
574 BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
575 }
576
577 // Verify we can list the keys imported
578 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
0d37ae3a 579 UniValue arr = retValue.get_array();
60f762a5
S
580 BOOST_CHECK(arr.size() == n1);
581
582 // Put addresses into a set
583 std::unordered_set<std::string> myaddrs;
0d37ae3a 584 for (UniValue element : arr.getValues()) {
60f762a5
S
585 myaddrs.insert(element.get_str());
586 }
06c19063 587
60f762a5
S
588 // Make new addresses for the set
589 for (int i=0; i<n2; i++) {
80ed13d5 590 myaddrs.insert(EncodePaymentAddress(pwalletMain->GenerateNewZKey()));
60f762a5
S
591 }
592
593 // Verify number of addresses stored in wallet is n1+n2
594 int numAddrs = myaddrs.size();
595 BOOST_CHECK(numAddrs == n1+n2);
596 pwalletMain->GetPaymentAddresses(addrs);
06c19063
S
597 BOOST_CHECK(addrs.size()==numAddrs);
598
60f762a5
S
599 // Ask wallet to list addresses
600 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
601 arr = retValue.get_array();
602 BOOST_CHECK(arr.size() == numAddrs);
06c19063 603
4b2e5571 604 // Create a set from them
60f762a5 605 std::unordered_set<std::string> listaddrs;
0d37ae3a 606 for (UniValue element : arr.getValues()) {
60f762a5
S
607 listaddrs.insert(element.get_str());
608 }
06c19063 609
60f762a5
S
610 // Verify the two sets of addresses are the same
611 BOOST_CHECK(listaddrs.size() == numAddrs);
612 BOOST_CHECK(myaddrs == listaddrs);
badb9a9c
S
613
614 // Add one more address
615 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress"));
616 std::string newaddress = retValue.get_str();
e5eab182
JG
617 auto address = DecodePaymentAddress(newaddress);
618 BOOST_CHECK(IsValidPaymentAddress(address));
619 BOOST_ASSERT(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
620 auto newAddr = boost::get<libzcash::SproutPaymentAddress>(address);
badb9a9c 621 BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr));
e346a0b3
S
622
623 // Check if too many args
624 BOOST_CHECK_THROW(CallRPC("z_getnewaddress toomanyargs"), runtime_error);
60f762a5 625}
b922924d
S
626
627
628
629/**
fc4b127e 630 * Test Async RPC operations.
b922924d
S
631 * Tip: Create mock operations by subclassing AsyncRPCOperation.
632 */
fc4b127e 633
b922924d
S
634class MockSleepOperation : public AsyncRPCOperation {
635public:
636 std::chrono::milliseconds naptime;
637 MockSleepOperation(int t=1000) {
638 this->naptime = std::chrono::milliseconds(t);
639 }
640 virtual ~MockSleepOperation() {
641 }
642 virtual void main() {
643 set_state(OperationStatus::EXECUTING);
644 start_execution_clock();
645 std::this_thread::sleep_for(std::chrono::milliseconds(naptime));
646 stop_execution_clock();
0d37ae3a 647 set_result(UniValue(UniValue::VSTR, "done"));
b922924d
S
648 set_state(OperationStatus::SUCCESS);
649 }
650};
651
652
653/*
654 * Test Aysnc RPC queue and operations.
655 */
656BOOST_AUTO_TEST_CASE(rpc_wallet_async_operations)
657{
658 std::shared_ptr<AsyncRPCQueue> q = std::make_shared<AsyncRPCQueue>();
659 BOOST_CHECK(q->getNumberOfWorkers() == 0);
660 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
661 BOOST_CHECK(ids.size()==0);
662
663 std::shared_ptr<AsyncRPCOperation> op1 = std::make_shared<AsyncRPCOperation>();
06c19063 664 q->addOperation(op1);
b922924d 665 BOOST_CHECK(q->getOperationCount() == 1);
06c19063 666
b922924d
S
667 OperationStatus status = op1->getState();
668 BOOST_CHECK(status == OperationStatus::READY);
06c19063 669
b922924d
S
670 AsyncRPCOperationId id1 = op1->getId();
671 int64_t creationTime1 = op1->getCreationTime();
06c19063 672
b922924d
S
673 q->addWorker();
674 BOOST_CHECK(q->getNumberOfWorkers() == 1);
06c19063
S
675
676 // an AsyncRPCOperation doesn't do anything so will finish immediately
b922924d
S
677 std::this_thread::sleep_for(std::chrono::seconds(1));
678 BOOST_CHECK(q->getOperationCount() == 0);
679
680 // operation should be a success
681 BOOST_CHECK_EQUAL(op1->isCancelled(), false);
682 BOOST_CHECK_EQUAL(op1->isExecuting(), false);
683 BOOST_CHECK_EQUAL(op1->isReady(), false);
684 BOOST_CHECK_EQUAL(op1->isFailed(), false);
685 BOOST_CHECK_EQUAL(op1->isSuccess(), true);
0d37ae3a
JG
686 BOOST_CHECK_EQUAL(op1->getError().isNull(), true);
687 BOOST_CHECK_EQUAL(op1->getResult().isNull(), false);
b922924d
S
688 BOOST_CHECK_EQUAL(op1->getStateAsString(), "success");
689 BOOST_CHECK_NE(op1->getStateAsString(), "executing");
06c19063 690
b922924d
S
691 // Create a second operation which just sleeps
692 std::shared_ptr<AsyncRPCOperation> op2(new MockSleepOperation(2500));
693 AsyncRPCOperationId id2 = op2->getId();
694 int64_t creationTime2 = op2->getCreationTime();
695
696 // it's different from the previous operation
697 BOOST_CHECK_NE(op1.get(), op2.get());
698 BOOST_CHECK_NE(id1, id2);
699 BOOST_CHECK_NE(creationTime1, creationTime2);
700
701 // Only the first operation has been added to the queue
702 std::vector<AsyncRPCOperationId> v = q->getAllOperationIds();
703 std::set<AsyncRPCOperationId> opids(v.begin(), v.end());
704 BOOST_CHECK(opids.size() == 1);
705 BOOST_CHECK(opids.count(id1)==1);
706 BOOST_CHECK(opids.count(id2)==0);
707 std::shared_ptr<AsyncRPCOperation> p1 = q->getOperationForId(id1);
708 BOOST_CHECK_EQUAL(p1.get(), op1.get());
709 std::shared_ptr<AsyncRPCOperation> p2 = q->getOperationForId(id2);
710 BOOST_CHECK(!p2); // null ptr as not added to queue yet
711
712 // Add operation 2 and 3 to the queue
713 q->addOperation(op2);
714 std::shared_ptr<AsyncRPCOperation> op3(new MockSleepOperation(1000));
715 q->addOperation(op3);
716 std::this_thread::sleep_for(std::chrono::milliseconds(500));
717 BOOST_CHECK_EQUAL(op2->isExecuting(), true);
718 op2->cancel(); // too late, already executing
719 op3->cancel();
720 std::this_thread::sleep_for(std::chrono::milliseconds(3000));
721 BOOST_CHECK_EQUAL(op2->isSuccess(), true);
722 BOOST_CHECK_EQUAL(op2->isCancelled(), false);
723 BOOST_CHECK_EQUAL(op3->isCancelled(), true);
06c19063
S
724
725
b922924d
S
726 v = q->getAllOperationIds();
727 std::copy( v.begin(), v.end(), std::inserter( opids, opids.end() ) );
728 BOOST_CHECK(opids.size() == 3);
729 BOOST_CHECK(opids.count(id1)==1);
730 BOOST_CHECK(opids.count(id2)==1);
731 BOOST_CHECK(opids.count(op3->getId())==1);
732 q->finishAndWait();
733}
734
735
736// The CountOperation will increment this global
737std::atomic<int64_t> gCounter(0);
738
739class CountOperation : public AsyncRPCOperation {
740public:
741 CountOperation() {}
742 virtual ~CountOperation() {}
06c19063 743 virtual void main() {
b922924d
S
744 set_state(OperationStatus::EXECUTING);
745 gCounter++;
746 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
747 set_state(OperationStatus::SUCCESS);
748 }
749};
750
751// This tests the queue waiting for multiple workers to finish
752BOOST_AUTO_TEST_CASE(rpc_wallet_async_operations_parallel_wait)
753{
754 gCounter = 0;
06c19063 755
b922924d
S
756 std::shared_ptr<AsyncRPCQueue> q = std::make_shared<AsyncRPCQueue>();
757 q->addWorker();
758 q->addWorker();
759 q->addWorker();
760 q->addWorker();
761 BOOST_CHECK(q->getNumberOfWorkers() == 4);
762
763 int64_t numOperations = 10; // 10 * 1000ms / 4 = 2.5 secs to finish
764 for (int i=0; i<numOperations; i++) {
765 std::shared_ptr<AsyncRPCOperation> op(new CountOperation());
766 q->addOperation(op);
767 }
768
769 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
770 BOOST_CHECK(ids.size()==numOperations);
771 q->finishAndWait();
772 BOOST_CHECK_EQUAL(q->isFinishing(), true);
773 BOOST_CHECK_EQUAL(numOperations, gCounter.load());
774}
775
776// This tests the queue shutting down immediately
777BOOST_AUTO_TEST_CASE(rpc_wallet_async_operations_parallel_cancel)
778{
779 gCounter = 0;
06c19063 780
b922924d
S
781 std::shared_ptr<AsyncRPCQueue> q = std::make_shared<AsyncRPCQueue>();
782 q->addWorker();
783 q->addWorker();
784 BOOST_CHECK(q->getNumberOfWorkers() == 2);
785
fc4b127e 786 int numOperations = 10000; // 10000 seconds to complete
b922924d
S
787 for (int i=0; i<numOperations; i++) {
788 std::shared_ptr<AsyncRPCOperation> op(new CountOperation());
789 q->addOperation(op);
790 }
791 std::vector<AsyncRPCOperationId> ids = q->getAllOperationIds();
792 BOOST_CHECK(ids.size()==numOperations);
793 q->closeAndWait();
b922924d
S
794
795 int numSuccess = 0;
06c19063 796 int numCancelled = 0;
b922924d
S
797 for (auto & id : ids) {
798 std::shared_ptr<AsyncRPCOperation> ptr = q->popOperationForId(id);
799 if (ptr->isCancelled()) {
800 numCancelled++;
801 } else if (ptr->isSuccess()) {
802 numSuccess++;
803 }
804 }
06c19063 805
b922924d
S
806 BOOST_CHECK_EQUAL(numOperations, numSuccess+numCancelled);
807 BOOST_CHECK_EQUAL(gCounter.load(), numSuccess);
808 BOOST_CHECK(q->getOperationCount() == 0);
809 ids = q->getAllOperationIds();
810 BOOST_CHECK(ids.size()==0);
811}
812
fc4b127e
S
813// This tests z_getoperationstatus, z_getoperationresult, z_listoperationids
814BOOST_AUTO_TEST_CASE(rpc_z_getoperations)
815{
816 std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
817 std::shared_ptr<AsyncRPCQueue> sharedInstance = AsyncRPCQueue::sharedInstance();
818 BOOST_CHECK(q == sharedInstance);
819
820 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationstatus"));
821 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationstatus []"));
822 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationstatus [\"opid-1234\"]"));
823 BOOST_CHECK_THROW(CallRPC("z_getoperationstatus [] toomanyargs"), runtime_error);
824 BOOST_CHECK_THROW(CallRPC("z_getoperationstatus not_an_array"), runtime_error);
825
826 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationresult"));
827 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationresult []"));
828 BOOST_CHECK_NO_THROW(CallRPC("z_getoperationresult [\"opid-1234\"]"));
829 BOOST_CHECK_THROW(CallRPC("z_getoperationresult [] toomanyargs"), runtime_error);
830 BOOST_CHECK_THROW(CallRPC("z_getoperationresult not_an_array"), runtime_error);
06c19063 831
fc4b127e
S
832 std::shared_ptr<AsyncRPCOperation> op1 = std::make_shared<AsyncRPCOperation>();
833 q->addOperation(op1);
834 std::shared_ptr<AsyncRPCOperation> op2 = std::make_shared<AsyncRPCOperation>();
835 q->addOperation(op2);
06c19063 836
fc4b127e
S
837 BOOST_CHECK(q->getOperationCount() == 2);
838 BOOST_CHECK(q->getNumberOfWorkers() == 0);
839 q->addWorker();
840 BOOST_CHECK(q->getNumberOfWorkers() == 1);
841 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
842 BOOST_CHECK(q->getOperationCount() == 0);
06c19063 843
e346a0b3
S
844 // Check if too many args
845 BOOST_CHECK_THROW(CallRPC("z_listoperationids toomany args"), runtime_error);
846
0d37ae3a 847 UniValue retValue;
fc4b127e
S
848 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listoperationids"));
849 BOOST_CHECK(retValue.get_array().size() == 2);
850
851 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getoperationstatus"));
0d37ae3a 852 UniValue array = retValue.get_array();
fc4b127e
S
853 BOOST_CHECK(array.size() == 2);
854
855 // idempotent
856 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getoperationstatus"));
857 array = retValue.get_array();
06c19063
S
858 BOOST_CHECK(array.size() == 2);
859
0d37ae3a
JG
860 for (UniValue v : array.getValues()) {
861 UniValue obj = v.get_obj();
862 UniValue id = find_value(obj, "id");
06c19063 863
0d37ae3a 864 UniValue result;
fc4b127e
S
865 // removes result from internal storage
866 BOOST_CHECK_NO_THROW(result = CallRPC("z_getoperationresult [\"" + id.get_str() + "\"]"));
0d37ae3a 867 UniValue resultArray = result.get_array();
fc4b127e 868 BOOST_CHECK(resultArray.size() == 1);
06c19063 869
0d37ae3a
JG
870 UniValue resultObj = resultArray[0].get_obj();
871 UniValue resultId = find_value(resultObj, "id");
fc4b127e 872 BOOST_CHECK_EQUAL(id.get_str(), resultId.get_str());
06c19063
S
873
874 // verify the operation has been removed
da5e7e51
S
875 BOOST_CHECK_NO_THROW(result = CallRPC("z_getoperationresult [\"" + id.get_str() + "\"]"));
876 resultArray = result.get_array();
877 BOOST_CHECK(resultArray.size() == 0);
fc4b127e 878 }
06c19063 879
fc4b127e
S
880 // operations removed
881 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getoperationstatus"));
882 array = retValue.get_array();
883 BOOST_CHECK(array.size() == 0);
884
885 q->close();
886}
887
888BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
889{
890 SelectParams(CBaseChainParams::TESTNET);
891
892 LOCK(pwalletMain->cs_wallet);
893
894 BOOST_CHECK_THROW(CallRPC("z_sendmany"), runtime_error);
895 BOOST_CHECK_THROW(CallRPC("z_sendmany toofewargs"), runtime_error);
af53da02 896 BOOST_CHECK_THROW(CallRPC("z_sendmany just too many args here"), runtime_error);
fc4b127e
S
897
898 // bad from address
da5e7e51 899 BOOST_CHECK_THROW(CallRPC("z_sendmany "
ee64b5e7 900 "INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ []"), runtime_error);
fc4b127e 901 // empty amounts
da5e7e51 902 BOOST_CHECK_THROW(CallRPC("z_sendmany "
ee64b5e7 903 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ []"), runtime_error);
fc4b127e
S
904
905 // don't have the spending key for this address
da5e7e51
S
906 BOOST_CHECK_THROW(CallRPC("z_sendmany "
907 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"
908 "UkJ1oSfbhTJhm72WiZizvkZz5aH1 []"), runtime_error);
fc4b127e
S
909
910 // duplicate address
da5e7e51 911 BOOST_CHECK_THROW(CallRPC("z_sendmany "
ee64b5e7
JG
912 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
913 "[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0},"
914 " {\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":12.0} ]"
da5e7e51 915 ), runtime_error);
fc4b127e 916
af53da02
S
917 // invalid fee amount, cannot be negative
918 BOOST_CHECK_THROW(CallRPC("z_sendmany "
919 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
920 "[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
921 "1 -0.0001"
922 ), runtime_error);
923
924 // invalid fee amount, bigger than MAX_MONEY
925 BOOST_CHECK_THROW(CallRPC("z_sendmany "
926 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
927 "[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
928 "1 21000001"
929 ), runtime_error);
930
931 // fee amount is bigger than sum of outputs
932 BOOST_CHECK_THROW(CallRPC("z_sendmany "
933 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
934 "[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
935 "1 50.00000001"
936 ), runtime_error);
937
fc4b127e 938 // memo bigger than allowed length of ZC_MEMO_SIZE
cff6f0ac
S
939 std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
940 std::fill(v.begin(),v.end(), 'A');
fc4b127e 941 std::string badmemo(v.begin(), v.end());
80ed13d5
JG
942 auto pa = pwalletMain->GenerateNewZKey();
943 std::string zaddr1 = EncodePaymentAddress(pa);
ee64b5e7 944 BOOST_CHECK_THROW(CallRPC(string("z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ ")
da5e7e51 945 + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), runtime_error);
06c19063 946
072099d7
S
947 // Mutable tx containing contextual information we need to build tx
948 UniValue retValue = CallRPC("getblockcount");
949 int nHeight = retValue.get_int();
950 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
951 if (mtx.nVersion == 1) {
952 mtx.nVersion = 2;
953 }
954
06c19063 955 // Test constructor of AsyncRPCOperation_sendmany
fc4b127e 956 try {
072099d7 957 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, "",{}, {}, -1));
0d37ae3a 958 } catch (const UniValue& objError) {
da5e7e51 959 BOOST_CHECK( find_error(objError, "Minconf cannot be negative"));
fc4b127e
S
960 }
961
962 try {
072099d7 963 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, "",{}, {}, 1));
0d37ae3a 964 } catch (const UniValue& objError) {
da5e7e51 965 BOOST_CHECK( find_error(objError, "From address parameter missing"));
fc4b127e
S
966 }
967
968 try {
072099d7 969 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ", {}, {}, 1) );
0d37ae3a 970 } catch (const UniValue& objError) {
da5e7e51 971 BOOST_CHECK( find_error(objError, "No recipients"));
fc4b127e
S
972 }
973
974 try {
975 std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
072099d7 976 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "INVALID", recipients, {}, 1) );
0d37ae3a 977 } catch (const UniValue& objError) {
80ed13d5 978 BOOST_CHECK( find_error(objError, "Invalid from address"));
fc4b127e
S
979 }
980
f92f0047 981 // Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
fc4b127e
S
982 try {
983 std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
072099d7 984 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U", recipients, {}, 1) );
0d37ae3a 985 } catch (const UniValue& objError) {
80ed13d5 986 BOOST_CHECK( find_error(objError, "Invalid from address"));
fc4b127e
S
987 }
988
989 // Note: The following will crash as a google test because AsyncRPCOperation_sendmany
990 // invokes a method on pwalletMain, which is undefined in the google test environment.
991 try {
992 std::vector<SendManyRecipient> recipients = { SendManyRecipient("dummy",1.0, "") };
072099d7 993 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP", recipients, {}, 1) );
0d37ae3a 994 } catch (const UniValue& objError) {
da5e7e51 995 BOOST_CHECK( find_error(objError, "no spending key found for zaddr"));
fc4b127e
S
996 }
997}
998
cff6f0ac 999
fc4b127e
S
1000// TODO: test private methods
1001BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
1002{
1003 SelectParams(CBaseChainParams::TESTNET);
1004
1005 LOCK(pwalletMain->cs_wallet);
1006
0d37ae3a 1007 UniValue retValue;
06c19063 1008
072099d7
S
1009 // Mutable tx containing contextual information we need to build tx
1010 retValue = CallRPC("getblockcount");
1011 int nHeight = retValue.get_int();
1012 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
1013 if (mtx.nVersion == 1) {
1014 mtx.nVersion = 2;
1015 }
1016
fc4b127e
S
1017 // add keys manually
1018 BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
1019 std::string taddr1 = retValue.get_str();
80ed13d5
JG
1020 auto pa = pwalletMain->GenerateNewZKey();
1021 std::string zaddr1 = EncodePaymentAddress(pa);
06c19063 1022
fc4b127e
S
1023 // there are no utxos to spend
1024 {
1025 std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
072099d7 1026 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, taddr1, {}, recipients, 1) );
fc4b127e
S
1027 operation->main();
1028 BOOST_CHECK(operation->isFailed());
1029 std::string msg = operation->getErrorMessage();
1030 BOOST_CHECK( msg.find("Insufficient funds, no UTXOs found") != string::npos);
1031 }
b639bb1e
S
1032
1033 // minconf cannot be zero when sending from zaddr
1034 {
1035 try {
1036 std::vector<SendManyRecipient> recipients = {SendManyRecipient(taddr1, 100.0, "DEADBEEF")};
072099d7 1037 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 0));
b639bb1e
S
1038 BOOST_CHECK(false); // Fail test if an exception is not thrown
1039 } catch (const UniValue& objError) {
1040 BOOST_CHECK(find_error(objError, "Minconf cannot be zero when sending from zaddr"));
1041 }
1042 }
06c19063 1043
b639bb1e 1044
fc4b127e
S
1045 // there are no unspent notes to spend
1046 {
1047 std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1,100.0, "DEADBEEF") };
072099d7 1048 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
fc4b127e
S
1049 operation->main();
1050 BOOST_CHECK(operation->isFailed());
1051 std::string msg = operation->getErrorMessage();
1052 BOOST_CHECK( msg.find("Insufficient funds, no unspent notes") != string::npos);
1053 }
1054
cff6f0ac
S
1055 // get_memo_from_hex_string())
1056 {
1057 std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
072099d7 1058 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
cff6f0ac
S
1059 std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
1060 TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
06c19063 1061
cff6f0ac 1062 std::string memo = "DEADBEEF";
a6bbb26e 1063 std::array<unsigned char, ZC_MEMO_SIZE> array = proxy.get_memo_from_hex_string(memo);
cff6f0ac
S
1064 BOOST_CHECK_EQUAL(array[0], 0xDE);
1065 BOOST_CHECK_EQUAL(array[1], 0xAD);
1066 BOOST_CHECK_EQUAL(array[2], 0xBE);
1067 BOOST_CHECK_EQUAL(array[3], 0xEF);
1068 for (int i=4; i<ZC_MEMO_SIZE; i++) {
1069 BOOST_CHECK_EQUAL(array[i], 0x00); // zero padding
1070 }
06c19063 1071
cff6f0ac
S
1072 // memo is longer than allowed
1073 std::vector<char> v (2 * (ZC_MEMO_SIZE+1));
1074 std::fill(v.begin(),v.end(), 'A');
1075 std::string bigmemo(v.begin(), v.end());
06c19063 1076
cff6f0ac
S
1077 try {
1078 proxy.get_memo_from_hex_string(bigmemo);
0d37ae3a 1079 } catch (const UniValue& objError) {
da5e7e51 1080 BOOST_CHECK( find_error(objError, "too big"));
cff6f0ac 1081 }
06c19063 1082
cff6f0ac
S
1083 // invalid hexadecimal string
1084 std::fill(v.begin(),v.end(), '@'); // not a hex character
1085 std::string badmemo(v.begin(), v.end());
06c19063 1086
cff6f0ac
S
1087 try {
1088 proxy.get_memo_from_hex_string(badmemo);
0d37ae3a 1089 } catch (const UniValue& objError) {
da5e7e51 1090 BOOST_CHECK( find_error(objError, "hexadecimal format"));
cff6f0ac 1091 }
06c19063 1092
cff6f0ac
S
1093 // odd length hexadecimal string
1094 std::fill(v.begin(),v.end(), 'A');
1095 v.resize(v.size() - 1);
da5e7e51 1096 assert(v.size() %2 == 1); // odd length
cff6f0ac
S
1097 std::string oddmemo(v.begin(), v.end());
1098 try {
1099 proxy.get_memo_from_hex_string(oddmemo);
0d37ae3a 1100 } catch (const UniValue& objError) {
da5e7e51 1101 BOOST_CHECK( find_error(objError, "hexadecimal format"));
cff6f0ac
S
1102 }
1103 }
06c19063
S
1104
1105
cff6f0ac
S
1106 // add_taddr_change_output_to_tx() will append a vout to a raw transaction
1107 {
1108 std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1,100.0, "DEADBEEF") };
072099d7 1109 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
cff6f0ac
S
1110 std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
1111 TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
06c19063 1112
cff6f0ac
S
1113 CTransaction tx = proxy.getTx();
1114 BOOST_CHECK(tx.vout.size() == 0);
06c19063 1115
bf69507c 1116 CAmount amount = AmountFromValue(ValueFromString("123.456"));
cff6f0ac
S
1117 proxy.add_taddr_change_output_to_tx(amount);
1118 tx = proxy.getTx();
1119 BOOST_CHECK(tx.vout.size() == 1);
1120 CTxOut out = tx.vout[0];
1121 BOOST_CHECK_EQUAL(out.nValue, amount);
06c19063 1122
bf69507c 1123 amount = AmountFromValue(ValueFromString("1.111"));
cff6f0ac
S
1124 proxy.add_taddr_change_output_to_tx(amount);
1125 tx = proxy.getTx();
1126 BOOST_CHECK(tx.vout.size() == 2);
1127 out = tx.vout[1];
1128 BOOST_CHECK_EQUAL(out.nValue, amount);
1129 }
06c19063 1130
cff6f0ac
S
1131 // add_taddr_outputs_to_tx() will append many vouts to a raw transaction
1132 {
1133 std::vector<SendManyRecipient> recipients = {
ee64b5e7
JG
1134 SendManyRecipient("tmTGScYwiLMzHe4uGZtBYmuqoW4iEoYNMXt",CAmount(1.23), ""),
1135 SendManyRecipient("tmUSbHz3vxnwLvRyNDXbwkZxjVyDodMJEhh",CAmount(4.56), ""),
1136 SendManyRecipient("tmYZAXYPCP56Xa5JQWWPZuK7o7bfUQW6kkd",CAmount(7.89), ""),
cff6f0ac 1137 };
072099d7 1138 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, recipients, {}, 1) );
cff6f0ac
S
1139 std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
1140 TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
06c19063 1141
cff6f0ac 1142 proxy.add_taddr_outputs_to_tx();
06c19063 1143
cff6f0ac
S
1144 CTransaction tx = proxy.getTx();
1145 BOOST_CHECK(tx.vout.size() == 3);
1146 BOOST_CHECK_EQUAL(tx.vout[0].nValue, CAmount(1.23));
1147 BOOST_CHECK_EQUAL(tx.vout[1].nValue, CAmount(4.56));
1148 BOOST_CHECK_EQUAL(tx.vout[2].nValue, CAmount(7.89));
1149 }
06c19063 1150
cff6f0ac
S
1151
1152 // Raw joinsplit is a zaddr->zaddr
1153 {
1154 std::string raw = "020000000000000000000100000000000000001027000000000000183a0d4c46c369078705e39bcfebee59a978dbd210ce8de3efc9555a03fbabfd3cea16693d730c63850d7e48ccde79854c19adcb7e9dcd7b7d18805ee09083f6b16e1860729d2d4a90e2f2acd009cf78b5eb0f4a6ee4bdb64b1262d7ce9eb910c460b02022991e968d0c50ee44908e4ccccbc591d0053bcca154dd6d6fc400a29fa686af4682339832ccea362a62aeb9df0d5aa74f86a1e75ac0f48a8ccc41e0a940643c6c33e1d09223b0a46eaf47a1bb4407cfc12b1dcf83a29c0cef51e45c7876ca5b9e5bae86d92976eb3ef68f29cd29386a8be8451b50f82bf9da10c04651868655194da8f6ed3d241bb5b5ff93a3e2bbe44644544d88bcde5cc35978032ee92699c7a61fcbb395e7583f47e698c4d53ede54f956629400bf510fb5e22d03158cc10bdcaaf29e418ef18eb6480dd9c8b9e2a377809f9f32a556ef872febd0021d4ad013aa9f0b7255e98e408d302abefd33a71180b720271835b487ab309e160b06dfe51932120fb84a7ede16b20c53599a11071592109e10260f265ee60d48c62bfe24074020e9b586ce9e9356e68f2ad1a9538258234afe4b83a209f178f45202270eaeaeecaf2ce3100b2c5a714f75f35777a9ebff5ebf47059d2bbf6f3726190216468f2b152673b766225b093f3a2f827c86d6b48b42117fec1d0ac38dd7af700308dcfb02eba821612b16a2c164c47715b9b0c93900893b1aba2ea03765c94d87022db5be06ab338d1912e0936dfe87586d0a8ee49144a6cd2e306abdcb652faa3e0222739deb23154d778b50de75069a4a2cce1208cd1ced3cb4744c9888ce1c2fcd2e66dc31e62d3aa9e423d7275882525e9981f92e84ac85975b8660739407efbe1e34c2249420fde7e17db3096d5b22e83d051d01f0e6e7690dca7d168db338aadf0897fedac10de310db2b1bff762d322935dddbb60c2efb8b15d231fa17b84630371cb275c209f0c4c7d0c68b150ea5cd514122215e3f7fcfb351d69514788d67c2f3c8922581946e3a04bdf1f07f15696ca76eb95b10698bf1188fd882945c57657515889d042a6fc45d38cbc943540c4f0f6d1c45a1574c81f3e42d1eb8702328b729909adee8a5cfed7c79d54627d1fd389af941d878376f7927b9830ca659bf9ab18c5ca5192d52d02723008728d03701b8ab3e1c4a3109409ec0b13df334c7deec3523eeef4c97b5603e643de3a647b873f4c1b47fbfc6586ba66724f112e51fc93839648005043620aa3ce458e246d77977b19c53d98e3e812de006afc1a79744df236582943631d04cc02941ac4be500e4ed9fb9e3e7cc187b1c4050fad1d9d09d5fd70d5d01d615b439d8c0015d2eb10398bcdbf8c4b2bd559dbe4c288a186aed3f86f608da4d582e120c4a896e015e2241900d1daeccd05db968852677c71d752bec46de9962174b46f980e8cc603654daf8b98a3ee92dac066033954164a89568b70b1780c2ce2410b2f816dbeddb2cd463e0c8f21a52cf6427d9647a6fd4bafa8fb4cd4d47ac057b0160bee86c6b2fb8adce214c2bcdda277512200adf0eaa5d2114a2c077b009836a68ec254bfe56f51d147b9afe2ddd9cb917c0c2de19d81b7b8fd9f4574f51fa1207630dc13976f4d7587c962f761af267de71f3909a576e6bedaf6311633910d291ac292c467cc8331ef577aef7646a5d949322fa0367a49f20597a13def53136ee31610395e3e48d291fd8f58504374031fe9dcfba5e06086ebcf01a9106f6a4d6e16e19e4c5bb893f7da79419c94eca31a384be6fa1747284dee0fc3bbc8b1b860172c10b29c1594bb8c747d7fe05827358ff2160f49050001625ffe2e880bd7fc26cd0ffd89750745379a8e862816e08a5a2008043921ab6a4976064ac18f7ee37b6628bc0127d8d5ebd3548e41d8881a082d86f20b32e33094f15a0e6ea6074b08c6cd28142de94713451640a55985051f5577eb54572699d838cb34a79c8939e981c0c277d06a6e2ce69ccb74f8a691ff08f81d8b99e6a86223d29a2b7c8e7b041aba44ea678ae654277f7e91cbfa79158b989164a3d549d9f4feb0cc43169699c13e321fe3f4b94258c75d198ff9184269cd6986c55409e07528c93f64942c6c283ce3917b4bf4c3be2fe3173c8c38cccb35f1fbda0ca88b35a599c0678cb22aa8eabea8249dbd2e4f849fffe69803d299e435ebcd7df95854003d8eda17a74d98b4be0e62d45d7fe48c06a6f464a14f8e0570077cc631279092802a89823f031eef5e1028a6d6fdbd502869a731ee7d28b4d6c71b419462a30d31442d3ee444ffbcbd16d558c9000c97e949c2b1f9d6f6d8db7b9131ebd963620d3fc8595278d6f8fdf49084325373196d53e64142fa5a23eccd6ef908c4d80b8b3e6cc334b7f7012103a3682e4678e9b518163d262a39a2c1a69bf88514c52b7ccd7cc8dc80e71f7c2ec0701cff982573eb0c2c4daeb47fa0b586f4451c10d1da2e5d182b03dd067a5e971b3a6138ca6667aaf853d2ac03b80a1d5870905f2cfb6c78ec3c3719c02f973d638a0f973424a2b0f2b0023f136d60092fe15fba4bc180b9176bd0ff576e053f1af6939fe9ca256203ffaeb3e569f09774d2a6cbf91873e56651f4d6ff77e0b5374b0a1a201d7e523604e0247644544cc571d48c458a4f96f45580b";
0d37ae3a 1155 UniValue obj(UniValue::VOBJ);
cff6f0ac 1156 obj.push_back(Pair("rawtxn", raw));
06c19063 1157
cff6f0ac
S
1158 // we have the spending key for the dummy recipient zaddr1
1159 std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 0.0005, "ABCD") };
06c19063 1160
072099d7 1161 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, {}, recipients, 1) );
cff6f0ac
S
1162 std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
1163 TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
06c19063 1164
cff6f0ac
S
1165 // Enable test mode so tx is not sent
1166 static_cast<AsyncRPCOperation_sendmany *>(operation.get())->testmode = true;
06c19063 1167
da5e7e51
S
1168 // Pretend that the operation completed successfully
1169 proxy.set_state(OperationStatus::SUCCESS);
cff6f0ac 1170
da5e7e51 1171 // Verify test mode is returning output (since no input taddrs, signed and unsigned are the same).
cff6f0ac 1172 BOOST_CHECK_NO_THROW( proxy.sign_send_raw_transaction(obj) );
0d37ae3a
JG
1173 UniValue result = operation->getResult();
1174 BOOST_CHECK(!result.isNull());
1175 UniValue resultObj = result.get_obj();
da5e7e51
S
1176 std::string hex = find_value(resultObj, "hex").get_str();
1177 BOOST_CHECK_EQUAL(hex, raw);
cff6f0ac 1178 }
06c19063
S
1179
1180
7b79275e
S
1181 // Test the perform_joinsplit methods.
1182 {
1183 // Dummy input so the operation object can be instantiated.
1184 std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 0.0005, "ABCD") };
06c19063 1185
072099d7 1186 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(mtx, zaddr1, {}, recipients, 1) );
7b79275e 1187 std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
06c19063 1188 TEST_FRIEND_AsyncRPCOperation_sendmany proxy(ptr);
7b79275e
S
1189
1190 // Enable test mode so tx is not sent and proofs are not generated
1191 static_cast<AsyncRPCOperation_sendmany *>(operation.get())->testmode = true;
06c19063
S
1192
1193 AsyncJoinSplitInfo info;
7b79275e
S
1194 std::vector<boost::optional < ZCIncrementalWitness>> witnesses;
1195 uint256 anchor;
1196 try {
1197 proxy.perform_joinsplit(info, witnesses, anchor);
1198 } catch (const std::runtime_error & e) {
1199 BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos);
1200 }
1201
1202 try {
1203 std::vector<JSOutPoint> v;
1204 proxy.perform_joinsplit(info, v);
1205 } catch (const std::runtime_error & e) {
1206 BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos);
1207 }
1208
b230fe68 1209 info.notes.push_back(SproutNote());
7b79275e
S
1210 try {
1211 proxy.perform_joinsplit(info);
1212 } catch (const std::runtime_error & e) {
1213 BOOST_CHECK( string(e.what()).find("number of notes")!= string::npos);
1214 }
06c19063 1215
7b79275e
S
1216 info.notes.clear();
1217 info.vjsin.push_back(JSInput());
1218 info.vjsin.push_back(JSInput());
1219 info.vjsin.push_back(JSInput());
1220 try {
1221 proxy.perform_joinsplit(info);
1222 } catch (const std::runtime_error & e) {
1223 BOOST_CHECK( string(e.what()).find("unsupported joinsplit input")!= string::npos);
1224 }
06c19063 1225
7b79275e
S
1226 info.vjsin.clear();
1227 try {
1228 proxy.perform_joinsplit(info);
1229 } catch (const std::runtime_error & e) {
bef1b5ce 1230 BOOST_CHECK( string(e.what()).find("error verifying joinsplit")!= string::npos);
7b79275e
S
1231 }
1232 }
06c19063 1233
fc4b127e
S
1234}
1235
60f762a5 1236
73699cea
S
1237/*
1238 * This test covers storing encrypted zkeys in the wallet.
1239 */
1240BOOST_AUTO_TEST_CASE(rpc_wallet_encrypted_wallet_zkeys)
1241{
1242 LOCK2(cs_main, pwalletMain->cs_wallet);
0d37ae3a 1243 UniValue retValue;
73699cea
S
1244 int n = 100;
1245
1246 // wallet should currently be empty
e5eab182 1247 std::set<libzcash::SproutPaymentAddress> addrs;
73699cea
S
1248 pwalletMain->GetPaymentAddresses(addrs);
1249 BOOST_CHECK(addrs.size()==0);
1250
1251 // create keys
1252 for (int i = 0; i < n; i++) {
1253 CallRPC("z_getnewaddress");
1254 }
1255
1256 // Verify we can list the keys imported
1257 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
0d37ae3a 1258 UniValue arr = retValue.get_array();
73699cea
S
1259 BOOST_CHECK(arr.size() == n);
1260
d8e06e3f
JG
1261 // Verify that the wallet encryption RPC is disabled
1262 BOOST_CHECK_THROW(CallRPC("encryptwallet passphrase"), runtime_error);
1263
82bd9ee8 1264 // Encrypt the wallet (we can't call RPC encryptwallet as that shuts down node)
73699cea
S
1265 SecureString strWalletPass;
1266 strWalletPass.reserve(100);
1267 strWalletPass = "hello";
6be367ea
S
1268
1269 boost::filesystem::current_path(GetArg("-datadir","/tmp/thisshouldnothappen"));
73699cea 1270 BOOST_CHECK(pwalletMain->EncryptWallet(strWalletPass));
06c19063 1271
73699cea
S
1272 // Verify we can still list the keys imported
1273 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
1274 arr = retValue.get_array();
1275 BOOST_CHECK(arr.size() == n);
06c19063 1276
73699cea
S
1277 // Try to add a new key, but we can't as the wallet is locked
1278 BOOST_CHECK_THROW(CallRPC("z_getnewaddress"), runtime_error);
06c19063 1279
73699cea
S
1280 // We can't call RPC walletpassphrase as that invokes RPCRunLater which breaks tests.
1281 // So we manually unlock.
1282 BOOST_CHECK(pwalletMain->Unlock(strWalletPass));
06c19063 1283
73699cea
S
1284 // Now add a key
1285 BOOST_CHECK_NO_THROW(CallRPC("z_getnewaddress"));
06c19063 1286
73699cea
S
1287 // Verify the key has been added
1288 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
1289 arr = retValue.get_array();
06c19063 1290 BOOST_CHECK(arr.size() == n+1);
73699cea
S
1291
1292 // We can't simulate over RPC the wallet closing and being reloaded
1293 // but there are tests for this in gtest.
1294}
1295
06c19063 1296
d72c19a6
S
1297BOOST_AUTO_TEST_CASE(rpc_z_listunspent_parameters)
1298{
1299 SelectParams(CBaseChainParams::TESTNET);
1300
1301 LOCK(pwalletMain->cs_wallet);
1302
1303 UniValue retValue;
1304
1305 // too many args
1306 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 2 3 4 5"), runtime_error);
1307
1308 // minconf must be >= 0
1309 BOOST_CHECK_THROW(CallRPC("z_listunspent -1"), runtime_error);
1310
1311 // maxconf must be > minconf
1312 BOOST_CHECK_THROW(CallRPC("z_listunspent 2 1"), runtime_error);
1313
1314 // maxconf must not be out of range
1315 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 9999999999"), runtime_error);
1316
1317 // must be an array of addresses
1318 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 false ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP"), runtime_error);
1319
1320 // address must be string
1321 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 false [123456]"), runtime_error);
1322
1323 // no spending key
1324 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 false [\"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP\"]"), runtime_error);
1325
1326 // allow watch only
1327 BOOST_CHECK_NO_THROW(CallRPC("z_listunspent 1 999 true [\"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP\"]"));
1328
1329 // wrong network, mainnet instead of testnet
1330 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 true [\"zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U\"]"), runtime_error);
1331
1332 // create shielded address so we have the spending key
1333 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress"));
1334 std::string myzaddr = retValue.get_str();
1335
1336 // return empty array for this address
1337 BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listunspent 1 999 false [\"" + myzaddr + "\"]"));
1338 UniValue arr = retValue.get_array();
1339 BOOST_CHECK_EQUAL(0, arr.size());
1340
1341 // duplicate address error
1342 BOOST_CHECK_THROW(CallRPC("z_listunspent 1 999 false [\"" + myzaddr + "\", \"" + myzaddr + "\"]"), runtime_error);
1343}
1344
06c19063
S
1345
1346BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
1347{
1348 SelectParams(CBaseChainParams::TESTNET);
1349
1350 LOCK(pwalletMain->cs_wallet);
1351
1352 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase"), runtime_error);
1353 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase toofewargs"), runtime_error);
c5dabd2b 1354 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase too many args shown here"), runtime_error);
06c19063
S
1355
1356 // bad from address
1357 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1358 "INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1359
1360 // bad from address
1361 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1362 "** tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1363
1364 // bad to address
1365 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1366 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ INVALIDtnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1367
1368 // invalid fee amount, cannot be negative
1369 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1370 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
1371 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1372 "-0.0001"
1373 ), runtime_error);
1374
1375 // invalid fee amount, bigger than MAX_MONEY
1376 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1377 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
1378 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1379 "21000001"
1380 ), runtime_error);
1381
c5dabd2b
S
1382 // invalid limit, must be at least 0
1383 BOOST_CHECK_THROW(CallRPC("z_shieldcoinbase "
1384 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
1385 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1386 "100 -1"
1387 ), runtime_error);
1388
072099d7
S
1389 // Mutable tx containing contextual information we need to build tx
1390 UniValue retValue = CallRPC("getblockcount");
1391 int nHeight = retValue.get_int();
1392 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
1393 if (mtx.nVersion == 1) {
1394 mtx.nVersion = 2;
1395 }
1396
06c19063
S
1397 // Test constructor of AsyncRPCOperation_sendmany
1398 std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP";
1399 std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U";
1400
1401 try {
072099d7 1402 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(mtx, {}, testnetzaddr, -1 ));
06c19063
S
1403 } catch (const UniValue& objError) {
1404 BOOST_CHECK( find_error(objError, "Fee is out of range"));
1405 }
1406
1407 try {
072099d7 1408 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(mtx, {}, testnetzaddr, 1));
06c19063
S
1409 } catch (const UniValue& objError) {
1410 BOOST_CHECK( find_error(objError, "Empty inputs"));
1411 }
1412
1413 // Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
1414 try {
1415 std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
072099d7 1416 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, mainnetzaddr, 1) );
06c19063 1417 } catch (const UniValue& objError) {
80ed13d5 1418 BOOST_CHECK( find_error(objError, "Invalid to address"));
06c19063
S
1419 }
1420
1421}
1422
1423
1424
1425BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
1426{
1427 SelectParams(CBaseChainParams::TESTNET);
1428
1429 LOCK(pwalletMain->cs_wallet);
1430
072099d7
S
1431 // Mutable tx containing contextual information we need to build tx
1432 UniValue retValue = CallRPC("getblockcount");
1433 int nHeight = retValue.get_int();
1434 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
1435 if (mtx.nVersion == 1) {
1436 mtx.nVersion = 2;
1437 }
1438
06c19063
S
1439 // Test that option -mempooltxinputlimit is respected.
1440 mapArgs["-mempooltxinputlimit"] = "1";
1441
1442 // Add keys manually
80ed13d5
JG
1443 auto pa = pwalletMain->GenerateNewZKey();
1444 std::string zaddr = EncodePaymentAddress(pa);
06c19063
S
1445
1446 // Supply 2 inputs when mempool limit is 1
1447 {
1448 std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0}, ShieldCoinbaseUTXO{uint256(),0,0} };
072099d7 1449 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
06c19063
S
1450 operation->main();
1451 BOOST_CHECK(operation->isFailed());
1452 std::string msg = operation->getErrorMessage();
1453 BOOST_CHECK( msg.find("Number of inputs 2 is greater than mempooltxinputlimit of 1") != string::npos);
1454 }
1455
1456 // Insufficient funds
1457 {
1458 std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
072099d7 1459 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
06c19063
S
1460 operation->main();
1461 BOOST_CHECK(operation->isFailed());
1462 std::string msg = operation->getErrorMessage();
1463 BOOST_CHECK( msg.find("Insufficient coinbase funds") != string::npos);
1464 }
1465
1466 // Test the perform_joinsplit methods.
1467 {
1468 // Dummy input so the operation object can be instantiated.
1469 std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,100000} };
072099d7 1470 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(mtx, inputs, zaddr) );
06c19063
S
1471 std::shared_ptr<AsyncRPCOperation_shieldcoinbase> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_shieldcoinbase> (operation);
1472 TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
1473 static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
1474
1475 ShieldCoinbaseJSInfo info;
1476 info.vjsin.push_back(JSInput());
1477 info.vjsin.push_back(JSInput());
1478 info.vjsin.push_back(JSInput());
1479 try {
1480 proxy.perform_joinsplit(info);
1481 } catch (const std::runtime_error & e) {
1482 BOOST_CHECK( string(e.what()).find("unsupported joinsplit input")!= string::npos);
1483 }
1484
1485 info.vjsin.clear();
1486 try {
1487 proxy.perform_joinsplit(info);
1488 } catch (const std::runtime_error & e) {
bef1b5ce 1489 BOOST_CHECK( string(e.what()).find("error verifying joinsplit")!= string::npos);
06c19063
S
1490 }
1491 }
1492
1493}
1494
1495
6e9c7629
JG
1496BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
1497{
1498 SelectParams(CBaseChainParams::TESTNET);
1499
1500 LOCK(pwalletMain->cs_wallet);
1501
1502 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress"), runtime_error);
1503 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress toofewargs"), runtime_error);
1504 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress just too many args present for this method"), runtime_error);
1505
1506 // bad from address
1507 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1508 "[\"INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1509
1510 // bad from address
1511 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1512 "** tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1513
1514 // bad from address
1515 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1516 "[\"**\"] tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1517
1518 // bad from address
1519 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1520 "tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1521
1522 // bad from address
1523 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1524 "[tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ] tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1525
1526 // bad to address
1527 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1528 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] INVALIDtnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB"), runtime_error);
1529
1530 // duplicate address
1531 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1532 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\", \"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] "
1533 "tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn"
1534 ), runtime_error);
1535
1536 // invalid fee amount, cannot be negative
1537 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1538 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] "
1539 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1540 "-0.0001"
1541 ), runtime_error);
1542
1543 // invalid fee amount, bigger than MAX_MONEY
1544 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1545 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] "
1546 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1547 "21000001"
1548 ), runtime_error);
1549
1550 // invalid transparent limit, must be at least 0
1551 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1552 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] "
1553 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1554 "0.0001 -1"
1555 ), runtime_error);
1556
1557 // invalid shielded limit, must be at least 0
1558 BOOST_CHECK_THROW(CallRPC("z_mergetoaddress "
1559 "[\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] "
1560 "tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
1561 "0.0001 100 -1"
1562 ), runtime_error);
1563
1564 // memo bigger than allowed length of ZC_MEMO_SIZE
1565 std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
1566 std::fill(v.begin(),v.end(), 'A');
1567 std::string badmemo(v.begin(), v.end());
80ed13d5
JG
1568 auto pa = pwalletMain->GenerateNewZKey();
1569 std::string zaddr1 = EncodePaymentAddress(pa);
6e9c7629
JG
1570 BOOST_CHECK_THROW(CallRPC(string("z_mergetoaddress [\"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ\"] ")
1571 + zaddr1 + " 0.0001 100 100 " + badmemo), runtime_error);
1572
1573 // Mutable tx containing contextual information we need to build tx
1574 UniValue retValue = CallRPC("getblockcount");
1575 int nHeight = retValue.get_int();
1576 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
1577
1578 // Test constructor of AsyncRPCOperation_mergetoaddress
1579 MergeToAddressRecipient testnetzaddr(
1580 "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP",
1581 "testnet memo");
1582 MergeToAddressRecipient mainnetzaddr(
1583 "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U",
1584 "mainnet memo");
1585
1586 try {
1587 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(mtx, {}, {}, testnetzaddr, -1 ));
1588 BOOST_FAIL("Should have caused an error");
1589 } catch (const UniValue& objError) {
1590 BOOST_CHECK( find_error(objError, "Fee is out of range"));
1591 }
1592
1593 try {
1594 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(mtx, {}, {}, testnetzaddr, 1));
1595 BOOST_FAIL("Should have caused an error");
1596 } catch (const UniValue& objError) {
1597 BOOST_CHECK( find_error(objError, "No inputs"));
1598 }
1599
1600 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{ COutPoint{uint256(), 0}, 0} };
1601
1602 try {
1603 MergeToAddressRecipient badaddr("", "memo");
1604 std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, badaddr, 1));
1605 BOOST_FAIL("Should have caused an error");
1606 } catch (const UniValue& objError) {
1607 BOOST_CHECK( find_error(objError, "Recipient parameter missing"));
1608 }
1609
1610 // Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
1611 try {
1612 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{ COutPoint{uint256(), 0}, 0} };
1613 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, mainnetzaddr, 1) );
1614 BOOST_FAIL("Should have caused an error");
1615 } catch (const UniValue& objError) {
80ed13d5 1616 BOOST_CHECK( find_error(objError, "Invalid recipient address"));
6e9c7629
JG
1617 }
1618}
1619
1620
1621// TODO: test private methods
1622BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_internals)
1623{
1624 SelectParams(CBaseChainParams::TESTNET);
1625
1626 LOCK(pwalletMain->cs_wallet);
1627
1628 // Mutable tx containing contextual information we need to build tx
1629 UniValue retValue = CallRPC("getblockcount");
1630 int nHeight = retValue.get_int();
1631 CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), nHeight + 1);
1632
1633 // Test that option -mempooltxinputlimit is respected.
1634 mapArgs["-mempooltxinputlimit"] = "1";
1635
1636 // Add keys manually
1637 BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
1638 MergeToAddressRecipient taddr1(retValue.get_str(), "");
80ed13d5
JG
1639 auto pa = pwalletMain->GenerateNewZKey();
1640 MergeToAddressRecipient zaddr1(EncodePaymentAddress(pa), "DEADBEEF");
6e9c7629
JG
1641
1642 // Supply 2 inputs when mempool limit is 1
1643 {
1644 std::vector<MergeToAddressInputUTXO> inputs = {
1645 MergeToAddressInputUTXO{COutPoint{uint256(),0},0},
1646 MergeToAddressInputUTXO{COutPoint{uint256(),0},0}
1647 };
1648 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, zaddr1) );
1649 operation->main();
1650 BOOST_CHECK(operation->isFailed());
1651 std::string msg = operation->getErrorMessage();
1652 BOOST_CHECK( msg.find("Number of transparent inputs 2 is greater than mempooltxinputlimit of 1") != string::npos);
1653 }
1654
1655 // Insufficient funds
1656 {
1657 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{COutPoint{uint256(),0},0} };
1658 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, zaddr1) );
1659 operation->main();
1660 BOOST_CHECK(operation->isFailed());
1661 std::string msg = operation->getErrorMessage();
1662 BOOST_CHECK( msg.find("Insufficient funds, have 0.00 and miners fee is 0.0001") != string::npos);
1663 }
1664
1665 // get_memo_from_hex_string())
1666 {
1667 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{COutPoint{uint256(),0},100000} };
1668 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, zaddr1) );
1669 std::shared_ptr<AsyncRPCOperation_mergetoaddress> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_mergetoaddress> (operation);
1670 TEST_FRIEND_AsyncRPCOperation_mergetoaddress proxy(ptr);
1671
1672 std::string memo = "DEADBEEF";
a6bbb26e 1673 std::array<unsigned char, ZC_MEMO_SIZE> array = proxy.get_memo_from_hex_string(memo);
6e9c7629
JG
1674 BOOST_CHECK_EQUAL(array[0], 0xDE);
1675 BOOST_CHECK_EQUAL(array[1], 0xAD);
1676 BOOST_CHECK_EQUAL(array[2], 0xBE);
1677 BOOST_CHECK_EQUAL(array[3], 0xEF);
1678 for (int i=4; i<ZC_MEMO_SIZE; i++) {
1679 BOOST_CHECK_EQUAL(array[i], 0x00); // zero padding
1680 }
1681
1682 // memo is longer than allowed
1683 std::vector<char> v (2 * (ZC_MEMO_SIZE+1));
1684 std::fill(v.begin(),v.end(), 'A');
1685 std::string bigmemo(v.begin(), v.end());
1686
1687 try {
1688 proxy.get_memo_from_hex_string(bigmemo);
1689 BOOST_FAIL("Should have caused an error");
1690 } catch (const UniValue& objError) {
1691 BOOST_CHECK( find_error(objError, "too big"));
1692 }
1693
1694 // invalid hexadecimal string
1695 std::fill(v.begin(),v.end(), '@'); // not a hex character
1696 std::string badmemo(v.begin(), v.end());
1697
1698 try {
1699 proxy.get_memo_from_hex_string(badmemo);
1700 BOOST_FAIL("Should have caused an error");
1701 } catch (const UniValue& objError) {
1702 BOOST_CHECK( find_error(objError, "hexadecimal format"));
1703 }
1704
1705 // odd length hexadecimal string
1706 std::fill(v.begin(),v.end(), 'A');
1707 v.resize(v.size() - 1);
1708 assert(v.size() %2 == 1); // odd length
1709 std::string oddmemo(v.begin(), v.end());
1710 try {
1711 proxy.get_memo_from_hex_string(oddmemo);
1712 BOOST_FAIL("Should have caused an error");
1713 } catch (const UniValue& objError) {
1714 BOOST_CHECK( find_error(objError, "hexadecimal format"));
1715 }
1716 }
1717
1718 // Test the perform_joinsplit methods.
1719 {
1720 // Dummy input so the operation object can be instantiated.
1721 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{COutPoint{uint256(),0},100000} };
1722 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, zaddr1) );
1723 std::shared_ptr<AsyncRPCOperation_mergetoaddress> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_mergetoaddress> (operation);
1724 TEST_FRIEND_AsyncRPCOperation_mergetoaddress proxy(ptr);
1725
1726 // Enable test mode so tx is not sent and proofs are not generated
1727 static_cast<AsyncRPCOperation_sendmany *>(operation.get())->testmode = true;
1728
1729 MergeToAddressJSInfo info;
1730 std::vector<boost::optional < ZCIncrementalWitness>> witnesses;
1731 uint256 anchor;
1732 try {
1733 proxy.perform_joinsplit(info, witnesses, anchor);
1734 BOOST_FAIL("Should have caused an error");
1735 } catch (const std::runtime_error & e) {
1736 BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos);
1737 }
1738
1739 try {
1740 std::vector<JSOutPoint> v;
1741 proxy.perform_joinsplit(info, v);
1742 BOOST_FAIL("Should have caused an error");
1743 } catch (const std::runtime_error & e) {
1744 BOOST_CHECK( string(e.what()).find("anchor is null")!= string::npos);
1745 }
1746
b230fe68 1747 info.notes.push_back(SproutNote());
6e9c7629
JG
1748 try {
1749 proxy.perform_joinsplit(info);
1750 BOOST_FAIL("Should have caused an error");
1751 } catch (const std::runtime_error & e) {
1752 BOOST_CHECK( string(e.what()).find("number of notes")!= string::npos);
1753 }
1754
1755 info.notes.clear();
1756 info.vjsin.push_back(JSInput());
1757 info.vjsin.push_back(JSInput());
1758 info.vjsin.push_back(JSInput());
1759 try {
1760 proxy.perform_joinsplit(info);
1761 BOOST_FAIL("Should have caused an error");
1762 } catch (const std::runtime_error & e) {
1763 BOOST_CHECK( string(e.what()).find("unsupported joinsplit input")!= string::npos);
1764 }
1765
1766 info.vjsin.clear();
1767 try {
1768 proxy.perform_joinsplit(info);
1769 BOOST_FAIL("Should have caused an error");
1770 } catch (const std::runtime_error & e) {
1771 BOOST_CHECK( string(e.what()).find("error verifying joinsplit")!= string::npos);
1772 }
1773 }
1774
1775 // Raw joinsplit is a zaddr->zaddr
1776 {
1777 std::string raw = "020000000000000000000100000000000000001027000000000000183a0d4c46c369078705e39bcfebee59a978dbd210ce8de3efc9555a03fbabfd3cea16693d730c63850d7e48ccde79854c19adcb7e9dcd7b7d18805ee09083f6b16e1860729d2d4a90e2f2acd009cf78b5eb0f4a6ee4bdb64b1262d7ce9eb910c460b02022991e968d0c50ee44908e4ccccbc591d0053bcca154dd6d6fc400a29fa686af4682339832ccea362a62aeb9df0d5aa74f86a1e75ac0f48a8ccc41e0a940643c6c33e1d09223b0a46eaf47a1bb4407cfc12b1dcf83a29c0cef51e45c7876ca5b9e5bae86d92976eb3ef68f29cd29386a8be8451b50f82bf9da10c04651868655194da8f6ed3d241bb5b5ff93a3e2bbe44644544d88bcde5cc35978032ee92699c7a61fcbb395e7583f47e698c4d53ede54f956629400bf510fb5e22d03158cc10bdcaaf29e418ef18eb6480dd9c8b9e2a377809f9f32a556ef872febd0021d4ad013aa9f0b7255e98e408d302abefd33a71180b720271835b487ab309e160b06dfe51932120fb84a7ede16b20c53599a11071592109e10260f265ee60d48c62bfe24074020e9b586ce9e9356e68f2ad1a9538258234afe4b83a209f178f45202270eaeaeecaf2ce3100b2c5a714f75f35777a9ebff5ebf47059d2bbf6f3726190216468f2b152673b766225b093f3a2f827c86d6b48b42117fec1d0ac38dd7af700308dcfb02eba821612b16a2c164c47715b9b0c93900893b1aba2ea03765c94d87022db5be06ab338d1912e0936dfe87586d0a8ee49144a6cd2e306abdcb652faa3e0222739deb23154d778b50de75069a4a2cce1208cd1ced3cb4744c9888ce1c2fcd2e66dc31e62d3aa9e423d7275882525e9981f92e84ac85975b8660739407efbe1e34c2249420fde7e17db3096d5b22e83d051d01f0e6e7690dca7d168db338aadf0897fedac10de310db2b1bff762d322935dddbb60c2efb8b15d231fa17b84630371cb275c209f0c4c7d0c68b150ea5cd514122215e3f7fcfb351d69514788d67c2f3c8922581946e3a04bdf1f07f15696ca76eb95b10698bf1188fd882945c57657515889d042a6fc45d38cbc943540c4f0f6d1c45a1574c81f3e42d1eb8702328b729909adee8a5cfed7c79d54627d1fd389af941d878376f7927b9830ca659bf9ab18c5ca5192d52d02723008728d03701b8ab3e1c4a3109409ec0b13df334c7deec3523eeef4c97b5603e643de3a647b873f4c1b47fbfc6586ba66724f112e51fc93839648005043620aa3ce458e246d77977b19c53d98e3e812de006afc1a79744df236582943631d04cc02941ac4be500e4ed9fb9e3e7cc187b1c4050fad1d9d09d5fd70d5d01d615b439d8c0015d2eb10398bcdbf8c4b2bd559dbe4c288a186aed3f86f608da4d582e120c4a896e015e2241900d1daeccd05db968852677c71d752bec46de9962174b46f980e8cc603654daf8b98a3ee92dac066033954164a89568b70b1780c2ce2410b2f816dbeddb2cd463e0c8f21a52cf6427d9647a6fd4bafa8fb4cd4d47ac057b0160bee86c6b2fb8adce214c2bcdda277512200adf0eaa5d2114a2c077b009836a68ec254bfe56f51d147b9afe2ddd9cb917c0c2de19d81b7b8fd9f4574f51fa1207630dc13976f4d7587c962f761af267de71f3909a576e6bedaf6311633910d291ac292c467cc8331ef577aef7646a5d949322fa0367a49f20597a13def53136ee31610395e3e48d291fd8f58504374031fe9dcfba5e06086ebcf01a9106f6a4d6e16e19e4c5bb893f7da79419c94eca31a384be6fa1747284dee0fc3bbc8b1b860172c10b29c1594bb8c747d7fe05827358ff2160f49050001625ffe2e880bd7fc26cd0ffd89750745379a8e862816e08a5a2008043921ab6a4976064ac18f7ee37b6628bc0127d8d5ebd3548e41d8881a082d86f20b32e33094f15a0e6ea6074b08c6cd28142de94713451640a55985051f5577eb54572699d838cb34a79c8939e981c0c277d06a6e2ce69ccb74f8a691ff08f81d8b99e6a86223d29a2b7c8e7b041aba44ea678ae654277f7e91cbfa79158b989164a3d549d9f4feb0cc43169699c13e321fe3f4b94258c75d198ff9184269cd6986c55409e07528c93f64942c6c283ce3917b4bf4c3be2fe3173c8c38cccb35f1fbda0ca88b35a599c0678cb22aa8eabea8249dbd2e4f849fffe69803d299e435ebcd7df95854003d8eda17a74d98b4be0e62d45d7fe48c06a6f464a14f8e0570077cc631279092802a89823f031eef5e1028a6d6fdbd502869a731ee7d28b4d6c71b419462a30d31442d3ee444ffbcbd16d558c9000c97e949c2b1f9d6f6d8db7b9131ebd963620d3fc8595278d6f8fdf49084325373196d53e64142fa5a23eccd6ef908c4d80b8b3e6cc334b7f7012103a3682e4678e9b518163d262a39a2c1a69bf88514c52b7ccd7cc8dc80e71f7c2ec0701cff982573eb0c2c4daeb47fa0b586f4451c10d1da2e5d182b03dd067a5e971b3a6138ca6667aaf853d2ac03b80a1d5870905f2cfb6c78ec3c3719c02f973d638a0f973424a2b0f2b0023f136d60092fe15fba4bc180b9176bd0ff576e053f1af6939fe9ca256203ffaeb3e569f09774d2a6cbf91873e56651f4d6ff77e0b5374b0a1a201d7e523604e0247644544cc571d48c458a4f96f45580b";
1778 UniValue obj(UniValue::VOBJ);
1779 obj.push_back(Pair("rawtxn", raw));
1780
1781 // we have the spending key for the dummy recipient zaddr1
1782 std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{COutPoint{uint256(),0},100000} };
1783 std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(mtx, inputs, {}, zaddr1) );
1784 std::shared_ptr<AsyncRPCOperation_mergetoaddress> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_mergetoaddress> (operation);
1785 TEST_FRIEND_AsyncRPCOperation_mergetoaddress proxy(ptr);
1786
1787 // Enable test mode so tx is not sent
1788 static_cast<AsyncRPCOperation_sendmany *>(operation.get())->testmode = true;
1789
1790 // Pretend that the operation completed successfully
1791 proxy.set_state(OperationStatus::SUCCESS);
1792
1793 // Verify test mode is returning output (since no input taddrs, signed and unsigned are the same).
1794 BOOST_CHECK_NO_THROW( proxy.sign_send_raw_transaction(obj) );
1795 UniValue result = operation->getResult();
1796 BOOST_CHECK(!result.isNull());
1797 UniValue resultObj = result.get_obj();
1798 std::string hex = find_value(resultObj, "hex").get_str();
1799 BOOST_CHECK_EQUAL(hex, raw);
1800 }
1801}
1802
1803
b922924d 1804BOOST_AUTO_TEST_SUITE_END()
This page took 0.460478 seconds and 4 git commands to generate.