Line data Source code
1 : // Copyright (c) 2016-2020 The ZCash developers
2 : // Copyright (c) 2020-2022 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "fs.h"
7 :
8 : #include "wallet/test/wallet_test_fixture.h"
9 : #include "test/librust/utiltest.h"
10 :
11 : #include "rpc/server.h"
12 :
13 : #include "core_io.h"
14 : #include "key_io.h"
15 : #include "consensus/merkle.h"
16 : #include "wallet/wallet.h"
17 : #include "wallet/walletutil.h"
18 :
19 : #include "sapling/key_io_sapling.h"
20 : #include "sapling/address.h"
21 : #include "sapling/sapling_operation.h"
22 :
23 : #include <unordered_set>
24 :
25 : #include <boost/test/unit_test.hpp>
26 :
27 : #include <univalue.h>
28 :
29 :
30 : extern UniValue CallRPC(std::string args); // Implemented in rpc_tests.cpp
31 :
32 : namespace {
33 :
34 : /** Set the working directory for the duration of the scope. */
35 : class PushCurrentDirectory {
36 : public:
37 : explicit PushCurrentDirectory(const std::string &new_cwd)
38 : : old_cwd(fs::current_path()) {
39 : fs::current_path(new_cwd);
40 : }
41 :
42 : ~PushCurrentDirectory() {
43 : fs::current_path(old_cwd);
44 : }
45 : private:
46 : fs::path old_cwd;
47 : };
48 :
49 : }
50 :
51 : BOOST_FIXTURE_TEST_SUITE(sapling_rpc_wallet_tests, WalletTestingSetup)
52 :
53 : /**
54 : * This test covers RPC command validateaddress
55 : */
56 :
57 2 : BOOST_AUTO_TEST_CASE(rpc_wallet_sapling_validateaddress)
58 : {
59 1 : SelectParams(CBaseChainParams::MAIN);
60 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
61 :
62 1 : UniValue retValue;
63 :
64 : // Check number of args
65 3 : BOOST_CHECK_THROW(CallRPC("validateaddress"), std::runtime_error);
66 3 : BOOST_CHECK_THROW(CallRPC("validateaddress toomany args"), std::runtime_error);
67 :
68 : // Wallet should be empty:
69 2 : std::set<libzcash::SaplingPaymentAddress> addrs;
70 1 : m_wallet.GetSaplingPaymentAddresses(addrs);
71 2 : BOOST_CHECK(addrs.size()==0);
72 :
73 : // This Sapling address is not valid, it belongs to another network
74 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("validateaddress ptestsapling1nrn6exksuqtpld9gu6fwdz4hwg54h2x37gutdds89pfyg6mtjf63km45a8eare5qla45cj75vs8"));
75 2 : UniValue resultObj = retValue.get_obj();
76 1 : bool b = find_value(resultObj, "isvalid").get_bool();
77 1 : BOOST_CHECK_EQUAL(b, false);
78 :
79 : // This Sapling address is valid, but the spending key is not in this wallet
80 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("validateaddress ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej"));
81 1 : resultObj = retValue.get_obj();
82 1 : b = find_value(resultObj, "isvalid").get_bool();
83 1 : BOOST_CHECK_EQUAL(b, true);
84 1 : b = find_value(resultObj, "ismine").get_bool();
85 1 : BOOST_CHECK_EQUAL(b, false);
86 1 : BOOST_CHECK_EQUAL(find_value(resultObj, "diversifier").get_str(), "e1fd627f1b9a8e4c7e6657");
87 2 : BOOST_CHECK_EQUAL(find_value(resultObj, "diversifiedtransmissionkey").get_str(), "d35e0d0897edbd3cf02b3d2327622a14c685534dbd2d3f4f4fa3e0e56cc2f008");
88 :
89 1 : vpwallets.erase(vpwallets.begin());
90 1 : }
91 :
92 2 : BOOST_AUTO_TEST_CASE(rpc_wallet_getbalance)
93 : {
94 1 : {
95 1 : LOCK(m_wallet.cs_wallet);
96 1 : m_wallet.SetMinVersion(FEATURE_SAPLING);
97 1 : m_wallet.SetupSPKM(false);
98 : }
99 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
100 :
101 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance too many args"), std::runtime_error);
102 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance invalidaddress"), std::runtime_error);
103 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab"), std::runtime_error);
104 3 : BOOST_CHECK_NO_THROW(CallRPC("getshieldbalance ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej"));
105 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej -1"), std::runtime_error);
106 3 : BOOST_CHECK_NO_THROW(CallRPC("getshieldbalance ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej 0"));
107 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1"), std::runtime_error);
108 3 : BOOST_CHECK_NO_THROW(CallRPC("getshieldbalance *"));
109 3 : BOOST_CHECK_NO_THROW(CallRPC("getshieldbalance * 6"));
110 3 : BOOST_CHECK_THROW(CallRPC("getshieldbalance * -1"), std::runtime_error);
111 :
112 3 : BOOST_CHECK_THROW(CallRPC("listreceivedbyshieldaddress too many args"), std::runtime_error);
113 : // negative minconf not allowed
114 3 : BOOST_CHECK_THROW(CallRPC("listreceivedbyshieldaddress DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ -1"), std::runtime_error);
115 : // invalid zaddr, taddr not allowed
116 3 : BOOST_CHECK_THROW(CallRPC("listreceivedbyshieldaddress DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ 0"), std::runtime_error);
117 : // don't have the spending key
118 3 : BOOST_CHECK_THROW(CallRPC("listreceivedbyshieldaddress ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej 1"), std::runtime_error);
119 :
120 1 : vpwallets.erase(vpwallets.begin());
121 1 : }
122 :
123 2 : BOOST_AUTO_TEST_CASE(rpc_wallet_sapling_importkey_paymentaddress)
124 : {
125 1 : {
126 1 : LOCK(m_wallet.cs_wallet);
127 1 : m_wallet.SetMinVersion(FEATURE_SAPLING);
128 1 : m_wallet.SetupSPKM(false);
129 : }
130 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
131 :
132 2 : auto testAddress = [](const std::string& key) {
133 1 : UniValue ret;
134 3 : BOOST_CHECK_NO_THROW(ret = CallRPC("importsaplingkey " + key));
135 3 : auto defaultAddr = find_value(ret, "address").get_str();
136 3 : BOOST_CHECK_NO_THROW(ret = CallRPC("validateaddress " + defaultAddr));
137 1 : ret = ret.get_obj();
138 1 : BOOST_CHECK_EQUAL(true, find_value(ret, "isvalid").get_bool());
139 1 : BOOST_CHECK_EQUAL(true, find_value(ret, "ismine").get_bool());
140 1 : };
141 :
142 1 : testAddress("p-secret-spending-key-main1qv09u0wlqqqqpqp75kpmat6l3ce29k"
143 : "g9half9epsm80wya5n92j4d8mtmesrukzxlsmm2f74v3nvvx2shxy4z5v5x39p"
144 : "eelsy5y2uxmvadaku8crd20q6vt8cvd68wp08cjyec6cku0dcf5lc9c2kykg5c"
145 : "8uqmqlx8ccxpsw7ae243quhwr0zyekrrc520gs9z0j8pm954c3cev2yvp29vrc"
146 : "0zweu7stxkwhp593p6drheps9uhz9pvkrfgvpxzte8d60uzw0qxadnsc77tcd");
147 :
148 1 : vpwallets.erase(vpwallets.begin());
149 1 : }
150 :
151 : /*
152 : * This test covers RPC commands listsaplingaddresses, importsaplingkey, exportsaplingkey
153 : */
154 2 : BOOST_AUTO_TEST_CASE(rpc_wallet_sapling_importexport)
155 : {
156 1 : {
157 1 : LOCK(m_wallet.cs_wallet);
158 1 : m_wallet.SetMinVersion(FEATURE_SAPLING);
159 1 : m_wallet.SetupSPKM(false);
160 : }
161 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
162 :
163 1 : UniValue retValue;
164 1 : int n1 = 1000; // number of times to import/export
165 1 : int n2 = 1000; // number of addresses to create and list
166 :
167 : // error if no args
168 3 : BOOST_CHECK_THROW(CallRPC("importsaplingkey"), std::runtime_error);
169 3 : BOOST_CHECK_THROW(CallRPC("exportsaplingkey"), std::runtime_error);
170 :
171 : // error if too many args
172 3 : BOOST_CHECK_THROW(CallRPC("importsaplingkey way too many args"), std::runtime_error);
173 3 : BOOST_CHECK_THROW(CallRPC("exportsaplingkey toomany args"), std::runtime_error);
174 :
175 : // error if invalid args
176 1 : auto m = GetTestMasterSaplingSpendingKey();
177 4 : std::string prefix = std::string("importsaplingkey ") + KeyIO::EncodeSpendingKey(m) + " yes ";
178 3 : BOOST_CHECK_THROW(CallRPC(prefix + "-1"), std::runtime_error);
179 3 : BOOST_CHECK_THROW(CallRPC(prefix + "2147483647"), std::runtime_error); // allowed, but > height of active chain tip
180 3 : BOOST_CHECK_THROW(CallRPC(prefix + "2147483648"), std::runtime_error); // not allowed, > int32 used for nHeight
181 3 : BOOST_CHECK_THROW(CallRPC(prefix + "100badchars"), std::runtime_error);
182 :
183 : // wallet should currently be empty
184 2 : std::set<libzcash::SaplingPaymentAddress> saplingAddrs;
185 1 : m_wallet.GetSaplingPaymentAddresses(saplingAddrs);
186 2 : BOOST_CHECK(saplingAddrs.empty());
187 :
188 : // verify import and export key
189 1001 : for (int i = 0; i < n1; i++) {
190 : // create a random Sapling key locally
191 1000 : auto testSaplingSpendingKey = m.Derive(i);
192 1000 : auto testSaplingPaymentAddress = testSaplingSpendingKey.DefaultAddress();
193 2000 : std::string testSaplingAddr = KeyIO::EncodePaymentAddress(testSaplingPaymentAddress);
194 2000 : std::string testSaplingKey = KeyIO::EncodeSpendingKey(testSaplingSpendingKey);
195 3000 : BOOST_CHECK_NO_THROW(CallRPC(std::string("importsaplingkey ") + testSaplingKey));
196 3000 : BOOST_CHECK_NO_THROW(retValue = CallRPC(std::string("exportsaplingkey ") + testSaplingAddr));
197 1000 : BOOST_CHECK_EQUAL(retValue.get_str(), testSaplingKey);
198 : }
199 :
200 : // Verify we can list the keys imported
201 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("listshieldaddresses"));
202 2 : UniValue arr = retValue.get_array();
203 2 : BOOST_CHECK((int) arr.size() == n1);
204 :
205 : // Put addresses into a set
206 2 : std::unordered_set<std::string> myaddrs;
207 1001 : for (const UniValue& element : arr.getValues()) {
208 1000 : myaddrs.insert(element.get_str());
209 : }
210 :
211 : // Make new addresses for the set
212 1001 : for (int i=0; i<n2; i++) {
213 2000 : myaddrs.insert(KeyIO::EncodePaymentAddress(m_wallet.GenerateNewSaplingZKey()));
214 : }
215 :
216 : // Verify number of addresses stored in wallet is n1+n2
217 1 : int numAddrs = myaddrs.size();
218 2 : BOOST_CHECK(numAddrs == n1 + n2);
219 1 : m_wallet.GetSaplingPaymentAddresses(saplingAddrs);
220 2 : BOOST_CHECK((int) saplingAddrs.size() == numAddrs);
221 :
222 : // Ask wallet to list addresses
223 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("listshieldaddresses"));
224 1 : arr = retValue.get_array();
225 2 : BOOST_CHECK((int) arr.size() == numAddrs);
226 :
227 : // Create a set from them
228 2 : std::unordered_set<std::string> listaddrs;
229 2001 : for (const UniValue& element : arr.getValues()) {
230 2000 : listaddrs.insert(element.get_str());
231 : }
232 :
233 : // Verify the two sets of addresses are the same
234 2 : BOOST_CHECK((int) listaddrs.size() == numAddrs);
235 2 : BOOST_CHECK(myaddrs == listaddrs);
236 :
237 1 : vpwallets.erase(vpwallets.begin());
238 1 : }
239 :
240 : // Check if address is of given type and spendable from our wallet.
241 1 : void CheckHaveAddr(CWallet& pwallet, const libzcash::PaymentAddress& addr)
242 : {
243 :
244 2 : BOOST_CHECK(IsValidPaymentAddress(addr));
245 1 : auto addr_of_type = boost::get<libzcash::SaplingPaymentAddress>(&addr);
246 1 : BOOST_ASSERT(addr_of_type != nullptr);
247 2 : BOOST_CHECK(pwallet.HaveSpendingKeyForPaymentAddress(*addr_of_type));
248 1 : }
249 :
250 2 : BOOST_AUTO_TEST_CASE(rpc_wallet_getnewshieldaddress)
251 : {
252 1 : {
253 1 : LOCK(m_wallet.cs_wallet);
254 1 : m_wallet.SetMinVersion(FEATURE_SAPLING);
255 1 : m_wallet.SetupSPKM(false);
256 : }
257 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
258 :
259 : // No parameter defaults to sapling address
260 1 : UniValue addr = CallRPC("getnewshieldaddress");
261 1 : CheckHaveAddr(m_wallet, KeyIO::DecodePaymentAddress(addr.get_str()));
262 : // Too many arguments will throw with the help
263 3 : BOOST_CHECK_THROW(CallRPC("getnewshieldaddress many args"), std::runtime_error);
264 :
265 1 : vpwallets.erase(vpwallets.begin());
266 1 : }
267 :
268 2 : BOOST_AUTO_TEST_CASE(rpc_shieldsendmany_parameters)
269 : {
270 1 : {
271 1 : LOCK(m_wallet.cs_wallet);
272 1 : m_wallet.SetMinVersion(FEATURE_SAPLING);
273 1 : m_wallet.SetupSPKM(false);
274 : }
275 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
276 :
277 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany"), std::runtime_error);
278 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany toofewargs"), std::runtime_error);
279 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany just too many args here"), std::runtime_error);
280 :
281 : // bad from address
282 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
283 : "INVALIDDMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ []"), std::runtime_error);
284 : // empty amounts
285 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
286 : "DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ []"), std::runtime_error);
287 :
288 : // don't have the spending key for this address
289 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
290 : "ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej []"), std::runtime_error);
291 :
292 : // duplicate address
293 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
294 : "DDTBEPEaub5sk31mUifiv5nHGXtHGnuAJc "
295 : "[{\"address\":\"DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ\", \"amount\":50.0},"
296 : " {\"address\":\"DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ\", \"amount\":12.0} ]"
297 : ), std::runtime_error);
298 :
299 : // invalid fee amount, cannot be negative
300 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
301 : "DDTBEPEaub5sk31mUifiv5nHGXtHGnuAJc "
302 : "[{\"address\":\"DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ\", \"amount\":50.0}] "
303 : "1 -0.0001"
304 : ), std::runtime_error);
305 :
306 : // invalid fee amount, bigger than MAX_MONEY
307 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
308 : "DDTBEPEaub5sk31mUifiv5nHGXtHGnuAJc "
309 : "[{\"address\":\"DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ\", \"amount\":50.0}] "
310 : "1 21000001"
311 : ), std::runtime_error);
312 :
313 : // fee amount is bigger than sum of outputs
314 3 : BOOST_CHECK_THROW(CallRPC("shieldsendmany "
315 : "DDTBEPEaub5sk31mUifiv5nHGXtHGnuAJc "
316 : "[{\"address\":\"DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ\", \"amount\":50.0}] "
317 : "1 50.00000001"
318 : ), std::runtime_error);
319 :
320 : // memo bigger than allowed length of ZC_MEMO_SIZE
321 1 : std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
322 1 : std::fill(v.begin(),v.end(), 'A');
323 2 : std::string badmemo(v.begin(), v.end());
324 1 : auto pa = m_wallet.GenerateNewSaplingZKey();
325 2 : std::string zaddr1 = KeyIO::EncodePaymentAddress(pa);
326 3 : BOOST_CHECK_THROW(CallRPC(std::string("shieldsendmany DMKU6mc52un1MThGCsnNwAtEvncaTdAuaZ ")
327 : + "[{\"address\":\"" + zaddr1 + "\", \"amount\":123.456}]"), std::runtime_error);
328 :
329 1 : vpwallets.erase(vpwallets.begin());
330 1 : }
331 :
332 : // TODO: test private methods
333 2 : BOOST_AUTO_TEST_CASE(saplingOperationTests)
334 : {
335 1 : {
336 2 : LOCK2(cs_main, m_wallet.cs_wallet);
337 1 : m_wallet.SetupSPKM(false);
338 : }
339 2 : auto consensusParams = Params().GetConsensus();
340 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
341 :
342 1 : UniValue retValue;
343 :
344 : // add keys manually
345 2 : BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewaddress"));
346 1 : const std::string& taddrStr = retValue.get_str();
347 2 : const CTxDestination& taddr1 = DecodeDestination(taddrStr);
348 1 : const auto& zaddr1 = m_wallet.GenerateNewSaplingZKey();
349 2 : std::string ret;
350 :
351 : // there are no utxos to spend
352 1 : {
353 3 : std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, COIN, "DEADBEEF", false) };
354 1 : SaplingOperation operation(consensusParams, &m_wallet);
355 1 : operation.setFromAddress(taddr1);
356 2 : auto res = operation.setRecipients(recipients)->buildAndSend(ret);
357 2 : BOOST_CHECK(!res);
358 4 : BOOST_CHECK(res.getError().find("Insufficient funds, no available UTXO to spend") != std::string::npos);
359 : }
360 :
361 : // minconf cannot be zero when sending from zaddr
362 1 : {
363 3 : std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, COIN, "DEADBEEF", false) };
364 1 : SaplingOperation operation(consensusParams, &m_wallet);
365 1 : operation.setFromAddress(zaddr1);
366 2 : auto res = operation.setRecipients(recipients)->setMinDepth(0)->buildAndSend(ret);
367 2 : BOOST_CHECK(!res);
368 4 : BOOST_CHECK(res.getError().find("Minconf cannot be zero when sending from shielded address") != std::string::npos);
369 : }
370 :
371 : // there are no unspent notes to spend
372 1 : {
373 3 : std::vector<SendManyRecipient> recipients = { SendManyRecipient(taddr1, COIN, false) };
374 1 : SaplingOperation operation(consensusParams, &m_wallet);
375 1 : operation.setFromAddress(zaddr1);
376 2 : auto res = operation.setRecipients(recipients)->buildAndSend(ret);
377 2 : BOOST_CHECK(!res);
378 4 : BOOST_CHECK(res.getError().find("Insufficient funds, no available notes to spend") != std::string::npos);
379 : }
380 :
381 : // GetMemoFromString
382 1 : {
383 1 : std::string memoStr = "Sapling memo!";
384 1 : std::array<unsigned char, ZC_MEMO_SIZE> memo;
385 :
386 2 : BOOST_CHECK(GetMemoFromString(memoStr, memo));
387 1 : BOOST_CHECK_EQUAL(memo[0], 0x53); // S
388 1 : BOOST_CHECK_EQUAL(memo[1], 0x61); // a
389 1 : BOOST_CHECK_EQUAL(memo[2], 0x70); // p
390 1 : BOOST_CHECK_EQUAL(memo[3], 0x6C); // l
391 1 : BOOST_CHECK_EQUAL(memo[4], 0x69); // i
392 1 : BOOST_CHECK_EQUAL(memo[5], 0x6E); // n
393 1 : BOOST_CHECK_EQUAL(memo[6], 0x67); // g
394 1 : BOOST_CHECK_EQUAL(memo[12], 0x21); // !
395 500 : for (int i = 13; i < ZC_MEMO_SIZE; i++) {
396 499 : BOOST_CHECK_EQUAL(memo[i], 0x00); // zero padding
397 : }
398 :
399 : // memo is longer than allowed
400 2 : std::vector<char> v (2 * (ZC_MEMO_SIZE+1));
401 1 : std::fill(v.begin(),v.end(), 'A');
402 2 : std::string bigmemo(v.begin(), v.end());
403 :
404 2 : OperationResult res = GetMemoFromString(bigmemo, memo);
405 2 : BOOST_CHECK(!res);
406 2 : const std::string& errStr = res.getError();
407 2 : BOOST_CHECK(errStr.find("too big") != std::string::npos);
408 : }
409 :
410 1 : vpwallets.erase(vpwallets.begin());
411 1 : }
412 :
413 :
414 2 : BOOST_AUTO_TEST_CASE(rpc_shieldsendmany_taddr_to_sapling)
415 : {
416 1 : {
417 2 : LOCK2(cs_main, m_wallet.cs_wallet);
418 1 : m_wallet.SetupSPKM(false);
419 : }
420 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
421 :
422 2 : UniValue retValue;
423 :
424 : // add keys manually
425 1 : auto res = m_wallet.getNewAddress("");
426 2 : BOOST_CHECK(res);
427 2 : CTxDestination taddr = *res.getObjResult();
428 2 : std::string taddr1 = EncodeDestination(taddr);
429 1 : auto zaddr1 = m_wallet.GenerateNewSaplingZKey();
430 :
431 2 : auto consensusParams = Params().GetConsensus();
432 :
433 : // Add a fake transaction to the wallet
434 2 : CMutableTransaction mtx;
435 1 : mtx.vout.emplace_back(5 * COIN, GetScriptForDestination(taddr));
436 : // Add to wallet and get the updated wtx
437 2 : CWalletTx wtxIn(&m_wallet, MakeTransactionRef(mtx));
438 1 : m_wallet.LoadToWallet(wtxIn);
439 1 : CWalletTx& wtx = m_wallet.mapWallet.at(mtx.GetHash());
440 :
441 : // Fake-mine the transaction
442 1 : BOOST_CHECK_EQUAL(0, chainActive.Height());
443 1 : CBlock block;
444 2 : block.hashPrevBlock = chainActive.Tip()->GetBlockHash();
445 1 : block.vtx.emplace_back(wtx.tx);
446 1 : block.hashMerkleRoot = BlockMerkleRoot(block);
447 1 : auto blockHash = block.GetHash();
448 2 : CBlockIndex fakeIndex {block};
449 1 : fakeIndex.nHeight = 1;
450 1 : BlockMap::iterator mi = mapBlockIndex.emplace(blockHash, &fakeIndex).first;
451 1 : fakeIndex.phashBlock = &((*mi).first);
452 1 : chainActive.SetTip(&fakeIndex);
453 3 : BOOST_CHECK(chainActive.Contains(&fakeIndex));
454 1 : BOOST_CHECK_EQUAL(1, chainActive.Height());
455 2 : m_wallet.BlockConnected(std::make_shared<CBlock>(block), mi->second);
456 2 : BOOST_CHECK_MESSAGE(m_wallet.GetAvailableBalance() > 0, "tx not confirmed");
457 :
458 3 : std::vector<SendManyRecipient> recipients = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD", false) };
459 2 : SaplingOperation operation(consensusParams, &m_wallet);
460 1 : operation.setFromAddress(taddr);
461 2 : BOOST_CHECK(operation.setRecipients(recipients)
462 : ->setMinDepth(0)
463 : ->build());
464 :
465 : // try from auto-selected transparent address
466 3 : std::vector<SendManyRecipient> recipients2 = { SendManyRecipient(zaddr1, 1 * COIN, "ABCD", false) };
467 1 : SaplingOperation operation2(consensusParams, &m_wallet);
468 2 : BOOST_CHECK(operation2.setSelectTransparentCoins(true)
469 : ->setRecipients(recipients2)
470 : ->setMinDepth(0)
471 : ->build());
472 :
473 : // Get the transaction
474 : // Test mode does not send the transaction to the network.
475 2 : auto hexTx = EncodeHexTx(operation.getFinalTx());
476 3 : CDataStream ss(ParseHex(hexTx), SER_NETWORK, PROTOCOL_VERSION);
477 2 : CTransaction tx(deserialize, ss);
478 1 : BOOST_ASSERT(!tx.sapData->vShieldedOutput.empty());
479 :
480 : // We shouldn't be able to decrypt with the empty ovk
481 3 : BOOST_CHECK(!libzcash::AttemptSaplingOutDecryption(
482 : tx.sapData->vShieldedOutput[0].outCiphertext,
483 : uint256(),
484 : tx.sapData->vShieldedOutput[0].cv,
485 : tx.sapData->vShieldedOutput[0].cmu,
486 : tx.sapData->vShieldedOutput[0].ephemeralKey));
487 :
488 3 : BOOST_CHECK(libzcash::AttemptSaplingOutDecryption(
489 : tx.sapData->vShieldedOutput[0].outCiphertext,
490 : m_wallet.GetSaplingScriptPubKeyMan()->getCommonOVK(),
491 : tx.sapData->vShieldedOutput[0].cv,
492 : tx.sapData->vShieldedOutput[0].cmu,
493 : tx.sapData->vShieldedOutput[0].ephemeralKey));
494 :
495 : // Tear down
496 1 : chainActive.SetTip(nullptr);
497 1 : mapBlockIndex.erase(blockHash);
498 1 : vpwallets.erase(vpwallets.begin());
499 1 : }
500 :
501 2 : BOOST_AUTO_TEST_CASE(rpc_listshieldunspent_parameters)
502 : {
503 1 : {
504 1 : LOCK(m_wallet.cs_wallet);
505 1 : m_wallet.SetupSPKM(false);
506 : }
507 1 : vpwallets.insert(vpwallets.begin(), &m_wallet);
508 :
509 1 : UniValue retValue;
510 :
511 : // too many args
512 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 2 3 4 5"), std::runtime_error);
513 :
514 : // minconf must be >= 0
515 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent -1"), std::runtime_error);
516 :
517 : // maxconf must be > minconf
518 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 2 1"), std::runtime_error);
519 :
520 : // maxconf must not be out of range
521 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 9999999999"), std::runtime_error);
522 :
523 : // must be an array of addresses
524 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 999 false ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej"), std::runtime_error);
525 :
526 : // address must be string
527 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 999 false [123456]"), std::runtime_error);
528 :
529 : // no spending key
530 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 999 false [\"ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej\"]"), std::runtime_error);
531 :
532 : // allow watch only
533 3 : BOOST_CHECK_NO_THROW(CallRPC("listshieldunspent 1 999 true [\"ps1u87kylcmn28yclnx2uy0psnvuhs2xn608ukm6n2nshrpg2nzyu3n62ls8j77m9cgp40dx40evej\"]"));
534 :
535 : // wrong network, testnet/regtest instead of mainnet
536 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 999 true [\"ptestsapling1wpurflqllgkcs48m46yu9ktlfe3ahndely20dpaanqq3lw9l5xw7yfehst68yclvlpz7x8cltxe\"]"), std::runtime_error);
537 :
538 : // create shielded address so we have the spending key
539 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("getnewshieldaddress"));
540 2 : std::string myzaddr = retValue.get_str();
541 :
542 : // return empty array for this address
543 3 : BOOST_CHECK_NO_THROW(retValue = CallRPC("listshieldunspent 1 999 false [\"" + myzaddr + "\"]"));
544 2 : UniValue arr = retValue.get_array();
545 1 : BOOST_CHECK_EQUAL(0, arr.size());
546 :
547 : // duplicate address error
548 3 : BOOST_CHECK_THROW(CallRPC("listshieldunspent 1 999 false [\"" + myzaddr + "\", \"" + myzaddr + "\"]"), std::runtime_error);
549 :
550 1 : vpwallets.erase(vpwallets.begin());
551 1 : }
552 :
553 : BOOST_AUTO_TEST_SUITE_END()
|