LCOV - code coverage report
Current view: top level - src/test/librust - sapling_rpc_wallet_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 284 284 100.0 %
Date: 2025-04-02 01:23:23 Functions: 20 20 100.0 %

          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()

Generated by: LCOV version 1.14