2017-08-02 13:19:28 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2017 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-12-12 21:32:50 +01:00
# include <chainparams.h>
2018-03-30 10:48:29 +02:00
# include <init.h>
2017-11-10 01:57:53 +01:00
# include <net.h>
2018-04-19 23:42:40 +02:00
# include <scheduler.h>
2018-07-09 10:15:50 +02:00
# include <outputtype.h>
2017-11-10 01:57:53 +01:00
# include <util.h>
# include <utilmoneystr.h>
# include <validation.h>
2018-03-29 11:08:38 +02:00
# include <walletinitinterface.h>
2017-11-10 01:57:53 +01:00
# include <wallet/rpcwallet.h>
2017-10-08 22:48:07 +02:00
# include <wallet/wallet.h>
# include <wallet/walletutil.h>
2017-08-02 13:48:52 +02:00
2018-03-29 11:08:38 +02:00
class WalletInit : public WalletInitInterface {
public :
//! Return the wallets help message.
2018-04-28 22:54:58 +02:00
void AddWalletOptions ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Wallets parameter interaction
2018-04-13 15:02:59 +02:00
bool ParameterInteraction ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Register wallet RPCs.
2018-04-13 15:02:59 +02:00
void RegisterRPC ( CRPCTable & tableRPC ) const override ;
2018-03-29 11:08:38 +02:00
//! Responsible for reading and validating the -wallet arguments and verifying the wallet database.
// This function will perform salvage on the wallet if requested, as long as only one wallet is
// being loaded (WalletParameterInteraction forbids -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet).
2018-04-13 15:02:59 +02:00
bool Verify ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Load wallet databases.
2018-04-13 15:02:59 +02:00
bool Open ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Complete startup of wallets.
2018-04-13 15:02:59 +02:00
void Start ( CScheduler & scheduler ) const override ;
2018-03-29 11:08:38 +02:00
//! Flush all wallets in preparation for shutdown.
2018-04-13 15:02:59 +02:00
void Flush ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Stop all wallets. Wallets will be flushed first.
2018-04-13 15:02:59 +02:00
void Stop ( ) const override ;
2018-03-29 11:08:38 +02:00
//! Close all wallets.
2018-04-13 15:02:59 +02:00
void Close ( ) const override ;
2018-03-29 11:08:38 +02:00
} ;
2018-04-13 15:05:55 +02:00
const WalletInitInterface & g_wallet_init_interface = WalletInit ( ) ;
2018-03-29 11:08:38 +02:00
2018-04-28 22:54:58 +02:00
void WalletInit : : AddWalletOptions ( ) const
2017-08-02 13:48:52 +02:00
{
2018-04-28 22:54:58 +02:00
gArgs . AddArg ( " -addresstype " , strprintf ( " What type of addresses to use ( \" legacy \" , \" p2sh-segwit \" , or \" bech32 \" , default: \" %s \" ) " , FormatOutputType ( DEFAULT_ADDRESS_TYPE ) ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -changetype " , " What type of change to use ( \" legacy \" , \" p2sh-segwit \" , or \" bech32 \" ). Default is same as -addresstype, except when -addresstype=p2sh-segwit a native segwit output is used when sending to a native segwit address) " , false , OptionsCategory : : WALLET ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -disablewallet " , " Do not load the wallet and disable wallet RPC calls " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -discardfee=<amt> " , strprintf ( " The fee rate (in %s/kB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
" Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target " ,
2018-04-28 22:54:58 +02:00
CURRENCY_UNIT , FormatMoney ( DEFAULT_DISCARD_FEE ) ) , false , OptionsCategory : : WALLET ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -fallbackfee=<amt> " , strprintf ( " A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s) " ,
2018-04-28 22:54:58 +02:00
CURRENCY_UNIT , FormatMoney ( DEFAULT_FALLBACK_FEE ) ) , false , OptionsCategory : : WALLET ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -keypool=<n> " , strprintf ( " Set key pool size to <n> (default: %u) " , DEFAULT_KEYPOOL_SIZE ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -mintxfee=<amt> " , strprintf ( " Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) " ,
2018-04-28 22:54:58 +02:00
CURRENCY_UNIT , FormatMoney ( DEFAULT_TRANSACTION_MINFEE ) ) , false , OptionsCategory : : WALLET ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -paytxfee=<amt> " , strprintf ( " Fee (in %s/kB) to add to transactions you send (default: %s) " ,
2018-04-28 22:54:58 +02:00
CURRENCY_UNIT , FormatMoney ( CFeeRate { DEFAULT_PAY_TX_FEE } . GetFeePerK ( ) ) ) , false , OptionsCategory : : WALLET ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -rescan " , " Rescan the block chain for missing wallet transactions on startup " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -salvagewallet " , " Attempt to recover private keys from a corrupt wallet on startup " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -spendzeroconfchange " , strprintf ( " Spend unconfirmed change when sending transactions (default: %u) " , DEFAULT_SPEND_ZEROCONF_CHANGE ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -txconfirmtarget=<n> " , strprintf ( " If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) " , DEFAULT_TX_CONFIRM_TARGET ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -upgradewallet " , " Upgrade wallet to latest format on startup " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -wallet=<path> " , " Specify wallet database path. Can be specified multiple times to load multiple wallets. Path is interpreted relative to <walletdir> if it is not absolute, and will be created if it does not exist (as a directory containing a wallet.dat file and log files). For backwards compatibility this will also accept names of existing data files in <walletdir>.) " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -walletbroadcast " , strprintf ( " Make the wallet broadcast transactions (default: %u) " , DEFAULT_WALLETBROADCAST ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -walletdir=<dir> " , " Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>) " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -walletnotify=<cmd> " , " Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) " , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -walletrbf " , strprintf ( " Send transactions with full-RBF opt-in enabled (RPC only, default: %u) " , DEFAULT_WALLET_RBF ) , false , OptionsCategory : : WALLET ) ;
gArgs . AddArg ( " -zapwallettxes=<mode> " , " Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup "
" (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) " , false , OptionsCategory : : WALLET ) ;
2018-04-28 22:54:58 +02:00
gArgs . AddArg ( " -dblogsize=<n> " , strprintf ( " Flush wallet database activity from memory to disk log every <n> megabytes (default: %u) " , DEFAULT_WALLET_DBLOGSIZE ) , true , OptionsCategory : : WALLET_DEBUG_TEST ) ;
gArgs . AddArg ( " -flushwallet " , strprintf ( " Run a thread to flush wallet periodically (default: %u) " , DEFAULT_FLUSHWALLET ) , true , OptionsCategory : : WALLET_DEBUG_TEST ) ;
gArgs . AddArg ( " -privdb " , strprintf ( " Sets the DB_PRIVATE flag in the wallet db environment (default: %u) " , DEFAULT_WALLET_PRIVDB ) , true , OptionsCategory : : WALLET_DEBUG_TEST ) ;
2018-05-29 18:49:44 +02:00
gArgs . AddArg ( " -walletrejectlongchains " , strprintf ( " Wallet will not create transactions that violate mempool chain limits (default: %u) " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) , true , OptionsCategory : : WALLET_DEBUG_TEST ) ;
2017-08-02 13:48:52 +02:00
}
2018-04-13 15:02:59 +02:00
bool WalletInit : : ParameterInteraction ( ) const
2017-08-02 13:48:52 +02:00
{
2017-11-02 01:39:23 +01:00
if ( gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ) {
for ( const std : : string & wallet : gArgs . GetArgs ( " -wallet " ) ) {
LogPrintf ( " %s: parameter interaction: -disablewallet -> ignoring -wallet=%s \n " , __func__ , wallet ) ;
}
2017-08-02 13:48:52 +02:00
return true ;
2017-11-02 01:39:23 +01:00
}
2017-11-15 21:44:36 +01:00
gArgs . SoftSetArg ( " -wallet " , " " ) ;
2017-11-02 01:39:23 +01:00
const bool is_multiwallet = gArgs . GetArgs ( " -wallet " ) . size ( ) > 1 ;
2017-08-02 13:48:52 +02:00
if ( gArgs . GetBoolArg ( " -blocksonly " , DEFAULT_BLOCKSONLY ) & & gArgs . SoftSetBoolArg ( " -walletbroadcast " , false ) ) {
LogPrintf ( " %s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0 \n " , __func__ ) ;
}
if ( gArgs . GetBoolArg ( " -salvagewallet " , false ) ) {
if ( is_multiwallet ) {
return InitError ( strprintf ( " %s is only allowed with a single wallet file " , " -salvagewallet " ) ) ;
}
// Rewrite just private keys: rescan to find transactions
if ( gArgs . SoftSetBoolArg ( " -rescan " , true ) ) {
LogPrintf ( " %s: parameter interaction: -salvagewallet=1 -> setting -rescan=1 \n " , __func__ ) ;
}
}
2018-04-19 17:07:54 +02:00
bool zapwallettxes = gArgs . GetBoolArg ( " -zapwallettxes " , false ) ;
2017-08-02 13:48:52 +02:00
// -zapwallettxes implies dropping the mempool on startup
2018-04-19 17:07:54 +02:00
if ( zapwallettxes & & gArgs . SoftSetBoolArg ( " -persistmempool " , false ) ) {
LogPrintf ( " %s: parameter interaction: -zapwallettxes enabled -> setting -persistmempool=0 \n " , __func__ ) ;
2017-08-02 13:48:52 +02:00
}
// -zapwallettxes implies a rescan
2018-04-19 17:07:54 +02:00
if ( zapwallettxes ) {
2017-08-02 13:48:52 +02:00
if ( is_multiwallet ) {
return InitError ( strprintf ( " %s is only allowed with a single wallet file " , " -zapwallettxes " ) ) ;
}
if ( gArgs . SoftSetBoolArg ( " -rescan " , true ) ) {
2018-04-19 17:07:54 +02:00
LogPrintf ( " %s: parameter interaction: -zapwallettxes enabled -> setting -rescan=1 \n " , __func__ ) ;
2017-08-02 13:48:52 +02:00
}
}
if ( is_multiwallet ) {
if ( gArgs . GetBoolArg ( " -upgradewallet " , false ) ) {
return InitError ( strprintf ( " %s is only allowed with a single wallet file " , " -upgradewallet " ) ) ;
}
}
if ( gArgs . GetBoolArg ( " -sysperms " , false ) )
return InitError ( " -sysperms is not allowed in combination with enabled wallet functionality " ) ;
if ( gArgs . GetArg ( " -prune " , 0 ) & & gArgs . GetBoolArg ( " -rescan " , false ) )
return InitError ( _ ( " Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. " ) ) ;
if ( : : minRelayTxFee . GetFeePerK ( ) > HIGH_TX_FEE_PER_KB )
InitWarning ( AmountHighWarn ( " -minrelaytxfee " ) + " " +
_ ( " The wallet will avoid paying less than the minimum relay fee. " ) ) ;
if ( gArgs . IsArgSet ( " -maxtxfee " ) )
{
CAmount nMaxFee = 0 ;
if ( ! ParseMoney ( gArgs . GetArg ( " -maxtxfee " , " " ) , nMaxFee ) )
return InitError ( AmountErrMsg ( " maxtxfee " , gArgs . GetArg ( " -maxtxfee " , " " ) ) ) ;
if ( nMaxFee > HIGH_MAX_TX_FEE )
InitWarning ( _ ( " -maxtxfee is set very high! Fees this large could be paid on a single transaction. " ) ) ;
maxTxFee = nMaxFee ;
if ( CFeeRate ( maxTxFee , 1000 ) < : : minRelayTxFee )
{
return InitError ( strprintf ( _ ( " Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) " ) ,
gArgs . GetArg ( " -maxtxfee " , " " ) , : : minRelayTxFee . ToString ( ) ) ) ;
}
}
return true ;
}
2018-04-13 15:02:59 +02:00
void WalletInit : : RegisterRPC ( CRPCTable & t ) const
2017-08-28 19:33:59 +02:00
{
2017-11-02 01:41:29 +01:00
if ( gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ) {
return ;
}
2017-08-28 19:33:59 +02:00
RegisterWalletRPCCommands ( t ) ;
}
2018-04-13 15:02:59 +02:00
bool WalletInit : : Verify ( ) const
2017-08-02 13:48:52 +02:00
{
2017-11-02 01:41:29 +01:00
if ( gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ) {
2017-08-02 13:48:52 +02:00
return true ;
2017-11-02 01:41:29 +01:00
}
2017-08-02 13:48:52 +02:00
2018-01-18 19:15:00 +01:00
if ( gArgs . IsArgSet ( " -walletdir " ) ) {
fs : : path wallet_dir = gArgs . GetArg ( " -walletdir " , " " ) ;
if ( ! fs : : exists ( wallet_dir ) ) {
return InitError ( strprintf ( _ ( " Specified -walletdir \" %s \" does not exist " ) , wallet_dir . string ( ) ) ) ;
} else if ( ! fs : : is_directory ( wallet_dir ) ) {
return InitError ( strprintf ( _ ( " Specified -walletdir \" %s \" is not a directory " ) , wallet_dir . string ( ) ) ) ;
} else if ( ! wallet_dir . is_absolute ( ) ) {
return InitError ( strprintf ( _ ( " Specified -walletdir \" %s \" is a relative path " ) , wallet_dir . string ( ) ) ) ;
2017-11-18 01:36:37 +01:00
}
2017-10-12 11:04:46 +02:00
}
LogPrintf ( " Using wallet directory %s \n " , GetWalletDir ( ) . string ( ) ) ;
2017-08-02 13:48:52 +02:00
uiInterface . InitMessage ( _ ( " Verifying wallet(s)... " ) ) ;
2018-04-18 19:11:28 +02:00
std : : vector < std : : string > wallet_files = gArgs . GetArgs ( " -wallet " ) ;
// Parameter interaction code should have thrown an error if -salvagewallet
// was enabled with more than wallet file, so the wallet_files size check
// here should have no effect.
bool salvage_wallet = gArgs . GetBoolArg ( " -salvagewallet " , false ) & & wallet_files . size ( ) < = 1 ;
2017-08-02 13:48:52 +02:00
// Keep track of each wallet absolute path to detect duplicates.
std : : set < fs : : path > wallet_paths ;
2018-06-15 19:38:54 +02:00
for ( const auto & wallet_file : wallet_files ) {
2018-04-18 19:11:28 +02:00
fs : : path wallet_path = fs : : absolute ( wallet_file , GetWalletDir ( ) ) ;
2017-08-02 13:48:52 +02:00
if ( ! wallet_paths . insert ( wallet_path ) . second ) {
2018-04-18 19:11:28 +02:00
return InitError ( strprintf ( _ ( " Error loading wallet %s. Duplicate -wallet filename specified. " ) , wallet_file ) ) ;
2017-08-02 13:48:52 +02:00
}
2018-04-18 20:17:09 +02:00
std : : string error_string ;
std : : string warning_string ;
bool verify_success = CWallet : : Verify ( wallet_file , salvage_wallet , error_string , warning_string ) ;
if ( ! error_string . empty ( ) ) InitError ( error_string ) ;
if ( ! warning_string . empty ( ) ) InitWarning ( warning_string ) ;
if ( ! verify_success ) return false ;
2017-08-02 13:48:52 +02:00
}
return true ;
}
2018-04-13 15:02:59 +02:00
bool WalletInit : : Open ( ) const
2017-08-02 13:48:52 +02:00
{
if ( gArgs . GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ) {
LogPrintf ( " Wallet disabled! \n " ) ;
return true ;
}
for ( const std : : string & walletFile : gArgs . GetArgs ( " -wallet " ) ) {
2018-05-22 17:18:07 +02:00
std : : shared_ptr < CWallet > pwallet = CWallet : : CreateWalletFromFile ( walletFile , fs : : absolute ( walletFile , GetWalletDir ( ) ) ) ;
2017-08-02 13:48:52 +02:00
if ( ! pwallet ) {
return false ;
}
2018-04-17 19:22:23 +02:00
AddWallet ( pwallet ) ;
2017-08-02 13:48:52 +02:00
}
return true ;
}
2017-08-28 18:31:53 +02:00
2018-04-13 15:02:59 +02:00
void WalletInit : : Start ( CScheduler & scheduler ) const
2017-07-06 12:16:40 +02:00
{
2018-05-22 17:18:07 +02:00
for ( const std : : shared_ptr < CWallet > & pwallet : GetWallets ( ) ) {
2018-04-19 23:42:40 +02:00
pwallet - > postInitProcess ( ) ;
2017-08-29 17:47:06 +02:00
}
2018-04-19 23:42:40 +02:00
// Run a thread to flush wallet periodically
scheduler . scheduleEvery ( MaybeCompactWalletDB , 500 ) ;
2017-08-29 17:47:06 +02:00
}
2018-04-13 15:02:59 +02:00
void WalletInit : : Flush ( ) const
2017-07-06 12:16:40 +02:00
{
2018-05-22 17:18:07 +02:00
for ( const std : : shared_ptr < CWallet > & pwallet : GetWallets ( ) ) {
2017-08-28 18:53:56 +02:00
pwallet - > Flush ( false ) ;
}
}
2018-04-13 15:02:59 +02:00
void WalletInit : : Stop ( ) const
2017-07-06 12:16:40 +02:00
{
2018-05-22 17:18:07 +02:00
for ( const std : : shared_ptr < CWallet > & pwallet : GetWallets ( ) ) {
2017-08-28 18:53:56 +02:00
pwallet - > Flush ( true ) ;
2017-08-28 18:31:53 +02:00
}
}
2017-08-28 18:41:33 +02:00
2018-04-13 15:02:59 +02:00
void WalletInit : : Close ( ) const
2017-07-06 12:16:40 +02:00
{
2018-05-22 17:18:07 +02:00
for ( const std : : shared_ptr < CWallet > & pwallet : GetWallets ( ) ) {
2018-04-17 19:22:23 +02:00
RemoveWallet ( pwallet ) ;
2017-08-28 18:41:33 +02:00
}
}