2022-12-24 23:49:50 +00:00
// Copyright (c) 2011-2022 The Bitcoin Core developers
2021-12-01 13:10:43 +13:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include <wallet/rpc/util.h>
2021-12-01 19:20:33 +13:00
2022-10-14 13:55:53 +08:00
# include <common/url.h>
2021-12-01 19:20:33 +13:00
# include <rpc/util.h>
2023-01-18 10:40:08 -03:00
# include <util/system.h>
2021-12-03 12:44:42 +13:00
# include <util/translation.h>
2021-12-01 19:20:33 +13:00
# include <wallet/context.h>
# include <wallet/wallet.h>
# include <univalue.h>
2022-09-28 12:10:38 +01:00
# include <boost/date_time/posix_time/posix_time.hpp>
2021-11-12 11:13:29 -05:00
namespace wallet {
2021-12-01 19:20:33 +13:00
static const std : : string WALLET_ENDPOINT_BASE = " /wallet/ " ;
const std : : string HELP_REQUIRING_PASSPHRASE { " \n Requires wallet passphrase to be set with walletpassphrase call if wallet is encrypted. \n " } ;
2022-09-28 12:10:38 +01:00
int64_t ParseISO8601DateTime ( const std : : string & str )
{
static const boost : : posix_time : : ptime epoch = boost : : posix_time : : from_time_t ( 0 ) ;
static const std : : locale loc ( std : : locale : : classic ( ) ,
new boost : : posix_time : : time_input_facet ( " %Y-%m-%dT%H:%M:%SZ " ) ) ;
std : : istringstream iss ( str ) ;
iss . imbue ( loc ) ;
boost : : posix_time : : ptime ptime ( boost : : date_time : : not_a_date_time ) ;
iss > > ptime ;
if ( ptime . is_not_a_date_time ( ) | | epoch > ptime )
return 0 ;
return ( ptime - epoch ) . total_seconds ( ) ;
}
2021-12-01 19:20:33 +13:00
bool GetAvoidReuseFlag ( const CWallet & wallet , const UniValue & param ) {
bool can_avoid_reuse = wallet . IsWalletFlagSet ( WALLET_FLAG_AVOID_REUSE ) ;
bool avoid_reuse = param . isNull ( ) ? can_avoid_reuse : param . get_bool ( ) ;
if ( avoid_reuse & & ! can_avoid_reuse ) {
throw JSONRPCError ( RPC_WALLET_ERROR , " wallet does not have the \" avoid reuse \" feature enabled " ) ;
}
return avoid_reuse ;
}
/** Used by RPC commands that have an include_watchonly parameter.
* We default to true for watchonly wallets if include_watchonly isn ' t
* explicitly set .
*/
bool ParseIncludeWatchonly ( const UniValue & include_watchonly , const CWallet & wallet )
{
if ( include_watchonly . isNull ( ) ) {
// if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
return wallet . IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ;
}
// otherwise return whatever include_watchonly was set to
return include_watchonly . get_bool ( ) ;
}
bool GetWalletNameFromJSONRPCRequest ( const JSONRPCRequest & request , std : : string & wallet_name )
{
if ( URL_DECODE & & request . URI . substr ( 0 , WALLET_ENDPOINT_BASE . size ( ) ) = = WALLET_ENDPOINT_BASE ) {
// wallet endpoint was used
wallet_name = URL_DECODE ( request . URI . substr ( WALLET_ENDPOINT_BASE . size ( ) ) ) ;
return true ;
}
return false ;
}
std : : shared_ptr < CWallet > GetWalletForJSONRPCRequest ( const JSONRPCRequest & request )
{
CHECK_NONFATAL ( request . mode = = JSONRPCRequest : : EXECUTE ) ;
WalletContext & context = EnsureWalletContext ( request . context ) ;
std : : string wallet_name ;
if ( GetWalletNameFromJSONRPCRequest ( request , wallet_name ) ) {
2022-12-27 15:25:51 +00:00
std : : shared_ptr < CWallet > pwallet = GetWallet ( context , wallet_name ) ;
2021-12-01 19:20:33 +13:00
if ( ! pwallet ) throw JSONRPCError ( RPC_WALLET_NOT_FOUND , " Requested wallet does not exist or is not loaded " ) ;
return pwallet ;
}
2022-03-25 22:41:21 +00:00
size_t count { 0 } ;
auto wallet = GetDefaultWallet ( context , count ) ;
if ( wallet ) return wallet ;
2021-12-01 19:20:33 +13:00
2022-03-25 22:41:21 +00:00
if ( count = = 0 ) {
2021-12-01 19:20:33 +13:00
throw JSONRPCError (
RPC_WALLET_NOT_FOUND , " No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created) " ) ;
}
throw JSONRPCError ( RPC_WALLET_NOT_SPECIFIED ,
" Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path). " ) ;
}
void EnsureWalletIsUnlocked ( const CWallet & wallet )
{
if ( wallet . IsLocked ( ) ) {
throw JSONRPCError ( RPC_WALLET_UNLOCK_NEEDED , " Error: Please enter the wallet passphrase with walletpassphrase first. " ) ;
}
}
WalletContext & EnsureWalletContext ( const std : : any & context )
{
auto wallet_context = util : : AnyPtr < WalletContext > ( context ) ;
if ( ! wallet_context ) {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Wallet context not found " ) ;
}
return * wallet_context ;
}
// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan ( CWallet & wallet , bool also_create )
{
LegacyScriptPubKeyMan * spk_man = wallet . GetLegacyScriptPubKeyMan ( ) ;
if ( ! spk_man & & also_create ) {
spk_man = wallet . GetOrCreateLegacyScriptPubKeyMan ( ) ;
}
if ( ! spk_man ) {
2022-06-14 20:54:45 +02:00
throw JSONRPCError ( RPC_WALLET_ERROR , " Only legacy wallets are supported by this command " ) ;
2021-12-01 19:20:33 +13:00
}
return * spk_man ;
}
const LegacyScriptPubKeyMan & EnsureConstLegacyScriptPubKeyMan ( const CWallet & wallet )
{
const LegacyScriptPubKeyMan * spk_man = wallet . GetLegacyScriptPubKeyMan ( ) ;
if ( ! spk_man ) {
2022-06-14 20:54:45 +02:00
throw JSONRPCError ( RPC_WALLET_ERROR , " Only legacy wallets are supported by this command " ) ;
2021-12-01 19:20:33 +13:00
}
return * spk_man ;
}
std : : string LabelFromValue ( const UniValue & value )
{
2022-12-15 11:02:32 +01:00
static const std : : string empty_string ;
if ( value . isNull ( ) ) return empty_string ;
const std : : string & label { value . get_str ( ) } ;
2021-12-01 19:20:33 +13:00
if ( label = = " * " )
throw JSONRPCError ( RPC_WALLET_INVALID_LABEL_NAME , " Invalid label name " ) ;
return label ;
}
2021-12-03 12:44:42 +13:00
2022-06-29 19:04:48 +02:00
void PushParentDescriptors ( const CWallet & wallet , const CScript & script_pubkey , UniValue & entry )
{
UniValue parent_descs ( UniValue : : VARR ) ;
for ( const auto & desc : wallet . GetWalletDescriptors ( script_pubkey ) ) {
parent_descs . push_back ( desc . descriptor - > ToString ( ) ) ;
}
entry . pushKV ( " parent_descs " , parent_descs ) ;
}
2021-12-14 20:10:21 -03:00
void HandleWalletError ( const std : : shared_ptr < CWallet > wallet , DatabaseStatus & status , bilingual_str & error )
2021-12-03 12:44:42 +13:00
{
if ( ! wallet ) {
// Map bad format to not found, since bad format is returned when the
// wallet directory exists, but doesn't contain a data file.
RPCErrorCode code = RPC_WALLET_ERROR ;
switch ( status ) {
case DatabaseStatus : : FAILED_NOT_FOUND :
case DatabaseStatus : : FAILED_BAD_FORMAT :
code = RPC_WALLET_NOT_FOUND ;
break ;
case DatabaseStatus : : FAILED_ALREADY_LOADED :
code = RPC_WALLET_ALREADY_LOADED ;
break ;
2021-12-14 20:10:21 -03:00
case DatabaseStatus : : FAILED_ALREADY_EXISTS :
code = RPC_WALLET_ALREADY_EXISTS ;
break ;
case DatabaseStatus : : FAILED_INVALID_BACKUP_FILE :
code = RPC_INVALID_PARAMETER ;
break ;
2021-12-03 12:44:42 +13:00
default : // RPC_WALLET_ERROR is returned for all other cases.
break ;
}
throw JSONRPCError ( code , error . original ) ;
}
2021-11-12 11:13:29 -05:00
}
} // namespace wallet