2014-03-18 02:11:00 -07:00
// Copyright (c) 2013-2014 The Bitcoin Core developers
2023-01-23 10:31:54 -08:00
// Copyright (c) 2020-2023 The Zcash developers
2014-12-12 20:09:33 -08:00
// Distributed under the MIT software license, see the accompanying
2019-07-18 07:16:09 -07:00
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
2014-03-18 02:11:00 -07:00
2016-01-14 16:55:17 -08:00
# include "rpc/server.h"
# include "rpc/client.h"
2013-11-30 02:10:35 -08:00
2015-11-17 08:35:44 -08:00
# include "consensus/merkle.h"
2017-03-01 07:54:22 -08:00
# include "fs.h"
2018-04-25 04:58:22 -07:00
# include "key_io.h"
2015-02-04 16:21:11 -08:00
# include "main.h"
2015-02-03 12:09:47 -08:00
# include "wallet/wallet.h"
2013-11-30 02:10:35 -08:00
2016-08-12 17:44:03 -07:00
# include "zcash/Address.hpp"
2016-09-03 22:25:13 -07:00
# include "asyncrpcqueue.h"
# include "asyncrpcoperation.h"
2019-05-28 16:58:49 -07:00
# include "wallet/asyncrpcoperation_common.h"
2017-12-11 08:43:09 -08:00
# include "wallet/asyncrpcoperation_mergetoaddress.h"
2016-09-03 22:25:13 -07:00
# include "wallet/asyncrpcoperation_sendmany.h"
2017-09-15 12:59:27 -07:00
# include "wallet/asyncrpcoperation_shieldcoinbase.h"
2022-05-24 15:50:53 -07:00
# include "wallet/memo.h"
2017-09-15 12:59:27 -07:00
2016-09-07 11:51:29 -07:00
# include "init.h"
2022-07-06 09:25:28 -07:00
# include "util/test.h"
2016-09-03 22:25:13 -07:00
2020-07-17 12:07:40 -07:00
# include "test/test_bitcoin.h"
# include "test/test_util.h"
# include "wallet/test/wallet_test_fixture.h"
2016-09-03 22:25:13 -07:00
2018-05-03 03:53:51 -07:00
# include <array>
2016-09-03 22:25:13 -07:00
# include <chrono>
2020-10-20 17:39:13 -07:00
# include <optional>
2016-09-03 22:25:13 -07:00
# include <thread>
2020-10-20 17:05:00 -07:00
# include <variant>
2016-09-03 22:25:13 -07:00
2016-08-12 17:44:03 -07:00
# include <fstream>
# include <unordered_set>
2013-11-30 02:10:35 -08:00
# include <boost/algorithm/string.hpp>
# include <boost/test/unit_test.hpp>
2016-08-12 17:44:03 -07:00
# include <boost/format.hpp>
2013-11-30 02:10:35 -08:00
2015-09-04 07:11:34 -07:00
# include <univalue.h>
2015-05-18 05:02:18 -07:00
2013-11-30 02:10:35 -08:00
using namespace std ;
2014-01-23 11:18:26 -08:00
extern CWallet * pwalletMain ;
2018-01-14 14:56:16 -08:00
namespace {
2017-01-06 10:15:56 -08:00
bool find_error ( const UniValue & objError , const std : : string & expected ) {
2016-09-08 11:06:18 -07:00
return find_value ( objError , " message " ) . get_str ( ) . find ( expected ) ! = string : : npos ;
}
2018-01-14 14:56:16 -08:00
/** Set the working directory for the duration of the scope. */
class PushCurrentDirectory {
public :
PushCurrentDirectory ( const std : : string & new_cwd )
2017-03-01 08:05:50 -08:00
: old_cwd ( fs : : current_path ( ) ) {
fs : : current_path ( new_cwd ) ;
2018-01-14 14:56:16 -08:00
}
~ PushCurrentDirectory ( ) {
2017-03-01 08:05:50 -08:00
fs : : current_path ( old_cwd ) ;
2018-01-14 14:56:16 -08:00
}
private :
2017-03-01 08:05:50 -08:00
fs : : path old_cwd ;
2018-01-14 14:56:16 -08:00
} ;
2023-04-17 03:21:54 -07:00
CWalletTx FakeWalletTx ( ) {
CMutableTransaction mtx ;
mtx . vout . resize ( 1 ) ;
mtx . vout [ 0 ] . nValue = 1 ;
return CWalletTx ( nullptr , mtx ) ;
}
2018-01-14 14:56:16 -08:00
}
2017-12-21 01:35:16 -08:00
static UniValue ValueFromString ( const std : : string & str )
{
UniValue value ;
BOOST_CHECK ( value . setNumStr ( str ) ) ;
return value ;
}
2021-09-24 13:24:41 -07:00
static SaplingPaymentAddress DefaultSaplingAddress ( CWallet * pwallet ) {
2021-10-20 16:13:52 -07:00
auto usk = pwallet - > GenerateUnifiedSpendingKeyForAccount ( 0 ) ;
2021-09-24 13:24:41 -07:00
return usk . value ( )
. ToFullViewingKey ( )
2021-11-30 19:35:26 -08:00
. GetSaplingKey ( ) . value ( )
2021-09-24 13:24:41 -07:00
. FindAddress ( libzcash : : diversifier_index_t ( 0 ) ) . first ;
}
2016-04-18 05:54:57 -07:00
BOOST_FIXTURE_TEST_SUITE ( rpc_wallet_tests , WalletTestingSetup )
2013-11-30 02:10:35 -08:00
BOOST_AUTO_TEST_CASE ( rpc_addmultisig )
{
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2014-01-23 11:18:26 -08:00
2013-11-30 02:10:35 -08:00
rpcfn_type addmultisig = tableRPC [ " addmultisigaddress " ] - > actor ;
// old, 65-byte-long:
const char address1Hex [ ] = " 0434e3e09f49ea168c5bbf53f877ff4206923858aab7c7e1df25bc263978107c95e35065a27ef6f1b27222db0ec97e0e895eaca603d3ee0d4c060ce3d8a00286c8 " ;
// new, compressed:
const char address2Hex [ ] = " 0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4 " ;
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
2015-05-18 05:02:18 -07:00
UniValue v ;
2018-04-20 07:09:23 -07:00
CTxDestination address ;
2013-11-30 02:10:35 -08:00
BOOST_CHECK_NO_THROW ( v = addmultisig ( createArgs ( 1 , address1Hex ) , false ) ) ;
2020-07-09 15:53:54 -07:00
address = keyIO . DecodeDestination ( v . get_str ( ) ) ;
2020-02-18 08:20:43 -08:00
BOOST_CHECK ( IsValidDestination ( address ) & & IsScriptDestination ( address ) ) ;
2013-11-30 02:10:35 -08:00
BOOST_CHECK_NO_THROW ( v = addmultisig ( createArgs ( 1 , address1Hex , address2Hex ) , false ) ) ;
2020-07-09 15:53:54 -07:00
address = keyIO . DecodeDestination ( v . get_str ( ) ) ;
2020-02-18 08:20:43 -08:00
BOOST_CHECK ( IsValidDestination ( address ) & & IsScriptDestination ( address ) ) ;
2013-11-30 02:10:35 -08:00
BOOST_CHECK_NO_THROW ( v = addmultisig ( createArgs ( 2 , address1Hex , address2Hex ) , false ) ) ;
2020-07-09 15:53:54 -07:00
address = keyIO . DecodeDestination ( v . get_str ( ) ) ;
2020-02-18 08:20:43 -08:00
BOOST_CHECK ( IsValidDestination ( address ) & & IsScriptDestination ( address ) ) ;
2013-11-30 02:10:35 -08:00
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 0 ) , false ) , runtime_error ) ;
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 1 ) , false ) , runtime_error ) ;
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 2 , address1Hex ) , false ) , runtime_error ) ;
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 1 , " " ) , false ) , runtime_error ) ;
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 1 , " NotAValidPubkey " ) , false ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
string short1 ( address1Hex , address1Hex + sizeof ( address1Hex ) - 2 ) ; // last byte missing
2013-11-30 02:10:35 -08:00
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 2 , short1 . c_str ( ) ) , false ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
string short2 ( address1Hex + 1 , address1Hex + sizeof ( address1Hex ) ) ; // first byte missing
2013-11-30 02:10:35 -08:00
BOOST_CHECK_THROW ( addmultisig ( createArgs ( 2 , short2 . c_str ( ) ) , false ) , runtime_error ) ;
}
BOOST_AUTO_TEST_CASE ( rpc_wallet )
{
// Test RPC calls for various wallet statistics
2018-07-31 09:23:26 -07:00
KeyIO keyIO ( Params ( ) ) ;
2015-05-18 05:02:18 -07:00
UniValue r ;
2013-11-30 02:10:35 -08:00
2014-04-22 23:05:05 -07:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2014-01-23 11:18:26 -08:00
2022-02-07 15:35:06 -08:00
CPubKey demoPubkey = pwalletMain - > GenerateNewKey ( true ) ;
2018-04-20 07:09:23 -07:00
CTxDestination demoAddress ( CTxDestination ( demoPubkey . GetID ( ) ) ) ;
2015-05-18 05:02:18 -07:00
UniValue retValue ;
2014-10-02 09:19:18 -07:00
string strPurpose = " receive " ;
2018-07-31 09:23:26 -07:00
BOOST_CHECK_NO_THROW ( { /*Initialize Wallet with the demo pubkey*/
2014-10-02 09:19:18 -07:00
CWalletDB walletdb ( pwalletMain - > strWalletFile ) ;
2018-07-31 09:23:26 -07:00
pwalletMain - > SetAddressBook ( demoPubkey . GetID ( ) , " " , strPurpose ) ;
2014-10-02 09:19:18 -07:00
} ) ;
2014-03-10 11:23:19 -07:00
2022-02-07 15:35:06 -08:00
CPubKey setaccountDemoPubkey = pwalletMain - > GenerateNewKey ( true ) ;
2018-04-20 07:09:23 -07:00
CTxDestination setaccountDemoAddress ( CTxDestination ( setaccountDemoPubkey . GetID ( ) ) ) ;
2014-12-22 23:41:14 -08:00
/*********************************
2023-03-17 15:11:40 -07:00
* getbalance
2014-12-22 23:41:14 -08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( CallRPC ( " getbalance " ) ) ;
2020-07-09 15:53:54 -07:00
BOOST_CHECK_THROW ( CallRPC ( " getbalance " + keyIO . EncodeDestination ( demoAddress ) ) , runtime_error ) ;
2014-12-22 23:41:14 -08:00
2014-03-10 11:23:19 -07:00
/*********************************
2023-03-17 15:11:40 -07:00
* listunspent
2014-03-10 11:23:19 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-30 02:10:35 -08:00
BOOST_CHECK_NO_THROW ( CallRPC ( " listunspent " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " listunspent string " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " listunspent 0 string " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " listunspent 0 1 not_array " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " listunspent 0 1 [] extra " ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
BOOST_CHECK_NO_THROW ( r = CallRPC ( " listunspent 0 1 [] " ) ) ;
2013-11-30 02:10:35 -08:00
BOOST_CHECK ( r . get_array ( ) . empty ( ) ) ;
2014-03-10 11:23:19 -07:00
/*********************************
2023-01-31 12:05:52 -08:00
* listreceivedbyaddress
2014-10-02 09:19:18 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-30 02:10:35 -08:00
BOOST_CHECK_NO_THROW ( CallRPC ( " listreceivedbyaddress " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " listreceivedbyaddress 0 " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " listreceivedbyaddress not_int " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " listreceivedbyaddress 0 not_bool " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " listreceivedbyaddress 0 true " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " listreceivedbyaddress 0 true extra " ) , runtime_error ) ;
2014-12-22 23:41:14 -08:00
/*********************************
* listsinceblock
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( CallRPC ( " listsinceblock " ) ) ;
/*********************************
* listtransactions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( CallRPC ( " listtransactions " ) ) ;
2018-07-27 14:05:24 -07:00
BOOST_CHECK_NO_THROW ( CallRPC ( " listtransactions * " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " listtransactions * 20 " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " listtransactions * 20 0 " ) ) ;
2020-07-09 15:53:54 -07:00
BOOST_CHECK_THROW ( CallRPC ( " listtransactions " + keyIO . EncodeDestination ( demoAddress ) + " not_int " ) , runtime_error ) ;
2014-12-22 23:41:14 -08:00
/*********************************
* listlockunspent
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( CallRPC ( " listlockunspent " ) ) ;
/*********************************
* listaddressgroupings
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( CallRPC ( " listaddressgroupings " ) ) ;
2021-10-27 17:44:09 -07:00
/*********************************
2023-01-31 12:05:52 -08:00
* walletconfirmbackup
2021-10-27 17:44:09 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_THROW ( CallRPC ( string ( " walletconfirmbackup \" badmnemonic \" " ) ) , runtime_error ) ;
2014-03-10 11:23:19 -07:00
/*********************************
2023-01-31 12:05:52 -08:00
* getrawchangeaddress
2014-10-02 09:19:18 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-03-10 11:23:19 -07:00
BOOST_CHECK_NO_THROW ( CallRPC ( " getrawchangeaddress " ) ) ;
/*********************************
2023-01-31 12:05:52 -08:00
* getnewaddress
2014-10-02 09:19:18 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-03-10 11:23:19 -07:00
BOOST_CHECK_NO_THROW ( CallRPC ( " getnewaddress " ) ) ;
2014-10-02 09:19:18 -07:00
/*********************************
2023-03-17 15:11:40 -07:00
* signmessage + verifymessage
2014-10-02 09:19:18 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2020-07-09 15:53:54 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " signmessage " + keyIO . EncodeDestination ( demoAddress ) + " mymessage " ) ) ;
2014-10-02 09:19:18 -07:00
BOOST_CHECK_THROW ( CallRPC ( " signmessage " ) , runtime_error ) ;
/* Should throw error because this address is not loaded in the wallet */
2016-10-03 23:51:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " signmessage t1h8SqgtM3QM5e2M8EzhhT1yL2PXXtA6oqe mymessage " ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
/* missing arguments */
2020-07-09 15:53:54 -07:00
BOOST_CHECK_THROW ( CallRPC ( " verifymessage " + keyIO . EncodeDestination ( demoAddress ) ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " verifymessage " + keyIO . EncodeDestination ( demoAddress ) + " " + retValue . get_str ( ) ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
/* Illegal address */
2016-10-03 23:51:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1Gpg " + retValue . get_str ( ) + " mymessage " ) , runtime_error ) ;
2014-10-02 09:19:18 -07:00
/* wrong address */
2016-10-03 23:51:32 -07:00
BOOST_CHECK ( CallRPC ( " verifymessage t1VtArtnn1dGPiD2WFfMXYXW5mHM3q1GpgV " + retValue . get_str ( ) + " mymessage " ) . get_bool ( ) = = false ) ;
2014-10-02 09:19:18 -07:00
/* Correct address and signature but wrong message */
2020-07-09 15:53:54 -07:00
BOOST_CHECK ( CallRPC ( " verifymessage " + keyIO . EncodeDestination ( demoAddress ) + " " + retValue . get_str ( ) + " wrongmessage " ) . get_bool ( ) = = false ) ;
2014-10-02 09:19:18 -07:00
/* Correct address, message and signature*/
2020-07-09 15:53:54 -07:00
BOOST_CHECK ( CallRPC ( " verifymessage " + keyIO . EncodeDestination ( demoAddress ) + " " + retValue . get_str ( ) + " mymessage " ) . get_bool ( ) = = true ) ;
2014-10-02 09:19:18 -07:00
2021-10-05 06:41:08 -07:00
/*********************************
2023-01-31 12:05:52 -08:00
* listaddresses
2021-10-05 06:41:08 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " listaddresses " ) ) ;
UniValue arr = retValue . get_array ( ) ;
2021-10-06 19:39:52 -07:00
{
BOOST_CHECK_EQUAL ( 1 , arr . size ( ) ) ;
bool notFound = true ;
for ( auto a : arr . getValues ( ) ) {
auto source = find_value ( a . get_obj ( ) , " source " ) ;
2022-03-22 10:18:30 -07:00
if ( source . get_str ( ) = = " mnemonic_seed " ) {
2021-10-06 19:39:52 -07:00
auto t_obj = find_value ( a . get_obj ( ) , " transparent " ) ;
auto addrs = find_value ( t_obj , " addresses " ) . get_array ( ) ;
BOOST_CHECK_EQUAL ( 2 , addrs . size ( ) ) ;
for ( auto addr : addrs . getValues ( ) ) {
notFound & = keyIO . DecodeDestination ( addr . get_str ( ) ) ! = demoAddress ;
}
}
}
BOOST_CHECK ( ! notFound ) ;
2021-10-05 06:41:08 -07:00
}
2015-04-24 18:27:30 -07:00
/*********************************
2023-03-17 15:11:40 -07:00
* fundrawtransaction
2015-04-24 18:27:30 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOST_CHECK_THROW ( CallRPC ( " fundrawtransaction 28z " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000 " ) , runtime_error ) ;
2016-08-27 21:03:41 -07:00
/*
* getblocksubsidy
*/
BOOST_CHECK_THROW ( CallRPC ( " getblocksubsidy too many args " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " getblocksubsidy -1 " ) , runtime_error ) ;
2019-11-01 11:10:15 -07:00
2016-08-27 21:03:41 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 50000 " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue obj = retValue . get_obj ( ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , 10.0 ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 2.5 ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK ( ! obj . exists ( " fundingstreams " ) ) ;
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 653599 " ) ) ; // Blossom activation - 1
obj = retValue . get_obj ( ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , 10.0 ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 2.5 ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK ( ! obj . exists ( " fundingstreams " ) ) ;
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 653600 " ) ) ; // Blossom activation
obj = retValue . get_obj ( ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , 5.0 ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 1.25 ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK ( ! obj . exists ( " fundingstreams " ) ) ;
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 1046399 " ) ) ;
obj = retValue . get_obj ( ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , 5.0 ) ;
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 1.25 ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK ( ! obj . exists ( " fundingstreams " ) ) ;
2020-10-16 08:57:04 -07:00
auto check_funding_streams = [ ] ( UniValue obj , std : : vector < std : : string > recipients , std : : vector < double > amounts , std : : vector < std : : string > addresses ) {
2020-07-10 06:05:40 -07:00
size_t n = recipients . size ( ) ;
BOOST_REQUIRE_EQUAL ( amounts . size ( ) , n ) ;
UniValue fundingstreams = find_value ( obj , " fundingstreams " ) ;
BOOST_CHECK_EQUAL ( fundingstreams . size ( ) , n ) ;
if ( fundingstreams . size ( ) ! = n ) return ;
for ( int i = 0 ; i < n ; i + + ) {
UniValue fsobj = fundingstreams [ i ] ;
BOOST_CHECK_EQUAL ( find_value ( fsobj , " recipient " ) . get_str ( ) , recipients [ i ] ) ;
BOOST_CHECK_EQUAL ( find_value ( fsobj , " specification " ) . get_str ( ) , " https://zips.z.cash/zip-0214 " ) ;
BOOST_CHECK_EQUAL ( find_value ( fsobj , " value " ) . get_real ( ) , amounts [ i ] ) ;
2020-10-18 18:59:11 -07:00
BOOST_CHECK_EQUAL ( find_value ( fsobj , " address " ) . get_str ( ) , addresses [ i ] ) ;
2020-07-10 06:05:40 -07:00
}
2020-07-09 10:27:10 -07:00
} ;
bool canopyEnabled =
Params ( ) . GetConsensus ( ) . vUpgrades [ Consensus : : UPGRADE_CANOPY ] . nActivationHeight ! = Consensus : : NetworkUpgrade : : NO_ACTIVATION_HEIGHT ;
2019-11-01 13:46:15 -07:00
// slow start + blossom activation + (pre blossom halving - blossom activation) * 2
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 1046400 " ) ) ;
2016-08-27 21:03:41 -07:00
obj = retValue . get_obj ( ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , canopyEnabled ? 2.5 : 3.125 ) ;
2017-01-06 10:15:56 -08:00
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 0.0 ) ;
2020-07-10 06:05:40 -07:00
if ( canopyEnabled ) {
check_funding_streams ( obj , { " Electric Coin Company " , " Zcash Foundation " , " Major Grants " } ,
2020-10-16 08:57:04 -07:00
{ 0.21875 , 0.15625 , 0.25 } ,
{
" t3LmX1cxWPPPqL4TZHx42HU3U5ghbFjRiif " ,
" t3dvVE3SQEi7kqNzwrfNePxZ1d4hUyztBA1 " ,
" t3XyYW8yBFRuMnfvm5KLGFbEVz25kckZXym "
} ) ;
2020-07-10 06:05:40 -07:00
}
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 2726399 " ) ) ;
2016-08-27 21:03:41 -07:00
obj = retValue . get_obj ( ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , canopyEnabled ? 2.5 : 3.125 ) ;
2017-01-06 10:15:56 -08:00
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 0.0 ) ;
2020-07-10 06:05:40 -07:00
if ( canopyEnabled ) {
check_funding_streams ( obj , { " Electric Coin Company " , " Zcash Foundation " , " Major Grants " } ,
2020-10-16 08:57:04 -07:00
{ 0.21875 , 0.15625 , 0.25 } ,
{
" t3XHAGxRP2FNfhAjxGjxbrQPYtQQjc3RCQD " ,
" t3dvVE3SQEi7kqNzwrfNePxZ1d4hUyztBA1 " ,
" t3XyYW8yBFRuMnfvm5KLGFbEVz25kckZXym "
} ) ;
2020-07-10 06:05:40 -07:00
}
2017-03-16 11:30:41 -07:00
2019-11-01 11:10:15 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getblocksubsidy 2726400 " ) ) ;
2016-08-27 21:03:41 -07:00
obj = retValue . get_obj ( ) ;
2019-11-01 11:10:15 -07:00
BOOST_CHECK_EQUAL ( find_value ( obj , " miner " ) . get_real ( ) , 1.5625 ) ;
2017-01-06 10:15:56 -08:00
BOOST_CHECK_EQUAL ( find_value ( obj , " founders " ) . get_real ( ) , 0.0 ) ;
2020-07-09 10:27:10 -07:00
BOOST_CHECK ( find_value ( obj , " fundingstreams " ) . empty ( ) ) ;
2017-03-16 11:30:41 -07:00
/*
* getblock
*/
BOOST_CHECK_THROW ( CallRPC ( " getblock too many args " ) , runtime_error ) ;
2020-02-17 04:52:40 -08:00
BOOST_CHECK_NO_THROW ( CallRPC ( " getblock -1 " ) ) ; // negative heights relative are allowed
BOOST_CHECK_THROW ( CallRPC ( " getblock -2147483647 " ) , runtime_error ) ; // allowed, but chain tip - height < 0
2017-03-16 11:30:41 -07:00
BOOST_CHECK_THROW ( CallRPC ( " getblock 2147483647 " ) , runtime_error ) ; // allowed, but > height of active chain tip
BOOST_CHECK_THROW ( CallRPC ( " getblock 2147483648 " ) , runtime_error ) ; // not allowed, > int32 used for nHeight
BOOST_CHECK_THROW ( CallRPC ( " getblock 100badchars " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " getblock 0 " ) ) ;
2018-04-30 11:51:59 -07:00
BOOST_CHECK_NO_THROW ( CallRPC ( " getblock 0 0 " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " getblock 0 1 " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " getblock 0 2 " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " getblock 0 -1 " ) , runtime_error ) ; // bad verbosity
BOOST_CHECK_THROW ( CallRPC ( " getblock 0 3 " ) , runtime_error ) ; // bad verbosity
2019-05-01 09:03:24 -07:00
/*
* migration ( sprout to sapling )
*/
BOOST_CHECK_NO_THROW ( CallRPC ( " z_setmigration true " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_setmigration false " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_setmigration " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_setmigration nonboolean " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_setmigration 1 " ) , runtime_error ) ;
2013-11-30 02:10:35 -08:00
}
2016-09-07 23:01:32 -07:00
BOOST_AUTO_TEST_CASE ( rpc_wallet_getbalance )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2016-09-07 23:01:32 -07:00
2021-12-29 12:44:55 -08:00
UniValue retValue ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getnewaddress " ) ) ;
std : : string taddr1 = retValue . get_str ( ) ;
2017-09-15 12:59:27 -07:00
2016-09-07 23:01:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_getbalance too many args " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_getbalance invalidaddress " ) , runtime_error ) ;
2021-12-29 12:44:55 -08:00
// address does not belong to wallet
BOOST_CHECK_THROW ( CallRPC ( " z_getbalance tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( std : : string ( " z_getbalance " ) + taddr1 ) ) ;
// negative minconf not allowed
BOOST_CHECK_THROW ( CallRPC ( std : : string ( " z_getbalance " ) + taddr1 + " -1 " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( std : : string ( " z_getbalance " ) + taddr1 + std : : string ( " 0 " ) ) ) ;
// don't have the spending key
2016-09-07 23:01:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_getbalance tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1 " ) , runtime_error ) ;
2017-09-15 12:59:27 -07:00
2016-09-07 23:01:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_gettotalbalance too manyargs " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_gettotalbalance -1 " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_gettotalbalance 0 " ) ) ;
2017-09-15 12:59:27 -07:00
2016-09-07 23:01:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_listreceivedbyaddress too many args " ) , runtime_error ) ;
// negative minconf not allowed
2016-10-03 23:51:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_listreceivedbyaddress tmC6YZnCUhm19dEXxh3Jb7srdBJxDawaCab -1 " ) , runtime_error ) ;
2016-09-07 23:01:32 -07:00
// don't have the spending key
BOOST_CHECK_THROW ( CallRPC ( " z_listreceivedbyaddress tnRZ8bPq2pff3xBWhTJhNkVUkm2uhzksDeW5PvEa7aFKGT9Qi3YgTALZfjaY4jU3HLVKBtHdSXxoPoLA3naMPcHBcY88FcF 1 " ) , runtime_error ) ;
}
2016-10-31 20:05:48 -07:00
/**
* This test covers RPC command z_validateaddress
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_validateaddress )
{
SelectParams ( CBaseChainParams : : MAIN ) ;
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2017-01-06 10:15:56 -08:00
UniValue retValue ;
2016-10-31 20:05:48 -07:00
// Check number of args
BOOST_CHECK_THROW ( CallRPC ( " z_validateaddress " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_validateaddress toomany args " ) , runtime_error ) ;
// Wallet should be empty
2018-04-25 18:51:17 -07:00
std : : set < libzcash : : SproutPaymentAddress > addrs ;
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-10-31 20:05:48 -07:00
BOOST_CHECK ( addrs . size ( ) = = 0 ) ;
// This address is not valid, it belongs to another network
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_validateaddress ztaaga95QAPyp1kSQ1hD2kguCpzyMHjxWZqaYDEkzbvo7uYQYAw2S8X4Kx98AvhhofMtQL8PAXKHuZsmhRcanavKRKmdCzk " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue resultObj = retValue . get_obj ( ) ;
2016-10-31 20:05:48 -07:00
bool b = find_value ( resultObj , " isvalid " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , false ) ;
// This address is valid, but the spending key is not in this wallet
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_validateaddress zcfA19SDAKRYHLoRDoShcoz4nPohqWxuHcqg8WAxsiB2jFrrs6k7oSvst3UZvMYqpMNSRBkxBsnyjjngX5L55FxMzLKach8 " ) ) ;
resultObj = retValue . get_obj ( ) ;
b = find_value ( resultObj , " isvalid " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , true ) ;
2018-06-12 03:25:07 -07:00
BOOST_CHECK_EQUAL ( find_value ( resultObj , " type " ) . get_str ( ) , " sprout " ) ;
2016-10-31 20:05:48 -07:00
b = find_value ( resultObj , " ismine " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , false ) ;
// Let's import a spending key to the wallet and validate its payment address
BOOST_CHECK_NO_THROW ( CallRPC ( " z_importkey SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT " ) ) ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_validateaddress zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL " ) ) ;
resultObj = retValue . get_obj ( ) ;
b = find_value ( resultObj , " isvalid " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , true ) ;
2018-06-12 03:25:07 -07:00
BOOST_CHECK_EQUAL ( find_value ( resultObj , " type " ) . get_str ( ) , " sprout " ) ;
2016-10-31 20:05:48 -07:00
b = find_value ( resultObj , " ismine " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , true ) ;
BOOST_CHECK_EQUAL ( find_value ( resultObj , " payingkey " ) . get_str ( ) , " f5bb3c888ccc9831e3f6ba06e7528e26a312eec3acc1823be8918b6a3a5e20ad " ) ;
BOOST_CHECK_EQUAL ( find_value ( resultObj , " transmissionkey " ) . get_str ( ) , " 7a58c7132446564e6b810cf895c20537b3528357dc00150a8e201f491efa9c1a " ) ;
2018-06-12 03:25:07 -07:00
// This Sapling address is not valid, it belongs to another network
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_validateaddress ztestsapling1knww2nyjc62njkard0jmx7hlsj6twxmxwprn7anvrv4dc2zxanl3nemc0qx2hvplxmd2uau8gyw " ) ) ;
resultObj = retValue . get_obj ( ) ;
b = find_value ( resultObj , " isvalid " ) . get_bool ( ) ;
BOOST_CHECK_EQUAL ( b , false ) ;
// This Sapling address is valid, but the spending key is not in this wallet
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_validateaddress zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9slya " ) ) ;
resultObj = retValue . get_obj ( ) ;
b = find_value ( resultObj , " isvalid " ) . get_bool ( ) ;
2018-09-21 15:43:31 -07:00
BOOST_CHECK_EQUAL ( b , true ) ;
BOOST_CHECK_EQUAL ( find_value ( resultObj , " type " ) . get_str ( ) , " sapling " ) ;
b = find_value ( resultObj , " ismine " ) . get_bool ( ) ;
2018-06-12 03:25:07 -07:00
BOOST_CHECK_EQUAL ( b , false ) ;
2018-09-21 15:43:31 -07:00
BOOST_CHECK_EQUAL ( find_value ( resultObj , " diversifier " ) . get_str ( ) , " 1787997c30e94f050c634d " ) ;
BOOST_CHECK_EQUAL ( find_value ( resultObj , " diversifiedtransmissionkey " ) . get_str ( ) , " 34ed1f60f5db5763beee1ddbb37dd5f7e541d4d4fbdcc09fbfcc6b8e949bbe9d " ) ;
2016-10-31 20:05:48 -07:00
}
2019-11-11 15:49:11 -08:00
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_importkey_paymentaddress ) {
SelectParams ( CBaseChainParams : : MAIN ) ;
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
auto testAddress = [ ] ( const std : : string & type , const std : : string & key ) {
UniValue ret ;
BOOST_CHECK_NO_THROW ( ret = CallRPC ( " z_importkey " + key ) ) ;
auto defaultAddr = find_value ( ret , " address " ) . get_str ( ) ;
BOOST_CHECK_EQUAL ( type , find_value ( ret , " type " ) . get_str ( ) ) ;
BOOST_CHECK_NO_THROW ( ret = CallRPC ( " z_validateaddress " + defaultAddr ) ) ;
ret = ret . get_obj ( ) ;
BOOST_CHECK_EQUAL ( true , find_value ( ret , " isvalid " ) . get_bool ( ) ) ;
BOOST_CHECK_EQUAL ( true , find_value ( ret , " ismine " ) . get_bool ( ) ) ;
BOOST_CHECK_EQUAL ( type , find_value ( ret , " type " ) . get_str ( ) ) ;
} ;
testAddress ( " sapling " , " secret-extended-key-main1qya4wae0qqqqqqpxfq3ukywunn "
" dtr8xf39hktp3w4z94smuu3l8wr6h4cwxklzzemtg9sk5c7tamfqs48ml6rvuvyup8 "
" ne6jz9g7l0asew0htdpjgfss29et84uvqhynjayl3laphks2wxy3c8vhqr4wrca3wl "
" ft2fhcacqtvfwsht4t33l8ckpyr8djmzj7swlvhdhepvc3ehycf9cja335ex6rlpka "
" 8z2gzkul3mztga2ups55c3xvn9j6vpdfm5a5v60g9v3sztcpvxqhm " ) ;
testAddress ( " sprout " ,
" SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT " ) ;
2016-10-31 20:05:48 -07:00
}
2016-08-12 17:44:03 -07:00
/*
* This test covers RPC command z_exportwallet
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_exportwallet )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2016-10-31 20:05:48 -07:00
2016-08-24 08:35:04 -07:00
// wallet should be empty
2018-04-25 18:51:17 -07:00
std : : set < libzcash : : SproutPaymentAddress > addrs ;
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK ( addrs . size ( ) = = 0 ) ;
// wallet should have one key
2018-10-08 15:25:29 -07:00
libzcash : : SproutPaymentAddress addr = pwalletMain - > GenerateNewSproutZKey ( ) ;
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK ( addrs . size ( ) = = 1 ) ;
2017-09-15 12:59:27 -07:00
2017-01-09 21:25:42 -08:00
// Set up paths
2017-03-01 08:05:50 -08:00
fs : : path tmppath = fs : : temp_directory_path ( ) ;
fs : : path tmpfilename = fs : : unique_path ( " %%%%%%%% " ) ;
fs : : path exportfilepath = tmppath / tmpfilename ;
2017-01-09 21:25:42 -08:00
// export will fail since exportdir is not set
BOOST_CHECK_THROW ( CallRPC ( string ( " z_exportwallet " ) + tmpfilename . string ( ) ) , runtime_error ) ;
// set exportdir
2018-04-14 15:10:44 -07:00
mapArgs [ " -exportdir " ] = tmppath . string ( ) ;
2017-01-09 21:25:42 -08:00
// run some tests
2016-08-12 17:44:03 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_exportwallet " ) , runtime_error ) ;
2016-10-12 10:15:12 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_exportwallet toomany args " ) , runtime_error ) ;
2017-01-09 21:25:42 -08:00
BOOST_CHECK_THROW ( CallRPC ( string ( " z_exportwallet invalid!*/_chars.txt " ) ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( string ( " z_exportwallet " ) + tmpfilename . string ( ) ) ) ;
2016-08-12 17:44:03 -07:00
2018-04-25 18:51:17 -07:00
libzcash : : SproutSpendingKey key ;
2018-08-03 02:10:26 -07:00
BOOST_CHECK ( pwalletMain - > GetSproutSpendingKey ( addr , key ) ) ;
2016-08-12 17:44:03 -07:00
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
std : : string s1 = keyIO . EncodePaymentAddress ( addr ) ;
std : : string s2 = keyIO . EncodeSpendingKey ( key ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// There's no way to really delete a private key so we will read in the
// exported wallet file and search for the spending key and payment address.
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
EnsureWalletIsUnlocked ( ) ;
ifstream file ;
2017-01-09 21:25:42 -08:00
file . open ( exportfilepath . string ( ) . c_str ( ) , std : : ios : : in | std : : ios : : ate ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK ( file . is_open ( ) ) ;
bool fVerified = false ;
int64_t nFilesize = std : : max ( ( int64_t ) 1 , ( int64_t ) file . tellg ( ) ) ;
file . seekg ( 0 , file . beg ) ;
while ( file . good ( ) ) {
std : : string line ;
std : : getline ( file , line ) ;
if ( line . empty ( ) | | line [ 0 ] = = ' # ' )
continue ;
if ( line . find ( s1 ) ! = std : : string : : npos & & line . find ( s2 ) ! = std : : string : : npos ) {
fVerified = true ;
break ;
}
}
BOOST_CHECK ( fVerified ) ;
}
/*
* This test covers RPC command z_importwallet
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_importwallet )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// error if no args
BOOST_CHECK_THROW ( CallRPC ( " z_importwallet " ) , runtime_error ) ;
2016-10-12 10:15:12 -07:00
// error if too many args
BOOST_CHECK_THROW ( CallRPC ( " z_importwallet toomany args " ) , runtime_error ) ;
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
2016-08-12 17:44:03 -07:00
// create a random key locally
2018-04-25 18:51:17 -07:00
auto testSpendingKey = libzcash : : SproutSpendingKey : : random ( ) ;
2016-08-12 17:44:03 -07:00
auto testPaymentAddress = testSpendingKey . address ( ) ;
2020-07-09 15:53:54 -07:00
std : : string testAddr = keyIO . EncodePaymentAddress ( testPaymentAddress ) ;
std : : string testKey = keyIO . EncodeSpendingKey ( testSpendingKey ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// create test data using the random key
std : : string format_str = " # Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700) \n "
" # * Created on 2016-08-12T21:55:36Z \n "
" # * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52), \n "
" # mined on 2009-01-03T18:15:05Z \n "
" \n "
" # Zkeys \n "
" \n "
" %s 2016-08-12T21:55:36Z # zaddr=%s \n "
" \n "
" \n # End of dump " ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
boost : : format formatobject ( format_str ) ;
std : : string testWalletDump = ( formatobject % testKey % testAddr ) . str ( ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// write test data to file
2017-03-01 08:05:50 -08:00
fs : : path temp = fs : : temp_directory_path ( ) /
fs : : unique_path ( ) ;
2018-04-14 15:10:44 -07:00
const std : : string path = temp . string ( ) ;
2016-08-12 17:44:03 -07:00
std : : ofstream file ( path ) ;
file < < testWalletDump ;
file < < std : : flush ;
// wallet should currently be empty
2018-04-25 18:51:17 -07:00
std : : set < libzcash : : SproutPaymentAddress > addrs ;
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK ( addrs . size ( ) = = 0 ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// import test data from file into wallet
BOOST_CHECK_NO_THROW ( CallRPC ( string ( " z_importwallet " ) + path ) ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// wallet should now have one zkey
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK ( addrs . size ( ) = = 1 ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// check that we have the spending key for the address
2021-12-16 15:28:43 -08:00
auto decoded = keyIO . DecodePaymentAddress ( testAddr ) ;
BOOST_CHECK ( decoded . has_value ( ) ) ;
libzcash : : PaymentAddress address ( decoded . value ( ) ) ;
BOOST_ASSERT ( std : : holds_alternative < libzcash : : SproutPaymentAddress > ( address ) ) ;
auto sprout_addr = std : : get < libzcash : : SproutPaymentAddress > ( address ) ;
BOOST_CHECK ( pwalletMain - > HaveSproutSpendingKey ( sprout_addr ) ) ;
2017-09-15 12:59:27 -07:00
2016-08-24 08:35:04 -07:00
// Verify the spending key is the same as the test data
2018-04-25 18:51:17 -07:00
libzcash : : SproutSpendingKey k ;
2021-12-16 15:28:43 -08:00
BOOST_CHECK ( pwalletMain - > GetSproutSpendingKey ( sprout_addr , k ) ) ;
2020-07-09 15:53:54 -07:00
BOOST_CHECK_EQUAL ( testKey , keyIO . EncodeSpendingKey ( k ) ) ;
2016-08-12 17:44:03 -07:00
}
/*
2021-10-07 16:43:56 -07:00
* This test covers RPC commands z_listaddresses , z_importkey , z_exportkey ,
* listaddresses , z_importviewingkey , z_exportviewingkey
2016-08-12 17:44:03 -07:00
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_importexport )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2017-01-06 10:15:56 -08:00
UniValue retValue ;
2016-08-12 17:44:03 -07:00
int n1 = 1000 ; // number of times to import/export
int n2 = 1000 ; // number of addresses to create and list
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// error if no args
2017-09-15 12:59:27 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_importkey " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_exportkey " ) , runtime_error ) ;
2016-08-12 17:44:03 -07:00
2016-10-12 10:15:12 -07:00
// error if too many args
2017-01-31 08:19:11 -08:00
BOOST_CHECK_THROW ( CallRPC ( " z_importkey way too many args " ) , runtime_error ) ;
2016-10-12 10:15:12 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_exportkey toomany args " ) , runtime_error ) ;
2017-03-23 20:05:32 -07:00
// error if invalid args
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
2018-04-25 18:51:17 -07:00
auto sk = libzcash : : SproutSpendingKey : : random ( ) ;
2020-07-09 15:53:54 -07:00
std : : string prefix = std : : string ( " z_importkey " ) + keyIO . EncodeSpendingKey ( sk ) + " yes " ;
2017-03-23 20:05:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( prefix + " -1 " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( prefix + " 2147483647 " ) , runtime_error ) ; // allowed, but > height of active chain tip
BOOST_CHECK_THROW ( CallRPC ( prefix + " 2147483648 " ) , runtime_error ) ; // not allowed, > int32 used for nHeight
BOOST_CHECK_THROW ( CallRPC ( prefix + " 100badchars " ) , runtime_error ) ;
2016-08-12 17:44:03 -07:00
// wallet should currently be empty
2021-10-07 16:43:56 -07:00
std : : set < libzcash : : SproutPaymentAddress > sproutAddrs ;
pwalletMain - > GetSproutPaymentAddresses ( sproutAddrs ) ;
BOOST_CHECK ( sproutAddrs . size ( ) = = 0 ) ;
2018-08-01 11:59:57 -07:00
std : : set < libzcash : : SaplingPaymentAddress > saplingAddrs ;
pwalletMain - > GetSaplingPaymentAddresses ( saplingAddrs ) ;
BOOST_CHECK ( saplingAddrs . empty ( ) ) ;
2016-08-12 17:44:03 -07:00
2019-01-29 20:18:10 -08:00
auto m = GetTestMasterSaplingSpendingKey ( ) ;
2016-08-12 17:44:03 -07:00
// verify import and export key
for ( int i = 0 ; i < n1 ; i + + ) {
2018-07-11 14:01:07 -07:00
// create a random Sprout key locally
2018-04-25 18:51:17 -07:00
auto testSpendingKey = libzcash : : SproutSpendingKey : : random ( ) ;
2016-08-12 17:44:03 -07:00
auto testPaymentAddress = testSpendingKey . address ( ) ;
2020-07-09 15:53:54 -07:00
std : : string testAddr = keyIO . EncodePaymentAddress ( testPaymentAddress ) ;
std : : string testKey = keyIO . EncodeSpendingKey ( testSpendingKey ) ;
2016-08-12 17:44:03 -07:00
BOOST_CHECK_NO_THROW ( CallRPC ( string ( " z_importkey " ) + testKey ) ) ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( string ( " z_exportkey " ) + testAddr ) ) ;
BOOST_CHECK_EQUAL ( retValue . get_str ( ) , testKey ) ;
2018-08-28 16:07:07 -07:00
2021-10-07 16:43:56 -07:00
// create a random Sapling key locally; split between IVKs and spending keys.
2018-08-28 16:07:07 -07:00
auto testSaplingSpendingKey = m . Derive ( i ) ;
2021-09-21 10:17:33 -07:00
auto testSaplingPaymentAddress = testSaplingSpendingKey . ToXFVK ( ) . DefaultAddress ( ) ;
2021-10-07 16:43:56 -07:00
if ( i % 2 = = 0 ) {
std : : string testSaplingAddr = keyIO . EncodePaymentAddress ( testSaplingPaymentAddress ) ;
std : : string testSaplingKey = keyIO . EncodeSpendingKey ( testSaplingSpendingKey ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( string ( " z_importkey " ) + testSaplingKey ) ) ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( string ( " z_exportkey " ) + testSaplingAddr ) ) ;
BOOST_CHECK_EQUAL ( retValue . get_str ( ) , testSaplingKey ) ;
} else {
std : : string testSaplingAddr = keyIO . EncodePaymentAddress ( testSaplingPaymentAddress ) ;
std : : string testSaplingKey = keyIO . EncodeViewingKey ( testSaplingSpendingKey . ToXFVK ( ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( string ( " z_importviewingkey " ) + testSaplingKey ) ) ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( string ( " z_exportviewingkey " ) + testSaplingAddr ) ) ;
BOOST_CHECK_EQUAL ( retValue . get_str ( ) , testSaplingKey ) ;
}
2016-08-12 17:44:03 -07:00
}
// Verify we can list the keys imported
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue arr = retValue . get_array ( ) ;
2021-10-07 16:43:56 -07:00
BOOST_CHECK ( arr . size ( ) = = n1 + ( n1 / 2 ) ) ;
2016-08-12 17:44:03 -07:00
2021-10-06 19:39:52 -07:00
// Verify that the keys imported are also available from listaddresses
{
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " listaddresses " ) ) ;
auto listarr = retValue . get_array ( ) ;
bool sproutCountMatch = false ;
2021-10-07 16:43:56 -07:00
bool saplingSpendingKeyMatch = false ;
bool saplingIVKMatch = false ;
2021-10-06 19:39:52 -07:00
for ( auto a : listarr . getValues ( ) ) {
auto source = find_value ( a . get_obj ( ) , " source " ) ;
if ( source . get_str ( ) = = " legacy_random " ) {
auto sprout_obj = find_value ( a . get_obj ( ) , " sprout " ) . get_obj ( ) ;
auto sprout_addrs = find_value ( sprout_obj , " addresses " ) . get_array ( ) ;
sproutCountMatch = ( sprout_addrs . size ( ) = = n1 ) ;
}
if ( source . get_str ( ) = = " imported " ) {
2021-10-07 18:58:31 -07:00
int addr_count = 0 ;
for ( auto sapling_obj : find_value ( a . get_obj ( ) , " sapling " ) . get_array ( ) . getValues ( ) ) {
auto sapling_addrs = find_value ( sapling_obj , " addresses " ) . get_array ( ) ;
addr_count + = sapling_addrs . size ( ) ;
}
saplingSpendingKeyMatch = ( addr_count = = n1 / 2 ) ;
2021-10-07 16:43:56 -07:00
}
if ( source . get_str ( ) = = " imported_watchonly " ) {
2021-10-07 18:58:31 -07:00
int addr_count = 0 ;
for ( auto sapling_obj : find_value ( a . get_obj ( ) , " sapling " ) . get_array ( ) . getValues ( ) ) {
auto sapling_addrs = find_value ( sapling_obj , " addresses " ) . get_array ( ) ;
addr_count + = sapling_addrs . size ( ) ;
}
saplingIVKMatch = ( addr_count = = n1 / 2 ) ;
2021-10-06 19:39:52 -07:00
}
}
BOOST_CHECK ( sproutCountMatch ) ;
2021-10-07 16:43:56 -07:00
BOOST_CHECK ( saplingSpendingKeyMatch ) ;
BOOST_CHECK ( saplingIVKMatch ) ;
2021-10-06 19:39:52 -07:00
}
2016-08-12 17:44:03 -07:00
// Put addresses into a set
std : : unordered_set < std : : string > myaddrs ;
2017-01-06 10:15:56 -08:00
for ( UniValue element : arr . getValues ( ) ) {
2016-08-12 17:44:03 -07:00
myaddrs . insert ( element . get_str ( ) ) ;
}
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// Make new addresses for the set
for ( int i = 0 ; i < n2 ; i + + ) {
2020-07-09 15:53:54 -07:00
myaddrs . insert ( keyIO . EncodePaymentAddress ( pwalletMain - > GenerateNewSproutZKey ( ) ) ) ;
2016-08-12 17:44:03 -07:00
}
2021-10-07 16:43:56 -07:00
// Verify number of addresses stored in wallet is correct
2016-08-12 17:44:03 -07:00
int numAddrs = myaddrs . size ( ) ;
2021-10-07 16:43:56 -07:00
// sprout_addrs + sapling addrs with spend authority + new sprout addrs
BOOST_CHECK ( numAddrs = = ( n1 + ( n1 / 2 ) + n2 ) ) ;
pwalletMain - > GetSproutPaymentAddresses ( sproutAddrs ) ;
2018-08-01 11:59:57 -07:00
pwalletMain - > GetSaplingPaymentAddresses ( saplingAddrs ) ;
2021-10-07 16:43:56 -07:00
// here we also include the watchonly sapling addresses
BOOST_CHECK ( sproutAddrs . size ( ) + saplingAddrs . size ( ) = = numAddrs + ( n1 / 2 ) ) ;
2017-09-15 12:59:27 -07:00
2016-08-12 17:44:03 -07:00
// Ask wallet to list addresses
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
arr = retValue . get_array ( ) ;
BOOST_CHECK ( arr . size ( ) = = numAddrs ) ;
2017-09-15 12:59:27 -07:00
2016-08-24 08:35:04 -07:00
// Create a set from them
2016-08-12 17:44:03 -07:00
std : : unordered_set < std : : string > listaddrs ;
2017-01-06 10:15:56 -08:00
for ( UniValue element : arr . getValues ( ) ) {
2016-08-12 17:44:03 -07:00
listaddrs . insert ( element . get_str ( ) ) ;
}
2017-09-15 12:59:27 -07:00
2021-10-06 19:39:52 -07:00
// Verify that the newly added sprout keys imported are also available from listaddresses
{
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " listaddresses " ) ) ;
auto listarr = retValue . get_array ( ) ;
bool sproutCountMatch = false ;
for ( auto a : listarr . getValues ( ) ) {
auto source = find_value ( a . get_obj ( ) , " source " ) ;
if ( source . get_str ( ) = = " legacy_random " ) {
auto sprout_obj = find_value ( a . get_obj ( ) , " sprout " ) . get_obj ( ) ;
auto sprout_addrs = find_value ( sprout_obj , " addresses " ) . get_array ( ) ;
sproutCountMatch = ( sprout_addrs . size ( ) = = n1 + n2 ) ;
}
}
BOOST_CHECK ( sproutCountMatch ) ;
}
2021-10-05 06:41:08 -07:00
2016-08-12 17:44:03 -07:00
// Verify the two sets of addresses are the same
BOOST_CHECK ( listaddrs . size ( ) = = numAddrs ) ;
BOOST_CHECK ( myaddrs = = listaddrs ) ;
2018-12-23 16:38:48 -08:00
}
2016-10-12 10:15:12 -07:00
2018-12-23 16:38:48 -08:00
// Check if address is of given type and spendable from our wallet.
template < typename ADDR_TYPE >
2021-12-16 15:28:43 -08:00
void CheckHaveAddr ( const std : : optional < libzcash : : PaymentAddress > & addr ) {
BOOST_CHECK ( addr . has_value ( ) ) ;
auto addr_of_type = std : : get_if < ADDR_TYPE > ( & ( addr . value ( ) ) ) ;
2018-12-23 16:38:48 -08:00
BOOST_ASSERT ( addr_of_type ! = nullptr ) ;
2023-02-13 21:50:41 -08:00
BOOST_CHECK ( pwalletMain - > ZTXOSelectorForAddress (
* addr_of_type ,
true ,
TransparentCoinbasePolicy : : Allow ,
2023-03-09 00:22:13 -08:00
false ) . has_value ( ) ) ;
2016-08-12 17:44:03 -07:00
}
2016-09-03 22:25:13 -07:00
2018-12-23 16:38:48 -08:00
BOOST_AUTO_TEST_CASE ( rpc_wallet_z_getnewaddress ) {
using namespace libzcash ;
2021-09-24 13:24:41 -07:00
UniValue addr ;
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
2018-12-23 16:38:48 -08:00
// No parameter defaults to sapling address
addr = CallRPC ( " z_getnewaddress " ) ;
2020-07-09 15:53:54 -07:00
CheckHaveAddr < SaplingPaymentAddress > ( keyIO . DecodePaymentAddress ( addr . get_str ( ) ) ) ;
2018-12-23 16:38:48 -08:00
// Passing 'sapling' should also work
addr = CallRPC ( " z_getnewaddress sapling " ) ;
2020-07-09 15:53:54 -07:00
CheckHaveAddr < SaplingPaymentAddress > ( keyIO . DecodePaymentAddress ( addr . get_str ( ) ) ) ;
2016-09-03 22:25:13 -07:00
2018-12-23 16:38:48 -08:00
// Should also support sprout
addr = CallRPC ( " z_getnewaddress sprout " ) ;
2020-07-09 15:53:54 -07:00
CheckHaveAddr < SproutPaymentAddress > ( keyIO . DecodePaymentAddress ( addr . get_str ( ) ) ) ;
2018-12-23 16:38:48 -08:00
2022-01-12 15:50:09 -08:00
// Requesting a sprout address during IBD should fail
bool ibd = TestSetIBD ( true ) ;
CheckRPCThrows ( " z_getnewaddress sprout " , " Error: Creating a Sprout address during initial block download is not supported. " ) ;
TestSetIBD ( ibd ) ;
2018-12-23 16:38:48 -08:00
// Should throw on invalid argument
2020-01-17 05:30:14 -08:00
CheckRPCThrows ( " z_getnewaddress garbage " , " Invalid address type " ) ;
// Too many arguments will throw with the help
BOOST_CHECK_THROW ( CallRPC ( " z_getnewaddress many args " ) , runtime_error ) ;
2021-10-07 08:41:09 -07:00
{
UniValue list ;
BOOST_CHECK_NO_THROW ( list = CallRPC ( " listaddresses " ) ) ;
auto listarr = list . get_array ( ) ;
bool sproutCountMatch = false ;
2021-10-08 09:30:39 -07:00
bool saplingExtfvksMatch = false ;
2021-10-19 19:04:21 -07:00
bool saplingSpendAuth0 = false ;
bool saplingSpendAuth1 = false ;
2021-10-07 08:41:09 -07:00
bool saplingCountMismatch = true ;
for ( auto a : listarr . getValues ( ) ) {
auto source = find_value ( a . get_obj ( ) , " source " ) ;
if ( source . get_str ( ) = = " legacy_random " ) {
2021-10-19 19:04:21 -07:00
auto sproutObj = find_value ( a . get_obj ( ) , " sprout " ) . get_obj ( ) ;
auto sproutAddrs = find_value ( sproutObj , " addresses " ) . get_array ( ) ;
sproutCountMatch = ( sproutAddrs . size ( ) = = 1 ) ;
2021-10-07 08:41:09 -07:00
}
2022-03-22 10:18:30 -07:00
if ( source . get_str ( ) = = " mnemonic_seed " ) {
2021-10-07 08:41:09 -07:00
auto sapling_addr_sets = find_value ( a . get_obj ( ) , " sapling " ) . get_array ( ) ;
2021-10-08 09:30:39 -07:00
saplingExtfvksMatch = ( sapling_addr_sets . size ( ) = = 2 ) ;
2021-10-07 08:41:09 -07:00
2021-10-19 19:04:21 -07:00
for ( auto saplingObj : sapling_addr_sets . getValues ( ) ) {
auto keypath = find_value ( saplingObj , " zip32KeyPath " ) . get_str ( ) ;
2021-10-28 12:07:58 -07:00
saplingSpendAuth0 | = ( keypath = = " m/32'/133'/2147483647'/0' " ) ;
saplingSpendAuth1 | = ( keypath = = " m/32'/133'/2147483647'/1' " ) ;
2021-10-19 19:04:21 -07:00
auto saplingAddrs = find_value ( saplingObj , " addresses " ) . get_array ( ) ;
saplingCountMismatch & = ( saplingAddrs . size ( ) ! = 1 ) ;
2021-10-07 08:41:09 -07:00
}
}
}
BOOST_CHECK ( sproutCountMatch ) ;
2021-10-08 09:30:39 -07:00
BOOST_CHECK ( saplingExtfvksMatch ) ;
2021-10-07 08:41:09 -07:00
BOOST_CHECK ( ! saplingCountMismatch ) ;
2021-10-19 19:04:21 -07:00
BOOST_CHECK ( saplingSpendAuth0 ) ;
BOOST_CHECK ( saplingSpendAuth1 ) ;
2021-10-07 08:41:09 -07:00
}
2018-12-23 16:38:48 -08:00
}
2016-09-03 22:25:13 -07:00
/**
2016-09-04 23:18:26 -07:00
* Test Async RPC operations .
2016-09-03 22:25:13 -07:00
* Tip : Create mock operations by subclassing AsyncRPCOperation .
*/
2016-09-04 23:18:26 -07:00
2016-09-03 22:25:13 -07:00
class MockSleepOperation : public AsyncRPCOperation {
public :
std : : chrono : : milliseconds naptime ;
MockSleepOperation ( int t = 1000 ) {
this - > naptime = std : : chrono : : milliseconds ( t ) ;
}
virtual ~ MockSleepOperation ( ) {
}
virtual void main ( ) {
set_state ( OperationStatus : : EXECUTING ) ;
start_execution_clock ( ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( naptime ) ) ;
stop_execution_clock ( ) ;
2017-01-06 10:15:56 -08:00
set_result ( UniValue ( UniValue : : VSTR , " done " ) ) ;
2016-09-03 22:25:13 -07:00
set_state ( OperationStatus : : SUCCESS ) ;
}
} ;
/*
2021-11-12 02:02:19 -08:00
* Test Async RPC queue and operations .
2016-09-03 22:25:13 -07:00
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_async_operations )
{
std : : shared_ptr < AsyncRPCQueue > q = std : : make_shared < AsyncRPCQueue > ( ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 0 ) ;
std : : vector < AsyncRPCOperationId > ids = q - > getAllOperationIds ( ) ;
BOOST_CHECK ( ids . size ( ) = = 0 ) ;
std : : shared_ptr < AsyncRPCOperation > op1 = std : : make_shared < AsyncRPCOperation > ( ) ;
2017-09-15 12:59:27 -07:00
q - > addOperation ( op1 ) ;
2016-09-03 22:25:13 -07:00
BOOST_CHECK ( q - > getOperationCount ( ) = = 1 ) ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
OperationStatus status = op1 - > getState ( ) ;
BOOST_CHECK ( status = = OperationStatus : : READY ) ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
AsyncRPCOperationId id1 = op1 - > getId ( ) ;
int64_t creationTime1 = op1 - > getCreationTime ( ) ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
q - > addWorker ( ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 1 ) ;
2017-09-15 12:59:27 -07:00
// an AsyncRPCOperation doesn't do anything so will finish immediately
2016-09-03 22:25:13 -07:00
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
BOOST_CHECK ( q - > getOperationCount ( ) = = 0 ) ;
// operation should be a success
BOOST_CHECK_EQUAL ( op1 - > isCancelled ( ) , false ) ;
BOOST_CHECK_EQUAL ( op1 - > isExecuting ( ) , false ) ;
BOOST_CHECK_EQUAL ( op1 - > isReady ( ) , false ) ;
BOOST_CHECK_EQUAL ( op1 - > isFailed ( ) , false ) ;
BOOST_CHECK_EQUAL ( op1 - > isSuccess ( ) , true ) ;
2017-01-06 10:15:56 -08:00
BOOST_CHECK_EQUAL ( op1 - > getError ( ) . isNull ( ) , true ) ;
BOOST_CHECK_EQUAL ( op1 - > getResult ( ) . isNull ( ) , false ) ;
2016-09-03 22:25:13 -07:00
BOOST_CHECK_EQUAL ( op1 - > getStateAsString ( ) , " success " ) ;
BOOST_CHECK_NE ( op1 - > getStateAsString ( ) , " executing " ) ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
// Create a second operation which just sleeps
std : : shared_ptr < AsyncRPCOperation > op2 ( new MockSleepOperation ( 2500 ) ) ;
AsyncRPCOperationId id2 = op2 - > getId ( ) ;
int64_t creationTime2 = op2 - > getCreationTime ( ) ;
// it's different from the previous operation
BOOST_CHECK_NE ( op1 . get ( ) , op2 . get ( ) ) ;
BOOST_CHECK_NE ( id1 , id2 ) ;
BOOST_CHECK_NE ( creationTime1 , creationTime2 ) ;
// Only the first operation has been added to the queue
std : : vector < AsyncRPCOperationId > v = q - > getAllOperationIds ( ) ;
std : : set < AsyncRPCOperationId > opids ( v . begin ( ) , v . end ( ) ) ;
BOOST_CHECK ( opids . size ( ) = = 1 ) ;
BOOST_CHECK ( opids . count ( id1 ) = = 1 ) ;
BOOST_CHECK ( opids . count ( id2 ) = = 0 ) ;
std : : shared_ptr < AsyncRPCOperation > p1 = q - > getOperationForId ( id1 ) ;
BOOST_CHECK_EQUAL ( p1 . get ( ) , op1 . get ( ) ) ;
std : : shared_ptr < AsyncRPCOperation > p2 = q - > getOperationForId ( id2 ) ;
BOOST_CHECK ( ! p2 ) ; // null ptr as not added to queue yet
// Add operation 2 and 3 to the queue
q - > addOperation ( op2 ) ;
std : : shared_ptr < AsyncRPCOperation > op3 ( new MockSleepOperation ( 1000 ) ) ;
q - > addOperation ( op3 ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 500 ) ) ;
BOOST_CHECK_EQUAL ( op2 - > isExecuting ( ) , true ) ;
op2 - > cancel ( ) ; // too late, already executing
op3 - > cancel ( ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 3000 ) ) ;
BOOST_CHECK_EQUAL ( op2 - > isSuccess ( ) , true ) ;
BOOST_CHECK_EQUAL ( op2 - > isCancelled ( ) , false ) ;
BOOST_CHECK_EQUAL ( op3 - > isCancelled ( ) , true ) ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
v = q - > getAllOperationIds ( ) ;
std : : copy ( v . begin ( ) , v . end ( ) , std : : inserter ( opids , opids . end ( ) ) ) ;
BOOST_CHECK ( opids . size ( ) = = 3 ) ;
BOOST_CHECK ( opids . count ( id1 ) = = 1 ) ;
BOOST_CHECK ( opids . count ( id2 ) = = 1 ) ;
BOOST_CHECK ( opids . count ( op3 - > getId ( ) ) = = 1 ) ;
q - > finishAndWait ( ) ;
}
// The CountOperation will increment this global
std : : atomic < int64_t > gCounter ( 0 ) ;
class CountOperation : public AsyncRPCOperation {
public :
CountOperation ( ) { }
virtual ~ CountOperation ( ) { }
2017-09-15 12:59:27 -07:00
virtual void main ( ) {
2016-09-03 22:25:13 -07:00
set_state ( OperationStatus : : EXECUTING ) ;
gCounter + + ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1000 ) ) ;
set_state ( OperationStatus : : SUCCESS ) ;
}
} ;
// This tests the queue waiting for multiple workers to finish
BOOST_AUTO_TEST_CASE ( rpc_wallet_async_operations_parallel_wait )
{
gCounter = 0 ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
std : : shared_ptr < AsyncRPCQueue > q = std : : make_shared < AsyncRPCQueue > ( ) ;
q - > addWorker ( ) ;
q - > addWorker ( ) ;
q - > addWorker ( ) ;
q - > addWorker ( ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 4 ) ;
int64_t numOperations = 10 ; // 10 * 1000ms / 4 = 2.5 secs to finish
for ( int i = 0 ; i < numOperations ; i + + ) {
std : : shared_ptr < AsyncRPCOperation > op ( new CountOperation ( ) ) ;
q - > addOperation ( op ) ;
}
std : : vector < AsyncRPCOperationId > ids = q - > getAllOperationIds ( ) ;
BOOST_CHECK ( ids . size ( ) = = numOperations ) ;
q - > finishAndWait ( ) ;
BOOST_CHECK_EQUAL ( q - > isFinishing ( ) , true ) ;
BOOST_CHECK_EQUAL ( numOperations , gCounter . load ( ) ) ;
}
// This tests the queue shutting down immediately
BOOST_AUTO_TEST_CASE ( rpc_wallet_async_operations_parallel_cancel )
{
gCounter = 0 ;
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
std : : shared_ptr < AsyncRPCQueue > q = std : : make_shared < AsyncRPCQueue > ( ) ;
q - > addWorker ( ) ;
q - > addWorker ( ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 2 ) ;
2016-09-04 23:18:26 -07:00
int numOperations = 10000 ; // 10000 seconds to complete
2016-09-03 22:25:13 -07:00
for ( int i = 0 ; i < numOperations ; i + + ) {
std : : shared_ptr < AsyncRPCOperation > op ( new CountOperation ( ) ) ;
q - > addOperation ( op ) ;
}
std : : vector < AsyncRPCOperationId > ids = q - > getAllOperationIds ( ) ;
BOOST_CHECK ( ids . size ( ) = = numOperations ) ;
q - > closeAndWait ( ) ;
int numSuccess = 0 ;
2017-09-15 12:59:27 -07:00
int numCancelled = 0 ;
2016-09-03 22:25:13 -07:00
for ( auto & id : ids ) {
std : : shared_ptr < AsyncRPCOperation > ptr = q - > popOperationForId ( id ) ;
if ( ptr - > isCancelled ( ) ) {
numCancelled + + ;
} else if ( ptr - > isSuccess ( ) ) {
numSuccess + + ;
}
}
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
BOOST_CHECK_EQUAL ( numOperations , numSuccess + numCancelled ) ;
BOOST_CHECK_EQUAL ( gCounter . load ( ) , numSuccess ) ;
BOOST_CHECK ( q - > getOperationCount ( ) = = 0 ) ;
ids = q - > getAllOperationIds ( ) ;
BOOST_CHECK ( ids . size ( ) = = 0 ) ;
}
2016-09-04 23:18:26 -07:00
// This tests z_getoperationstatus, z_getoperationresult, z_listoperationids
BOOST_AUTO_TEST_CASE ( rpc_z_getoperations )
{
std : : shared_ptr < AsyncRPCQueue > q = getAsyncRPCQueue ( ) ;
std : : shared_ptr < AsyncRPCQueue > sharedInstance = AsyncRPCQueue : : sharedInstance ( ) ;
BOOST_CHECK ( q = = sharedInstance ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationstatus " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationstatus [] " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationstatus [ \" opid-1234 \" ] " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_getoperationstatus [] toomanyargs " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_getoperationstatus not_an_array " ) , runtime_error ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationresult " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationresult [] " ) ) ;
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getoperationresult [ \" opid-1234 \" ] " ) ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_getoperationresult [] toomanyargs " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_getoperationresult not_an_array " ) , runtime_error ) ;
2017-09-15 12:59:27 -07:00
2016-09-04 23:18:26 -07:00
std : : shared_ptr < AsyncRPCOperation > op1 = std : : make_shared < AsyncRPCOperation > ( ) ;
q - > addOperation ( op1 ) ;
std : : shared_ptr < AsyncRPCOperation > op2 = std : : make_shared < AsyncRPCOperation > ( ) ;
q - > addOperation ( op2 ) ;
2017-09-15 12:59:27 -07:00
2016-09-04 23:18:26 -07:00
BOOST_CHECK ( q - > getOperationCount ( ) = = 2 ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 0 ) ;
q - > addWorker ( ) ;
BOOST_CHECK ( q - > getNumberOfWorkers ( ) = = 1 ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 1000 ) ) ;
BOOST_CHECK ( q - > getOperationCount ( ) = = 0 ) ;
2017-09-15 12:59:27 -07:00
2016-10-12 10:15:12 -07:00
// Check if too many args
BOOST_CHECK_THROW ( CallRPC ( " z_listoperationids toomany args " ) , runtime_error ) ;
2017-01-06 10:15:56 -08:00
UniValue retValue ;
2016-09-04 23:18:26 -07:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listoperationids " ) ) ;
BOOST_CHECK ( retValue . get_array ( ) . size ( ) = = 2 ) ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_getoperationstatus " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue array = retValue . get_array ( ) ;
2016-09-04 23:18:26 -07:00
BOOST_CHECK ( array . size ( ) = = 2 ) ;
// idempotent
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_getoperationstatus " ) ) ;
array = retValue . get_array ( ) ;
2017-09-15 12:59:27 -07:00
BOOST_CHECK ( array . size ( ) = = 2 ) ;
2017-01-06 10:15:56 -08:00
for ( UniValue v : array . getValues ( ) ) {
UniValue obj = v . get_obj ( ) ;
UniValue id = find_value ( obj , " id " ) ;
2017-09-15 12:59:27 -07:00
2017-01-06 10:15:56 -08:00
UniValue result ;
2016-09-04 23:18:26 -07:00
// removes result from internal storage
BOOST_CHECK_NO_THROW ( result = CallRPC ( " z_getoperationresult [ \" " + id . get_str ( ) + " \" ] " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue resultArray = result . get_array ( ) ;
2016-09-04 23:18:26 -07:00
BOOST_CHECK ( resultArray . size ( ) = = 1 ) ;
2017-09-15 12:59:27 -07:00
2017-01-06 10:15:56 -08:00
UniValue resultObj = resultArray [ 0 ] . get_obj ( ) ;
UniValue resultId = find_value ( resultObj , " id " ) ;
2016-09-04 23:18:26 -07:00
BOOST_CHECK_EQUAL ( id . get_str ( ) , resultId . get_str ( ) ) ;
2017-09-15 12:59:27 -07:00
// verify the operation has been removed
2016-09-08 11:06:18 -07:00
BOOST_CHECK_NO_THROW ( result = CallRPC ( " z_getoperationresult [ \" " + id . get_str ( ) + " \" ] " ) ) ;
resultArray = result . get_array ( ) ;
BOOST_CHECK ( resultArray . size ( ) = = 0 ) ;
2016-09-04 23:18:26 -07:00
}
2017-09-15 12:59:27 -07:00
2016-09-04 23:18:26 -07:00
// operations removed
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_getoperationstatus " ) ) ;
array = retValue . get_array ( ) ;
BOOST_CHECK ( array . size ( ) = = 0 ) ;
q - > close ( ) ;
}
BOOST_AUTO_TEST_CASE ( rpc_z_sendmany_parameters )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2016-09-04 23:18:26 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany toofewargs " ) , runtime_error ) ;
2021-09-23 07:53:20 -07:00
// too many arguments:
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany addr [] 1 0.001 true true " ) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
// bad from address
2016-09-08 11:06:18 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
2016-10-03 23:51:32 -07:00
" INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ [] " ) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
// empty amounts
2016-09-08 11:06:18 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
2016-10-03 23:51:32 -07:00
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ [] " ) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
// don't have the spending key for this address
2016-09-08 11:06:18 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
" tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
" UkJ1oSfbhTJhm72WiZizvkZz5aH1 [] " ) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
// duplicate address
2016-09-08 11:06:18 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
2016-10-03 23:51:32 -07:00
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
2021-10-28 16:15:32 -07:00
" [{ \" address \" : \" tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn \" , \" amount \" :50.0}, "
" { \" address \" : \" tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn \" , \" amount \" :12.0}] "
2016-09-08 11:06:18 -07:00
) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
2016-11-30 14:18:29 -08:00
// invalid fee amount, cannot be negative
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
2021-10-28 16:15:32 -07:00
" [{ \" address \" : \" tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn \" , \" amount \" :50.0}] "
2020-12-17 11:39:58 -08:00
" 1 -0.00001 "
2016-11-30 14:18:29 -08:00
) , runtime_error ) ;
// invalid fee amount, bigger than MAX_MONEY
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
2021-10-28 16:15:32 -07:00
" [{ \" address \" : \" tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn \" , \" amount \" :50.0}] "
2016-11-30 14:18:29 -08:00
" 1 21000001 "
) , runtime_error ) ;
// fee amount is bigger than sum of outputs
BOOST_CHECK_THROW ( CallRPC ( " z_sendmany "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
2021-10-28 16:15:32 -07:00
" [{ \" address \" : \" tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn \" , \" amount \" :50.0}] "
2016-11-30 14:18:29 -08:00
" 1 50.00000001 "
) , runtime_error ) ;
2016-09-04 23:18:26 -07:00
// memo bigger than allowed length of ZC_MEMO_SIZE
2016-09-06 00:06:12 -07:00
std : : vector < char > v ( 2 * ( ZC_MEMO_SIZE + 1 ) ) ; // x2 for hexadecimal string format
std : : fill ( v . begin ( ) , v . end ( ) , ' A ' ) ;
2016-09-04 23:18:26 -07:00
std : : string badmemo ( v . begin ( ) , v . end ( ) ) ;
2018-10-08 13:23:03 -07:00
auto pa = pwalletMain - > GenerateNewSproutZKey ( ) ;
2020-07-09 15:53:54 -07:00
KeyIO keyIO ( Params ( ) ) ;
std : : string zaddr1 = keyIO . EncodePaymentAddress ( pa ) ;
2016-10-03 23:51:32 -07:00
BOOST_CHECK_THROW ( CallRPC ( string ( " z_sendmany tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ " )
2021-10-28 16:15:32 -07:00
+ " [{ \" address \" : \" " + zaddr1 + " \" , \" amount \" :123.456}] " ) , runtime_error ) ;
2017-09-15 12:59:27 -07:00
2018-02-15 22:19:36 -08:00
// Mutable tx containing contextual information we need to build tx
UniValue retValue = CallRPC ( " getblockcount " ) ;
int nHeight = retValue . get_int ( ) ;
2022-02-11 15:41:35 -08:00
TransactionBuilder builder ( Params ( ) . GetConsensus ( ) , nHeight + 1 , std : : nullopt , pwalletMain ) ;
2016-09-04 23:18:26 -07:00
}
2019-05-28 16:58:49 -07:00
BOOST_AUTO_TEST_CASE ( asyncrpcoperation_sign_send_raw_transaction ) {
// Raw joinsplit is a zaddr->zaddr
std : : string raw = " 020000000000000000000100000000000000001027000000000000183a0d4c46c369078705e39bcfebee59a978dbd210ce8de3efc9555a03fbabfd3cea16693d730c63850d7e48ccde79854c19adcb7e9dcd7b7d18805ee09083f6b16e1860729d2d4a90e2f2acd009cf78b5eb0f4a6ee4bdb64b1262d7ce9eb910c460b02022991e968d0c50ee44908e4ccccbc591d0053bcca154dd6d6fc400a29fa686af4682339832ccea362a62aeb9df0d5aa74f86a1e75ac0f48a8ccc41e0a940643c6c33e1d09223b0a46eaf47a1bb4407cfc12b1dcf83a29c0cef51e45c7876ca5b9e5bae86d92976eb3ef68f29cd29386a8be8451b50f82bf9da10c04651868655194da8f6ed3d241bb5b5ff93a3e2bbe44644544d88bcde5cc35978032ee92699c7a61fcbb395e7583f47e698c4d53ede54f956629400bf510fb5e22d03158cc10bdcaaf29e418ef18eb6480dd9c8b9e2a377809f9f32a556ef872febd0021d4ad013aa9f0b7255e98e408d302abefd33a71180b720271835b487ab309e160b06dfe51932120fb84a7ede16b20c53599a11071592109e10260f265ee60d48c62bfe24074020e9b586ce9e9356e68f2ad1a9538258234afe4b83a209f178f45202270eaeaeecaf2ce3100b2c5a714f75f35777a9ebff5ebf47059d2bbf6f3726190216468f2b152673b766225b093f3a2f827c86d6b48b42117fec1d0ac38dd7af700308dcfb02eba821612b16a2c164c47715b9b0c93900893b1aba2ea03765c94d87022db5be06ab338d1912e0936dfe87586d0a8ee49144a6cd2e306abdcb652faa3e0222739deb23154d778b50de75069a4a2cce1208cd1ced3cb4744c9888ce1c2fcd2e66dc31e62d3aa9e423d7275882525e9981f92e84ac85975b8660739407efbe1e34c2249420fde7e17db3096d5b22e83d051d01f0e6e7690dca7d168db338aadf0897fedac10de310db2b1bff762d322935dddbb60c2efb8b15d231fa17b84630371cb275c209f0c4c7d0c68b150ea5cd514122215e3f7fcfb351d69514788d67c2f3c8922581946e3a04bdf1f07f15696ca76eb95b10698bf1188fd882945c57657515889d042a6fc45d38cbc943540c4f0f6d1c45a1574c81f3e42d1eb8702328b729909adee8a5cfed7c79d54627d1fd389af941d878376f7927b9830ca659bf9ab18c5ca5192d52d02723008728d03701b8ab3e1c4a3109409ec0b13df334c7deec3523eeef4c97b5603e643de3a647b873f4c1b47fbfc6586ba66724f112e51fc93839648005043620aa3ce458e246d77977b19c53d98e3e812de006afc1a79744df236582943631d04cc02941ac4be500e4ed9fb9e3e7cc187b1c4050fad1d9d09d5fd70d5d01d615b439d8c0015d2eb10398bcdbf8c4b2bd559dbe4c288a186aed3f86f608da4d582e120c4a896e015e2241900d1daeccd05db968852677c71d752bec46de9962174b46f980e8cc603654daf8b98a3ee92dac066033954164a89568b70b1780c2ce2410b2f816dbeddb2cd463e0c8f21a52cf6427d9647a6fd4bafa8fb4cd4d47ac057b0160bee86c6b2fb8adce214c2bcdda277512200adf0eaa5d2114a2c077b009836a68ec254bfe56f51d147b9afe2ddd9cb917c0c2de19d81b7b8fd9f4574f51fa1207630dc13976f4d7587c962f761af267de71f3909a576e6bedaf6311633910d291ac292c467cc8331ef577aef7646a5d949322fa0367a49f20597a13def53136ee31610395e3e48d291fd8f58504374031fe9dcfba5e06086ebcf01a9106f6a4d6e16e19e4c5bb893f7da79419c94eca31a384be6fa1747284dee0fc3bbc8b1b860172c10b29c1594bb8c747d7fe05827358ff2160f49050001625ffe2e880bd7fc26cd0ffd89750745379a8e862816e08a5a2008043921ab6a4976064ac18f7ee37b6628bc0127d8d5ebd3548e41d8881a082d86f20b32e33094f15a0e6ea6074b08c6cd28142de94713451640a55985051f5577eb54572699d838cb34a79c8939e981c0c277d06a6e2ce69ccb74f8a691ff08f81d8b99e6a86223d29a2b7c8e7b041aba44ea678ae654277f7e91cbfa79158b989164a3d549d9f4feb0cc43169699c13e321fe3f4b94258c75d198ff9184269cd6986c55409e07528c93f64942c6c283ce3917b4bf4c3be2fe3173c8c38cccb35f1fbda0ca88b35a599c0678cb22aa8eabea8249dbd2e4f849fffe69803d299e435ebcd7df95854003d8eda17a74d98b4be0e62d45d7fe48c06a6f464a14f8e0570077cc631279092802a89823f031eef5e1028a6d6fdbd502869a731ee7d28b4d6c71b419462a30d31442d3ee444ffbcbd16d558c9000c97e949c2b1f9d6f6d8db7b9131ebd963620d3fc8595278d6f8fdf49084325373196d53e64142fa5a23eccd6ef908c4d80b8b3e6cc334b7f7012103a3682e4678e9b518163d262a39a2c1a69bf88514c52b7ccd7cc8dc80e71f7c2ec0701cff982573eb0c2c4daeb47fa0b586f4451c10d1da2e5d182b03dd067a5e971b3a6138ca6667aaf853d2ac03b80a1d5870905f2cfb6c78ec3c3719c02f973d638a0f973424a2b0f2b0023f136d60092fe15fba4bc180b9176bd0ff576e053f1af6939fe9ca256203ffaeb3e569f09774d2a6cbf91873e56651f4d6ff77e0b5374b0a1a201d7e523604e0247644544cc571d48c458a4f96f45580b " ;
UniValue obj ( UniValue : : VOBJ ) ;
2020-05-14 11:34:27 -07:00
obj . pushKV ( " rawtxn " , raw ) ;
2019-05-28 16:58:49 -07:00
// Verify test mode is returning output (since no input taddrs, signed and unsigned are the same).
2020-10-20 17:44:15 -07:00
std : : pair < CTransaction , UniValue > txAndResult = SignSendRawTransaction ( obj , std : : nullopt , true ) ;
2019-05-28 16:58:49 -07:00
UniValue resultObj = txAndResult . second . get_obj ( ) ;
std : : string hex = find_value ( resultObj , " hex " ) . get_str ( ) ;
BOOST_CHECK_EQUAL ( hex , raw ) ;
}
2016-09-06 00:06:12 -07:00
2016-09-04 23:18:26 -07:00
// TODO: test private methods
BOOST_AUTO_TEST_CASE ( rpc_z_sendmany_internals )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2020-10-13 13:58:20 -07:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2021-12-28 08:30:02 -08:00
KeyIO keyIO ( Params ( ) ) ;
2016-09-04 23:18:26 -07:00
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2016-09-04 23:18:26 -07:00
2017-01-06 10:15:56 -08:00
UniValue retValue ;
2017-09-15 12:59:27 -07:00
2018-02-15 22:19:36 -08:00
// Mutable tx containing contextual information we need to build tx
2019-06-25 03:08:26 -07:00
// We removed the ability to create pre-Sapling Sprout proofs, so we can
// only create Sapling-onwards transactions.
int nHeight = consensusParams . vUpgrades [ Consensus : : UPGRADE_SAPLING ] . nActivationHeight ;
2018-02-15 22:19:36 -08:00
2016-09-04 23:18:26 -07:00
// add keys manually
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getnewaddress " ) ) ;
2022-01-12 12:07:10 -08:00
auto taddr1 = std : : get < CKeyID > ( keyIO . DecodePaymentAddress ( retValue . get_str ( ) ) . value ( ) ) ;
2021-12-28 08:30:02 -08:00
2022-01-12 15:54:12 -08:00
if ( ! pwalletMain - > HaveMnemonicSeed ( ) ) {
2021-12-28 08:30:02 -08:00
pwalletMain - > GenerateNewSeed ( ) ;
}
2022-01-12 15:54:12 -08:00
auto zaddr1 = pwalletMain - > GenerateNewLegacySaplingZKey ( ) ;
2017-09-15 12:59:27 -07:00
2016-09-04 23:18:26 -07:00
// there are no utxos to spend
{
2023-02-13 21:50:41 -08:00
auto selector = pwalletMain - > ZTXOSelectorForAddress (
taddr1 ,
true ,
2023-03-16 12:57:57 -07:00
// In the real transaction builder we use either Require or Disallow, but here we
// are checking that there are no UTXOs at all, so we allow either to be selected to
// confirm this.
TransparentCoinbasePolicy : : Allow ,
2023-03-09 00:22:13 -08:00
false ) . value ( ) ;
2023-03-22 14:34:18 -07:00
WalletTxBuilder builder ( Params ( ) , minRelayTxFee ) ;
2022-05-26 15:28:35 -07:00
std : : vector < Payment > recipients = { Payment ( zaddr1 , 100 * COIN , Memo : : FromHexOrThrow ( " DEADBEEF " ) ) } ;
2023-03-09 00:22:13 -08:00
TransactionStrategy strategy ( PrivacyPolicy : : AllowRevealedSenders ) ;
2023-04-03 11:05:55 -07:00
std : : shared_ptr < AsyncRPCOperation > operation ( new AsyncRPCOperation_sendmany ( std : : move ( builder ) , selector , recipients , 1 , 1 , strategy , std : : nullopt ) ) ;
2016-09-04 23:18:26 -07:00
operation - > main ( ) ;
BOOST_CHECK ( operation - > isFailed ( ) ) ;
std : : string msg = operation - > getErrorMessage ( ) ;
2021-12-28 08:30:02 -08:00
BOOST_CHECK ( msg . find ( " Insufficient funds " ) ! = string : : npos ) ;
2016-09-04 23:18:26 -07:00
}
2017-07-11 11:29:43 -07:00
2016-09-04 23:18:26 -07:00
// there are no unspent notes to spend
{
2023-02-13 21:50:41 -08:00
auto selector = pwalletMain - > ZTXOSelectorForAddress (
zaddr1 ,
true ,
TransparentCoinbasePolicy : : Disallow ,
2023-03-09 00:22:13 -08:00
false ) . value ( ) ;
2023-03-22 14:34:18 -07:00
WalletTxBuilder builder ( Params ( ) , minRelayTxFee ) ;
2022-05-26 15:28:35 -07:00
std : : vector < Payment > recipients = { Payment ( taddr1 , 100 * COIN , Memo : : FromHexOrThrow ( " DEADBEEF " ) ) } ;
2023-03-09 00:22:13 -08:00
TransactionStrategy strategy ( PrivacyPolicy : : AllowRevealedRecipients ) ;
2023-04-03 11:05:55 -07:00
std : : shared_ptr < AsyncRPCOperation > operation ( new AsyncRPCOperation_sendmany ( std : : move ( builder ) , selector , recipients , 1 , 1 , strategy , std : : nullopt ) ) ;
2016-09-04 23:18:26 -07:00
operation - > main ( ) ;
BOOST_CHECK ( operation - > isFailed ( ) ) ;
std : : string msg = operation - > getErrorMessage ( ) ;
2022-01-08 17:10:38 -08:00
BOOST_CHECK ( msg . find ( " Insufficient funds: have 0.00 " ) ! = string : : npos ) ;
2016-09-04 23:18:26 -07:00
}
2022-05-24 15:50:53 -07:00
}
2016-09-04 23:18:26 -07:00
2022-05-24 15:50:53 -07:00
BOOST_AUTO_TEST_CASE ( memo_hex_parsing ) {
std : : string memo = " DEADBEEF " ;
MemoBytes memoBytes = Memo : : FromHexOrThrow ( memo ) . ToBytes ( ) ;
BOOST_CHECK_EQUAL ( memoBytes [ 0 ] , 0xDE ) ;
BOOST_CHECK_EQUAL ( memoBytes [ 1 ] , 0xAD ) ;
BOOST_CHECK_EQUAL ( memoBytes [ 2 ] , 0xBE ) ;
BOOST_CHECK_EQUAL ( memoBytes [ 3 ] , 0xEF ) ;
for ( int i = 4 ; i < ZC_MEMO_SIZE ; i + + ) {
BOOST_CHECK_EQUAL ( memoBytes [ i ] , 0x00 ) ; // zero padding
}
2017-09-15 12:59:27 -07:00
2022-05-24 15:50:53 -07:00
// memo is longer than allowed
std : : vector < char > v ( 2 * ( ZC_MEMO_SIZE + 1 ) ) ;
std : : fill ( v . begin ( ) , v . end ( ) , ' A ' ) ;
std : : string bigmemo ( v . begin ( ) , v . end ( ) ) ;
BOOST_CHECK ( std : : get < MemoError > ( Memo : : FromHex ( bigmemo ) ) = = MemoError : : MemoTooLong ) ;
2017-09-15 12:59:27 -07:00
2022-05-24 15:50:53 -07:00
// invalid hexadecimal string
std : : fill ( v . begin ( ) , v . end ( ) , ' @ ' ) ; // not a hex character
std : : string badmemo ( v . begin ( ) , v . end ( ) ) ;
BOOST_CHECK ( std : : get < MemoError > ( Memo : : FromHex ( badmemo ) ) = = MemoError : : HexDecodeError ) ;
2017-09-15 12:59:27 -07:00
2022-05-24 15:50:53 -07:00
// odd length hexadecimal string
std : : fill ( v . begin ( ) , v . end ( ) , ' A ' ) ;
v . resize ( v . size ( ) - 1 ) ;
assert ( v . size ( ) % 2 = = 1 ) ; // odd length
std : : string oddmemo ( v . begin ( ) , v . end ( ) ) ;
BOOST_CHECK ( std : : get < MemoError > ( Memo : : FromHex ( oddmemo ) ) = = MemoError : : HexDecodeError ) ;
2016-09-04 23:18:26 -07:00
}
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
/*
* This test covers storing encrypted zkeys in the wallet .
*/
BOOST_AUTO_TEST_CASE ( rpc_wallet_encrypted_wallet_zkeys )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2021-09-24 13:24:41 -07:00
2017-01-06 10:15:56 -08:00
UniValue retValue ;
2016-09-21 14:02:35 -07:00
int n = 100 ;
// wallet should currently be empty
2018-04-25 18:51:17 -07:00
std : : set < libzcash : : SproutPaymentAddress > addrs ;
2018-08-03 02:10:26 -07:00
pwalletMain - > GetSproutPaymentAddresses ( addrs ) ;
2016-09-21 14:02:35 -07:00
BOOST_CHECK ( addrs . size ( ) = = 0 ) ;
// create keys
for ( int i = 0 ; i < n ; i + + ) {
2018-11-14 15:20:22 -08:00
CallRPC ( " z_getnewaddress sprout " ) ;
2016-09-21 14:02:35 -07:00
}
// Verify we can list the keys imported
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
2017-01-06 10:15:56 -08:00
UniValue arr = retValue . get_array ( ) ;
2016-09-21 14:02:35 -07:00
BOOST_CHECK ( arr . size ( ) = = n ) ;
2016-10-20 12:45:44 -07:00
// Verify that the wallet encryption RPC is disabled
BOOST_CHECK_THROW ( CallRPC ( " encryptwallet passphrase " ) , runtime_error ) ;
2016-09-29 22:07:38 -07:00
// Encrypt the wallet (we can't call RPC encryptwallet as that shuts down node)
2016-09-21 14:02:35 -07:00
SecureString strWalletPass ;
strWalletPass . reserve ( 100 ) ;
strWalletPass = " hello " ;
2016-10-14 12:44:22 -07:00
2018-01-14 14:56:16 -08:00
PushCurrentDirectory push_dir ( GetArg ( " -datadir " , " /tmp/thisshouldnothappen " ) ) ;
2016-09-21 14:02:35 -07:00
BOOST_CHECK ( pwalletMain - > EncryptWallet ( strWalletPass ) ) ;
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
// Verify we can still list the keys imported
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
arr = retValue . get_array ( ) ;
BOOST_CHECK ( arr . size ( ) = = n ) ;
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
// Try to add a new key, but we can't as the wallet is locked
2018-11-14 15:20:22 -08:00
BOOST_CHECK_THROW ( CallRPC ( " z_getnewaddress sprout " ) , runtime_error ) ;
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
// We can't call RPC walletpassphrase as that invokes RPCRunLater which breaks tests.
// So we manually unlock.
BOOST_CHECK ( pwalletMain - > Unlock ( strWalletPass ) ) ;
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
// Now add a key
2018-11-14 15:20:22 -08:00
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getnewaddress sprout " ) ) ;
2017-09-15 12:59:27 -07:00
2016-09-21 14:02:35 -07:00
// Verify the key has been added
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
arr = retValue . get_array ( ) ;
2017-09-15 12:59:27 -07:00
BOOST_CHECK ( arr . size ( ) = = n + 1 ) ;
2016-09-21 14:02:35 -07:00
// We can't simulate over RPC the wallet closing and being reloaded
// but there are tests for this in gtest.
}
2018-09-27 13:06:33 -07:00
BOOST_AUTO_TEST_CASE ( rpc_wallet_encrypted_wallet_sapzkeys )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2021-09-24 13:24:41 -07:00
2018-09-27 13:06:33 -07:00
UniValue retValue ;
int n = 100 ;
2021-08-19 14:32:24 -07:00
if ( ! pwalletMain - > HaveMnemonicSeed ( ) )
2018-09-27 13:06:33 -07:00
{
pwalletMain - > GenerateNewSeed ( ) ;
}
// wallet should currently be empty
std : : set < libzcash : : SaplingPaymentAddress > addrs ;
pwalletMain - > GetSaplingPaymentAddresses ( addrs ) ;
BOOST_CHECK ( addrs . size ( ) = = 0 ) ;
// create keys
for ( int i = 0 ; i < n ; i + + ) {
CallRPC ( " z_getnewaddress sapling " ) ;
}
// Verify we can list the keys imported
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
UniValue arr = retValue . get_array ( ) ;
BOOST_CHECK ( arr . size ( ) = = n ) ;
// Verify that the wallet encryption RPC is disabled
BOOST_CHECK_THROW ( CallRPC ( " encryptwallet passphrase " ) , runtime_error ) ;
// Encrypt the wallet (we can't call RPC encryptwallet as that shuts down node)
SecureString strWalletPass ;
strWalletPass . reserve ( 100 ) ;
strWalletPass = " hello " ;
2020-07-17 12:07:40 -07:00
PushCurrentDirectory push_dir ( GetArg ( " -datadir " , " /tmp/thisshouldnothappen " ) ) ;
2018-09-27 13:06:33 -07:00
BOOST_CHECK ( pwalletMain - > EncryptWallet ( strWalletPass ) ) ;
// Verify we can still list the keys imported
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
arr = retValue . get_array ( ) ;
BOOST_CHECK ( arr . size ( ) = = n ) ;
// Try to add a new key, but we can't as the wallet is locked
BOOST_CHECK_THROW ( CallRPC ( " z_getnewaddress sapling " ) , runtime_error ) ;
// We can't call RPC walletpassphrase as that invokes RPCRunLater which breaks tests.
// So we manually unlock.
BOOST_CHECK ( pwalletMain - > Unlock ( strWalletPass ) ) ;
// Now add a key
BOOST_CHECK_NO_THROW ( CallRPC ( " z_getnewaddress sapling " ) ) ;
// Verify the key has been added
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listaddresses " ) ) ;
arr = retValue . get_array ( ) ;
2021-08-19 14:32:24 -07:00
BOOST_CHECK_EQUAL ( arr . size ( ) , n + 1 ) ;
2018-09-27 13:06:33 -07:00
// We can't simulate over RPC the wallet closing and being reloaded
// but there are tests for this in gtest.
}
2016-09-21 14:02:35 -07:00
2017-09-15 12:59:27 -07:00
2018-03-28 10:38:57 -07:00
BOOST_AUTO_TEST_CASE ( rpc_z_listunspent_parameters )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2018-03-28 10:38:57 -07:00
UniValue retValue ;
// too many args
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 2 3 4 5 " ) , runtime_error ) ;
// minconf must be >= 0
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent -1 " ) , runtime_error ) ;
// maxconf must be > minconf
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 2 1 " ) , runtime_error ) ;
// maxconf must not be out of range
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 9999999999 " ) , runtime_error ) ;
// must be an array of addresses
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 999 false ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP " ) , runtime_error ) ;
// address must be string
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 999 false [123456] " ) , runtime_error ) ;
// no spending key
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 999 false [ \" ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP \" ] " ) , runtime_error ) ;
// allow watch only
BOOST_CHECK_NO_THROW ( CallRPC ( " z_listunspent 1 999 true [ \" ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP \" ] " ) ) ;
// wrong network, mainnet instead of testnet
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 999 true [ \" zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U \" ] " ) , runtime_error ) ;
// create shielded address so we have the spending key
2018-11-14 15:20:22 -08:00
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_getnewaddress sprout " ) ) ;
2018-03-28 10:38:57 -07:00
std : : string myzaddr = retValue . get_str ( ) ;
// return empty array for this address
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " z_listunspent 1 999 false [ \" " + myzaddr + " \" ] " ) ) ;
UniValue arr = retValue . get_array ( ) ;
BOOST_CHECK_EQUAL ( 0 , arr . size ( ) ) ;
// duplicate address error
BOOST_CHECK_THROW ( CallRPC ( " z_listunspent 1 999 false [ \" " + myzaddr + " \" , \" " + myzaddr + " \" ] " ) , runtime_error ) ;
}
2017-09-15 12:59:27 -07:00
BOOST_AUTO_TEST_CASE ( rpc_z_shieldcoinbase_parameters )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2017-09-15 12:59:27 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase toofewargs " ) , runtime_error ) ;
2017-11-01 10:40:24 -07:00
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase too many args shown here " ) , runtime_error ) ;
2017-09-15 12:59:27 -07:00
// bad from address
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" INVALIDtmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB " ) , runtime_error ) ;
// bad from address
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" ** tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB " ) , runtime_error ) ;
// bad to address
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ INVALIDtnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB " ) , runtime_error ) ;
// invalid fee amount, cannot be negative
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
" tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
2020-12-17 11:39:58 -08:00
" -0.00001 "
2017-09-15 12:59:27 -07:00
) , runtime_error ) ;
// invalid fee amount, bigger than MAX_MONEY
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
" tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
" 21000001 "
) , runtime_error ) ;
2017-11-01 10:40:24 -07:00
// invalid limit, must be at least 0
BOOST_CHECK_THROW ( CallRPC ( " z_shieldcoinbase "
" tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
" tnpoQJVnYBZZqkFadj2bJJLThNCxbADGB5gSGeYTAGGrT5tejsxY9Zc1BtY8nnHmZkB "
" 100 -1 "
) , runtime_error ) ;
2020-03-17 13:56:25 -07:00
// Test constructor of AsyncRPCOperation_shieldcoinbase
2021-12-29 15:26:20 -08:00
KeyIO keyIO ( Params ( ) ) ;
2023-04-17 10:47:11 -07:00
UniValue retValue ;
BOOST_CHECK_NO_THROW ( retValue = CallRPC ( " getnewaddress " ) ) ;
auto taddr2 = std : : get < CKeyID > ( keyIO . DecodePaymentAddress ( retValue . get_str ( ) ) . value ( ) ) ;
2021-12-29 15:26:20 -08:00
auto testnetzaddr = std : : get < libzcash : : SproutPaymentAddress > ( keyIO . DecodePaymentAddress ( " ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP " ) . value ( ) ) ;
2023-04-17 10:47:11 -07:00
auto selector = pwalletMain - > ZTXOSelectorForAddress (
taddr2 ,
true ,
// In the real transaction builder we use either Require or Disallow, but here we
// are checking that there are no UTXOs at all, so we allow either to be selected to
// confirm this.
TransparentCoinbasePolicy : : Allow ,
false ) . value ( ) ;
WalletTxBuilder builder ( Params ( ) , minRelayTxFee ) ;
2017-09-15 12:59:27 -07:00
try {
2023-04-17 10:47:11 -07:00
std : : shared_ptr < AsyncRPCOperation > operation ( new AsyncRPCOperation_shieldcoinbase ( std : : move ( builder ) , selector , testnetzaddr , PrivacyPolicy : : AllowRevealedSenders , SHIELD_COINBASE_DEFAULT_LIMIT , 1 ) ) ;
2017-09-15 12:59:27 -07:00
} catch ( const UniValue & objError ) {
BOOST_CHECK ( find_error ( objError , " Empty inputs " ) ) ;
}
}
2017-12-11 08:43:09 -08:00
BOOST_AUTO_TEST_CASE ( rpc_z_mergetoaddress_parameters )
{
SelectParams ( CBaseChainParams : : TESTNET ) ;
2019-12-31 11:18:16 -08:00
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2017-12-11 08:43:09 -08:00
BOOST_CHECK_THROW ( CallRPC ( " z_mergetoaddress " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_mergetoaddress toofewargs " ) , runtime_error ) ;
BOOST_CHECK_THROW ( CallRPC ( " z_mergetoaddress just too many args present for this method " ) , runtime_error ) ;
2018-10-30 23:49:45 -07:00
std : : string taddr1 = " tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ " ;
std : : string taddr2 = " tmYmhvdKqEte49iohoB9utgL1kPbGgWSdNc " ;
std : : string aSproutAddr = " ztVtBC7vJFXPsZC8S3hXRu51rZysoJkSe6r1t9wk56bELrV9xTK6dx5TgSCH6RTw1dRD7HuApmcY1nhuQW9QfvE4MQXRRYU " ;
2018-10-30 23:59:48 -07:00
std : : string aSaplingAddr = " ztestsapling19rnyu293v44f0kvtmszhx35lpdug574twc0lwyf4s7w0umtkrdq5nfcauxrxcyfmh3m7slemqsj " ;
CheckRPCThrows ( " z_mergetoaddress [] " + taddr1 ,
" Invalid parameter, fromaddresses array is empty. " ) ;
2018-10-30 23:49:45 -07:00
2017-12-11 08:43:09 -08:00
// bad from address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" INVALID " + taddr1 + " \" ] " + taddr2 ,
" Unknown address format: INVALID " + taddr1 ) ;
2017-12-11 08:43:09 -08:00
// bad from address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress ** " + taddr2 ,
2023-04-15 14:02:41 -07:00
" Error parsing JSON: ** " ) ;
2017-12-11 08:43:09 -08:00
// bad from address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" ** \" ] " + taddr2 ,
" Unknown address format: ** " ) ;
2017-12-11 08:43:09 -08:00
// bad from address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress " + taddr1 + " " + taddr2 ,
2023-04-15 14:02:41 -07:00
" Error parsing JSON: " + taddr1 ) ;
2017-12-11 08:43:09 -08:00
// bad from address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ " + taddr1 + " ] " + taddr2 ,
2023-04-15 14:02:41 -07:00
" Error parsing JSON: [ " + taddr1 + " ] " ) ;
2017-12-11 08:43:09 -08:00
// bad to address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] INVALID " + taddr2 ,
" Invalid parameter, unknown address format: INVALID " + taddr2 ) ;
2017-12-11 08:43:09 -08:00
// duplicate address
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" , \" " + taddr1 + " \" ] " + taddr2 ,
" Invalid parameter, duplicated address: " + taddr1 ) ;
2017-12-11 08:43:09 -08:00
// invalid fee amount, cannot be negative
2020-12-17 11:39:58 -08:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] " + taddr2 + " -0.00001 " ,
2018-10-30 23:49:45 -07:00
" Amount out of range " ) ;
2017-12-11 08:43:09 -08:00
// invalid fee amount, bigger than MAX_MONEY
2018-10-30 23:49:45 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] " + taddr2 + " 21000001 " ,
" Amount out of range " ) ;
2017-12-11 08:43:09 -08:00
// invalid transparent limit, must be at least 0
2020-12-17 11:39:58 -08:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] " + taddr2 + " 0.00001 -1 " ,
2018-10-30 23:49:45 -07:00
" Limit on maximum number of UTXOs cannot be negative " ) ;
2017-12-11 08:43:09 -08:00
// invalid shielded limit, must be at least 0
2020-12-17 11:39:58 -08:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] " + taddr2 + " 0.00001 100 -1 " ,
2018-10-30 23:49:45 -07:00
" Limit on maximum number of notes cannot be negative " ) ;
2017-12-11 08:43:09 -08:00
2018-10-30 23:59:48 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" ANY_TADDR \" , \" " + taddr1 + " \" ] " + taddr2 ,
2018-12-11 13:25:35 -08:00
" Cannot specify specific taddrs when using \" ANY_TADDR \" " ) ;
2018-10-30 23:59:48 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" ANY_SPROUT \" , \" " + aSproutAddr + " \" ] " + taddr2 ,
2018-12-11 13:25:35 -08:00
" Cannot specify specific zaddrs when using \" ANY_SPROUT \" or \" ANY_SAPLING \" " ) ;
2018-10-30 23:59:48 -07:00
CheckRPCThrows ( " z_mergetoaddress [ \" ANY_SAPLING \" , \" " + aSaplingAddr + " \" ] " + taddr2 ,
2018-12-11 13:25:35 -08:00
" Cannot specify specific zaddrs when using \" ANY_SPROUT \" or \" ANY_SAPLING \" " ) ;
2018-10-30 23:59:48 -07:00
2017-12-11 08:43:09 -08:00
// memo bigger than allowed length of ZC_MEMO_SIZE
std : : vector < char > v ( 2 * ( ZC_MEMO_SIZE + 1 ) ) ; // x2 for hexadecimal string format
std : : fill ( v . begin ( ) , v . end ( ) , ' A ' ) ;
std : : string badmemo ( v . begin ( ) , v . end ( ) ) ;
2020-12-17 11:39:58 -08:00
CheckRPCThrows ( " z_mergetoaddress [ \" " + taddr1 + " \" ] " + aSproutAddr + " 0.00001 100 100 " + badmemo ,
2023-04-17 03:21:54 -07:00
strprintf ( " Invalid parameter, memo is longer than the maximum allowed %d characters. " , ZC_MEMO_SIZE ) ) ;
2017-12-11 08:43:09 -08:00
// Mutable tx containing contextual information we need to build tx
UniValue retValue = CallRPC ( " getblockcount " ) ;
int nHeight = retValue . get_int ( ) ;
2022-05-19 08:30:17 -07:00
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( Params ( ) . GetConsensus ( ) , nHeight + 1 , false ) ;
2017-12-11 08:43:09 -08:00
// Test constructor of AsyncRPCOperation_mergetoaddress
2021-12-29 16:00:27 -08:00
KeyIO keyIO ( Params ( ) ) ;
2017-12-11 08:43:09 -08:00
MergeToAddressRecipient testnetzaddr (
2021-12-29 16:00:27 -08:00
keyIO . DecodePaymentAddress ( " ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP " ) . value ( ) ,
2023-04-17 03:21:54 -07:00
Memo ( ) ) ;
WalletTxBuilder builder ( Params ( ) , minRelayTxFee ) ;
auto selector = CWallet : : LegacyTransparentZTXOSelector (
true ,
TransparentCoinbasePolicy : : Disallow ) ;
TransactionStrategy strategy ( PrivacyPolicy : : AllowRevealedRecipients ) ;
2017-12-11 08:43:09 -08:00
try {
2023-04-17 03:21:54 -07:00
auto operation = AsyncRPCOperation_mergetoaddress ( builder , selector , { } , testnetzaddr , strategy , - 1 ) ;
BOOST_FAIL ( " Fee value of -1 expected to be out of the valid range of values. " ) ;
2017-12-11 08:43:09 -08:00
} catch ( const UniValue & objError ) {
BOOST_CHECK ( find_error ( objError , " Fee is out of range " ) ) ;
}
2023-04-17 03:21:54 -07:00
{
auto operation = AsyncRPCOperation_mergetoaddress ( builder , selector , { } , testnetzaddr , strategy , 1 ) ;
operation . main ( ) ;
BOOST_CHECK_EQUAL ( operation . getErrorMessage ( ) , " Insufficient funds: have -0.00000001, need 0.00000001; note that coinbase outputs will not be selected if you specify ANY_TADDR, any transparent recipients are included, or if the `privacyPolicy` parameter is not set to `AllowRevealedSenders` or weaker. " ) ;
2017-12-11 08:43:09 -08:00
}
2023-04-17 03:21:54 -07:00
auto wtx = FakeWalletTx ( ) ;
SpendableInputs inputs ;
inputs . utxos . emplace_back ( COutput ( & wtx , 0 , 100 , true ) ) ;
inputs . sproutNoteEntries . emplace_back ( SproutNoteEntry { JSOutPoint ( ) , SproutPaymentAddress ( ) , SproutNote ( ) , " " , 0 } ) ;
inputs . saplingNoteEntries . emplace_back ( SaplingNoteEntry { SaplingOutPoint ( ) , SaplingPaymentAddress ( ) , SaplingNote ( { } , uint256 ( ) , 0 , uint256 ( ) , Zip212Enabled : : BeforeZip212 ) , " " , 0 } ) ;
2017-12-11 08:43:09 -08:00
2023-04-17 03:21:54 -07:00
{
auto operation = AsyncRPCOperation_mergetoaddress ( builder , selector , inputs , testnetzaddr , strategy , 1 ) ;
operation . main ( ) ;
BOOST_CHECK_EQUAL ( operation . getErrorMessage ( ) , " Insufficient funds: have 0.00, need 0.00000001; note that coinbase outputs will not be selected if you specify ANY_TADDR, any transparent recipients are included, or if the `privacyPolicy` parameter is not set to `AllowRevealedSenders` or weaker. " ) ;
2018-10-18 14:37:58 -07:00
}
2017-12-11 08:43:09 -08:00
}
2020-01-19 09:25:44 -08:00
void TestWTxStatus ( const Consensus : : Params consensusParams , const int delta ) {
auto AddTrx = [ & consensusParams ] ( ) {
2022-02-07 15:35:06 -08:00
auto taddr = pwalletMain - > GenerateNewKey ( true ) . GetID ( ) ;
2022-05-19 08:30:17 -07:00
CMutableTransaction mtx = CreateNewContextualCMutableTransaction ( consensusParams , 1 , false ) ;
2020-01-19 09:25:44 -08:00
CScript scriptPubKey = CScript ( ) < < OP_DUP < < OP_HASH160 < < ToByteVector ( taddr ) < < OP_EQUALVERIFY < < OP_CHECKSIG ;
mtx . vout . push_back ( CTxOut ( 5 * COIN , scriptPubKey ) ) ;
CWalletTx wtx ( pwalletMain , mtx ) ;
2022-03-01 12:53:50 -08:00
pwalletMain - > LoadWalletTx ( wtx ) ;
2020-01-19 09:25:44 -08:00
return wtx ;
} ;
vector < uint256 > hashes ;
CWalletTx wtx ;
auto FakeMine = [ & ] ( const int height , bool has_trx ) {
BOOST_CHECK_EQUAL ( height , chainActive . Height ( ) ) ;
CBlock block ;
if ( has_trx ) block . vtx . push_back ( wtx ) ;
2015-11-17 08:35:44 -08:00
block . hashMerkleRoot = BlockMerkleRoot ( block ) ;
2020-01-19 09:25:44 -08:00
auto blockHash = block . GetHash ( ) ;
CBlockIndex fakeIndex { block } ;
fakeIndex . nHeight = height + 1 ;
mapBlockIndex . insert ( std : : make_pair ( blockHash , & fakeIndex ) ) ;
chainActive . SetTip ( & fakeIndex ) ;
BOOST_CHECK ( chainActive . Contains ( & fakeIndex ) ) ;
BOOST_CHECK_EQUAL ( height + 1 , chainActive . Height ( ) ) ;
if ( has_trx ) {
wtx . SetMerkleBranch ( block ) ;
2022-03-01 12:53:50 -08:00
pwalletMain - > LoadWalletTx ( wtx ) ;
2020-01-19 09:25:44 -08:00
}
hashes . push_back ( blockHash ) ;
UniValue retValue = CallRPC ( " gettransaction " + wtx . GetHash ( ) . GetHex ( ) ) ;
return retValue . get_obj ( ) ;
} ;
// Add a transaction to the wallet
wtx = AddTrx ( ) ;
// Mine blocks but never include the transaction, check status of wallet trx
for ( int i = 0 ; i < = delta + 1 ; i + + ) {
auto retObj = FakeMine ( i , false ) ;
BOOST_CHECK_EQUAL ( find_value ( retObj , " confirmations " ) . get_real ( ) , - 1 ) ;
auto status = find_value ( retObj , " status " ) . get_str ( ) ;
if ( i > = delta - TX_EXPIRING_SOON_THRESHOLD & & i < = delta )
BOOST_CHECK_EQUAL ( status , " expiringsoon " ) ;
else if ( i > = delta - TX_EXPIRING_SOON_THRESHOLD )
BOOST_CHECK_EQUAL ( status , " expired " ) ;
else
BOOST_CHECK_EQUAL ( status , " waiting " ) ;
}
// Now mine including the transaction, check status
auto retObj = FakeMine ( delta + 2 , true ) ;
BOOST_CHECK_EQUAL ( find_value ( retObj , " confirmations " ) . get_real ( ) , 1 ) ;
BOOST_CHECK_EQUAL ( find_value ( retObj , " status " ) . get_str ( ) , " mined " ) ;
// Cleanup
chainActive . SetTip ( NULL ) ;
for ( auto hash : hashes )
mapBlockIndex . erase ( hash ) ;
}
BOOST_AUTO_TEST_CASE ( rpc_gettransaction_status_sapling )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
TestWTxStatus ( RegtestActivateSapling ( ) , DEFAULT_PRE_BLOSSOM_TX_EXPIRY_DELTA ) ;
RegtestDeactivateSapling ( ) ;
}
BOOST_AUTO_TEST_CASE ( rpc_gettransaction_status_blossom )
{
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
2020-07-10 10:34:53 -07:00
auto params = RegtestActivateBlossom ( true ) . GetConsensus ( ) ;
2020-01-19 09:25:44 -08:00
2020-07-10 10:34:53 -07:00
TestWTxStatus ( params , DEFAULT_POST_BLOSSOM_TX_EXPIRY_DELTA ) ;
2020-01-19 09:25:44 -08:00
RegtestDeactivateBlossom ( ) ;
}
2017-09-15 12:59:27 -07:00
2016-09-03 22:25:13 -07:00
BOOST_AUTO_TEST_SUITE_END ( )