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