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