2011-08-09 13:27:58 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2018-07-27 00:36:45 +02:00
// Copyright (c) 2009-2018 The Bitcoin Core developers
2014-10-26 08:03:12 +01:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2011-06-26 19:23:24 +02:00
2017-11-10 01:57:53 +01:00
# include <wallet/wallet.h>
2013-04-13 07:13:08 +02:00
2017-11-10 01:57:53 +01:00
# include <checkpoints.h>
# include <chain.h>
# include <wallet/coincontrol.h>
# include <consensus/consensus.h>
# include <consensus/validation.h>
# include <fs.h>
# include <key.h>
2017-09-20 03:12:25 +02:00
# include <key_io.h>
2017-11-10 01:57:53 +01:00
# include <keystore.h>
# include <validation.h>
# include <net.h>
# include <policy/fees.h>
# include <policy/policy.h>
# include <policy/rbf.h>
# include <primitives/block.h>
# include <primitives/transaction.h>
# include <script/script.h>
2018-05-16 21:17:40 +02:00
# include <shutdown.h>
2017-11-10 01:57:53 +01:00
# include <timedata.h>
# include <txmempool.h>
# include <utilmoneystr.h>
# include <wallet/fees.h>
2018-04-18 19:11:28 +02:00
# include <wallet/walletutil.h>
2013-04-13 07:13:08 +02:00
2018-04-17 19:22:23 +02:00
# include <algorithm>
2014-10-01 08:50:24 +02:00
# include <assert.h>
2017-01-18 00:06:16 +01:00
# include <future>
2014-10-01 08:50:24 +02:00
2012-11-03 15:58:41 +01:00
# include <boost/algorithm/string/replace.hpp>
2011-06-26 19:23:24 +02:00
2018-07-30 18:50:43 +02:00
static const size_t OUTPUT_GROUP_MAX_ENTRIES = 10 ;
2018-04-19 15:44:34 +02:00
static CCriticalSection cs_wallets ;
2018-05-22 17:18:07 +02:00
static std : : vector < std : : shared_ptr < CWallet > > vpwallets GUARDED_BY ( cs_wallets ) ;
2018-04-17 19:22:23 +02:00
2018-05-22 17:18:07 +02:00
bool AddWallet ( const std : : shared_ptr < CWallet > & wallet )
2018-04-17 19:22:23 +02:00
{
2018-04-19 15:44:34 +02:00
LOCK ( cs_wallets ) ;
2018-04-17 19:22:23 +02:00
assert ( wallet ) ;
2018-05-22 17:18:07 +02:00
std : : vector < std : : shared_ptr < CWallet > > : : const_iterator i = std : : find ( vpwallets . begin ( ) , vpwallets . end ( ) , wallet ) ;
2018-04-17 19:22:23 +02:00
if ( i ! = vpwallets . end ( ) ) return false ;
vpwallets . push_back ( wallet ) ;
return true ;
}
2018-05-22 17:18:07 +02:00
bool RemoveWallet ( const std : : shared_ptr < CWallet > & wallet )
2018-04-17 19:22:23 +02:00
{
2018-04-19 15:44:34 +02:00
LOCK ( cs_wallets ) ;
2018-04-17 19:22:23 +02:00
assert ( wallet ) ;
2018-05-22 17:18:07 +02:00
std : : vector < std : : shared_ptr < CWallet > > : : iterator i = std : : find ( vpwallets . begin ( ) , vpwallets . end ( ) , wallet ) ;
2018-04-17 19:22:23 +02:00
if ( i = = vpwallets . end ( ) ) return false ;
vpwallets . erase ( i ) ;
return true ;
}
2018-04-18 14:46:11 +02:00
bool HasWallets ( )
{
2018-04-19 15:44:34 +02:00
LOCK ( cs_wallets ) ;
2018-04-18 14:46:11 +02:00
return ! vpwallets . empty ( ) ;
}
2018-05-22 17:18:07 +02:00
std : : vector < std : : shared_ptr < CWallet > > GetWallets ( )
2018-04-17 19:22:23 +02:00
{
2018-04-19 15:44:34 +02:00
LOCK ( cs_wallets ) ;
2018-04-17 19:22:23 +02:00
return vpwallets ;
}
2018-05-22 17:18:07 +02:00
std : : shared_ptr < CWallet > GetWallet ( const std : : string & name )
2018-04-17 19:22:23 +02:00
{
2018-04-19 15:44:34 +02:00
LOCK ( cs_wallets ) ;
2018-05-22 17:18:07 +02:00
for ( const std : : shared_ptr < CWallet > & wallet : vpwallets ) {
2018-04-17 19:22:23 +02:00
if ( wallet - > GetName ( ) = = name ) return wallet ;
}
return nullptr ;
}
2018-04-28 23:36:43 +02:00
// Custom deleter for shared_ptr<CWallet>.
static void ReleaseWallet ( CWallet * wallet )
{
2018-06-16 01:02:52 +02:00
wallet - > WalletLogPrintf ( " Releasing wallet \n " ) ;
2018-04-28 23:36:43 +02:00
wallet - > BlockUntilSyncedToCurrentChain ( ) ;
wallet - > Flush ( ) ;
delete wallet ;
}
2016-06-01 20:29:39 +02:00
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000 ;
2016-02-22 10:48:44 +01:00
2016-01-07 22:31:27 +01:00
const uint256 CMerkleTx : : ABANDON_HASH ( uint256S ( " 0000000000000000000000000000000000000000000000000000000000000001 " ) ) ;
2014-10-26 08:03:12 +01:00
/** @defgroup mapWallet
*
* @ {
*/
2011-06-26 19:23:24 +02:00
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
std : : string COutput : : ToString ( ) const
{
2016-11-12 01:54:51 +01:00
return strprintf ( " COutput(%s, %d, %d) [ % s ] " , tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)) ;
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
}
2018-08-02 00:23:19 +02:00
/** A class to identify which pubkeys a script and a keystore have in common. */
2017-04-20 14:23:48 +02:00
class CAffectedKeysVisitor : public boost : : static_visitor < void > {
private :
const CKeyStore & keystore ;
std : : vector < CKeyID > & vKeys ;
public :
2018-08-02 00:23:19 +02:00
/**
* @ param [ in ] keystoreIn The CKeyStore that is queried for the presence of a pubkey .
* @ param [ out ] vKeysIn A vector to which a script ' s pubkey identifiers are appended if they are in the keystore .
*/
2017-04-20 14:23:48 +02:00
CAffectedKeysVisitor ( const CKeyStore & keystoreIn , std : : vector < CKeyID > & vKeysIn ) : keystore ( keystoreIn ) , vKeys ( vKeysIn ) { }
2018-08-02 00:23:19 +02:00
/**
* Apply the visitor to each destination in a script , recursively to the redeemscript
* in the case of p2sh destinations .
* @ param [ in ] script The CScript from which destinations are extracted .
* @ post Any CKeyIDs that script and keystore have in common are appended to the visitor ' s vKeys .
*/
2017-04-20 14:23:48 +02:00
void Process ( const CScript & script ) {
txnouttype type ;
std : : vector < CTxDestination > vDest ;
int nRequired ;
if ( ExtractDestinations ( script , type , vDest , nRequired ) ) {
for ( const CTxDestination & dest : vDest )
boost : : apply_visitor ( * this , dest ) ;
}
}
void operator ( ) ( const CKeyID & keyId ) {
if ( keystore . HaveKey ( keyId ) )
vKeys . push_back ( keyId ) ;
}
void operator ( ) ( const CScriptID & scriptId ) {
CScript script ;
if ( keystore . GetCScript ( scriptId , script ) )
Process ( script ) ;
}
2017-08-26 04:55:52 +02:00
void operator ( ) ( const WitnessV0ScriptHash & scriptID )
{
CScriptID id ;
CRIPEMD160 ( ) . Write ( scriptID . begin ( ) , 32 ) . Finalize ( id . begin ( ) ) ;
CScript script ;
if ( keystore . GetCScript ( id , script ) ) {
Process ( script ) ;
}
}
void operator ( ) ( const WitnessV0KeyHash & keyid )
{
CKeyID id ( keyid ) ;
if ( keystore . HaveKey ( id ) ) {
vKeys . push_back ( id ) ;
}
}
template < typename X >
void operator ( ) ( const X & none ) { }
2017-04-20 14:23:48 +02:00
} ;
2014-02-15 22:38:28 +01:00
const CWalletTx * CWallet : : GetWalletTx ( const uint256 & hash ) const
{
LOCK ( cs_wallet ) ;
std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( hash ) ;
if ( it = = mapWallet . end ( ) )
2017-08-07 07:36:37 +02:00
return nullptr ;
2014-02-15 22:38:28 +01:00
return & ( it - > second ) ;
}
2017-12-08 12:39:22 +01:00
CPubKey CWallet : : GenerateNewKey ( WalletBatch & batch , bool internal )
2012-02-18 15:02:36 +01:00
{
2017-05-05 08:53:39 +02:00
assert ( ! IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) ;
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2012-03-22 03:56:31 +01:00
bool fCompressed = CanSupportFeature ( FEATURE_COMPRPUBKEY ) ; // default to compressed public keys if we want 0.6.0 wallets
2012-02-18 15:06:32 +01:00
2013-05-01 06:52:05 +02:00
CKey secret ;
2016-01-02 12:34:08 +01:00
// Create new metadata
int64_t nCreationTime = GetTime ( ) ;
CKeyMetadata metadata ( nCreationTime ) ;
// use HD key derivation if HD was enabled during wallet creation
2016-08-17 14:09:47 +02:00
if ( IsHDEnabled ( ) ) {
2017-12-08 12:39:22 +01:00
DeriveNewChildKey ( batch , metadata , secret , ( CanSupportFeature ( FEATURE_HD_SPLIT ) ? internal : false ) ) ;
2016-01-02 12:34:08 +01:00
} else {
secret . MakeNewKey ( fCompressed ) ;
}
2012-02-18 15:06:32 +01:00
// Compressed public keys were introduced in version 0.6.0
2017-07-15 03:00:30 +02:00
if ( fCompressed ) {
2012-03-22 03:56:31 +01:00
SetMinVersion ( FEATURE_COMPRPUBKEY ) ;
2017-07-15 03:00:30 +02:00
}
2012-02-18 15:06:32 +01:00
2013-05-01 06:52:05 +02:00
CPubKey pubkey = secret . GetPubKey ( ) ;
2014-11-06 10:17:48 +01:00
assert ( secret . VerifyPubKey ( pubkey ) ) ;
2013-06-20 01:13:55 +02:00
2016-01-02 12:34:08 +01:00
mapKeyMetadata [ pubkey . GetID ( ) ] = metadata ;
2016-11-08 22:28:20 +01:00
UpdateTimeFirstKey ( nCreationTime ) ;
2013-06-20 01:13:55 +02:00
2017-12-08 12:39:22 +01:00
if ( ! AddKeyPubKeyWithDB ( batch , secret , pubkey ) ) {
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : AddKey failed " ) ;
2017-07-15 03:00:30 +02:00
}
2013-05-01 06:52:05 +02:00
return pubkey ;
2012-02-18 15:02:36 +01:00
}
2011-06-26 19:23:24 +02:00
2017-12-08 12:39:22 +01:00
void CWallet : : DeriveNewChildKey ( WalletBatch & batch , CKeyMetadata & metadata , CKey & secret , bool internal )
2016-07-20 01:43:11 +02:00
{
// for now we use a fixed keypath scheme of m/0'/0'/k
2018-04-04 18:47:55 +02:00
CKey seed ; //seed (256bit)
2016-07-20 01:43:11 +02:00
CExtKey masterKey ; //hd master key
CExtKey accountKey ; //key at m/0'
2017-01-10 16:45:30 +01:00
CExtKey chainChildKey ; //key at m/0'/0' (external) or m/0'/1' (internal)
2016-07-20 01:43:11 +02:00
CExtKey childKey ; //key at m/0'/0'/<n>'
2018-04-04 18:47:55 +02:00
// try to get the seed
if ( ! GetKey ( hdChain . seed_id , seed ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : seed not found " ) ;
2016-07-20 01:43:11 +02:00
2018-04-04 18:47:55 +02:00
masterKey . SetSeed ( seed . begin ( ) , seed . size ( ) ) ;
2016-07-20 01:43:11 +02:00
// derive m/0'
// use hardened derivation (child keys >= 0x80000000 are hardened after bip32)
masterKey . Derive ( accountKey , BIP32_HARDENED_KEY_LIMIT ) ;
2017-01-10 16:45:30 +01:00
// derive m/0'/0' (external chain) OR m/0'/1' (internal chain)
2017-03-24 10:57:55 +01:00
assert ( internal ? CanSupportFeature ( FEATURE_HD_SPLIT ) : true ) ;
2017-01-10 16:45:30 +01:00
accountKey . Derive ( chainChildKey , BIP32_HARDENED_KEY_LIMIT + ( internal ? 1 : 0 ) ) ;
2016-07-20 01:43:11 +02:00
// derive child key at next index, skip keys already known to the wallet
do {
// always derive hardened keys
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened child-index-range
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649
2017-01-26 21:02:55 +01:00
if ( internal ) {
chainChildKey . Derive ( childKey , hdChain . nInternalChainCounter | BIP32_HARDENED_KEY_LIMIT ) ;
metadata . hdKeypath = " m/0'/1'/ " + std : : to_string ( hdChain . nInternalChainCounter ) + " ' " ;
2017-01-10 16:45:30 +01:00
hdChain . nInternalChainCounter + + ;
2017-01-26 21:02:55 +01:00
}
else {
chainChildKey . Derive ( childKey , hdChain . nExternalChainCounter | BIP32_HARDENED_KEY_LIMIT ) ;
metadata . hdKeypath = " m/0'/0'/ " + std : : to_string ( hdChain . nExternalChainCounter ) + " ' " ;
2017-01-10 16:45:30 +01:00
hdChain . nExternalChainCounter + + ;
2017-01-26 21:02:55 +01:00
}
2016-07-20 01:43:11 +02:00
} while ( HaveKey ( childKey . key . GetPubKey ( ) . GetID ( ) ) ) ;
secret = childKey . key ;
2018-04-04 17:43:45 +02:00
metadata . hd_seed_id = hdChain . seed_id ;
2016-07-20 01:43:11 +02:00
// update the chain model in the database
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteHDChain ( hdChain ) )
2016-07-20 01:43:11 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : Writing HD chain model failed " ) ;
}
2017-12-08 12:39:22 +01:00
bool CWallet : : AddKeyPubKeyWithDB ( WalletBatch & batch , const CKey & secret , const CPubKey & pubkey )
2011-06-26 19:23:24 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2017-07-15 03:00:30 +02:00
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is
// tunneled through to it.
2017-12-08 12:39:22 +01:00
bool needsDB = ! encrypted_batch ;
2017-07-15 03:00:30 +02:00
if ( needsDB ) {
2017-12-08 12:39:22 +01:00
encrypted_batch = & batch ;
2017-07-15 03:00:30 +02:00
}
if ( ! CCryptoKeyStore : : AddKeyPubKey ( secret , pubkey ) ) {
2017-12-08 12:39:22 +01:00
if ( needsDB ) encrypted_batch = nullptr ;
2011-06-25 14:57:32 +02:00
return false ;
2017-07-15 03:00:30 +02:00
}
2017-12-08 12:39:22 +01:00
if ( needsDB ) encrypted_batch = nullptr ;
2014-07-26 21:05:11 +02:00
// check if we need to remove from watch-only
CScript script ;
script = GetScriptForDestination ( pubkey . GetID ( ) ) ;
2017-07-15 03:00:30 +02:00
if ( HaveWatchOnly ( script ) ) {
2015-06-10 09:03:08 +02:00
RemoveWatchOnly ( script ) ;
2017-07-15 03:00:30 +02:00
}
2015-06-10 09:03:08 +02:00
script = GetScriptForRawPubKey ( pubkey ) ;
2017-07-15 03:00:30 +02:00
if ( HaveWatchOnly ( script ) ) {
2014-07-26 21:05:11 +02:00
RemoveWatchOnly ( script ) ;
2017-07-15 03:00:30 +02:00
}
2014-07-26 21:05:11 +02:00
2013-05-01 06:52:05 +02:00
if ( ! IsCrypted ( ) ) {
2017-12-08 12:39:22 +01:00
return batch . WriteKey ( pubkey ,
2013-06-10 15:36:29 +02:00
secret . GetPrivKey ( ) ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ pubkey . GetID ( ) ] ) ;
2013-05-01 06:52:05 +02:00
}
2011-07-13 13:43:50 +02:00
return true ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2017-07-15 03:00:30 +02:00
bool CWallet : : AddKeyPubKey ( const CKey & secret , const CPubKey & pubkey )
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
return CWallet : : AddKeyPubKeyWithDB ( batch , secret , pubkey ) ;
2017-07-15 03:00:30 +02:00
}
2013-06-10 15:36:29 +02:00
bool CWallet : : AddCryptedKey ( const CPubKey & vchPubKey ,
2017-01-27 02:33:45 +01:00
const std : : vector < unsigned char > & vchCryptedSecret )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
if ( ! CCryptoKeyStore : : AddCryptedKey ( vchPubKey , vchCryptedSecret ) )
return false ;
2011-07-08 15:08:27 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
if ( encrypted_batch )
return encrypted_batch - > WriteCryptedKey ( vchPubKey ,
2013-06-10 15:36:29 +02:00
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
else
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . WriteCryptedKey ( vchPubKey ,
2013-06-10 15:36:29 +02:00
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2018-07-27 08:22:42 +02:00
void CWallet : : LoadKeyMetadata ( const CKeyID & keyID , const CKeyMetadata & meta )
2013-06-20 01:13:55 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2016-11-08 22:28:20 +01:00
UpdateTimeFirstKey ( meta . nCreateTime ) ;
2016-11-08 22:55:02 +01:00
mapKeyMetadata [ keyID ] = meta ;
2013-06-20 01:13:55 +02:00
}
2018-07-27 08:22:42 +02:00
void CWallet : : LoadScriptMetadata ( const CScriptID & script_id , const CKeyMetadata & meta )
2017-12-08 18:50:46 +01:00
{
AssertLockHeld ( cs_wallet ) ; // m_script_metadata
UpdateTimeFirstKey ( meta . nCreateTime ) ;
m_script_metadata [ script_id ] = meta ;
}
2013-05-02 18:43:07 +02:00
bool CWallet : : LoadCryptedKey ( const CPubKey & vchPubKey , const std : : vector < unsigned char > & vchCryptedSecret )
{
return CCryptoKeyStore : : AddCryptedKey ( vchPubKey , vchCryptedSecret ) ;
}
2017-03-02 21:24:50 +01:00
/**
* Update wallet first key creation time . This should be called whenever keys
* are added to the wallet , with the oldest key creation time .
*/
2016-11-08 22:28:20 +01:00
void CWallet : : UpdateTimeFirstKey ( int64_t nCreateTime )
{
AssertLockHeld ( cs_wallet ) ;
if ( nCreateTime < = 1 ) {
// Cannot determine birthday information, so set the wallet birthday to
// the beginning of time.
nTimeFirstKey = 1 ;
} else if ( ! nTimeFirstKey | | nCreateTime < nTimeFirstKey ) {
nTimeFirstKey = nCreateTime ;
}
}
2012-01-05 03:40:52 +01:00
bool CWallet : : AddCScript ( const CScript & redeemScript )
2011-10-03 19:05:43 +02:00
{
2012-01-05 03:40:52 +01:00
if ( ! CCryptoKeyStore : : AddCScript ( redeemScript ) )
2011-10-03 19:05:43 +02:00
return false ;
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . WriteCScript ( Hash160 ( redeemScript ) , redeemScript ) ;
2011-10-03 19:05:43 +02:00
}
2014-06-10 09:42:42 +02:00
bool CWallet : : LoadCScript ( const CScript & redeemScript )
{
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
* that never can be redeemed . However , old wallets may still contain
* these . Do not add them to the wallet and warn . */
if ( redeemScript . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
{
2017-08-23 03:02:33 +02:00
std : : string strAddr = EncodeDestination ( CScriptID ( redeemScript ) ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s. \n " , __func__ , redeemScript . size ( ) , MAX_SCRIPT_ELEMENT_SIZE , strAddr ) ;
2014-06-10 09:42:42 +02:00
return true ;
}
return CCryptoKeyStore : : AddCScript ( redeemScript ) ;
}
2016-11-08 22:55:02 +01:00
bool CWallet : : AddWatchOnly ( const CScript & dest )
2013-07-26 01:06:01 +02:00
{
if ( ! CCryptoKeyStore : : AddWatchOnly ( dest ) )
return false ;
2017-12-08 18:50:46 +01:00
const CKeyMetadata & meta = m_script_metadata [ CScriptID ( dest ) ] ;
2016-11-08 22:55:02 +01:00
UpdateTimeFirstKey ( meta . nCreateTime ) ;
2014-07-26 21:05:11 +02:00
NotifyWatchonlyChanged ( true ) ;
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . WriteWatchOnly ( dest , meta ) ;
2016-11-08 22:55:02 +01:00
}
bool CWallet : : AddWatchOnly ( const CScript & dest , int64_t nCreateTime )
{
2017-12-08 18:50:46 +01:00
m_script_metadata [ CScriptID ( dest ) ] . nCreateTime = nCreateTime ;
2016-11-08 22:55:02 +01:00
return AddWatchOnly ( dest ) ;
2013-07-26 01:06:01 +02:00
}
2014-07-26 21:05:11 +02:00
bool CWallet : : RemoveWatchOnly ( const CScript & dest )
{
AssertLockHeld ( cs_wallet ) ;
if ( ! CCryptoKeyStore : : RemoveWatchOnly ( dest ) )
return false ;
if ( ! HaveWatchOnly ( ) )
NotifyWatchonlyChanged ( false ) ;
2017-12-08 12:39:22 +01:00
if ( ! WalletBatch ( * database ) . EraseWatchOnly ( dest ) )
2017-03-08 13:08:26 +01:00
return false ;
2014-07-26 21:05:11 +02:00
return true ;
}
2014-06-09 21:11:59 +02:00
bool CWallet : : LoadWatchOnly ( const CScript & dest )
2013-07-26 01:06:01 +02:00
{
return CCryptoKeyStore : : AddWatchOnly ( dest ) ;
}
2011-11-26 07:02:04 +01:00
bool CWallet : : Unlock ( const SecureString & strWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
2016-11-10 08:00:05 +01:00
CKeyingMaterial _vMasterKey ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
2017-06-02 03:18:57 +02:00
for ( const MasterKeyMap : : value_type & pMasterKey : mapMasterKeys )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
return false ;
2016-11-10 08:00:05 +01:00
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , _vMasterKey ) )
2013-05-07 16:47:00 +02:00
continue ; // try another master key
2016-11-10 08:00:05 +01:00
if ( CCryptoKeyStore : : Unlock ( _vMasterKey ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return true ;
}
2012-04-06 18:39:12 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
}
2011-11-26 07:02:04 +01:00
bool CWallet : : ChangeWalletPassphrase ( const SecureString & strOldWalletPassphrase , const SecureString & strNewWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
bool fWasLocked = IsLocked ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
Lock ( ) ;
CCrypter crypter ;
2016-11-10 08:00:05 +01:00
CKeyingMaterial _vMasterKey ;
2017-06-02 03:18:57 +02:00
for ( MasterKeyMap : : value_type & pMasterKey : mapMasterKeys )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
if ( ! crypter . SetKeyFromPassphrase ( strOldWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
return false ;
2016-11-10 08:00:05 +01:00
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , _vMasterKey ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
2016-11-10 08:00:05 +01:00
if ( CCryptoKeyStore : : Unlock ( _vMasterKey ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nStartTime = GetTimeMillis ( ) ;
2011-06-28 15:31:09 +02:00
crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) ;
2017-09-11 21:43:49 +02:00
pMasterKey . second . nDeriveIterations = static_cast < unsigned int > ( pMasterKey . second . nDeriveIterations * ( 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ) ;
2011-06-28 15:31:09 +02:00
nStartTime = GetTimeMillis ( ) ;
crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) ;
2017-09-11 21:43:49 +02:00
pMasterKey . second . nDeriveIterations = ( pMasterKey . second . nDeriveIterations + static_cast < unsigned int > ( pMasterKey . second . nDeriveIterations * 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ) / 2 ;
2011-06-28 15:31:09 +02:00
if ( pMasterKey . second . nDeriveIterations < 25000 )
pMasterKey . second . nDeriveIterations = 25000 ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Wallet passphrase changed to an nDeriveIterations of %i \n " , pMasterKey . second . nDeriveIterations ) ;
2011-06-28 15:31:09 +02:00
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( ! crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
return false ;
2016-11-10 08:00:05 +01:00
if ( ! crypter . Encrypt ( _vMasterKey , pMasterKey . second . vchCryptedKey ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
2017-12-08 12:39:22 +01:00
WalletBatch ( * database ) . WriteMasterKey ( pMasterKey . first , pMasterKey . second ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( fWasLocked )
Lock ( ) ;
return true ;
}
}
}
2011-08-26 20:37:23 +02:00
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
}
2018-04-27 20:01:02 +02:00
void CWallet : : ChainStateFlushed ( const CBlockLocator & loc )
2012-04-15 22:10:54 +02:00
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
batch . WriteBestBlock ( loc ) ;
2012-04-15 22:10:54 +02:00
}
2011-07-10 16:07:22 +02:00
2018-07-27 08:22:42 +02:00
void CWallet : : SetMinVersion ( enum WalletFeature nVersion , WalletBatch * batch_in , bool fExplicit )
2012-02-18 14:55:02 +01:00
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // nWalletVersion
2012-02-18 14:55:02 +01:00
if ( nWalletVersion > = nVersion )
2018-07-27 08:22:42 +02:00
return ;
2012-02-18 14:55:02 +01:00
2012-03-22 03:56:31 +01:00
// when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
if ( fExplicit & & nVersion > nWalletMaxVersion )
nVersion = FEATURE_LATEST ;
2012-02-18 14:55:02 +01:00
nWalletVersion = nVersion ;
2012-03-22 03:56:31 +01:00
if ( nVersion > nWalletMaxVersion )
nWalletMaxVersion = nVersion ;
2012-02-18 14:55:02 +01:00
{
2017-12-08 12:39:22 +01:00
WalletBatch * batch = batch_in ? batch_in : new WalletBatch ( * database ) ;
2012-02-18 14:55:02 +01:00
if ( nWalletVersion > 40000 )
2017-12-08 12:39:22 +01:00
batch - > WriteMinVersion ( nWalletVersion ) ;
if ( ! batch_in )
delete batch ;
2012-02-18 14:55:02 +01:00
}
}
2012-03-22 03:56:31 +01:00
bool CWallet : : SetMaxVersion ( int nVersion )
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // nWalletVersion, nWalletMaxVersion
2012-03-22 03:56:31 +01:00
// cannot downgrade below current version
if ( nWalletVersion > nVersion )
return false ;
nWalletMaxVersion = nVersion ;
return true ;
}
2017-01-27 02:33:45 +01:00
std : : set < uint256 > CWallet : : GetConflicts ( const uint256 & txid ) const
2014-02-14 02:12:51 +01:00
{
2017-01-27 02:33:45 +01:00
std : : set < uint256 > result ;
2014-02-14 02:12:51 +01:00
AssertLockHeld ( cs_wallet ) ;
std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( txid ) ;
if ( it = = mapWallet . end ( ) )
return result ;
const CWalletTx & wtx = it - > second ;
2014-02-15 22:38:28 +01:00
std : : pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range ;
2014-02-14 02:12:51 +01:00
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : wtx . tx - > vin )
2014-02-14 02:12:51 +01:00
{
2014-02-15 22:38:28 +01:00
if ( mapTxSpends . count ( txin . prevout ) < = 1 )
continue ; // No conflict if zero or one spends
range = mapTxSpends . equal_range ( txin . prevout ) ;
2016-09-02 18:19:01 +02:00
for ( TxSpends : : const_iterator _it = range . first ; _it ! = range . second ; + + _it )
result . insert ( _it - > second ) ;
2014-02-14 02:12:51 +01:00
}
return result ;
}
2016-12-09 19:45:27 +01:00
bool CWallet : : HasWalletSpend ( const uint256 & txid ) const
{
AssertLockHeld ( cs_wallet ) ;
auto iter = mapTxSpends . lower_bound ( COutPoint ( txid , 0 ) ) ;
return ( iter ! = mapTxSpends . end ( ) & & iter - > first . hash = = txid ) ;
}
2015-02-04 21:19:27 +01:00
void CWallet : : Flush ( bool shutdown )
{
2017-12-08 12:39:22 +01:00
database - > Flush ( shutdown ) ;
2015-02-04 21:19:27 +01:00
}
2017-01-27 02:33:45 +01:00
void CWallet : : SyncMetaData ( std : : pair < TxSpends : : iterator , TxSpends : : iterator > range )
2014-02-14 02:12:51 +01:00
{
// We want all the wallet transactions in range to have the same metadata as
// the oldest (smallest nOrderPos).
// So: find smallest nOrderPos:
int nMinOrderPos = std : : numeric_limits < int > : : max ( ) ;
2017-08-07 07:36:37 +02:00
const CWalletTx * copyFrom = nullptr ;
2018-01-26 17:28:31 +01:00
for ( TxSpends : : iterator it = range . first ; it ! = range . second ; + + it ) {
2017-01-19 22:08:03 +01:00
const CWalletTx * wtx = & mapWallet . at ( it - > second ) ;
2018-01-26 17:28:31 +01:00
if ( wtx - > nOrderPos < nMinOrderPos ) {
2018-06-29 11:30:25 +02:00
nMinOrderPos = wtx - > nOrderPos ;
2018-01-26 17:28:31 +01:00
copyFrom = wtx ;
2014-02-14 02:12:51 +01:00
}
}
2017-08-17 15:26:32 +02:00
2018-05-17 22:07:32 +02:00
if ( ! copyFrom ) {
return ;
}
2017-08-17 15:26:32 +02:00
2014-02-14 02:12:51 +01:00
// Now copy data from copyFrom to rest:
2014-02-15 22:38:28 +01:00
for ( TxSpends : : iterator it = range . first ; it ! = range . second ; + + it )
2014-02-14 02:12:51 +01:00
{
const uint256 & hash = it - > second ;
2017-01-19 22:08:03 +01:00
CWalletTx * copyTo = & mapWallet . at ( hash ) ;
2014-02-14 02:12:51 +01:00
if ( copyFrom = = copyTo ) continue ;
2017-08-28 09:24:17 +02:00
assert ( copyFrom & & " Oldest wallet transaction in range assumed to have been found. " ) ;
2015-03-12 00:48:53 +01:00
if ( ! copyFrom - > IsEquivalentTo ( * copyTo ) ) continue ;
2014-02-14 02:12:51 +01:00
copyTo - > mapValue = copyFrom - > mapValue ;
copyTo - > vOrderForm = copyFrom - > vOrderForm ;
// fTimeReceivedIsTxTime not copied on purpose
// nTimeReceived not copied on purpose
copyTo - > nTimeSmart = copyFrom - > nTimeSmart ;
copyTo - > fFromMe = copyFrom - > fFromMe ;
copyTo - > strFromAccount = copyFrom - > strFromAccount ;
// nOrderPos not copied on purpose
// cached members not copied on purpose
}
}
2014-10-26 08:03:12 +01:00
/**
* Outpoint is spent if any non - conflicted transaction
* spends it :
*/
2014-02-15 22:38:28 +01:00
bool CWallet : : IsSpent ( const uint256 & hash , unsigned int n ) const
2014-02-14 02:12:51 +01:00
{
2014-02-15 22:38:28 +01:00
const COutPoint outpoint ( hash , n ) ;
2017-01-27 02:33:45 +01:00
std : : pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range ;
2014-02-15 22:38:28 +01:00
range = mapTxSpends . equal_range ( outpoint ) ;
2014-02-14 02:12:51 +01:00
2014-02-15 22:38:28 +01:00
for ( TxSpends : : const_iterator it = range . first ; it ! = range . second ; + + it )
2014-02-14 02:12:51 +01:00
{
2014-02-15 22:38:28 +01:00
const uint256 & wtxid = it - > second ;
std : : map < uint256 , CWalletTx > : : const_iterator mit = mapWallet . find ( wtxid ) ;
2016-01-07 22:31:27 +01:00
if ( mit ! = mapWallet . end ( ) ) {
int depth = mit - > second . GetDepthInMainChain ( ) ;
if ( depth > 0 | | ( depth = = 0 & & ! mit - > second . isAbandoned ( ) ) )
return true ; // Spent
}
2014-02-14 02:12:51 +01:00
}
2014-02-15 22:38:28 +01:00
return false ;
}
void CWallet : : AddToSpends ( const COutPoint & outpoint , const uint256 & wtxid )
{
2017-01-27 02:33:45 +01:00
mapTxSpends . insert ( std : : make_pair ( outpoint , wtxid ) ) ;
2014-02-15 22:38:28 +01:00
2018-05-25 15:27:58 +02:00
setLockedCoins . erase ( outpoint ) ;
2017-01-27 02:33:45 +01:00
std : : pair < TxSpends : : iterator , TxSpends : : iterator > range ;
2014-02-15 22:38:28 +01:00
range = mapTxSpends . equal_range ( outpoint ) ;
SyncMetaData ( range ) ;
}
void CWallet : : AddToSpends ( const uint256 & wtxid )
{
2017-08-13 16:04:57 +02:00
auto it = mapWallet . find ( wtxid ) ;
assert ( it ! = mapWallet . end ( ) ) ;
CWalletTx & thisTx = it - > second ;
2014-02-15 22:38:28 +01:00
if ( thisTx . IsCoinBase ( ) ) // Coinbases don't spend anything!
return ;
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : thisTx . tx - > vin )
2014-02-15 22:38:28 +01:00
AddToSpends ( txin . prevout , wtxid ) ;
2014-02-14 02:12:51 +01:00
}
2011-11-26 07:02:04 +01:00
bool CWallet : : EncryptWallet ( const SecureString & strWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
if ( IsCrypted ( ) )
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2016-11-10 08:00:05 +01:00
CKeyingMaterial _vMasterKey ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2016-11-10 08:00:05 +01:00
_vMasterKey . resize ( WALLET_CRYPTO_KEY_SIZE ) ;
GetStrongRandBytes ( & _vMasterKey [ 0 ] , WALLET_CRYPTO_KEY_SIZE ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
CMasterKey kMasterKey ;
2014-06-24 14:27:32 +02:00
2011-08-26 20:37:23 +02:00
kMasterKey . vchSalt . resize ( WALLET_CRYPTO_SALT_SIZE ) ;
2016-04-16 12:25:12 +02:00
GetStrongRandBytes ( & kMasterKey . vchSalt [ 0 ] , WALLET_CRYPTO_SALT_SIZE ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
2013-04-13 07:13:08 +02:00
int64_t nStartTime = GetTimeMillis ( ) ;
2011-08-26 20:37:23 +02:00
crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , 25000 , kMasterKey . nDerivationMethod ) ;
2017-09-11 21:43:49 +02:00
kMasterKey . nDeriveIterations = static_cast < unsigned int > ( 2500000 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
nStartTime = GetTimeMillis ( ) ;
crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , kMasterKey . nDeriveIterations , kMasterKey . nDerivationMethod ) ;
2017-09-11 21:43:49 +02:00
kMasterKey . nDeriveIterations = ( kMasterKey . nDeriveIterations + static_cast < unsigned int > ( kMasterKey . nDeriveIterations * 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ) / 2 ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
if ( kMasterKey . nDeriveIterations < 25000 )
kMasterKey . nDeriveIterations = 25000 ;
2011-06-28 15:31:09 +02:00
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Encrypting Wallet with an nDeriveIterations of %i \n " , kMasterKey . nDeriveIterations ) ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , kMasterKey . nDeriveIterations , kMasterKey . nDerivationMethod ) )
return false ;
2016-11-10 08:00:05 +01:00
if ( ! crypter . Encrypt ( _vMasterKey , kMasterKey . vchCryptedKey ) )
2011-08-26 20:37:23 +02:00
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
mapMasterKeys [ + + nMasterKeyMaxID ] = kMasterKey ;
2017-12-08 12:39:22 +01:00
assert ( ! encrypted_batch ) ;
encrypted_batch = new WalletBatch ( * database ) ;
if ( ! encrypted_batch - > TxnBegin ( ) ) {
delete encrypted_batch ;
encrypted_batch = nullptr ;
2017-03-08 13:08:26 +01:00
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2017-12-08 12:39:22 +01:00
encrypted_batch - > WriteMasterKey ( nMasterKeyMaxID , kMasterKey ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2016-11-10 08:00:05 +01:00
if ( ! EncryptKeys ( _vMasterKey ) )
2011-07-08 15:08:27 +02:00
{
2017-12-08 12:39:22 +01:00
encrypted_batch - > TxnAbort ( ) ;
delete encrypted_batch ;
2014-09-28 16:11:17 +02:00
// We now probably have half of our keys encrypted in memory, and half not...
2015-04-28 16:48:28 +02:00
// die and let the user reload the unencrypted wallet.
2014-10-01 08:50:24 +02:00
assert ( false ) ;
2011-07-08 15:08:27 +02:00
}
2012-02-18 14:55:02 +01:00
// Encryption was introduced in version 0.4.0
2017-12-08 12:39:22 +01:00
SetMinVersion ( FEATURE_WALLETCRYPT , encrypted_batch , true ) ;
2012-02-18 14:55:02 +01:00
2017-12-08 12:39:22 +01:00
if ( ! encrypted_batch - > TxnCommit ( ) ) {
delete encrypted_batch ;
2017-03-08 13:08:26 +01:00
// We now have keys encrypted in memory, but not on disk...
// die to avoid confusion and let the user reload the unencrypted wallet.
assert ( false ) ;
2011-07-08 15:08:27 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2017-12-08 12:39:22 +01:00
delete encrypted_batch ;
encrypted_batch = nullptr ;
2017-03-08 13:08:26 +01:00
2011-11-17 20:01:25 +01:00
Lock ( ) ;
Unlock ( strWalletPassphrase ) ;
2016-07-21 21:19:02 +02:00
2018-04-04 18:47:55 +02:00
// if we are using HD, replace the HD seed with a new one
2016-08-17 14:09:47 +02:00
if ( IsHDEnabled ( ) ) {
2018-07-27 08:22:42 +02:00
SetHDSeed ( GenerateNewSeed ( ) ) ;
2016-07-21 21:19:02 +02:00
}
2011-11-17 20:01:25 +01:00
NewKeyPool ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
Lock ( ) ;
2011-08-26 20:37:23 +02:00
2011-11-11 03:12:46 +01:00
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
2017-12-08 12:39:22 +01:00
database - > Rewrite ( ) ;
2012-05-05 16:07:14 +02:00
2011-11-11 03:12:46 +01:00
}
2012-05-06 19:40:58 +02:00
NotifyStatusChanged ( this ) ;
2011-11-10 21:29:23 +01:00
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return true ;
2011-06-26 19:23:24 +02:00
}
2016-09-10 04:21:44 +02:00
DBErrors CWallet : : ReorderTransactions ( )
{
2016-09-28 17:57:25 +02:00
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2016-09-28 17:57:25 +02:00
// Old wallets didn't have any defined order for transactions
// Probably a bad idea to change the output of this
// First: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap.
2017-01-27 02:33:45 +01:00
typedef std : : pair < CWalletTx * , CAccountingEntry * > TxPair ;
typedef std : : multimap < int64_t , TxPair > TxItems ;
2016-09-28 17:57:25 +02:00
TxItems txByTime ;
2017-06-04 22:02:43 +02:00
for ( auto & entry : mapWallet )
2016-09-28 17:57:25 +02:00
{
2017-06-04 22:02:43 +02:00
CWalletTx * wtx = & entry . second ;
2017-06-21 21:10:00 +02:00
txByTime . insert ( std : : make_pair ( wtx - > nTimeReceived , TxPair ( wtx , nullptr ) ) ) ;
2016-09-28 17:57:25 +02:00
}
2017-01-27 02:33:45 +01:00
std : : list < CAccountingEntry > acentries ;
2017-12-08 12:39:22 +01:00
batch . ListAccountCreditDebit ( " " , acentries ) ;
2017-06-02 03:18:57 +02:00
for ( CAccountingEntry & entry : acentries )
2016-09-28 17:57:25 +02:00
{
2017-06-21 21:10:00 +02:00
txByTime . insert ( std : : make_pair ( entry . nTime , TxPair ( nullptr , & entry ) ) ) ;
2016-09-28 17:57:25 +02:00
}
nOrderPosNext = 0 ;
std : : vector < int64_t > nOrderPosOffsets ;
for ( TxItems : : iterator it = txByTime . begin ( ) ; it ! = txByTime . end ( ) ; + + it )
{
CWalletTx * const pwtx = ( * it ) . second . first ;
CAccountingEntry * const pacentry = ( * it ) . second . second ;
2017-06-21 21:10:00 +02:00
int64_t & nOrderPos = ( pwtx ! = nullptr ) ? pwtx - > nOrderPos : pacentry - > nOrderPos ;
2016-09-28 17:57:25 +02:00
if ( nOrderPos = = - 1 )
{
nOrderPos = nOrderPosNext + + ;
nOrderPosOffsets . push_back ( nOrderPos ) ;
if ( pwtx )
{
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteTx ( * pwtx ) )
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_FAIL ;
2016-09-28 17:57:25 +02:00
}
else
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteAccountingEntry ( pacentry - > nEntryNo , * pacentry ) )
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_FAIL ;
2016-09-28 17:57:25 +02:00
}
else
{
int64_t nOrderPosOff = 0 ;
2017-06-02 03:18:57 +02:00
for ( const int64_t & nOffsetStart : nOrderPosOffsets )
2016-09-28 17:57:25 +02:00
{
if ( nOrderPos > = nOffsetStart )
+ + nOrderPosOff ;
}
nOrderPos + = nOrderPosOff ;
nOrderPosNext = std : : max ( nOrderPosNext , nOrderPos + 1 ) ;
if ( ! nOrderPosOff )
continue ;
// Since we're changing the order, write it back
if ( pwtx )
{
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteTx ( * pwtx ) )
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_FAIL ;
2016-09-28 17:57:25 +02:00
}
else
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteAccountingEntry ( pacentry - > nEntryNo , * pacentry ) )
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_FAIL ;
2016-09-28 17:57:25 +02:00
}
}
2017-12-08 12:39:22 +01:00
batch . WriteOrderPosNext ( nOrderPosNext ) ;
2016-09-28 17:57:25 +02:00
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_OK ;
2016-09-10 04:21:44 +02:00
}
2017-12-08 12:39:22 +01:00
int64_t CWallet : : IncOrderPosNext ( WalletBatch * batch )
2012-09-08 06:55:36 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // nOrderPosNext
2013-04-13 07:13:08 +02:00
int64_t nRet = nOrderPosNext + + ;
2017-12-08 12:39:22 +01:00
if ( batch ) {
batch - > WriteOrderPosNext ( nOrderPosNext ) ;
2012-11-13 23:52:37 +01:00
} else {
2017-12-08 12:39:22 +01:00
WalletBatch ( * database ) . WriteOrderPosNext ( nOrderPosNext ) ;
2012-11-13 23:52:37 +01:00
}
2012-09-08 06:55:36 +02:00
return nRet ;
}
2016-06-02 15:00:59 +02:00
bool CWallet : : AccountMove ( std : : string strFrom , std : : string strTo , CAmount nAmount , std : : string strComment )
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
if ( ! batch . TxnBegin ( ) )
2016-06-02 15:00:59 +02:00
return false ;
int64_t nNow = GetAdjustedTime ( ) ;
// Debit
CAccountingEntry debit ;
2017-12-08 12:39:22 +01:00
debit . nOrderPos = IncOrderPosNext ( & batch ) ;
2016-06-02 15:00:59 +02:00
debit . strAccount = strFrom ;
debit . nCreditDebit = - nAmount ;
debit . nTime = nNow ;
debit . strOtherAccount = strTo ;
debit . strComment = strComment ;
2017-12-08 12:39:22 +01:00
AddAccountingEntry ( debit , & batch ) ;
2016-06-02 15:00:59 +02:00
// Credit
CAccountingEntry credit ;
2017-12-08 12:39:22 +01:00
credit . nOrderPos = IncOrderPosNext ( & batch ) ;
2016-06-02 15:00:59 +02:00
credit . strAccount = strTo ;
credit . nCreditDebit = nAmount ;
credit . nTime = nNow ;
credit . strOtherAccount = strFrom ;
credit . strComment = strComment ;
2017-12-08 12:39:22 +01:00
AddAccountingEntry ( credit , & batch ) ;
2016-06-02 15:00:59 +02:00
2017-12-08 12:39:22 +01:00
if ( ! batch . TxnCommit ( ) )
2016-06-02 15:00:59 +02:00
return false ;
return true ;
}
2017-10-20 19:27:55 +02:00
bool CWallet : : GetLabelDestination ( CTxDestination & dest , const std : : string & label , bool bForceNew )
2016-06-03 08:16:42 +02:00
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2016-06-03 08:16:42 +02:00
CAccount account ;
2017-12-08 12:39:22 +01:00
batch . ReadAccount ( label , account ) ;
2016-06-03 08:16:42 +02:00
if ( ! bForceNew ) {
if ( ! account . vchPubKey . IsValid ( ) )
bForceNew = true ;
else {
2017-12-01 01:49:11 +01:00
// Check if the current key has been used (TODO: check other addresses with the same key)
2018-02-11 03:06:35 +01:00
CScript scriptPubKey = GetScriptForDestination ( GetDestinationForKey ( account . vchPubKey , m_default_address_type ) ) ;
2017-01-27 02:33:45 +01:00
for ( std : : map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ;
2016-06-03 08:16:42 +02:00
it ! = mapWallet . end ( ) & & account . vchPubKey . IsValid ( ) ;
+ + it )
2017-06-02 03:18:57 +02:00
for ( const CTxOut & txout : ( * it ) . second . tx - > vout )
2016-06-03 08:16:42 +02:00
if ( txout . scriptPubKey = = scriptPubKey ) {
bForceNew = true ;
break ;
}
}
}
// Generate a new key
if ( bForceNew ) {
2017-01-10 16:45:30 +01:00
if ( ! GetKeyFromPool ( account . vchPubKey , false ) )
2016-06-03 08:16:42 +02:00
return false ;
2018-02-11 03:06:35 +01:00
LearnRelatedScripts ( account . vchPubKey , m_default_address_type ) ;
dest = GetDestinationForKey ( account . vchPubKey , m_default_address_type ) ;
2017-10-20 19:27:55 +02:00
SetAddressBook ( dest , label , " receive " ) ;
2017-12-08 12:39:22 +01:00
batch . WriteAccount ( label , account ) ;
2017-12-18 05:34:39 +01:00
} else {
2018-02-11 03:06:35 +01:00
dest = GetDestinationForKey ( account . vchPubKey , m_default_address_type ) ;
2016-06-03 08:16:42 +02:00
}
return true ;
}
2011-07-13 11:56:38 +02:00
void CWallet : : MarkDirty ( )
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2017-06-02 03:28:42 +02:00
for ( std : : pair < const uint256 , CWalletTx > & item : mapWallet )
2011-07-13 11:56:38 +02:00
item . second . MarkDirty ( ) ;
}
}
2016-12-09 19:45:27 +01:00
bool CWallet : : MarkReplaced ( const uint256 & originalHash , const uint256 & newHash )
{
LOCK ( cs_wallet ) ;
auto mi = mapWallet . find ( originalHash ) ;
// There is a bug if MarkReplaced is not called on an existing wallet transaction.
assert ( mi ! = mapWallet . end ( ) ) ;
CWalletTx & wtx = ( * mi ) . second ;
// Ensure for now that we're not overwriting data
assert ( wtx . mapValue . count ( " replaced_by_txid " ) = = 0 ) ;
wtx . mapValue [ " replaced_by_txid " ] = newHash . ToString ( ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database , " r+ " ) ;
2016-12-09 19:45:27 +01:00
bool success = true ;
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteTx ( wtx ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: Updating batch tx %s failed \n " , __func__ , wtx . GetHash ( ) . ToString ( ) ) ;
2016-12-09 19:45:27 +01:00
success = false ;
}
NotifyTransactionChanged ( this , originalHash , CT_UPDATED ) ;
return success ;
}
2016-06-08 06:41:03 +02:00
bool CWallet : : AddToWallet ( const CWalletTx & wtxIn , bool fFlushOnClose )
2011-06-26 19:23:24 +02:00
{
2016-06-08 06:41:03 +02:00
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database , " r+ " , fFlushOnClose ) ;
2016-06-08 06:41:03 +02:00
2011-06-26 19:23:24 +02:00
uint256 hash = wtxIn . GetHash ( ) ;
2014-02-14 02:12:51 +01:00
2016-06-08 06:25:31 +02:00
// Inserts only if not already there, returns tx inserted or tx found
2017-01-27 02:33:45 +01:00
std : : pair < std : : map < uint256 , CWalletTx > : : iterator , bool > ret = mapWallet . insert ( std : : make_pair ( hash , wtxIn ) ) ;
2016-06-08 06:25:31 +02:00
CWalletTx & wtx = ( * ret . first ) . second ;
wtx . BindWallet ( this ) ;
bool fInsertedNew = ret . second ;
2018-06-11 20:09:16 +02:00
if ( fInsertedNew ) {
2016-06-08 06:25:31 +02:00
wtx . nTimeReceived = GetAdjustedTime ( ) ;
2017-12-08 12:39:22 +01:00
wtx . nOrderPos = IncOrderPosNext ( & batch ) ;
2018-06-11 20:09:16 +02:00
wtx . m_it_wtxOrdered = wtxOrdered . insert ( std : : make_pair ( wtx . nOrderPos , TxPair ( & wtx , nullptr ) ) ) ;
2016-12-16 16:00:26 +01:00
wtx . nTimeSmart = ComputeTimeSmart ( wtx ) ;
2016-06-08 06:25:31 +02:00
AddToSpends ( hash ) ;
}
2011-06-26 19:23:24 +02:00
2016-06-08 06:25:31 +02:00
bool fUpdated = false ;
if ( ! fInsertedNew )
{
// Merge
if ( ! wtxIn . hashUnset ( ) & & wtxIn . hashBlock ! = wtx . hashBlock )
2011-06-26 19:23:24 +02:00
{
2016-06-08 06:25:31 +02:00
wtx . hashBlock = wtxIn . hashBlock ;
fUpdated = true ;
}
// If no longer abandoned, update
if ( wtxIn . hashBlock . IsNull ( ) & & wtx . isAbandoned ( ) )
{
wtx . hashBlock = wtxIn . hashBlock ;
fUpdated = true ;
}
if ( wtxIn . nIndex ! = - 1 & & ( wtxIn . nIndex ! = wtx . nIndex ) )
{
wtx . nIndex = wtxIn . nIndex ;
fUpdated = true ;
2011-06-26 19:23:24 +02:00
}
2016-06-08 06:25:31 +02:00
if ( wtxIn . fFromMe & & wtxIn . fFromMe ! = wtx . fFromMe )
{
wtx . fFromMe = wtxIn . fFromMe ;
fUpdated = true ;
}
2017-09-03 14:43:35 +02:00
// If we have a witness-stripped version of this transaction, and we
// see a new version with a witness, then we must be upgrading a pre-segwit
// wallet. Store the new version of the transaction with the witness,
// as the stripped-version must be invalid.
// TODO: Store all versions of the transaction, instead of just one.
if ( wtxIn . tx - > HasWitness ( ) & & ! wtx . tx - > HasWitness ( ) ) {
wtx . SetTx ( wtxIn . tx ) ;
fUpdated = true ;
}
2016-06-08 06:25:31 +02:00
}
2011-06-26 19:23:24 +02:00
2016-06-08 06:25:31 +02:00
//// debug print
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " AddToWallet %s %s%s \n " , wtxIn . GetHash ( ) . ToString ( ) , ( fInsertedNew ? " new " : " " ) , ( fUpdated ? " update " : " " ) ) ;
2011-06-26 19:23:24 +02:00
2016-06-08 06:25:31 +02:00
// Write to disk
if ( fInsertedNew | | fUpdated )
2017-12-08 12:39:22 +01:00
if ( ! batch . WriteTx ( wtx ) )
2016-06-08 06:25:31 +02:00
return false ;
2013-05-26 20:17:18 +02:00
2016-06-08 06:25:31 +02:00
// Break debit/credit balance caches:
wtx . MarkDirty ( ) ;
2011-06-26 19:23:24 +02:00
2016-06-08 06:25:31 +02:00
// Notify UI of new or updated transaction
NotifyTransactionChanged ( this , hash , fInsertedNew ? CT_NEW : CT_UPDATED ) ;
2012-11-03 15:58:41 +01:00
2016-06-08 06:25:31 +02:00
// notify an external script when a wallet transaction comes in or is updated
2017-08-01 21:17:40 +02:00
std : : string strCmd = gArgs . GetArg ( " -walletnotify " , " " ) ;
2012-11-03 15:58:41 +01:00
2017-07-27 01:09:05 +02:00
if ( ! strCmd . empty ( ) )
2016-06-08 06:25:31 +02:00
{
boost : : replace_all ( strCmd , " %s " , wtxIn . GetHash ( ) . GetHex ( ) ) ;
2018-02-08 01:19:34 +01:00
std : : thread t ( runCommand , strCmd ) ;
t . detach ( ) ; // thread runs free
2016-06-08 06:25:31 +02:00
}
return true ;
}
2018-07-27 08:22:42 +02:00
void CWallet : : LoadToWallet ( const CWalletTx & wtxIn )
2016-06-08 06:25:31 +02:00
{
uint256 hash = wtxIn . GetHash ( ) ;
2018-06-11 20:09:16 +02:00
const auto & ins = mapWallet . emplace ( hash , wtxIn ) ;
CWalletTx & wtx = ins . first - > second ;
2016-06-08 06:25:31 +02:00
wtx . BindWallet ( this ) ;
2018-06-11 20:09:16 +02:00
if ( /* insertion took place */ ins . second ) {
wtx . m_it_wtxOrdered = wtxOrdered . insert ( std : : make_pair ( wtx . nOrderPos , TxPair ( & wtx , nullptr ) ) ) ;
}
2016-06-08 06:25:31 +02:00
AddToSpends ( hash ) ;
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : wtx . tx - > vin ) {
2017-08-13 16:04:57 +02:00
auto it = mapWallet . find ( txin . prevout . hash ) ;
if ( it ! = mapWallet . end ( ) ) {
CWalletTx & prevtx = it - > second ;
2016-06-08 06:25:31 +02:00
if ( prevtx . nIndex = = - 1 & & ! prevtx . hashUnset ( ) ) {
MarkConflicted ( prevtx . hashBlock , wtx . GetHash ( ) ) ;
}
}
2012-05-05 16:07:14 +02:00
}
2011-06-26 19:23:24 +02:00
}
2017-03-07 00:21:27 +01:00
bool CWallet : : AddToWalletIfInvolvingMe ( const CTransactionRef & ptx , const CBlockIndex * pIndex , int posInBlock , bool fUpdate )
2011-06-26 19:23:24 +02:00
{
2017-03-07 00:21:27 +01:00
const CTransaction & tx = * ptx ;
2011-06-26 19:23:24 +02:00
{
2014-03-09 12:41:22 +01:00
AssertLockHeld ( cs_wallet ) ;
2015-11-26 18:42:07 +01:00
2017-08-07 07:36:37 +02:00
if ( pIndex ! = nullptr ) {
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : tx . vin ) {
2015-11-26 18:42:07 +01:00
std : : pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range = mapTxSpends . equal_range ( txin . prevout ) ;
while ( range . first ! = range . second ) {
if ( range . first - > second ! = tx . GetHash ( ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i) \n " , tx . GetHash ( ) . ToString ( ) , pIndex - > GetBlockHash ( ) . ToString ( ) , range . first - > second . ToString ( ) , range . first - > first . hash . ToString ( ) , range . first - > first . n ) ;
2016-04-26 13:55:13 +02:00
MarkConflicted ( pIndex - > GetBlockHash ( ) , range . first - > second ) ;
2015-11-26 18:42:07 +01:00
}
range . first + + ;
}
}
}
2014-09-06 21:59:59 +02:00
bool fExisted = mapWallet . count ( tx . GetHash ( ) ) ! = 0 ;
2011-08-26 20:37:23 +02:00
if ( fExisted & & ! fUpdate ) return false ;
2014-07-17 14:09:46 +02:00
if ( fExisted | | IsMine ( tx ) | | IsFromMe ( tx ) )
2011-08-26 20:37:23 +02:00
{
2017-07-18 21:49:56 +02:00
/* Check if any keys in the wallet keypool that were supposed to be unused
* have appeared in a new transaction . If so , remove those keys from the keypool .
* This can happen when restoring an old wallet backup that does not contain
* the mostly recently created transactions from newer versions of the wallet .
*/
// loop though all outputs
for ( const CTxOut & txout : tx . vout ) {
// extract addresses and check if they match with an unused keypool key
std : : vector < CKeyID > vAffected ;
CAffectedKeysVisitor ( * this , vAffected ) . Process ( txout . scriptPubKey ) ;
for ( const CKeyID & keyid : vAffected ) {
std : : map < CKeyID , int64_t > : : const_iterator mi = m_pool_key_to_index . find ( keyid ) ;
if ( mi ! = m_pool_key_to_index . end ( ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: Detected a used keypool key, mark all keypool key up to this key as used \n " , __func__ ) ;
2017-07-18 21:49:56 +02:00
MarkReserveKeysAsUsed ( mi - > second ) ;
if ( ! TopUpKeyPool ( ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: Topping up keypool failed (locked wallet) \n " , __func__ ) ;
2017-07-18 21:49:56 +02:00
}
}
}
}
2017-03-07 00:21:27 +01:00
CWalletTx wtx ( this , ptx ) ;
2014-08-31 05:55:27 +02:00
2011-08-26 20:37:23 +02:00
// Get merkle branch if transaction was found in a block
2017-08-07 07:36:37 +02:00
if ( pIndex ! = nullptr )
2016-04-26 13:55:13 +02:00
wtx . SetMerkleBranch ( pIndex , posInBlock ) ;
2014-08-31 05:55:27 +02:00
2016-06-08 06:41:03 +02:00
return AddToWallet ( wtx , false ) ;
2011-08-26 20:37:23 +02:00
}
2011-06-26 19:23:24 +02:00
}
return false ;
}
2017-04-28 20:10:21 +02:00
bool CWallet : : TransactionCanBeAbandoned ( const uint256 & hashTx ) const
{
LOCK2 ( cs_main , cs_wallet ) ;
const CWalletTx * wtx = GetWalletTx ( hashTx ) ;
2018-01-27 23:45:32 +01:00
return wtx & & ! wtx - > isAbandoned ( ) & & wtx - > GetDepthInMainChain ( ) = = 0 & & ! wtx - > InMempool ( ) ;
2017-04-28 20:10:21 +02:00
}
2018-07-12 22:02:31 +02:00
void CWallet : : MarkInputsDirty ( const CTransactionRef & tx )
{
for ( const CTxIn & txin : tx - > vin ) {
auto it = mapWallet . find ( txin . prevout . hash ) ;
if ( it ! = mapWallet . end ( ) ) {
it - > second . MarkDirty ( ) ;
}
}
}
2016-01-07 22:31:27 +01:00
bool CWallet : : AbandonTransaction ( const uint256 & hashTx )
{
LOCK2 ( cs_main , cs_wallet ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database , " r+ " ) ;
2016-01-07 22:31:27 +01:00
std : : set < uint256 > todo ;
std : : set < uint256 > done ;
// Can't mark abandoned if confirmed or in mempool
2017-08-13 16:04:57 +02:00
auto it = mapWallet . find ( hashTx ) ;
assert ( it ! = mapWallet . end ( ) ) ;
CWalletTx & origtx = it - > second ;
2018-01-27 23:45:32 +01:00
if ( origtx . GetDepthInMainChain ( ) ! = 0 | | origtx . InMempool ( ) ) {
2016-01-07 22:31:27 +01:00
return false ;
}
todo . insert ( hashTx ) ;
while ( ! todo . empty ( ) ) {
uint256 now = * todo . begin ( ) ;
todo . erase ( now ) ;
done . insert ( now ) ;
2017-08-13 16:04:57 +02:00
auto it = mapWallet . find ( now ) ;
assert ( it ! = mapWallet . end ( ) ) ;
CWalletTx & wtx = it - > second ;
2016-01-07 22:31:27 +01:00
int currentconfirm = wtx . GetDepthInMainChain ( ) ;
// If the orig tx was not in block, none of its spends can be
assert ( currentconfirm < = 0 ) ;
// if (currentconfirm < 0) {Tx and spends are already conflicted, no need to abandon}
if ( currentconfirm = = 0 & & ! wtx . isAbandoned ( ) ) {
// If the orig tx was not in block/mempool, none of its spends can be in mempool
assert ( ! wtx . InMempool ( ) ) ;
wtx . nIndex = - 1 ;
wtx . setAbandoned ( ) ;
wtx . MarkDirty ( ) ;
2017-12-08 12:39:22 +01:00
batch . WriteTx ( wtx ) ;
2016-01-11 11:15:41 +01:00
NotifyTransactionChanged ( this , wtx . GetHash ( ) , CT_UPDATED ) ;
2016-01-07 22:31:27 +01:00
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
2018-07-12 23:19:00 +02:00
TxSpends : : const_iterator iter = mapTxSpends . lower_bound ( COutPoint ( now , 0 ) ) ;
2016-01-07 22:31:27 +01:00
while ( iter ! = mapTxSpends . end ( ) & & iter - > first . hash = = now ) {
if ( ! done . count ( iter - > second ) ) {
todo . insert ( iter - > second ) ;
}
iter + + ;
}
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
2018-07-12 22:02:31 +02:00
MarkInputsDirty ( wtx . tx ) ;
2016-01-07 22:31:27 +01:00
}
}
return true ;
}
2015-11-26 18:42:07 +01:00
void CWallet : : MarkConflicted ( const uint256 & hashBlock , const uint256 & hashTx )
{
LOCK2 ( cs_main , cs_wallet ) ;
int conflictconfirms = 0 ;
2018-01-12 01:23:09 +01:00
CBlockIndex * pindex = LookupBlockIndex ( hashBlock ) ;
if ( pindex & & chainActive . Contains ( pindex ) ) {
conflictconfirms = - ( chainActive . Height ( ) - pindex - > nHeight + 1 ) ;
2015-11-26 18:42:07 +01:00
}
2016-02-09 20:23:09 +01:00
// If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain,
// for example when loading the wallet during a reindex. Do nothing in that
// case.
if ( conflictconfirms > = 0 )
return ;
2015-11-26 18:42:07 +01:00
// Do not flush the wallet here for performance reasons
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database , " r+ " , false ) ;
2015-11-26 18:42:07 +01:00
2016-01-07 22:31:12 +01:00
std : : set < uint256 > todo ;
2015-11-26 18:42:07 +01:00
std : : set < uint256 > done ;
2016-01-07 22:31:12 +01:00
todo . insert ( hashTx ) ;
2015-11-26 18:42:07 +01:00
while ( ! todo . empty ( ) ) {
2016-01-07 22:31:12 +01:00
uint256 now = * todo . begin ( ) ;
todo . erase ( now ) ;
2015-11-26 18:42:07 +01:00
done . insert ( now ) ;
2017-08-13 16:04:57 +02:00
auto it = mapWallet . find ( now ) ;
assert ( it ! = mapWallet . end ( ) ) ;
CWalletTx & wtx = it - > second ;
2015-11-26 18:42:07 +01:00
int currentconfirm = wtx . GetDepthInMainChain ( ) ;
if ( conflictconfirms < currentconfirm ) {
// Block is 'more conflicted' than current confirm; update.
// Mark transaction as conflicted with this block.
wtx . nIndex = - 1 ;
wtx . hashBlock = hashBlock ;
wtx . MarkDirty ( ) ;
2017-12-08 12:39:22 +01:00
batch . WriteTx ( wtx ) ;
2015-11-26 18:42:07 +01:00
// Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too
TxSpends : : const_iterator iter = mapTxSpends . lower_bound ( COutPoint ( now , 0 ) ) ;
while ( iter ! = mapTxSpends . end ( ) & & iter - > first . hash = = now ) {
if ( ! done . count ( iter - > second ) ) {
2016-01-07 22:31:12 +01:00
todo . insert ( iter - > second ) ;
2015-11-26 18:42:07 +01:00
}
iter + + ;
}
2016-01-06 23:24:30 +01:00
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be recomputed
2018-07-12 22:02:31 +02:00
MarkInputsDirty ( wtx . tx ) ;
2015-11-26 18:42:07 +01:00
}
}
}
2018-04-11 04:12:48 +02:00
void CWallet : : SyncTransaction ( const CTransactionRef & ptx , const CBlockIndex * pindex , int posInBlock , bool update_tx ) {
if ( ! AddToWalletIfInvolvingMe ( ptx , pindex , posInBlock , update_tx ) )
2014-02-15 22:38:28 +01:00
return ; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
2018-07-12 22:02:31 +02:00
MarkInputsDirty ( ptx ) ;
2013-10-19 18:34:06 +02:00
}
2017-03-30 03:12:42 +02:00
void CWallet : : TransactionAddedToMempool ( const CTransactionRef & ptx ) {
LOCK2 ( cs_main , cs_wallet ) ;
2017-04-11 16:34:30 +02:00
SyncTransaction ( ptx ) ;
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
auto it = mapWallet . find ( ptx - > GetHash ( ) ) ;
if ( it ! = mapWallet . end ( ) ) {
it - > second . fInMempool = true ;
}
}
void CWallet : : TransactionRemovedFromMempool ( const CTransactionRef & ptx ) {
LOCK ( cs_wallet ) ;
auto it = mapWallet . find ( ptx - > GetHash ( ) ) ;
if ( it ! = mapWallet . end ( ) ) {
it - > second . fInMempool = false ;
}
2017-03-30 03:12:42 +02:00
}
void CWallet : : BlockConnected ( const std : : shared_ptr < const CBlock > & pblock , const CBlockIndex * pindex , const std : : vector < CTransactionRef > & vtxConflicted ) {
2017-03-08 18:55:33 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-04-10 22:44:57 +02:00
// TODO: Temporarily ensure that mempool removals are notified before
2017-03-30 03:12:42 +02:00
// connected transactions. This shouldn't matter, but the abandoned
// state of transactions in our wallet is currently cleared when we
// receive another notification and there is a race condition where
// notification of a connected conflict might cause an outside process
2017-04-10 22:44:57 +02:00
// to abandon a transaction and then have it inadvertently cleared by
2017-03-30 03:12:42 +02:00
// the notification that the conflicted transaction was evicted.
for ( const CTransactionRef & ptx : vtxConflicted ) {
2017-04-11 16:34:30 +02:00
SyncTransaction ( ptx ) ;
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
TransactionRemovedFromMempool ( ptx ) ;
2017-03-30 03:12:42 +02:00
}
for ( size_t i = 0 ; i < pblock - > vtx . size ( ) ; i + + ) {
SyncTransaction ( pblock - > vtx [ i ] , pindex , i ) ;
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
TransactionRemovedFromMempool ( pblock - > vtx [ i ] ) ;
2017-03-30 03:12:42 +02:00
}
2017-01-18 00:06:16 +01:00
m_last_block_processed = pindex ;
2017-03-30 03:12:42 +02:00
}
void CWallet : : BlockDisconnected ( const std : : shared_ptr < const CBlock > & pblock ) {
2017-03-08 18:55:33 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-03-30 03:12:42 +02:00
for ( const CTransactionRef & ptx : pblock - > vtx ) {
2017-04-11 16:34:30 +02:00
SyncTransaction ( ptx ) ;
2017-03-30 03:12:42 +02:00
}
}
2011-06-26 19:23:24 +02:00
2017-01-18 00:06:16 +01:00
void CWallet : : BlockUntilSyncedToCurrentChain ( ) {
AssertLockNotHeld ( cs_main ) ;
AssertLockNotHeld ( cs_wallet ) ;
{
// Skip the queue-draining stuff if we know we're caught up with
// chainActive.Tip()...
// We could also take cs_wallet here, and call m_last_block_processed
// protected by cs_wallet instead of cs_main, but as long as we need
2018-03-18 15:26:45 +01:00
// cs_main here anyway, it's easier to just call it cs_main-protected.
2017-01-18 00:06:16 +01:00
LOCK ( cs_main ) ;
const CBlockIndex * initialChainTip = chainActive . Tip ( ) ;
2018-04-28 23:36:43 +02:00
if ( m_last_block_processed & & m_last_block_processed - > GetAncestor ( initialChainTip - > nHeight ) = = initialChainTip ) {
2017-01-18 00:06:16 +01:00
return ;
}
}
// ...otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function).
2017-12-24 18:13:13 +01:00
SyncWithValidationInterfaceQueue ( ) ;
2017-01-18 00:06:16 +01:00
}
2013-07-26 01:06:01 +02:00
isminetype CWallet : : IsMine ( const CTxIn & txin ) const
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2017-01-27 02:33:45 +01:00
std : : map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
2011-06-26 19:23:24 +02:00
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
2016-11-12 01:54:51 +01:00
if ( txin . prevout . n < prev . tx - > vout . size ( ) )
return IsMine ( prev . tx - > vout [ txin . prevout . n ] ) ;
2011-06-26 19:23:24 +02:00
}
}
2014-07-01 11:00:22 +02:00
return ISMINE_NO ;
2011-06-26 19:23:24 +02:00
}
2016-12-09 21:31:06 +01:00
// Note that this function doesn't distinguish between a 0-valued input,
// and a not-"is mine" (according to the filter) input.
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetDebit ( const CTxIn & txin , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2017-01-27 02:33:45 +01:00
std : : map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
2011-06-26 19:23:24 +02:00
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
2016-11-12 01:54:51 +01:00
if ( txin . prevout . n < prev . tx - > vout . size ( ) )
if ( IsMine ( prev . tx - > vout [ txin . prevout . n ] ) & filter )
return prev . tx - > vout [ txin . prevout . n ] . nValue ;
2011-06-26 19:23:24 +02:00
}
}
return 0 ;
}
2015-02-04 23:19:29 +01:00
isminetype CWallet : : IsMine ( const CTxOut & txout ) const
{
return : : IsMine ( * this , txout . scriptPubKey ) ;
}
CAmount CWallet : : GetCredit ( const CTxOut & txout , const isminefilter & filter ) const
{
if ( ! MoneyRange ( txout . nValue ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
return ( ( IsMine ( txout ) & filter ) ? txout . nValue : 0 ) ;
}
2011-10-03 19:05:43 +02:00
bool CWallet : : IsChange ( const CTxOut & txout ) const
{
2011-11-08 19:20:29 +01:00
// TODO: fix handling of 'change' outputs. The assumption is that any
2014-06-09 21:11:59 +02:00
// payment to a script that is ours, but is not in the address book
2011-11-08 19:20:29 +01:00
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
2014-06-09 21:11:59 +02:00
if ( : : IsMine ( * this , txout . scriptPubKey ) )
2012-04-06 18:39:12 +02:00
{
2014-06-09 21:11:59 +02:00
CTxDestination address ;
if ( ! ExtractDestination ( txout . scriptPubKey , address ) )
return true ;
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
if ( ! mapAddressBook . count ( address ) )
return true ;
}
2011-10-03 19:05:43 +02:00
return false ;
}
2015-02-04 23:19:29 +01:00
CAmount CWallet : : GetChange ( const CTxOut & txout ) const
{
if ( ! MoneyRange ( txout . nValue ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
return ( IsChange ( txout ) ? txout . nValue : 0 ) ;
}
bool CWallet : : IsMine ( const CTransaction & tx ) const
{
2017-06-02 03:18:57 +02:00
for ( const CTxOut & txout : tx . vout )
2015-02-04 23:19:29 +01:00
if ( IsMine ( txout ) )
return true ;
return false ;
}
bool CWallet : : IsFromMe ( const CTransaction & tx ) const
{
return ( GetDebit ( tx , ISMINE_ALL ) > 0 ) ;
}
CAmount CWallet : : GetDebit ( const CTransaction & tx , const isminefilter & filter ) const
{
CAmount nDebit = 0 ;
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : tx . vin )
2015-02-04 23:19:29 +01:00
{
nDebit + = GetDebit ( txin , filter ) ;
if ( ! MoneyRange ( nDebit ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
}
return nDebit ;
}
2016-12-09 21:31:06 +01:00
bool CWallet : : IsAllFromMe ( const CTransaction & tx , const isminefilter & filter ) const
{
LOCK ( cs_wallet ) ;
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : tx . vin )
2016-12-09 21:31:06 +01:00
{
auto mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi = = mapWallet . end ( ) )
return false ; // any unknown inputs can't be from us
const CWalletTx & prev = ( * mi ) . second ;
if ( txin . prevout . n > = prev . tx - > vout . size ( ) )
return false ; // invalid input!
if ( ! ( IsMine ( prev . tx - > vout [ txin . prevout . n ] ) & filter ) )
return false ;
}
return true ;
}
2015-02-04 23:19:29 +01:00
CAmount CWallet : : GetCredit ( const CTransaction & tx , const isminefilter & filter ) const
{
CAmount nCredit = 0 ;
2017-06-02 03:18:57 +02:00
for ( const CTxOut & txout : tx . vout )
2015-02-04 23:19:29 +01:00
{
nCredit + = GetCredit ( txout , filter ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
}
return nCredit ;
}
CAmount CWallet : : GetChange ( const CTransaction & tx ) const
{
CAmount nChange = 0 ;
2017-06-02 03:18:57 +02:00
for ( const CTxOut & txout : tx . vout )
2015-02-04 23:19:29 +01:00
{
nChange + = GetChange ( txout ) ;
if ( ! MoneyRange ( nChange ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
}
return nChange ;
}
2018-04-04 17:43:45 +02:00
CPubKey CWallet : : GenerateNewSeed ( )
2016-07-21 21:19:02 +02:00
{
2017-05-05 08:53:39 +02:00
assert ( ! IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) ;
2016-07-21 21:19:02 +02:00
CKey key ;
key . MakeNewKey ( true ) ;
2018-04-04 17:43:45 +02:00
return DeriveNewSeed ( key ) ;
2017-09-12 23:01:12 +02:00
}
2016-07-21 21:19:02 +02:00
2018-04-04 17:43:45 +02:00
CPubKey CWallet : : DeriveNewSeed ( const CKey & key )
2017-09-12 23:01:12 +02:00
{
2016-07-21 21:19:02 +02:00
int64_t nCreationTime = GetTime ( ) ;
CKeyMetadata metadata ( nCreationTime ) ;
2018-04-04 18:47:55 +02:00
// calculate the seed
CPubKey seed = key . GetPubKey ( ) ;
assert ( key . VerifyPubKey ( seed ) ) ;
2016-07-21 21:19:02 +02:00
2018-04-04 18:47:55 +02:00
// set the hd keypath to "s" -> Seed, refers the seed to itself
metadata . hdKeypath = " s " ;
metadata . hd_seed_id = seed . GetID ( ) ;
2016-07-21 21:19:02 +02:00
{
LOCK ( cs_wallet ) ;
// mem store the metadata
2018-04-04 18:47:55 +02:00
mapKeyMetadata [ seed . GetID ( ) ] = metadata ;
2016-07-21 21:19:02 +02:00
// write the key&metadata to the database
2018-04-04 18:47:55 +02:00
if ( ! AddKeyPubKey ( key , seed ) )
2016-08-19 18:31:35 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : AddKeyPubKey failed " ) ;
2016-07-21 21:19:02 +02:00
}
2018-04-04 18:47:55 +02:00
return seed ;
2016-07-21 21:19:02 +02:00
}
2018-07-27 08:22:42 +02:00
void CWallet : : SetHDSeed ( const CPubKey & seed )
2016-01-02 12:34:08 +01:00
{
LOCK ( cs_wallet ) ;
// store the keyid (hash160) together with
// the child index counter in the database
// as a hdchain object
CHDChain newHdChain ;
2017-03-29 18:33:13 +02:00
newHdChain . nVersion = CanSupportFeature ( FEATURE_HD_SPLIT ) ? CHDChain : : VERSION_HD_CHAIN_SPLIT : CHDChain : : VERSION_HD_BASE ;
2018-04-04 18:47:55 +02:00
newHdChain . seed_id = seed . GetID ( ) ;
2016-01-02 12:34:08 +01:00
SetHDChain ( newHdChain , false ) ;
}
2018-07-27 08:22:42 +02:00
void CWallet : : SetHDChain ( const CHDChain & chain , bool memonly )
2016-01-02 12:34:08 +01:00
{
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
if ( ! memonly & & ! WalletBatch ( * database ) . WriteHDChain ( chain ) )
2017-01-27 02:33:45 +01:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing chain failed " ) ;
2016-01-02 12:34:08 +01:00
hdChain = chain ;
}
2017-03-09 03:32:02 +01:00
bool CWallet : : IsHDEnabled ( ) const
2016-08-17 14:09:47 +02:00
{
2018-04-04 17:43:45 +02:00
return ! hdChain . seed_id . IsNull ( ) ;
2016-08-17 14:09:47 +02:00
}
2017-02-16 14:22:18 +01:00
void CWallet : : SetWalletFlag ( uint64_t flags )
{
LOCK ( cs_wallet ) ;
m_wallet_flags | = flags ;
if ( ! WalletBatch ( * database ) . WriteWalletFlags ( m_wallet_flags ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing wallet flags failed " ) ;
}
bool CWallet : : IsWalletFlagSet ( uint64_t flag )
{
return ( m_wallet_flags & flag ) ;
}
2017-05-05 08:53:39 +02:00
bool CWallet : : SetWalletFlags ( uint64_t overwriteFlags , bool memonly )
2017-02-16 14:22:18 +01:00
{
LOCK ( cs_wallet ) ;
m_wallet_flags = overwriteFlags ;
2017-05-05 08:53:39 +02:00
if ( ( ( overwriteFlags & g_known_wallet_flags ) > > 32 ) ^ ( overwriteFlags > > 32 ) ) {
// contains unknown non-tolerable wallet flags
return false ;
}
2017-02-16 14:22:18 +01:00
if ( ! memonly & & ! WalletBatch ( * database ) . WriteWalletFlags ( m_wallet_flags ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing wallet flags failed " ) ;
}
2017-05-05 08:53:39 +02:00
return true ;
2017-02-16 14:22:18 +01:00
}
2013-04-13 07:13:08 +02:00
int64_t CWalletTx : : GetTxTime ( ) const
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t n = nTimeSmart ;
2012-05-28 20:45:12 +02:00
return n ? n : nTimeReceived ;
2011-06-26 19:23:24 +02:00
}
2018-03-05 22:37:24 +01:00
// Helper for producing a max-sized low-S signature (eg 72 bytes)
bool CWallet : : DummySignInput ( CTxIn & tx_in , const CTxOut & txout ) const
{
// Fill in dummy signatures for fee calculation.
const CScript & scriptPubKey = txout . scriptPubKey ;
SignatureData sigdata ;
2018-03-27 22:34:39 +02:00
if ( ! ProduceSignature ( * this , DUMMY_SIGNATURE_CREATOR , scriptPubKey , sigdata ) )
2018-03-05 22:37:24 +01:00
{
return false ;
} else {
UpdateInput ( tx_in , sigdata ) ;
}
return true ;
}
// Helper for producing a bunch of max-sized low-S signatures (eg 72 bytes)
bool CWallet : : DummySignTx ( CMutableTransaction & txNew , const std : : vector < CTxOut > & txouts ) const
{
// Fill in dummy signatures for fee calculation.
int nIn = 0 ;
for ( const auto & txout : txouts )
{
if ( ! DummySignInput ( txNew . vin [ nIn ] , txout ) ) {
return false ;
}
nIn + + ;
}
return true ;
}
int64_t CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * wallet )
{
std : : vector < CTxOut > txouts ;
// Look up the inputs. We should have already checked that this transaction
// IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
// wallet, with a valid index into the vout array, and the ability to sign.
for ( auto & input : tx . vin ) {
const auto mi = wallet - > mapWallet . find ( input . prevout . hash ) ;
if ( mi = = wallet - > mapWallet . end ( ) ) {
return - 1 ;
}
assert ( input . prevout . n < mi - > second . tx - > vout . size ( ) ) ;
txouts . emplace_back ( mi - > second . tx - > vout [ input . prevout . n ] ) ;
}
return CalculateMaximumSignedTxSize ( tx , wallet , txouts ) ;
}
// txouts needs to be in the order of tx.vin
int64_t CalculateMaximumSignedTxSize ( const CTransaction & tx , const CWallet * wallet , const std : : vector < CTxOut > & txouts )
{
CMutableTransaction txNew ( tx ) ;
if ( ! wallet - > DummySignTx ( txNew , txouts ) ) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
return - 1 ;
}
return GetVirtualTransactionSize ( txNew ) ;
}
int CalculateMaximumSignedInputSize ( const CTxOut & txout , const CWallet * wallet )
{
CMutableTransaction txn ;
txn . vin . push_back ( CTxIn ( COutPoint ( ) ) ) ;
if ( ! wallet - > DummySignInput ( txn . vin [ 0 ] , txout ) ) {
// This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
// implies that we can sign for every input.
return - 1 ;
}
return GetVirtualTransactionInputSize ( txn . vin [ 0 ] ) ;
}
2017-01-27 02:33:45 +01:00
void CWalletTx : : GetAmounts ( std : : list < COutputEntry > & listReceived ,
std : : list < COutputEntry > & listSent , CAmount & nFee , std : : string & strSentAccount , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
2012-06-02 04:33:28 +02:00
nFee = 0 ;
2011-06-26 19:23:24 +02:00
listReceived . clear ( ) ;
listSent . clear ( ) ;
strSentAccount = strFromAccount ;
// Compute fee:
2014-04-23 00:46:19 +02:00
CAmount nDebit = GetDebit ( filter ) ;
2011-06-26 19:23:24 +02:00
if ( nDebit > 0 ) // debit>0 means we signed/sent this transaction
{
2016-11-12 01:54:51 +01:00
CAmount nValueOut = tx - > GetValueOut ( ) ;
2011-06-26 19:23:24 +02:00
nFee = nDebit - nValueOut ;
}
2011-10-03 19:05:43 +02:00
// Sent/received.
2016-11-12 01:54:51 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; + + i )
2011-06-26 19:23:24 +02:00
{
2016-11-12 01:54:51 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2014-04-29 19:39:01 +02:00
isminetype fIsMine = pwallet - > IsMine ( txout ) ;
2012-09-22 05:20:14 +02:00
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
if ( nDebit > 0 )
{
// Don't report 'change' txouts
if ( pwallet - > IsChange ( txout ) )
continue ;
}
2014-04-29 19:39:01 +02:00
else if ( ! ( fIsMine & filter ) )
2012-09-22 05:20:14 +02:00
continue ;
// In either case, we need to get the destination address
2012-05-14 23:44:52 +02:00
CTxDestination address ;
2015-12-12 03:07:11 +01:00
2015-12-12 19:45:53 +01:00
if ( ! ExtractDestination ( txout . scriptPubKey , address ) & & ! txout . scriptPubKey . IsUnspendable ( ) )
2011-06-26 19:23:24 +02:00
{
2018-06-16 01:02:52 +02:00
pwallet - > WalletLogPrintf ( " CWalletTx::GetAmounts: Unknown transaction type found, txid %s \n " ,
this - > GetHash ( ) . ToString ( ) ) ;
2012-09-22 05:20:14 +02:00
address = CNoDestination ( ) ;
2011-06-26 19:23:24 +02:00
}
2014-07-18 13:24:38 +02:00
COutputEntry output = { address , txout . nValue , ( int ) i } ;
2014-05-30 00:54:00 +02:00
2012-09-22 05:20:14 +02:00
// If we are debited by the transaction, add the output as a "sent" entry
2011-06-26 19:23:24 +02:00
if ( nDebit > 0 )
2014-05-30 00:54:00 +02:00
listSent . push_back ( output ) ;
2011-06-26 19:23:24 +02:00
2012-09-22 05:20:14 +02:00
// If we are receiving the output, add it as a "received" entry
2014-07-12 17:15:17 +02:00
if ( fIsMine & filter )
2014-05-30 00:54:00 +02:00
listReceived . push_back ( output ) ;
2011-06-26 19:23:24 +02:00
}
}
2017-03-02 21:24:50 +01:00
/**
* Scan active chain for relevant transactions after importing keys . This should
* be called whenever new keys are added to the wallet , with the oldest key
2017-06-22 23:16:24 +02:00
* creation time .
2017-03-02 21:24:50 +01:00
*
* @ return Earliest timestamp that could be successfully scanned from . Timestamp
2017-06-22 23:14:40 +02:00
* returned will be higher than startTime if relevant blocks could not be read .
2017-03-02 21:24:50 +01:00
*/
2017-12-13 00:13:58 +01:00
int64_t CWallet : : RescanFromTime ( int64_t startTime , const WalletRescanReserver & reserver , bool update )
2017-03-02 21:24:50 +01:00
{
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
// to be scanned.
2017-09-08 01:29:59 +02:00
CBlockIndex * startBlock = nullptr ;
{
LOCK ( cs_main ) ;
startBlock = chainActive . FindEarliestAtLeast ( startTime - TIMESTAMP_WINDOW ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: Rescanning last %i blocks \n " , __func__ , startBlock ? chainActive . Height ( ) - startBlock - > nHeight + 1 : 0 ) ;
2017-09-08 01:29:59 +02:00
}
2017-03-02 21:24:50 +01:00
if ( startBlock ) {
2017-12-13 00:13:58 +01:00
const CBlockIndex * const failedBlock = ScanForWalletTransactions ( startBlock , nullptr , reserver , update ) ;
2017-03-02 21:24:50 +01:00
if ( failedBlock ) {
2017-06-22 23:16:24 +02:00
return failedBlock - > GetBlockTimeMax ( ) + TIMESTAMP_WINDOW + 1 ;
2017-03-02 21:24:50 +01:00
}
}
return startTime ;
}
2014-10-26 08:03:12 +01:00
/**
* Scan the block chain ( starting in pindexStart ) for transactions
* from or to us . If fUpdate is true , found transactions that already
* exist in the wallet will be updated .
2017-02-16 16:49:03 +01:00
*
2017-05-15 15:11:03 +02:00
* Returns null if scan was successful . Otherwise , if a complete rescan was not
* possible ( due to pruning or corruption ) , returns pointer to the most recent
* block that could not be scanned .
2015-11-19 16:05:37 +01:00
*
* If pindexStop is not a nullptr , the scan will stop at the block - index
* defined by pindexStop
2017-09-08 01:29:59 +02:00
*
* Caller needs to make sure pindexStop ( and the optional pindexStart ) are on
* the main chain after to the addition of any new keys you want to detect
* transactions for .
2014-10-26 08:03:12 +01:00
*/
2017-12-13 00:13:58 +01:00
CBlockIndex * CWallet : : ScanForWalletTransactions ( CBlockIndex * pindexStart , CBlockIndex * pindexStop , const WalletRescanReserver & reserver , bool fUpdate )
2011-06-26 19:23:24 +02:00
{
2014-02-18 01:35:37 +01:00
int64_t nNow = GetTime ( ) ;
2015-04-23 00:19:11 +02:00
const CChainParams & chainParams = Params ( ) ;
2011-06-26 19:23:24 +02:00
2017-12-13 00:13:58 +01:00
assert ( reserver . isReserved ( ) ) ;
2015-11-19 16:05:37 +01:00
if ( pindexStop ) {
assert ( pindexStop - > nHeight > = pindexStart - > nHeight ) ;
}
2011-06-26 19:23:24 +02:00
CBlockIndex * pindex = pindexStart ;
2017-05-15 15:11:03 +02:00
CBlockIndex * ret = nullptr ;
2018-04-09 18:48:19 +02:00
2018-06-16 01:02:52 +02:00
if ( pindex ) WalletLogPrintf ( " Rescan started from block %d... \n " , pindex - > nHeight ) ;
2018-04-09 18:48:19 +02:00
2011-06-26 19:23:24 +02:00
{
2017-04-17 16:32:01 +02:00
fAbortRescan = false ;
2018-06-16 01:02:52 +02:00
ShowProgress ( strprintf ( " %s " + _ ( " Rescanning... " ) , GetDisplayName ( ) ) , 0 ) ; // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
2017-09-08 01:29:59 +02:00
CBlockIndex * tip = nullptr ;
2018-04-25 21:21:38 +02:00
double progress_begin ;
double progress_end ;
2017-09-08 01:29:59 +02:00
{
LOCK ( cs_main ) ;
2018-04-25 21:21:38 +02:00
progress_begin = GuessVerificationProgress ( chainParams . TxData ( ) , pindex ) ;
if ( pindexStop = = nullptr ) {
tip = chainActive . Tip ( ) ;
progress_end = GuessVerificationProgress ( chainParams . TxData ( ) , tip ) ;
} else {
progress_end = GuessVerificationProgress ( chainParams . TxData ( ) , pindexStop ) ;
}
2017-09-08 01:29:59 +02:00
}
2018-04-25 21:21:38 +02:00
double progress_current = progress_begin ;
2018-02-22 01:40:30 +01:00
while ( pindex & & ! fAbortRescan & & ! ShutdownRequested ( ) )
2011-06-26 19:23:24 +02:00
{
2018-04-25 21:21:38 +02:00
if ( pindex - > nHeight % 100 = = 0 & & progress_end - progress_begin > 0.0 ) {
2018-06-16 01:02:52 +02:00
ShowProgress ( strprintf ( " %s " + _ ( " Rescanning... " ) , GetDisplayName ( ) ) , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( progress_current - progress_begin ) / ( progress_end - progress_begin ) * 100 ) ) ) ) ;
2017-09-08 01:29:59 +02:00
}
2017-04-24 01:48:12 +02:00
if ( GetTime ( ) > = nNow + 60 ) {
nNow = GetTime ( ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Still rescanning. At block %d. Progress=%f \n " , pindex - > nHeight , progress_current ) ;
2017-04-24 01:48:12 +02:00
}
2013-06-10 15:38:13 +02:00
2011-06-26 19:23:24 +02:00
CBlock block ;
2017-12-13 22:06:51 +01:00
if ( ReadBlockFromDisk ( block , pindex , Params ( ) . GetConsensus ( ) ) ) {
2017-09-08 01:29:59 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
if ( pindex & & ! chainActive . Contains ( pindex ) ) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
ret = pindex ;
break ;
}
2017-02-16 16:49:03 +01:00
for ( size_t posInBlock = 0 ; posInBlock < block . vtx . size ( ) ; + + posInBlock ) {
2018-04-11 04:12:48 +02:00
SyncTransaction ( block . vtx [ posInBlock ] , pindex , posInBlock , fUpdate ) ;
2017-02-16 16:49:03 +01:00
}
} else {
2017-05-15 15:11:03 +02:00
ret = pindex ;
2011-06-26 19:23:24 +02:00
}
2015-11-19 16:05:37 +01:00
if ( pindex = = pindexStop ) {
break ;
}
2017-09-08 01:29:59 +02:00
{
LOCK ( cs_main ) ;
pindex = chainActive . Next ( pindex ) ;
2018-04-25 21:21:38 +02:00
progress_current = GuessVerificationProgress ( chainParams . TxData ( ) , pindex ) ;
if ( pindexStop = = nullptr & & tip ! = chainActive . Tip ( ) ) {
2017-09-08 01:29:59 +02:00
tip = chainActive . Tip ( ) ;
// in case the tip has changed, update progress max
2018-04-25 21:21:38 +02:00
progress_end = GuessVerificationProgress ( chainParams . TxData ( ) , tip ) ;
2017-09-08 01:29:59 +02:00
}
}
2011-06-26 19:23:24 +02:00
}
2017-04-17 16:32:01 +02:00
if ( pindex & & fAbortRescan ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Rescan aborted at block %d. Progress=%f \n " , pindex - > nHeight , progress_current ) ;
2018-02-22 01:40:30 +01:00
} else if ( pindex & & ShutdownRequested ( ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Rescan interrupted by shutdown request at block %d. Progress=%f \n " , pindex - > nHeight , progress_current ) ;
2017-04-17 16:32:01 +02:00
}
2018-06-16 01:02:52 +02:00
ShowProgress ( strprintf ( " %s " + _ ( " Rescanning... " ) , GetDisplayName ( ) ) , 100 ) ; // hide progress dialog in GUI
2011-06-26 19:23:24 +02:00
}
return ret ;
}
void CWallet : : ReacceptWalletTransactions ( )
{
2015-04-28 16:48:28 +02:00
// If transactions aren't being broadcasted, don't let them into local mempool either
2015-03-27 10:34:48 +01:00
if ( ! fBroadcastTransactions )
return ;
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-19 06:59:16 +01:00
std : : map < int64_t , CWalletTx * > mapSorted ;
// Sort pending wallet transactions based on their initial wallet insertion order
2017-06-02 03:28:42 +02:00
for ( std : : pair < const uint256 , CWalletTx > & item : mapWallet )
2011-06-26 19:23:24 +02:00
{
2014-02-15 22:38:28 +01:00
const uint256 & wtxid = item . first ;
CWalletTx & wtx = item . second ;
assert ( wtx . GetHash ( ) = = wtxid ) ;
2011-06-26 19:23:24 +02:00
2014-02-15 22:38:28 +01:00
int nDepth = wtx . GetDepthInMainChain ( ) ;
2016-01-07 22:31:27 +01:00
if ( ! wtx . IsCoinBase ( ) & & ( nDepth = = 0 & & ! wtx . isAbandoned ( ) ) ) {
2014-12-19 06:59:16 +01:00
mapSorted . insert ( std : : make_pair ( wtx . nOrderPos , & wtx ) ) ;
2011-06-26 19:23:24 +02:00
}
}
2014-12-19 06:59:16 +01:00
// Try to add wallet transactions to memory pool
2017-12-12 00:41:51 +01:00
for ( std : : pair < const int64_t , CWalletTx * > & item : mapSorted ) {
2014-12-19 06:59:16 +01:00
CWalletTx & wtx = * ( item . second ) ;
2016-10-25 20:27:04 +02:00
CValidationState state ;
wtx . AcceptToMemoryPool ( maxTxFee , state ) ;
2014-12-19 06:59:16 +01:00
}
2011-06-26 19:23:24 +02:00
}
2016-05-25 02:56:17 +02:00
bool CWalletTx : : RelayWalletTransaction ( CConnman * connman )
2011-06-26 19:23:24 +02:00
{
2015-03-27 10:34:48 +01:00
assert ( pwallet - > GetBroadcastTransactions ( ) ) ;
2016-12-06 07:39:14 +01:00
if ( ! IsCoinBase ( ) & & ! isAbandoned ( ) & & GetDepthInMainChain ( ) = = 0 )
2011-06-26 19:23:24 +02:00
{
2016-12-06 07:39:14 +01:00
CValidationState state ;
/* GetDepthInMainChain already catches known conflicts. */
if ( InMempool ( ) | | AcceptToMemoryPool ( maxTxFee , state ) ) {
2018-06-16 01:02:52 +02:00
pwallet - > WalletLogPrintf ( " Relaying wtx %s \n " , GetHash ( ) . ToString ( ) ) ;
2016-04-17 01:13:12 +02:00
if ( connman ) {
CInv inv ( MSG_TX , GetHash ( ) ) ;
connman - > ForEachNode ( [ & inv ] ( CNode * pnode )
{
pnode - > PushInventory ( inv ) ;
} ) ;
return true ;
}
2011-06-26 19:23:24 +02:00
}
}
2015-03-23 18:47:18 +01:00
return false ;
2011-06-26 19:23:24 +02:00
}
2017-01-27 02:33:45 +01:00
std : : set < uint256 > CWalletTx : : GetConflicts ( ) const
2014-02-14 02:12:51 +01:00
{
2017-01-27 02:33:45 +01:00
std : : set < uint256 > result ;
2017-08-07 07:36:37 +02:00
if ( pwallet ! = nullptr )
2014-02-14 02:12:51 +01:00
{
uint256 myHash = GetHash ( ) ;
2014-07-17 14:09:46 +02:00
result = pwallet - > GetConflicts ( myHash ) ;
2014-02-14 02:12:51 +01:00
result . erase ( myHash ) ;
}
return result ;
}
2014-12-19 02:00:01 +01:00
CAmount CWalletTx : : GetDebit ( const isminefilter & filter ) const
{
2016-11-12 01:54:51 +01:00
if ( tx - > vin . empty ( ) )
2014-12-19 02:00:01 +01:00
return 0 ;
CAmount debit = 0 ;
if ( filter & ISMINE_SPENDABLE )
{
if ( fDebitCached )
debit + = nDebitCached ;
else
{
2017-05-09 08:46:26 +02:00
nDebitCached = pwallet - > GetDebit ( * tx , ISMINE_SPENDABLE ) ;
2014-12-19 02:00:01 +01:00
fDebitCached = true ;
debit + = nDebitCached ;
}
}
if ( filter & ISMINE_WATCH_ONLY )
{
if ( fWatchDebitCached )
debit + = nWatchDebitCached ;
else
{
2017-05-09 08:46:26 +02:00
nWatchDebitCached = pwallet - > GetDebit ( * tx , ISMINE_WATCH_ONLY ) ;
2014-12-19 02:00:01 +01:00
fWatchDebitCached = true ;
debit + = nWatchDebitCached ;
}
}
return debit ;
}
CAmount CWalletTx : : GetCredit ( const isminefilter & filter ) const
{
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
2016-11-15 15:19:23 +01:00
CAmount credit = 0 ;
2014-12-19 02:00:01 +01:00
if ( filter & ISMINE_SPENDABLE )
{
// GetBalance can assume transactions in mapWallet won't change
if ( fCreditCached )
credit + = nCreditCached ;
else
{
2017-05-09 08:46:26 +02:00
nCreditCached = pwallet - > GetCredit ( * tx , ISMINE_SPENDABLE ) ;
2014-12-19 02:00:01 +01:00
fCreditCached = true ;
credit + = nCreditCached ;
}
}
if ( filter & ISMINE_WATCH_ONLY )
{
if ( fWatchCreditCached )
credit + = nWatchCreditCached ;
else
{
2017-05-09 08:46:26 +02:00
nWatchCreditCached = pwallet - > GetCredit ( * tx , ISMINE_WATCH_ONLY ) ;
2014-12-19 02:00:01 +01:00
fWatchCreditCached = true ;
credit + = nWatchCreditCached ;
}
}
return credit ;
}
CAmount CWalletTx : : GetImmatureCredit ( bool fUseCache ) const
{
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 & & IsInMainChain ( ) )
{
if ( fUseCache & & fImmatureCreditCached )
return nImmatureCreditCached ;
2017-05-09 08:46:26 +02:00
nImmatureCreditCached = pwallet - > GetCredit ( * tx , ISMINE_SPENDABLE ) ;
2014-12-19 02:00:01 +01:00
fImmatureCreditCached = true ;
return nImmatureCreditCached ;
}
return 0 ;
}
2018-06-25 20:39:36 +02:00
CAmount CWalletTx : : GetAvailableCredit ( bool fUseCache , const isminefilter & filter ) const
2014-12-19 02:00:01 +01:00
{
2017-06-21 21:10:00 +02:00
if ( pwallet = = nullptr )
2014-12-19 02:00:01 +01:00
return 0 ;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
2018-06-25 20:39:36 +02:00
CAmount * cache = nullptr ;
bool * cache_used = nullptr ;
if ( filter = = ISMINE_SPENDABLE ) {
cache = & nAvailableCreditCached ;
cache_used = & fAvailableCreditCached ;
2018-06-27 17:46:27 +02:00
} else if ( filter = = ISMINE_WATCH_ONLY ) {
cache = & nAvailableWatchCreditCached ;
cache_used = & fAvailableWatchCreditCached ;
2018-06-25 20:39:36 +02:00
}
if ( fUseCache & & cache_used & & * cache_used ) {
return * cache ;
}
2014-12-19 02:00:01 +01:00
CAmount nCredit = 0 ;
uint256 hashTx = GetHash ( ) ;
2016-11-12 01:54:51 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; i + + )
2014-12-19 02:00:01 +01:00
{
if ( ! pwallet - > IsSpent ( hashTx , i ) )
{
2016-11-12 01:54:51 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2018-06-25 20:39:36 +02:00
nCredit + = pwallet - > GetCredit ( txout , filter ) ;
2014-12-19 02:00:01 +01:00
if ( ! MoneyRange ( nCredit ) )
2017-07-04 21:22:53 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2014-12-19 02:00:01 +01:00
}
}
2018-06-25 20:39:36 +02:00
if ( cache ) {
* cache = nCredit ;
2018-07-17 10:22:10 +02:00
assert ( cache_used ) ;
2018-06-25 20:39:36 +02:00
* cache_used = true ;
}
2014-12-19 02:00:01 +01:00
return nCredit ;
}
2017-07-16 02:07:52 +02:00
CAmount CWalletTx : : GetImmatureWatchOnlyCredit ( const bool fUseCache ) const
2014-12-19 02:00:01 +01:00
{
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 & & IsInMainChain ( ) )
{
if ( fUseCache & & fImmatureWatchCreditCached )
return nImmatureWatchCreditCached ;
2017-05-09 08:46:26 +02:00
nImmatureWatchCreditCached = pwallet - > GetCredit ( * tx , ISMINE_WATCH_ONLY ) ;
2014-12-19 02:00:01 +01:00
fImmatureWatchCreditCached = true ;
return nImmatureWatchCreditCached ;
}
return 0 ;
}
CAmount CWalletTx : : GetChange ( ) const
{
if ( fChangeCached )
return nChangeCached ;
2017-05-09 08:46:26 +02:00
nChangeCached = pwallet - > GetChange ( * tx ) ;
2014-12-19 02:00:01 +01:00
fChangeCached = true ;
return nChangeCached ;
}
2015-11-30 16:15:15 +01:00
bool CWalletTx : : InMempool ( ) const
{
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
return fInMempool ;
2015-11-30 16:15:15 +01:00
}
2014-12-19 02:00:01 +01:00
bool CWalletTx : : IsTrusted ( ) const
{
// Quick answer in most cases
2017-05-09 08:46:26 +02:00
if ( ! CheckFinalTx ( * tx ) )
2014-12-19 02:00:01 +01:00
return false ;
int nDepth = GetDepthInMainChain ( ) ;
if ( nDepth > = 1 )
return true ;
if ( nDepth < 0 )
return false ;
2018-04-07 18:12:46 +02:00
if ( ! pwallet - > m_spend_zero_conf_change | | ! IsFromMe ( ISMINE_ALL ) ) // using wtx's cached debit
2014-12-19 02:00:01 +01:00
return false ;
2015-11-26 18:42:07 +01:00
// Don't trust unconfirmed transactions from us unless they are in the mempool.
2015-11-30 16:15:15 +01:00
if ( ! InMempool ( ) )
return false ;
2015-11-26 18:42:07 +01:00
2014-12-19 02:00:01 +01:00
// Trusted if all inputs are from us and are in the mempool:
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : tx - > vin )
2014-12-19 02:00:01 +01:00
{
// Transactions not sent by us: not trusted
const CWalletTx * parent = pwallet - > GetWalletTx ( txin . prevout . hash ) ;
2017-08-07 07:36:37 +02:00
if ( parent = = nullptr )
2014-12-19 02:00:01 +01:00
return false ;
2016-11-12 01:54:51 +01:00
const CTxOut & parentOut = parent - > tx - > vout [ txin . prevout . n ] ;
2014-12-19 02:00:01 +01:00
if ( pwallet - > IsMine ( parentOut ) ! = ISMINE_SPENDABLE )
return false ;
}
return true ;
}
2016-11-12 01:54:51 +01:00
bool CWalletTx : : IsEquivalentTo ( const CWalletTx & _tx ) const
2015-07-02 20:57:39 +02:00
{
2018-05-04 23:38:49 +02:00
CMutableTransaction tx1 { * this - > tx } ;
CMutableTransaction tx2 { * _tx . tx } ;
2017-05-18 09:42:14 +02:00
for ( auto & txin : tx1 . vin ) txin . scriptSig = CScript ( ) ;
for ( auto & txin : tx2 . vin ) txin . scriptSig = CScript ( ) ;
2015-07-02 20:57:39 +02:00
return CTransaction ( tx1 ) = = CTransaction ( tx2 ) ;
}
2016-05-25 02:56:17 +02:00
std : : vector < uint256 > CWallet : : ResendWalletTransactionsBefore ( int64_t nTime , CConnman * connman )
2015-03-23 18:47:18 +01:00
{
std : : vector < uint256 > result ;
LOCK ( cs_wallet ) ;
2017-08-05 19:48:37 +02:00
2015-03-23 18:47:18 +01:00
// Sort them in chronological order
2017-01-27 02:33:45 +01:00
std : : multimap < unsigned int , CWalletTx * > mapSorted ;
2017-06-02 03:28:42 +02:00
for ( std : : pair < const uint256 , CWalletTx > & item : mapWallet )
2015-03-23 18:47:18 +01:00
{
CWalletTx & wtx = item . second ;
// Don't rebroadcast if newer than nTime:
if ( wtx . nTimeReceived > nTime )
continue ;
2017-01-27 02:33:45 +01:00
mapSorted . insert ( std : : make_pair ( wtx . nTimeReceived , & wtx ) ) ;
2015-03-23 18:47:18 +01:00
}
2017-06-02 03:28:42 +02:00
for ( std : : pair < const unsigned int , CWalletTx * > & item : mapSorted )
2015-03-23 18:47:18 +01:00
{
CWalletTx & wtx = * item . second ;
2016-05-25 02:56:17 +02:00
if ( wtx . RelayWalletTransaction ( connman ) )
2015-03-23 18:47:18 +01:00
result . push_back ( wtx . GetHash ( ) ) ;
}
return result ;
}
2016-05-25 02:56:17 +02:00
void CWallet : : ResendWalletTransactions ( int64_t nBestBlockTime , CConnman * connman )
2011-06-26 19:23:24 +02:00
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
2015-03-27 10:34:48 +01:00
if ( GetTime ( ) < nNextResend | | ! fBroadcastTransactions )
2011-06-26 19:23:24 +02:00
return ;
2013-04-19 23:28:25 +02:00
bool fFirst = ( nNextResend = = 0 ) ;
nNextResend = GetTime ( ) + GetRand ( 30 * 60 ) ;
2011-06-26 19:23:24 +02:00
if ( fFirst )
return ;
// Only do it if there's been a new block since last time
2015-03-23 18:47:18 +01:00
if ( nBestBlockTime < nLastResend )
2011-06-26 19:23:24 +02:00
return ;
2013-04-19 23:28:25 +02:00
nLastResend = GetTime ( ) ;
2011-06-26 19:23:24 +02:00
2015-03-23 18:47:18 +01:00
// Rebroadcast unconfirmed txes older than 5 minutes before the last
// block was found:
2016-05-25 02:56:17 +02:00
std : : vector < uint256 > relayed = ResendWalletTransactionsBefore ( nBestBlockTime - 5 * 60 , connman ) ;
2015-03-23 18:47:18 +01:00
if ( ! relayed . empty ( ) )
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: rebroadcast %u unconfirmed transactions \n " , __func__ , relayed . size ( ) ) ;
2011-06-26 19:23:24 +02:00
}
2014-10-26 08:03:12 +01:00
/** @} */ // end of mapWallet
2011-06-26 19:23:24 +02:00
2014-10-26 08:03:12 +01:00
/** @defgroup Actions
*
* @ {
*/
2011-06-26 19:23:24 +02:00
2018-06-27 20:11:21 +02:00
CAmount CWallet : : GetBalance ( const isminefilter & filter , const int min_depth ) const
2011-06-26 19:23:24 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2011-06-26 19:23:24 +02:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet )
2011-06-26 19:23:24 +02:00
{
2017-06-04 22:02:43 +02:00
const CWalletTx * pcoin = & entry . second ;
2018-06-27 20:11:21 +02:00
if ( pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) > = min_depth ) {
2018-06-25 20:39:36 +02:00
nTotal + = pcoin - > GetAvailableCredit ( true , filter ) ;
}
2011-06-26 19:23:24 +02:00
}
}
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetUnconfirmedBalance ( ) const
2011-07-11 20:42:10 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2011-07-11 20:42:10 +02:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet )
2011-07-11 20:42:10 +02:00
{
2017-06-04 22:02:43 +02:00
const CWalletTx * pcoin = & entry . second ;
2016-03-17 17:48:05 +01:00
if ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 & & pcoin - > InMempool ( ) )
2012-02-14 12:08:00 +01:00
nTotal + = pcoin - > GetAvailableCredit ( ) ;
}
}
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetImmatureBalance ( ) const
2012-02-14 12:08:00 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2012-02-14 12:08:00 +01:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet )
2012-02-14 12:08:00 +01:00
{
2017-06-04 22:02:43 +02:00
const CWalletTx * pcoin = & entry . second ;
2012-06-18 08:32:33 +02:00
nTotal + = pcoin - > GetImmatureCredit ( ) ;
2011-07-11 20:42:10 +02:00
}
}
return nTotal ;
}
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetUnconfirmedWatchOnlyBalance ( ) const
2014-03-29 05:15:28 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2014-03-29 05:15:28 +01:00
{
2014-07-13 09:33:45 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet )
2014-03-29 05:15:28 +01:00
{
2017-06-04 22:02:43 +02:00
const CWalletTx * pcoin = & entry . second ;
2016-03-17 17:48:05 +01:00
if ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 & & pcoin - > InMempool ( ) )
2018-06-27 17:53:08 +02:00
nTotal + = pcoin - > GetAvailableCredit ( true , ISMINE_WATCH_ONLY ) ;
2014-03-29 05:15:28 +01:00
}
}
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetImmatureWatchOnlyBalance ( ) const
2014-03-29 05:15:28 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2014-03-29 05:15:28 +01:00
{
2014-07-13 09:33:45 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet )
2014-03-29 05:15:28 +01:00
{
2017-06-04 22:02:43 +02:00
const CWalletTx * pcoin = & entry . second ;
2014-03-29 05:15:28 +01:00
nTotal + = pcoin - > GetImmatureWatchOnlyCredit ( ) ;
}
}
return nTotal ;
}
2017-01-23 15:58:42 +01:00
// Calculate total balance in a different way from GetBalance. The biggest
// difference is that GetBalance sums up all unspent TxOuts paying to the
// wallet, while this sums up both spent and unspent TxOuts paying to the
// wallet, and then subtracts the values of TxIns spending from the wallet. This
// also has fewer restrictions on which unconfirmed transactions are considered
// trusted.
CAmount CWallet : : GetLegacyBalance ( const isminefilter & filter , int minDepth , const std : : string * account ) const
{
LOCK2 ( cs_main , cs_wallet ) ;
CAmount balance = 0 ;
for ( const auto & entry : mapWallet ) {
const CWalletTx & wtx = entry . second ;
const int depth = wtx . GetDepthInMainChain ( ) ;
if ( depth < 0 | | ! CheckFinalTx ( * wtx . tx ) | | wtx . GetBlocksToMaturity ( ) > 0 ) {
continue ;
}
// Loop through tx outputs and add incoming payments. For outgoing txs,
// treat change outputs specially, as part of the amount debited.
CAmount debit = wtx . GetDebit ( filter ) ;
const bool outgoing = debit > 0 ;
for ( const CTxOut & out : wtx . tx - > vout ) {
if ( outgoing & & IsChange ( out ) ) {
debit - = out . nValue ;
2017-10-20 19:27:55 +02:00
} else if ( IsMine ( out ) & filter & & depth > = minDepth & & ( ! account | | * account = = GetLabelName ( out . scriptPubKey ) ) ) {
2017-01-23 15:58:42 +01:00
balance + = out . nValue ;
}
}
// For outgoing txs, subtract amount debited.
if ( outgoing & & ( ! account | | * account = = wtx . strFromAccount ) ) {
balance - = debit ;
}
}
if ( account ) {
2017-12-08 12:39:22 +01:00
balance + = WalletBatch ( * database ) . GetAccountCreditDebit ( * account ) ;
2017-01-23 15:58:42 +01:00
}
return balance ;
}
2017-04-28 20:10:21 +02:00
CAmount CWallet : : GetAvailableBalance ( const CCoinControl * coinControl ) const
{
2017-05-04 23:02:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-04-28 20:10:21 +02:00
CAmount balance = 0 ;
std : : vector < COutput > vCoins ;
AvailableCoins ( vCoins , true , coinControl ) ;
for ( const COutput & out : vCoins ) {
if ( out . fSpendable ) {
balance + = out . tx - > tx - > vout [ out . i ] . nValue ;
}
}
return balance ;
}
2017-07-16 02:07:52 +02:00
void CWallet : : AvailableCoins ( std : : vector < COutput > & vCoins , bool fOnlySafe , const CCoinControl * coinControl , const CAmount & nMinimumAmount , const CAmount & nMaximumAmount , const CAmount & nMinimumSumAmount , const uint64_t nMaximumCount , const int nMinDepth , const int nMaxDepth ) const
2012-02-27 13:19:32 +01:00
{
2018-02-02 12:37:50 +01:00
AssertLockHeld ( cs_main ) ;
AssertLockHeld ( cs_wallet ) ;
2012-02-27 13:19:32 +01:00
vCoins . clear ( ) ;
2018-02-08 19:18:51 +01:00
CAmount nTotal = 0 ;
2012-02-27 13:19:32 +01:00
2018-02-08 19:18:51 +01:00
for ( const auto & entry : mapWallet )
2012-02-27 13:19:32 +01:00
{
2018-02-08 19:18:51 +01:00
const uint256 & wtxid = entry . first ;
const CWalletTx * pcoin = & entry . second ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
if ( ! CheckFinalTx ( * pcoin - > tx ) )
continue ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
if ( pcoin - > IsCoinBase ( ) & & pcoin - > GetBlocksToMaturity ( ) > 0 )
continue ;
2012-02-27 13:19:32 +01:00
2018-02-08 19:18:51 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( ) ;
if ( nDepth < 0 )
continue ;
2012-05-31 22:01:16 +02:00
2018-02-08 19:18:51 +01:00
// We should not consider coins which aren't at least in our mempool
// It's possible for these to be conflicted via ancestors which we may never be able to detect
if ( nDepth = = 0 & & ! pcoin - > InMempool ( ) )
continue ;
2012-02-27 13:19:32 +01:00
2018-02-08 19:18:51 +01:00
bool safeTx = pcoin - > IsTrusted ( ) ;
// We should not consider coins from transactions that are replacing
// other transactions.
//
// Example: There is a transaction A which is replaced by bumpfee
// transaction B. In this case, we want to prevent creation of
// a transaction B' which spends an output of B.
//
// Reason: If transaction A were initially confirmed, transactions B
// and B' would no longer be valid, so the user would have to create
// a new transaction C to replace B'. However, in the case of a
// one-block reorg, transactions B' and C might BOTH be accepted,
// when the user only wanted one of them. Specifically, there could
// be a 1-block reorg away from the chain where transactions A and C
// were accepted to another chain where B, B', and C were all
// accepted.
if ( nDepth = = 0 & & pcoin - > mapValue . count ( " replaces_txid " ) ) {
safeTx = false ;
}
2014-02-12 19:43:07 +01:00
2018-02-08 19:18:51 +01:00
// Similarly, we should not consider coins from transactions that
// have been replaced. In the example above, we would want to prevent
// creation of a transaction A' spending an output of A, because if
// transaction B were initially confirmed, conflicting with A and
// A', we wouldn't want to the user to create a transaction D
// intending to replace A', but potentially resulting in a scenario
// where A, A', and D could all be accepted (instead of just B and
// D, or just A and A' like the user would want).
if ( nDepth = = 0 & & pcoin - > mapValue . count ( " replaced_by_txid " ) ) {
safeTx = false ;
}
2016-03-17 17:48:05 +01:00
2018-02-08 19:18:51 +01:00
if ( fOnlySafe & & ! safeTx ) {
continue ;
}
2016-12-09 19:45:27 +01:00
2018-02-08 19:18:51 +01:00
if ( nDepth < nMinDepth | | nDepth > nMaxDepth )
continue ;
2017-02-23 17:20:16 +01:00
2018-02-08 19:18:51 +01:00
for ( unsigned int i = 0 ; i < pcoin - > tx - > vout . size ( ) ; i + + ) {
if ( pcoin - > tx - > vout [ i ] . nValue < nMinimumAmount | | pcoin - > tx - > vout [ i ] . nValue > nMaximumAmount )
2016-12-09 19:45:27 +01:00
continue ;
2018-02-08 19:18:51 +01:00
if ( coinControl & & coinControl - > HasSelected ( ) & & ! coinControl - > fAllowOtherInputs & & ! coinControl - > IsSelected ( COutPoint ( entry . first , i ) ) )
2017-03-07 19:17:32 +01:00
continue ;
2018-02-08 19:18:51 +01:00
if ( IsLockedCoin ( entry . first , i ) )
continue ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
if ( IsSpent ( wtxid , i ) )
continue ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
isminetype mine = IsMine ( pcoin - > tx - > vout [ i ] ) ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
if ( mine = = ISMINE_NO ) {
continue ;
}
2017-03-07 19:17:32 +01:00
2018-05-01 21:05:55 +02:00
bool solvable = IsSolvable ( * this , pcoin - > tx - > vout [ i ] . scriptPubKey ) ;
bool spendable = ( ( mine & ISMINE_SPENDABLE ) ! = ISMINE_NO ) | | ( ( ( mine & ISMINE_WATCH_ONLY ) ! = ISMINE_NO ) & & ( coinControl & & coinControl - > fAllowWatchOnly & & solvable ) ) ;
2017-03-07 19:17:32 +01:00
2018-05-01 21:05:55 +02:00
vCoins . push_back ( COutput ( pcoin , i , nDepth , spendable , solvable , safeTx ) ) ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
// Checks the sum amount of all UTXO's.
if ( nMinimumSumAmount ! = MAX_MONEY ) {
nTotal + = pcoin - > tx - > vout [ i ] . nValue ;
2017-03-07 19:17:32 +01:00
2018-02-08 19:18:51 +01:00
if ( nTotal > = nMinimumSumAmount ) {
2017-03-07 19:17:32 +01:00
return ;
}
2012-09-27 19:52:09 +02:00
}
2018-02-08 19:18:51 +01:00
// Checks the maximum number of UTXO's.
if ( nMaximumCount > 0 & & vCoins . size ( ) > = nMaximumCount ) {
return ;
}
2012-02-27 13:19:32 +01:00
}
}
}
2017-04-28 20:10:21 +02:00
std : : map < CTxDestination , std : : vector < COutput > > CWallet : : ListCoins ( ) const
{
// TODO: Add AssertLockHeld(cs_wallet) here.
//
// Because the return value from this function contains pointers to
// CWalletTx objects, callers to this function really should acquire the
// cs_wallet lock before calling it. However, the current caller doesn't
// acquire this lock yet. There was an attempt to add the missing lock in
// https://github.com/bitcoin/bitcoin/pull/10340, but that change has been
// postponed until after https://github.com/bitcoin/bitcoin/pull/10244 to
// avoid adding some extra complexity to the Qt code.
std : : map < CTxDestination , std : : vector < COutput > > result ;
std : : vector < COutput > availableCoins ;
LOCK2 ( cs_main , cs_wallet ) ;
2018-02-02 12:37:50 +01:00
AvailableCoins ( availableCoins ) ;
2017-04-28 20:10:21 +02:00
for ( auto & coin : availableCoins ) {
CTxDestination address ;
if ( coin . fSpendable & &
ExtractDestination ( FindNonChangeParentOutput ( * coin . tx - > tx , coin . i ) . scriptPubKey , address ) ) {
result [ address ] . emplace_back ( std : : move ( coin ) ) ;
}
}
std : : vector < COutPoint > lockedCoins ;
ListLockedCoins ( lockedCoins ) ;
for ( const auto & output : lockedCoins ) {
auto it = mapWallet . find ( output . hash ) ;
if ( it ! = mapWallet . end ( ) ) {
int depth = it - > second . GetDepthInMainChain ( ) ;
if ( depth > = 0 & & output . n < it - > second . tx - > vout . size ( ) & &
IsMine ( it - > second . tx - > vout [ output . n ] ) = = ISMINE_SPENDABLE ) {
CTxDestination address ;
if ( ExtractDestination ( FindNonChangeParentOutput ( * it - > second . tx , output . n ) . scriptPubKey , address ) ) {
result [ address ] . emplace_back (
& it - > second , output . n , depth , true /* spendable */ , true /* solvable */ , false /* safe */ ) ;
}
}
}
}
return result ;
}
const CTxOut & CWallet : : FindNonChangeParentOutput ( const CTransaction & tx , int output ) const
{
const CTransaction * ptx = & tx ;
int n = output ;
while ( IsChange ( ptx - > vout [ n ] ) & & ptx - > vin . size ( ) > 0 ) {
const COutPoint & prevout = ptx - > vin [ 0 ] . prevout ;
auto it = mapWallet . find ( prevout . hash ) ;
if ( it = = mapWallet . end ( ) | | it - > second . tx - > vout . size ( ) < = prevout . n | |
! IsMine ( it - > second . tx - > vout [ prevout . n ] ) ) {
break ;
}
ptx = it - > second . tx . get ( ) ;
n = prevout . n ;
}
return ptx - > vout [ n ] ;
}
2018-07-19 04:45:26 +02:00
bool CWallet : : SelectCoinsMinConf ( const CAmount & nTargetValue , const CoinEligibilityFilter & eligibility_filter , std : : vector < OutputGroup > groups ,
2018-03-05 22:42:49 +01:00
std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CoinSelectionParams & coin_selection_params , bool & bnb_used ) const
2011-06-26 19:23:24 +02:00
{
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
2018-07-19 04:45:26 +02:00
std : : vector < OutputGroup > utxo_pool ;
2018-03-05 22:42:49 +01:00
if ( coin_selection_params . use_bnb ) {
// Get long term estimate
FeeCalculation feeCalc ;
CCoinControl temp ;
temp . m_confirm_target = 1008 ;
2018-04-07 18:12:46 +02:00
CFeeRate long_term_feerate = GetMinimumFeeRate ( * this , temp , : : mempool , : : feeEstimator , & feeCalc ) ;
2016-12-02 21:29:20 +01:00
2018-03-05 22:42:49 +01:00
// Calculate cost of change
2018-04-07 18:12:46 +02:00
CAmount cost_of_change = GetDiscardRate ( * this , : : feeEstimator ) . GetFee ( coin_selection_params . change_spend_size ) + coin_selection_params . effective_fee . GetFee ( coin_selection_params . change_output_size ) ;
2011-06-26 19:23:24 +02:00
2018-03-05 22:42:49 +01:00
// Filter by the min conf specs and add to utxo_pool and calculate effective value
2018-07-19 04:45:26 +02:00
for ( OutputGroup & group : groups ) {
if ( ! group . EligibleForSpending ( eligibility_filter ) ) continue ;
group . fee = 0 ;
group . long_term_fee = 0 ;
group . effective_value = 0 ;
for ( auto it = group . m_outputs . begin ( ) ; it ! = group . m_outputs . end ( ) ; ) {
const CInputCoin & coin = * it ;
CAmount effective_value = coin . txout . nValue - ( coin . m_input_bytes < 0 ? 0 : coin_selection_params . effective_fee . GetFee ( coin . m_input_bytes ) ) ;
// Only include outputs that are positive effective value (i.e. not dust)
if ( effective_value > 0 ) {
group . fee + = coin . m_input_bytes < 0 ? 0 : coin_selection_params . effective_fee . GetFee ( coin . m_input_bytes ) ;
group . long_term_fee + = coin . m_input_bytes < 0 ? 0 : long_term_feerate . GetFee ( coin . m_input_bytes ) ;
group . effective_value + = effective_value ;
+ + it ;
} else {
it = group . Discard ( coin ) ;
}
2011-06-26 19:23:24 +02:00
}
2018-07-19 04:45:26 +02:00
if ( group . effective_value > 0 ) utxo_pool . push_back ( group ) ;
2018-03-05 22:42:49 +01:00
}
// Calculate the fees for things that aren't inputs
CAmount not_input_fees = coin_selection_params . effective_fee . GetFee ( coin_selection_params . tx_noinputs_size ) ;
bnb_used = true ;
return SelectCoinsBnB ( utxo_pool , nTargetValue , cost_of_change , setCoinsRet , nValueRet , not_input_fees ) ;
} else {
// Filter by the min conf specs and add to utxo_pool
2018-07-19 04:45:26 +02:00
for ( const OutputGroup & group : groups ) {
if ( ! group . EligibleForSpending ( eligibility_filter ) ) continue ;
utxo_pool . push_back ( group ) ;
2016-12-25 21:19:40 +01:00
}
2018-03-05 22:42:49 +01:00
bnb_used = false ;
return KnapsackSolver ( nTargetValue , utxo_pool , setCoinsRet , nValueRet ) ;
2011-06-26 19:23:24 +02:00
}
}
2018-03-15 07:42:18 +01:00
bool CWallet : : SelectCoins ( const std : : vector < COutput > & vAvailableCoins , const CAmount & nTargetValue , std : : set < CInputCoin > & setCoinsRet , CAmount & nValueRet , const CCoinControl & coin_control , CoinSelectionParams & coin_selection_params , bool & bnb_used ) const
2011-06-26 19:23:24 +02:00
{
2017-01-27 02:33:45 +01:00
std : : vector < COutput > vCoins ( vAvailableCoins ) ;
2013-08-12 17:03:03 +02:00
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
2018-03-05 22:42:49 +01:00
if ( coin_control . HasSelected ( ) & & ! coin_control . fAllowOtherInputs )
2013-08-12 17:03:03 +02:00
{
2018-03-05 22:42:49 +01:00
// We didn't use BnB here, so set it to false.
bnb_used = false ;
2017-06-02 03:18:57 +02:00
for ( const COutput & out : vCoins )
2013-08-12 17:03:03 +02:00
{
2015-04-25 03:29:00 +02:00
if ( ! out . fSpendable )
continue ;
2016-11-12 01:54:51 +01:00
nValueRet + = out . tx - > tx - > vout [ out . i ] . nValue ;
2018-07-19 04:45:26 +02:00
setCoinsRet . insert ( out . GetInputCoin ( ) ) ;
2013-08-12 17:03:03 +02:00
}
return ( nValueRet > = nTargetValue ) ;
}
2012-02-27 13:19:32 +01:00
2015-04-25 03:29:00 +02:00
// calculate value from preset inputs and store them
2017-04-07 11:38:33 +02:00
std : : set < CInputCoin > setPresetCoins ;
2015-04-25 03:29:00 +02:00
CAmount nValueFromPresetInputs = 0 ;
std : : vector < COutPoint > vPresetInputs ;
2018-03-05 22:42:49 +01:00
coin_control . ListSelected ( vPresetInputs ) ;
2017-06-02 03:18:57 +02:00
for ( const COutPoint & outpoint : vPresetInputs )
2015-04-25 03:29:00 +02:00
{
2018-03-05 22:42:49 +01:00
// For now, don't use BnB if preset inputs are selected. TODO: Enable this later
bnb_used = false ;
2018-03-15 07:42:18 +01:00
coin_selection_params . use_bnb = false ;
2018-03-05 22:42:49 +01:00
2017-01-27 02:33:45 +01:00
std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( outpoint . hash ) ;
2015-04-25 03:29:00 +02:00
if ( it ! = mapWallet . end ( ) )
{
const CWalletTx * pcoin = & it - > second ;
// Clearly invalid input, fail
2016-11-12 01:54:51 +01:00
if ( pcoin - > tx - > vout . size ( ) < = outpoint . n )
2015-04-25 03:29:00 +02:00
return false ;
2018-03-05 22:42:49 +01:00
// Just to calculate the marginal byte size
2016-11-12 01:54:51 +01:00
nValueFromPresetInputs + = pcoin - > tx - > vout [ outpoint . n ] . nValue ;
2018-03-07 18:18:37 +01:00
setPresetCoins . insert ( CInputCoin ( pcoin - > tx , outpoint . n ) ) ;
2015-04-25 03:29:00 +02:00
} else
return false ; // TODO: Allow non-wallet inputs
}
// remove preset inputs from vCoins
2018-03-05 22:42:49 +01:00
for ( std : : vector < COutput > : : iterator it = vCoins . begin ( ) ; it ! = vCoins . end ( ) & & coin_control . HasSelected ( ) ; )
2015-04-25 03:29:00 +02:00
{
2018-07-19 04:45:26 +02:00
if ( setPresetCoins . count ( it - > GetInputCoin ( ) ) )
2015-04-25 03:29:00 +02:00
it = vCoins . erase ( it ) ;
else
+ + it ;
}
2018-07-19 04:45:26 +02:00
// form groups from remaining coins; note that preset coins will not
// automatically have their associated (same address) coins included
2018-07-30 18:50:43 +02:00
if ( coin_control . m_avoid_partial_spends & & vCoins . size ( ) > OUTPUT_GROUP_MAX_ENTRIES ) {
// Cases where we have 11+ outputs all pointing to the same destination may result in
// privacy leaks as they will potentially be deterministically sorted. We solve that by
// explicitly shuffling the outputs before processing
std : : shuffle ( vCoins . begin ( ) , vCoins . end ( ) , FastRandomContext ( ) ) ;
}
2018-07-19 04:45:26 +02:00
std : : vector < OutputGroup > groups = GroupOutputs ( vCoins , ! coin_control . m_avoid_partial_spends ) ;
2018-05-22 04:13:34 +02:00
size_t max_ancestors = ( size_t ) std : : max < int64_t > ( 1 , gArgs . GetArg ( " -limitancestorcount " , DEFAULT_ANCESTOR_LIMIT ) ) ;
size_t max_descendants = ( size_t ) std : : max < int64_t > ( 1 , gArgs . GetArg ( " -limitdescendantcount " , DEFAULT_DESCENDANT_LIMIT ) ) ;
2017-08-01 21:17:40 +02:00
bool fRejectLongChains = gArgs . GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ;
2016-12-02 21:29:20 +01:00
2015-04-25 03:29:00 +02:00
bool res = nTargetValue < = nValueFromPresetInputs | |
2018-07-19 04:45:26 +02:00
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 1 , 6 , 0 ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) | |
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 1 , 1 , 0 ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) | |
( m_spend_zero_conf_change & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 0 , 1 , 2 ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) ) | |
( m_spend_zero_conf_change & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 0 , 1 , std : : min ( ( size_t ) 4 , max_ancestors / 3 ) , std : : min ( ( size_t ) 4 , max_descendants / 3 ) ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) ) | |
( m_spend_zero_conf_change & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 0 , 1 , max_ancestors / 2 , max_descendants / 2 ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) ) | |
( m_spend_zero_conf_change & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 0 , 1 , max_ancestors - 1 , max_descendants - 1 ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) ) | |
( m_spend_zero_conf_change & & ! fRejectLongChains & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , CoinEligibilityFilter ( 0 , 1 , std : : numeric_limits < uint64_t > : : max ( ) ) , groups , setCoinsRet , nValueRet , coin_selection_params , bnb_used ) ) ;
2015-04-25 03:29:00 +02:00
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
2018-07-19 04:45:26 +02:00
util : : insert ( setCoinsRet , setPresetCoins ) ;
2015-04-25 03:29:00 +02:00
// add preset inputs to the total value selected
nValueRet + = nValueFromPresetInputs ;
return res ;
2011-06-26 19:23:24 +02:00
}
2017-03-03 16:15:47 +01:00
bool CWallet : : SignTransaction ( CMutableTransaction & tx )
{
2017-04-10 14:05:49 +02:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2017-03-03 16:15:47 +01:00
// sign the new tx
int nIn = 0 ;
2018-05-18 02:54:18 +02:00
for ( auto & input : tx . vin ) {
2017-03-03 16:15:47 +01:00
std : : map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( input . prevout . hash ) ;
2017-03-27 14:00:14 +02:00
if ( mi = = mapWallet . end ( ) | | input . prevout . n > = mi - > second . tx - > vout . size ( ) ) {
return false ;
}
2017-03-03 16:15:47 +01:00
const CScript & scriptPubKey = mi - > second . tx - > vout [ input . prevout . n ] . scriptPubKey ;
const CAmount & amount = mi - > second . tx - > vout [ input . prevout . n ] . nValue ;
SignatureData sigdata ;
2018-05-20 22:47:14 +02:00
if ( ! ProduceSignature ( * this , MutableTransactionSignatureCreator ( & tx , nIn , amount , SIGHASH_ALL ) , scriptPubKey , sigdata ) ) {
2017-03-03 16:15:47 +01:00
return false ;
}
2018-05-18 02:54:18 +02:00
UpdateInput ( input , sigdata ) ;
2017-03-03 16:15:47 +01:00
nIn + + ;
}
return true ;
}
2017-07-10 20:29:06 +02:00
bool CWallet : : FundTransaction ( CMutableTransaction & tx , CAmount & nFeeRet , int & nChangePosInOut , std : : string & strFailReason , bool lockUnspents , const std : : set < int > & setSubtractFeeFromOutputs , CCoinControl coinControl )
2015-04-25 03:29:00 +02:00
{
2017-01-27 02:33:45 +01:00
std : : vector < CRecipient > vecSend ;
2015-04-25 03:29:00 +02:00
2017-12-14 04:17:58 +01:00
// Turn the txout set into a CRecipient vector.
for ( size_t idx = 0 ; idx < tx . vout . size ( ) ; idx + + ) {
2016-12-13 22:36:23 +01:00
const CTxOut & txOut = tx . vout [ idx ] ;
CRecipient recipient = { txOut . scriptPubKey , txOut . nValue , setSubtractFeeFromOutputs . count ( idx ) = = 1 } ;
2015-04-25 03:29:00 +02:00
vecSend . push_back ( recipient ) ;
}
coinControl . fAllowOtherInputs = true ;
2016-04-28 22:04:07 +02:00
2017-12-14 04:17:58 +01:00
for ( const CTxIn & txin : tx . vin ) {
2015-04-25 03:29:00 +02:00
coinControl . Select ( txin . prevout ) ;
2017-12-14 04:17:58 +01:00
}
2015-04-25 03:29:00 +02:00
2017-12-14 04:18:29 +01:00
// Acquire the locks to prevent races to the new locked unspents between the
// CreateTransaction call and LockCoin calls (when lockUnspents is true).
LOCK2 ( cs_main , cs_wallet ) ;
2015-04-25 03:29:00 +02:00
CReserveKey reservekey ( this ) ;
2017-02-02 21:30:03 +01:00
CTransactionRef tx_new ;
if ( ! CreateTransaction ( vecSend , tx_new , reservekey , nFeeRet , nChangePosInOut , strFailReason , coinControl , false ) ) {
2015-04-25 03:29:00 +02:00
return false ;
2017-06-28 22:41:55 +02:00
}
2017-07-10 20:29:06 +02:00
if ( nChangePosInOut ! = - 1 ) {
2017-02-02 21:30:03 +01:00
tx . vout . insert ( tx . vout . begin ( ) + nChangePosInOut , tx_new - > vout [ nChangePosInOut ] ) ;
2017-12-14 04:17:58 +01:00
// We don't have the normal Create/Commit cycle, and don't want to risk
// reusing change, so just remove the key from the keypool here.
2017-07-10 20:29:06 +02:00
reservekey . KeepKey ( ) ;
}
2015-04-25 03:29:00 +02:00
2017-12-14 04:17:58 +01:00
// Copy output sizes from new transaction; they may have had the fee
// subtracted from them.
for ( unsigned int idx = 0 ; idx < tx . vout . size ( ) ; idx + + ) {
2017-02-02 21:30:03 +01:00
tx . vout [ idx ] . nValue = tx_new - > vout [ idx ] . nValue ;
2017-12-14 04:17:58 +01:00
}
2016-12-13 22:36:23 +01:00
2017-12-14 04:17:58 +01:00
// Add new txins while keeping original txin scriptSig/order.
2017-02-02 21:30:03 +01:00
for ( const CTxIn & txin : tx_new - > vin ) {
2017-12-14 04:17:58 +01:00
if ( ! coinControl . IsSelected ( txin . prevout ) ) {
2015-04-25 03:29:00 +02:00
tx . vin . push_back ( txin ) ;
2016-04-06 16:56:14 +02:00
2017-12-14 04:17:58 +01:00
if ( lockUnspents ) {
LockCoin ( txin . prevout ) ;
2016-04-06 16:56:14 +02:00
}
}
2015-04-25 03:29:00 +02:00
}
return true ;
}
2018-01-15 17:10:13 +01:00
OutputType CWallet : : TransactionChangeType ( OutputType change_type , const std : : vector < CRecipient > & vecSend )
2018-01-23 17:56:15 +01:00
{
// If -changetype is specified, always use that change type.
2018-03-19 20:57:11 +01:00
if ( change_type ! = OutputType : : CHANGE_AUTO ) {
2018-01-15 17:10:13 +01:00
return change_type ;
2018-01-23 17:56:15 +01:00
}
2018-02-11 03:06:35 +01:00
// if m_default_address_type is legacy, use legacy address as change (even
2018-01-23 17:56:15 +01:00
// if some of the outputs are P2WPKH or P2WSH).
2018-02-11 03:06:35 +01:00
if ( m_default_address_type = = OutputType : : LEGACY ) {
return OutputType : : LEGACY ;
2018-01-23 17:56:15 +01:00
}
// if any destination is P2WPKH or P2WSH, use P2WPKH for the change
// output.
for ( const auto & recipient : vecSend ) {
// Check if any destination contains a witness program:
int witnessversion = 0 ;
std : : vector < unsigned char > witnessprogram ;
if ( recipient . scriptPubKey . IsWitnessProgram ( witnessversion , witnessprogram ) ) {
2018-02-11 03:06:35 +01:00
return OutputType : : BECH32 ;
2018-01-23 17:56:15 +01:00
}
}
2018-02-11 03:06:35 +01:00
// else use m_default_address_type for change
return m_default_address_type ;
2018-01-23 17:56:15 +01:00
}
2017-02-02 21:30:03 +01:00
bool CWallet : : CreateTransaction ( const std : : vector < CRecipient > & vecSend , CTransactionRef & tx , CReserveKey & reservekey , CAmount & nFeeRet ,
2018-07-19 04:45:26 +02:00
int & nChangePosInOut , std : : string & strFailReason , const CCoinControl & coin_control , bool sign )
2011-06-26 19:23:24 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nValue = 0 ;
2016-03-30 03:04:22 +02:00
int nChangePosRequest = nChangePosInOut ;
2014-07-23 14:34:36 +02:00
unsigned int nSubtractFeeFromAmount = 0 ;
2017-01-04 09:51:14 +01:00
for ( const auto & recipient : vecSend )
2011-06-26 19:23:24 +02:00
{
2014-07-23 14:34:36 +02:00
if ( nValue < 0 | | recipient . nAmount < 0 )
2013-04-25 23:31:22 +02:00
{
2016-11-22 18:48:01 +01:00
strFailReason = _ ( " Transaction amounts must not be negative " ) ;
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2014-07-23 14:34:36 +02:00
nValue + = recipient . nAmount ;
if ( recipient . fSubtractFeeFromAmount )
nSubtractFeeFromAmount + + ;
2011-06-26 19:23:24 +02:00
}
2016-11-22 18:48:01 +01:00
if ( vecSend . empty ( ) )
2013-04-25 23:31:22 +02:00
{
2016-11-22 18:48:01 +01:00
strFailReason = _ ( " Transaction must have at least one recipient " ) ;
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2011-06-26 19:23:24 +02:00
2014-06-07 13:53:27 +02:00
CMutableTransaction txNew ;
2011-06-26 19:23:24 +02:00
2013-08-25 20:13:25 +02:00
// Discourage fee sniping.
//
2015-06-01 21:03:51 +02:00
// For a large miner the value of the transactions in the best block and
2015-12-02 15:28:24 +01:00
// the mempool can exceed the cost of deliberately attempting to mine two
2015-06-01 21:03:51 +02:00
// blocks to orphan the current best block. By setting nLockTime such that
// only the next block can include the transaction, we discourage this
// practice as the height restricted and limited blocksize gives miners
// considering fee sniping fewer options for pulling off this attack.
//
// A simple way to think about this is from the wallet's point of view we
// always want the blockchain to move forward. By setting nLockTime this
// way we're basically making the statement that we only want this
// transaction to appear in the next block; we don't want to potentially
// encourage reorgs by allowing transactions to appear at lower heights
// than the next block in forks of the best chain.
//
// Of course, the subsidy is high enough, and transaction volume low
// enough, that fee sniping isn't a problem yet, but by implementing a fix
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
txNew . nLockTime = chainActive . Height ( ) ;
2013-08-25 20:13:25 +02:00
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
// e.g. high-latency mix networks and some CoinJoin implementations, have
// better privacy.
if ( GetRandInt ( 10 ) = = 0 )
txNew . nLockTime = std : : max ( 0 , ( int ) txNew . nLockTime - GetRandInt ( 100 ) ) ;
assert ( txNew . nLockTime < = ( unsigned int ) chainActive . Height ( ) ) ;
assert ( txNew . nLockTime < LOCKTIME_THRESHOLD ) ;
2017-04-25 21:39:32 +02:00
FeeCalculation feeCalc ;
2017-08-25 21:49:44 +02:00
CAmount nFeeNeeded ;
2018-03-05 22:37:24 +01:00
int nBytes ;
2011-06-26 19:23:24 +02:00
{
2017-04-07 11:38:33 +02:00
std : : set < CInputCoin > setCoins ;
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
{
2016-03-08 01:15:17 +01:00
std : : vector < COutput > vAvailableCoins ;
2017-06-28 22:41:55 +02:00
AvailableCoins ( vAvailableCoins , true , & coin_control ) ;
2018-03-05 22:42:49 +01:00
CoinSelectionParams coin_selection_params ; // Parameters for coin selection, init with dummy
2016-03-08 01:15:17 +01:00
2017-06-30 18:53:29 +02:00
// Create change script that will be used if we need change
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange ;
// coin control: send change to custom address
2017-06-28 22:41:55 +02:00
if ( ! boost : : get < CNoDestination > ( & coin_control . destChange ) ) {
scriptChange = GetScriptForDestination ( coin_control . destChange ) ;
} else { // no coin control: send change to newly generated address
2017-06-30 18:53:29 +02:00
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// Reserve a new key pair from key pool
2017-05-05 08:53:39 +02:00
if ( IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
strFailReason = _ ( " Can't generate a change-address key. Private keys are disabled for this wallet. " ) ;
return false ;
}
2017-06-30 18:53:29 +02:00
CPubKey vchPubKey ;
bool ret ;
ret = reservekey . GetReservedKey ( vchPubKey , true ) ;
if ( ! ret )
{
strFailReason = _ ( " Keypool ran out, please call keypoolrefill first " ) ;
return false ;
}
2018-02-11 03:06:35 +01:00
const OutputType change_type = TransactionChangeType ( coin_control . m_change_type ? * coin_control . m_change_type : m_default_change_type , vecSend ) ;
2018-01-23 17:56:15 +01:00
LearnRelatedScripts ( vchPubKey , change_type ) ;
scriptChange = GetScriptForDestination ( GetDestinationForKey ( vchPubKey , change_type ) ) ;
2017-06-30 18:53:29 +02:00
}
2017-06-30 19:16:53 +02:00
CTxOut change_prototype_txout ( 0 , scriptChange ) ;
2018-03-05 22:42:49 +01:00
coin_selection_params . change_output_size = GetSerializeSize ( change_prototype_txout , SER_DISK , 0 ) ;
2017-06-30 18:53:29 +02:00
2018-04-07 18:12:46 +02:00
CFeeRate discard_rate = GetDiscardRate ( * this , : : feeEstimator ) ;
2018-03-05 22:42:49 +01:00
// Get the fee rate to use effective values in coin selection
2018-04-07 18:12:46 +02:00
CFeeRate nFeeRateNeeded = GetMinimumFeeRate ( * this , coin_control , : : mempool , : : feeEstimator , & feeCalc ) ;
2018-03-05 22:42:49 +01:00
2014-11-02 00:14:47 +01:00
nFeeRet = 0 ;
2017-06-30 19:16:53 +02:00
bool pick_new_inputs = true ;
CAmount nValueIn = 0 ;
2018-03-05 22:42:49 +01:00
// BnB selector is the only selector used when this is true.
// That should only happen on the first pass through the loop.
coin_selection_params . use_bnb = nSubtractFeeFromAmount = = 0 ; // If we are doing subtract fee from recipient, then don't use BnB
2015-09-14 14:49:59 +02:00
// Start with no fee and loop until there is enough fee
2013-07-31 06:06:44 +02:00
while ( true )
2011-06-26 19:23:24 +02:00
{
2016-03-30 03:04:22 +02:00
nChangePosInOut = nChangePosRequest ;
2014-06-07 13:53:27 +02:00
txNew . vin . clear ( ) ;
txNew . vout . clear ( ) ;
2014-07-23 14:34:36 +02:00
bool fFirst = true ;
2011-06-26 19:23:24 +02:00
2015-03-18 19:22:49 +01:00
CAmount nValueToSelect = nValue ;
2014-07-23 14:34:36 +02:00
if ( nSubtractFeeFromAmount = = 0 )
2015-03-18 19:22:49 +01:00
nValueToSelect + = nFeeRet ;
2018-03-05 22:42:49 +01:00
2011-06-26 19:23:24 +02:00
// vouts to the payees
2018-03-05 22:42:49 +01:00
coin_selection_params . tx_noinputs_size = 11 ; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count, 1 output count, 1 witness overhead (dummy, flag, stack size)
2017-01-04 09:51:14 +01:00
for ( const auto & recipient : vecSend )
2013-04-25 00:27:00 +02:00
{
2014-07-23 14:34:36 +02:00
CTxOut txout ( recipient . nAmount , recipient . scriptPubKey ) ;
if ( recipient . fSubtractFeeFromAmount )
{
2017-08-28 09:20:50 +02:00
assert ( nSubtractFeeFromAmount ! = 0 ) ;
2014-07-23 14:34:36 +02:00
txout . nValue - = nFeeRet / nSubtractFeeFromAmount ; // Subtract fee equally from each selected recipient
if ( fFirst ) // first receiver pays the remainder not divisible by output count
{
fFirst = false ;
txout . nValue - = nFeeRet % nSubtractFeeFromAmount ;
}
}
2018-03-05 22:42:49 +01:00
// Include the fee cost for outputs. Note this is only used for BnB right now
coin_selection_params . tx_noinputs_size + = : : GetSerializeSize ( txout , SER_NETWORK , PROTOCOL_VERSION ) ;
2014-07-23 14:34:36 +02:00
2016-10-14 17:49:05 +02:00
if ( IsDust ( txout , : : dustRelayFee ) )
2013-04-25 23:31:22 +02:00
{
2014-07-23 14:34:36 +02:00
if ( recipient . fSubtractFeeFromAmount & & nFeeRet > 0 )
{
if ( txout . nValue < 0 )
strFailReason = _ ( " The transaction amount is too small to pay the fee " ) ;
else
strFailReason = _ ( " The transaction amount is too small to send after the fee has been deducted " ) ;
}
else
strFailReason = _ ( " Transaction amount too small " ) ;
2013-04-25 00:27:00 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2014-06-07 13:53:27 +02:00
txNew . vout . push_back ( txout ) ;
2013-04-25 00:27:00 +02:00
}
2011-06-26 19:23:24 +02:00
// Choose coins to use
2018-03-05 22:42:49 +01:00
bool bnb_used ;
2017-06-30 19:16:53 +02:00
if ( pick_new_inputs ) {
nValueIn = 0 ;
setCoins . clear ( ) ;
2018-03-05 22:42:49 +01:00
coin_selection_params . change_spend_size = CalculateMaximumSignedInputSize ( change_prototype_txout , this ) ;
coin_selection_params . effective_fee = nFeeRateNeeded ;
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , coin_control , coin_selection_params , bnb_used ) )
2017-06-30 19:16:53 +02:00
{
2018-03-05 22:42:49 +01:00
// If BnB was used, it was the first pass. No longer the first pass and continue loop with knapsack.
if ( bnb_used ) {
coin_selection_params . use_bnb = false ;
continue ;
}
else {
strFailReason = _ ( " Insufficient funds " ) ;
return false ;
}
2017-06-30 19:16:53 +02:00
}
2013-04-25 23:31:22 +02:00
}
2011-06-26 19:23:24 +02:00
2015-03-18 19:22:49 +01:00
const CAmount nChange = nValueIn - nValueToSelect ;
2011-07-24 16:37:09 +02:00
if ( nChange > 0 )
2011-06-26 19:23:24 +02:00
{
2011-09-28 18:30:06 +02:00
// Fill a vout to ourself
2013-04-25 00:27:00 +02:00
CTxOut newTxOut ( nChange , scriptChange ) ;
// Never create dust outputs; if we would, just
// add the dust to the fee.
2018-03-05 22:42:49 +01:00
// The nChange when BnB is used is always going to go to fees.
if ( IsDust ( newTxOut , discard_rate ) | | bnb_used )
2013-04-25 00:27:00 +02:00
{
2016-03-30 03:04:22 +02:00
nChangePosInOut = - 1 ;
2013-04-25 00:27:00 +02:00
nFeeRet + = nChange ;
}
else
{
2016-03-30 03:04:22 +02:00
if ( nChangePosInOut = = - 1 )
{
// Insert change txn at random position:
nChangePosInOut = GetRandInt ( txNew . vout . size ( ) + 1 ) ;
}
2016-06-08 15:34:18 +02:00
else if ( ( unsigned int ) nChangePosInOut > txNew . vout . size ( ) )
2016-03-30 03:04:22 +02:00
{
strFailReason = _ ( " Change index out of range " ) ;
return false ;
}
2017-01-27 02:33:45 +01:00
std : : vector < CTxOut > : : iterator position = txNew . vout . begin ( ) + nChangePosInOut ;
2014-06-07 13:53:27 +02:00
txNew . vout . insert ( position , newTxOut ) ;
2013-04-25 00:27:00 +02:00
}
2017-04-28 23:22:37 +02:00
} else {
nChangePosInOut = - 1 ;
}
2011-06-26 19:23:24 +02:00
2018-03-15 21:18:48 +01:00
// Dummy fill vin for maximum size estimation
2013-08-25 20:13:25 +02:00
//
2018-03-15 21:18:48 +01:00
for ( const auto & coin : setCoins ) {
txNew . vin . push_back ( CTxIn ( coin . outpoint , CScript ( ) ) ) ;
}
2011-06-26 19:23:24 +02:00
2018-03-05 22:37:24 +01:00
nBytes = CalculateMaximumSignedTxSize ( txNew , this ) ;
if ( nBytes < 0 ) {
2017-01-26 18:57:04 +01:00
strFailReason = _ ( " Signing transaction failed " ) ;
return false ;
2015-04-25 03:29:00 +02:00
}
2018-04-07 18:12:46 +02:00
nFeeNeeded = GetMinimumFee ( * this , nBytes , coin_control , : : mempool , : : feeEstimator , & feeCalc ) ;
if ( feeCalc . reason = = FeeReason : : FALLBACK & & ! m_allow_fallback_fee ) {
2017-12-12 21:32:50 +01:00
// eventually allow a fallback fee
strFailReason = _ ( " Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee. " ) ;
return false ;
}
2014-05-27 21:44:57 +02:00
2014-12-16 10:43:40 +01:00
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
if ( nFeeNeeded < : : minRelayTxFee . GetFee ( nBytes ) )
2011-06-26 19:23:24 +02:00
{
2014-12-16 10:43:40 +01:00
strFailReason = _ ( " Transaction too large for fee policy " ) ;
return false ;
2011-06-26 19:23:24 +02:00
}
2017-01-05 15:12:48 +01:00
if ( nFeeRet > = nFeeNeeded ) {
2017-06-30 19:16:53 +02:00
// Reduce fee to only the needed amount if possible. This
// prevents potential overpayment in fees if the coins
// selected to meet nFeeNeeded result in a transaction that
// requires less fee than the prior iteration.
// If we have no change and a big enough excess fee, then
// try to construct transaction again only without picking
// new inputs. We now know we only need the smaller fee
// (because of reduced tx size) and so we should add a
// change output. Only try this once.
2017-08-25 21:46:07 +02:00
if ( nChangePosInOut = = - 1 & & nSubtractFeeFromAmount = = 0 & & pick_new_inputs ) {
2018-03-05 22:42:49 +01:00
unsigned int tx_size_with_change = nBytes + coin_selection_params . change_output_size + 2 ; // Add 2 as a buffer in case increasing # of outputs changes compact size
2018-04-07 18:12:46 +02:00
CAmount fee_needed_with_change = GetMinimumFee ( * this , tx_size_with_change , coin_control , : : mempool , : : feeEstimator , nullptr ) ;
2017-08-25 21:46:07 +02:00
CAmount minimum_value_for_change = GetDustThreshold ( change_prototype_txout , discard_rate ) ;
if ( nFeeRet > = fee_needed_with_change + minimum_value_for_change ) {
pick_new_inputs = false ;
nFeeRet = fee_needed_with_change ;
continue ;
}
2017-06-30 19:16:53 +02:00
}
// If we have change output already, just increase it
2017-01-05 15:12:48 +01:00
if ( nFeeRet > nFeeNeeded & & nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded ;
2017-01-27 02:33:45 +01:00
std : : vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
2017-01-05 15:12:48 +01:00
change_position - > nValue + = extraFeePaid ;
nFeeRet - = extraFeePaid ;
}
2014-12-16 10:43:40 +01:00
break ; // Done, enough fee included.
2017-01-05 15:12:48 +01:00
}
2017-06-30 19:16:53 +02:00
else if ( ! pick_new_inputs ) {
// This shouldn't happen, we should have had enough excess
// fee to pay for the new output and still meet nFeeNeeded
2017-07-27 23:01:39 +02:00
// Or we should have just subtracted fee from recipients and
// nFeeNeeded should not have changed
2017-06-30 19:16:53 +02:00
strFailReason = _ ( " Transaction fee and change calculation failed " ) ;
return false ;
}
2014-05-27 21:44:57 +02:00
2017-01-05 15:10:08 +01:00
// Try to reduce change to include necessary fee
if ( nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet ;
2017-01-27 02:33:45 +01:00
std : : vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
2017-01-05 15:10:08 +01:00
// Only reduce change if remaining amount is still a large enough output.
if ( change_position - > nValue > = MIN_FINAL_CHANGE + additionalFeeNeeded ) {
change_position - > nValue - = additionalFeeNeeded ;
nFeeRet + = additionalFeeNeeded ;
break ; // Done, able to increase fee from change
}
}
2017-07-27 23:01:39 +02:00
// If subtracting fee from recipients, we now know what fee we
// need to subtract, we have no reason to reselect inputs
if ( nSubtractFeeFromAmount > 0 ) {
pick_new_inputs = false ;
}
2014-05-27 21:44:57 +02:00
// Include more fee and try again.
nFeeRet = nFeeNeeded ;
2018-03-05 22:42:49 +01:00
coin_selection_params . use_bnb = false ;
2014-05-27 21:44:57 +02:00
continue ;
2011-06-26 19:23:24 +02:00
}
}
2017-01-04 09:51:14 +01:00
2017-06-30 18:53:29 +02:00
if ( nChangePosInOut = = - 1 ) reservekey . ReturnKey ( ) ; // Return any reserved key if we don't have change
2018-03-15 21:18:48 +01:00
// Shuffle selected coins and fill in final vin
txNew . vin . clear ( ) ;
std : : vector < CInputCoin > selected_coins ( setCoins . begin ( ) , setCoins . end ( ) ) ;
std : : shuffle ( selected_coins . begin ( ) , selected_coins . end ( ) , FastRandomContext ( ) ) ;
// Note how the sequence number is set to non-maxint so that
// the nLockTime set above actually works.
//
// BIP125 defines opt-in RBF as any nSequence < maxint-1, so
// we use the highest possible value in that range (maxint-2)
// to avoid conflicting with other possible uses of nSequence,
// and in the spirit of "smallest possible change from prior
// behavior."
2018-04-07 18:12:46 +02:00
const uint32_t nSequence = coin_control . m_signal_bip125_rbf . get_value_or ( m_signal_rbf ) ? MAX_BIP125_RBF_SEQUENCE : ( CTxIn : : SEQUENCE_FINAL - 1 ) ;
2018-03-15 21:18:48 +01:00
for ( const auto & coin : selected_coins ) {
txNew . vin . push_back ( CTxIn ( coin . outpoint , CScript ( ) , nSequence ) ) ;
}
2017-01-04 09:51:14 +01:00
if ( sign )
{
int nIn = 0 ;
2018-03-15 21:18:48 +01:00
for ( const auto & coin : selected_coins )
2017-01-04 09:51:14 +01:00
{
2017-04-07 11:57:06 +02:00
const CScript & scriptPubKey = coin . txout . scriptPubKey ;
2017-01-04 09:51:14 +01:00
SignatureData sigdata ;
2018-05-20 22:47:14 +02:00
if ( ! ProduceSignature ( * this , MutableTransactionSignatureCreator ( & txNew , nIn , coin . txout . nValue , SIGHASH_ALL ) , scriptPubKey , sigdata ) )
2017-01-04 09:51:14 +01:00
{
strFailReason = _ ( " Signing transaction failed " ) ;
return false ;
} else {
2018-05-18 02:54:18 +02:00
UpdateInput ( txNew . vin . at ( nIn ) , sigdata ) ;
2017-01-04 09:51:14 +01:00
}
nIn + + ;
}
}
2017-02-02 21:30:03 +01:00
// Return the constructed transaction data.
tx = MakeTransactionRef ( std : : move ( txNew ) ) ;
2017-01-04 09:51:14 +01:00
// Limit size
2018-04-26 19:24:48 +02:00
if ( GetTransactionWeight ( * tx ) > MAX_STANDARD_TX_WEIGHT )
2017-01-04 09:51:14 +01:00
{
strFailReason = _ ( " Transaction too large " ) ;
return false ;
}
2011-06-26 19:23:24 +02:00
}
2017-08-01 21:17:40 +02:00
if ( gArgs . GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ) {
2016-12-02 21:45:43 +01:00
// Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp ;
2017-02-02 21:30:03 +01:00
CTxMemPoolEntry entry ( tx , 0 , 0 , 0 , false , 0 , lp ) ;
2016-12-02 21:45:43 +01:00
CTxMemPool : : setEntries setAncestors ;
2017-08-01 21:17:40 +02:00
size_t nLimitAncestors = gArgs . GetArg ( " -limitancestorcount " , DEFAULT_ANCESTOR_LIMIT ) ;
size_t nLimitAncestorSize = gArgs . GetArg ( " -limitancestorsize " , DEFAULT_ANCESTOR_SIZE_LIMIT ) * 1000 ;
size_t nLimitDescendants = gArgs . GetArg ( " -limitdescendantcount " , DEFAULT_DESCENDANT_LIMIT ) ;
size_t nLimitDescendantSize = gArgs . GetArg ( " -limitdescendantsize " , DEFAULT_DESCENDANT_SIZE_LIMIT ) * 1000 ;
2016-12-02 21:45:43 +01:00
std : : string errString ;
2018-07-28 17:09:58 +02:00
LOCK ( : : mempool . cs ) ;
if ( ! : : mempool . CalculateMemPoolAncestors ( entry , setAncestors , nLimitAncestors , nLimitAncestorSize , nLimitDescendants , nLimitDescendantSize , errString ) ) {
2016-12-02 21:45:43 +01:00
strFailReason = _ ( " Transaction has too long of a mempool chain " ) ;
return false ;
}
}
2017-04-25 21:39:32 +02:00
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " Fee Calculation: Fee:%d Bytes:%u Needed:%d Tgt:%d (requested %d) Reason: \" %s \" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) \n " ,
2017-08-25 21:49:44 +02:00
nFeeRet , nBytes , nFeeNeeded , feeCalc . returnedTarget , feeCalc . desiredTarget , StringForFeeReason ( feeCalc . reason ) , feeCalc . est . decay ,
2017-04-25 21:39:32 +02:00
feeCalc . est . pass . start , feeCalc . est . pass . end ,
100 * feeCalc . est . pass . withinTarget / ( feeCalc . est . pass . totalConfirmed + feeCalc . est . pass . inMempool + feeCalc . est . pass . leftMempool ) ,
feeCalc . est . pass . withinTarget , feeCalc . est . pass . totalConfirmed , feeCalc . est . pass . inMempool , feeCalc . est . pass . leftMempool ,
feeCalc . est . fail . start , feeCalc . est . fail . end ,
100 * feeCalc . est . fail . withinTarget / ( feeCalc . est . fail . totalConfirmed + feeCalc . est . fail . inMempool + feeCalc . est . fail . leftMempool ) ,
feeCalc . est . fail . withinTarget , feeCalc . est . fail . totalConfirmed , feeCalc . est . fail . inMempool , feeCalc . est . fail . leftMempool ) ;
2014-07-23 14:34:36 +02:00
return true ;
2011-06-26 19:23:24 +02:00
}
2014-10-26 08:03:12 +01:00
/**
* Call after CreateTransaction unless you want to abort
*/
2017-02-02 21:30:03 +01:00
bool CWallet : : CommitTransaction ( CTransactionRef tx , mapValue_t mapValue , std : : vector < std : : pair < std : : string , std : : string > > orderForm , std : : string fromAccount , CReserveKey & reservekey , CConnman * connman , CValidationState & state )
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2017-02-02 21:30:03 +01:00
CWalletTx wtxNew ( this , std : : move ( tx ) ) ;
wtxNew . mapValue = std : : move ( mapValue ) ;
wtxNew . vOrderForm = std : : move ( orderForm ) ;
wtxNew . strFromAccount = std : : move ( fromAccount ) ;
wtxNew . fTimeReceivedIsTxTime = true ;
wtxNew . fFromMe = true ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " CommitTransaction: \n %s " , wtxNew . tx - > ToString ( ) ) ; /* Continued */
2011-06-26 19:23:24 +02:00
{
// Take key pair from key pool so it won't be used again
reservekey . KeepKey ( ) ;
// Add tx to wallet, because if it has change it's also ours,
// otherwise just for transaction history.
2016-06-08 06:41:03 +02:00
AddToWallet ( wtxNew ) ;
2011-06-26 19:23:24 +02:00
2014-02-15 22:38:28 +01:00
// Notify that old coins are spent
2017-06-02 03:18:57 +02:00
for ( const CTxIn & txin : wtxNew . tx - > vin )
2011-06-26 19:23:24 +02:00
{
2017-01-19 22:08:03 +01:00
CWalletTx & coin = mapWallet . at ( txin . prevout . hash ) ;
2011-06-28 23:45:22 +02:00
coin . BindWallet ( this ) ;
2012-05-05 16:07:14 +02:00
NotifyTransactionChanged ( this , coin . GetHash ( ) , CT_UPDATED ) ;
2011-06-26 19:23:24 +02:00
}
}
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
// Get the inserted-CWalletTx from mapWallet so that the
// fInMempool flag is cached properly
2017-01-19 22:08:03 +01:00
CWalletTx & wtx = mapWallet . at ( wtxNew . GetHash ( ) ) ;
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
2015-03-27 10:34:48 +01:00
if ( fBroadcastTransactions )
2011-06-26 19:23:24 +02:00
{
2015-03-27 10:34:48 +01:00
// Broadcast
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
if ( ! wtx . AcceptToMemoryPool ( maxTxFee , state ) ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " CommitTransaction(): Transaction cannot be broadcast immediately, %s \n " , FormatStateMessage ( state ) ) ;
2016-12-08 20:49:28 +01:00
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
wtx . RelayWalletTransaction ( connman ) ;
2015-03-27 10:34:48 +01:00
}
2011-06-26 19:23:24 +02:00
}
}
return true ;
}
2016-09-10 03:53:23 +02:00
void CWallet : : ListAccountCreditDebit ( const std : : string & strAccount , std : : list < CAccountingEntry > & entries ) {
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
return batch . ListAccountCreditDebit ( strAccount , entries ) ;
2016-09-10 03:53:23 +02:00
}
2016-09-10 04:22:59 +02:00
bool CWallet : : AddAccountingEntry ( const CAccountingEntry & acentry )
2015-10-19 11:19:38 +02:00
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2016-09-10 04:22:59 +02:00
2017-12-08 12:39:22 +01:00
return AddAccountingEntry ( acentry , & batch ) ;
2016-09-10 04:22:59 +02:00
}
2017-12-08 12:39:22 +01:00
bool CWallet : : AddAccountingEntry ( const CAccountingEntry & acentry , WalletBatch * batch )
2015-10-19 11:19:38 +02:00
{
2017-12-08 12:39:22 +01:00
if ( ! batch - > WriteAccountingEntry ( + + nAccountingEntryNumber , acentry ) ) {
2015-10-19 11:19:38 +02:00
return false ;
2017-06-06 00:23:20 +02:00
}
2015-10-19 11:19:38 +02:00
laccentries . push_back ( acentry ) ;
CAccountingEntry & entry = laccentries . back ( ) ;
2017-06-21 21:10:00 +02:00
wtxOrdered . insert ( std : : make_pair ( entry . nOrderPos , TxPair ( nullptr , & entry ) ) ) ;
2015-10-19 11:19:38 +02:00
return true ;
}
2012-09-18 20:30:47 +02:00
DBErrors CWallet : : LoadWallet ( bool & fFirstRunRet )
2011-06-26 19:23:24 +02:00
{
2017-08-24 20:12:21 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
fFirstRunRet = false ;
2017-12-08 12:39:22 +01:00
DBErrors nLoadWalletRet = WalletBatch ( * database , " cr+ " ) . LoadWallet ( this ) ;
2018-03-09 15:03:40 +01:00
if ( nLoadWalletRet = = DBErrors : : NEED_REWRITE )
2011-11-10 21:29:23 +01:00
{
2017-12-08 12:39:22 +01:00
if ( database - > Rewrite ( " \x04 pool " ) )
2011-11-11 03:12:46 +01:00
{
2017-04-19 18:55:32 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2017-07-21 19:54:13 +02:00
m_pool_key_to_index . clear ( ) ;
2011-11-11 03:12:46 +01:00
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
2015-04-08 14:24:46 +02:00
// that requires a new key.
2011-11-11 03:12:46 +01:00
}
2011-11-10 21:29:23 +01:00
}
2018-04-29 20:15:05 +02:00
{
LOCK ( cs_KeyStore ) ;
// This wallet is in its first run if all of these are empty
2017-05-05 08:53:39 +02:00
fFirstRunRet = mapKeys . empty ( ) & & mapCryptedKeys . empty ( ) & & mapWatchKeys . empty ( ) & & setWatchOnly . empty ( ) & & mapScripts . empty ( ) & & ! IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ;
2018-04-29 20:15:05 +02:00
}
2017-07-29 02:00:49 +02:00
2018-03-09 15:03:40 +01:00
if ( nLoadWalletRet ! = DBErrors : : LOAD_OK )
2011-07-05 03:06:19 +02:00
return nLoadWalletRet ;
2011-06-26 19:23:24 +02:00
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_OK ;
2011-06-26 19:23:24 +02:00
}
2017-01-27 02:33:45 +01:00
DBErrors CWallet : : ZapSelectTx ( std : : vector < uint256 > & vHashIn , std : : vector < uint256 > & vHashOut )
2016-03-07 14:51:06 +01:00
{
2016-11-12 10:53:18 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2017-12-08 12:39:22 +01:00
DBErrors nZapSelectTxRet = WalletBatch ( * database , " cr+ " ) . ZapSelectTx ( vHashIn , vHashOut ) ;
2018-06-11 20:09:16 +02:00
for ( uint256 hash : vHashOut ) {
const auto & it = mapWallet . find ( hash ) ;
wtxOrdered . erase ( it - > second . m_it_wtxOrdered ) ;
mapWallet . erase ( it ) ;
}
2016-11-12 10:53:18 +01:00
2018-03-09 15:03:40 +01:00
if ( nZapSelectTxRet = = DBErrors : : NEED_REWRITE )
2016-03-07 14:51:06 +01:00
{
2017-12-08 12:39:22 +01:00
if ( database - > Rewrite ( " \x04 pool " ) )
2016-03-07 14:51:06 +01:00
{
2017-04-19 18:55:32 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2017-07-21 19:54:13 +02:00
m_pool_key_to_index . clear ( ) ;
2016-03-07 14:51:06 +01:00
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
}
}
2018-03-09 15:03:40 +01:00
if ( nZapSelectTxRet ! = DBErrors : : LOAD_OK )
2016-03-07 14:51:06 +01:00
return nZapSelectTxRet ;
MarkDirty ( ) ;
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_OK ;
2016-03-07 14:51:06 +01:00
}
2011-07-07 15:22:54 +02:00
2014-02-14 18:27:15 +01:00
DBErrors CWallet : : ZapWalletTx ( std : : vector < CWalletTx > & vWtx )
2014-02-14 17:33:07 +01:00
{
2017-12-08 12:39:22 +01:00
DBErrors nZapWalletTxRet = WalletBatch ( * database , " cr+ " ) . ZapWalletTx ( vWtx ) ;
2018-03-09 15:03:40 +01:00
if ( nZapWalletTxRet = = DBErrors : : NEED_REWRITE )
2014-02-14 17:33:07 +01:00
{
2017-12-08 12:39:22 +01:00
if ( database - > Rewrite ( " \x04 pool " ) )
2014-02-14 17:33:07 +01:00
{
LOCK ( cs_wallet ) ;
2017-04-19 18:55:32 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2017-07-21 19:54:13 +02:00
m_pool_key_to_index . clear ( ) ;
2014-02-14 17:33:07 +01:00
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
2014-10-26 08:03:12 +01:00
// that requires a new key.
2014-02-14 17:33:07 +01:00
}
}
2018-03-09 15:03:40 +01:00
if ( nZapWalletTxRet ! = DBErrors : : LOAD_OK )
2014-02-14 17:33:07 +01:00
return nZapWalletTxRet ;
2018-03-09 15:03:40 +01:00
return DBErrors : : LOAD_OK ;
2014-02-14 17:33:07 +01:00
}
2017-01-27 02:33:45 +01:00
bool CWallet : : SetAddressBook ( const CTxDestination & address , const std : : string & strName , const std : : string & strPurpose )
2011-07-07 15:22:54 +02:00
{
2014-02-18 18:11:46 +01:00
bool fUpdated = false ;
{
LOCK ( cs_wallet ) ; // mapAddressBook
std : : map < CTxDestination , CAddressBookData > : : iterator mi = mapAddressBook . find ( address ) ;
fUpdated = mi ! = mapAddressBook . end ( ) ;
mapAddressBook [ address ] . name = strName ;
if ( ! strPurpose . empty ( ) ) /* update purpose only if requested */
mapAddressBook [ address ] . purpose = strPurpose ;
}
2014-09-06 21:59:59 +02:00
NotifyAddressBookChanged ( this , address , strName , : : IsMine ( * this , address ) ! = ISMINE_NO ,
2014-02-18 18:11:46 +01:00
strPurpose , ( fUpdated ? CT_UPDATED : CT_NEW ) ) ;
2017-12-08 12:39:22 +01:00
if ( ! strPurpose . empty ( ) & & ! WalletBatch ( * database ) . WritePurpose ( EncodeDestination ( address ) , strPurpose ) )
2013-07-22 08:50:39 +02:00
return false ;
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . WriteName ( EncodeDestination ( address ) , strName ) ;
2011-07-07 15:22:54 +02:00
}
2013-07-22 08:50:39 +02:00
bool CWallet : : DelAddressBook ( const CTxDestination & address )
2011-07-07 15:22:54 +02:00
{
2013-11-18 16:55:54 +01:00
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // mapAddressBook
2017-03-08 13:08:26 +01:00
// Delete destdata tuples associated with address
2017-08-23 03:02:33 +02:00
std : : string strAddress = EncodeDestination ( address ) ;
2018-05-16 00:41:53 +02:00
for ( const std : : pair < const std : : string , std : : string > & item : mapAddressBook [ address ] . destdata )
2013-11-18 16:55:54 +01:00
{
2017-12-08 12:39:22 +01:00
WalletBatch ( * database ) . EraseDestData ( strAddress , item . first ) ;
2013-11-18 16:55:54 +01:00
}
2014-02-18 18:11:46 +01:00
mapAddressBook . erase ( address ) ;
2013-11-18 16:55:54 +01:00
}
2014-09-06 21:59:59 +02:00
NotifyAddressBookChanged ( this , address , " " , : : IsMine ( * this , address ) ! = ISMINE_NO , " " , CT_DELETED ) ;
2014-02-18 18:11:46 +01:00
2017-12-08 12:39:22 +01:00
WalletBatch ( * database ) . ErasePurpose ( EncodeDestination ( address ) ) ;
return WalletBatch ( * database ) . EraseName ( EncodeDestination ( address ) ) ;
2011-07-07 15:22:54 +02:00
}
2017-10-20 19:27:55 +02:00
const std : : string & CWallet : : GetLabelName ( const CScript & scriptPubKey ) const
2017-01-23 15:58:42 +01:00
{
CTxDestination address ;
if ( ExtractDestination ( scriptPubKey , address ) & & ! scriptPubKey . IsUnspendable ( ) ) {
auto mi = mapAddressBook . find ( address ) ;
if ( mi ! = mapAddressBook . end ( ) ) {
return mi - > second . name ;
}
}
// A scriptPubKey that doesn't have an entry in the address book is
2017-10-20 19:27:55 +02:00
// associated with the default label ("").
const static std : : string DEFAULT_LABEL_NAME ;
return DEFAULT_LABEL_NAME ;
2017-01-23 15:58:42 +01:00
}
2014-10-26 08:03:12 +01:00
/**
* Mark old keypool keys as used ,
2017-03-28 20:11:44 +02:00
* and generate all new keys
2014-10-26 08:03:12 +01:00
*/
2011-11-17 20:01:25 +01:00
bool CWallet : : NewKeyPool ( )
{
2017-05-05 08:53:39 +02:00
if ( IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
return false ;
}
2011-11-17 20:01:25 +01:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2017-04-19 19:11:16 +02:00
for ( int64_t nIndex : setInternalKeyPool ) {
2017-12-08 12:39:22 +01:00
batch . ErasePool ( nIndex ) ;
2017-04-19 19:11:16 +02:00
}
2017-04-19 18:55:32 +02:00
setInternalKeyPool . clear ( ) ;
2017-04-19 19:11:16 +02:00
for ( int64_t nIndex : setExternalKeyPool ) {
2017-12-08 12:39:22 +01:00
batch . ErasePool ( nIndex ) ;
2017-04-19 19:11:16 +02:00
}
2017-04-19 18:55:32 +02:00
setExternalKeyPool . clear ( ) ;
2011-11-17 20:01:25 +01:00
2018-04-21 09:10:12 +02:00
for ( int64_t nIndex : set_pre_split_keypool ) {
batch . ErasePool ( nIndex ) ;
}
set_pre_split_keypool . clear ( ) ;
2017-07-21 19:54:13 +02:00
m_pool_key_to_index . clear ( ) ;
2017-01-16 08:57:31 +01:00
if ( ! TopUpKeyPool ( ) ) {
2011-11-17 20:01:25 +01:00
return false ;
}
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " CWallet::NewKeyPool rewrote keypool \n " ) ;
2011-11-17 20:01:25 +01:00
}
return true ;
}
2017-01-10 16:45:30 +01:00
size_t CWallet : : KeypoolCountExternalKeys ( )
{
2017-04-19 18:55:32 +02:00
AssertLockHeld ( cs_wallet ) ; // setExternalKeyPool
2018-04-21 09:10:12 +02:00
return setExternalKeyPool . size ( ) + set_pre_split_keypool . size ( ) ;
2017-01-10 16:45:30 +01:00
}
2017-07-26 22:37:15 +02:00
void CWallet : : LoadKeyPool ( int64_t nIndex , const CKeyPool & keypool )
{
2017-07-21 19:54:13 +02:00
AssertLockHeld ( cs_wallet ) ;
2018-04-21 09:10:12 +02:00
if ( keypool . m_pre_split ) {
set_pre_split_keypool . insert ( nIndex ) ;
} else if ( keypool . fInternal ) {
2017-07-26 22:37:15 +02:00
setInternalKeyPool . insert ( nIndex ) ;
} else {
setExternalKeyPool . insert ( nIndex ) ;
}
m_max_keypool_index = std : : max ( m_max_keypool_index , nIndex ) ;
2017-07-21 19:54:13 +02:00
m_pool_key_to_index [ keypool . vchPubKey . GetID ( ) ] = nIndex ;
2017-07-26 22:37:15 +02:00
// If no metadata exists yet, create a default with the pool key's
// creation time. Note that this may be overwritten by actually
// stored metadata for that key later, which is fine.
CKeyID keyid = keypool . vchPubKey . GetID ( ) ;
if ( mapKeyMetadata . count ( keyid ) = = 0 )
mapKeyMetadata [ keyid ] = CKeyMetadata ( keypool . nTime ) ;
}
2013-06-25 22:07:29 +02:00
bool CWallet : : TopUpKeyPool ( unsigned int kpSize )
2011-06-26 19:23:24 +02:00
{
2017-05-05 08:53:39 +02:00
if ( IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
return false ;
}
2011-06-26 19:23:24 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( IsLocked ( ) )
return false ;
2011-06-26 19:23:24 +02:00
// Top up key pool
2013-06-25 22:07:29 +02:00
unsigned int nTargetSize ;
if ( kpSize > 0 )
nTargetSize = kpSize ;
else
2017-08-01 21:17:40 +02:00
nTargetSize = std : : max ( gArgs . GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2013-06-25 22:07:29 +02:00
2017-01-10 16:45:30 +01:00
// count amount of available keys (internal, external)
2017-01-17 08:55:30 +01:00
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
2017-04-19 18:55:32 +02:00
int64_t missingExternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - ( int64_t ) setExternalKeyPool . size ( ) , ( int64_t ) 0 ) ;
int64_t missingInternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - ( int64_t ) setInternalKeyPool . size ( ) , ( int64_t ) 0 ) ;
2017-01-10 16:45:30 +01:00
if ( ! IsHDEnabled ( ) | | ! CanSupportFeature ( FEATURE_HD_SPLIT ) )
{
// don't create extra internal keys
missingInternal = 0 ;
}
bool internal = false ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2017-01-10 16:45:30 +01:00
for ( int64_t i = missingInternal + missingExternal ; i - - ; )
2011-06-26 19:23:24 +02:00
{
2017-04-19 19:11:16 +02:00
if ( i < missingInternal ) {
2017-01-10 16:45:30 +01:00
internal = true ;
2017-04-19 19:11:16 +02:00
}
2017-07-11 18:15:02 +02:00
assert ( m_max_keypool_index < std : : numeric_limits < int64_t > : : max ( ) ) ; // How in the hell did you use so many keys?
int64_t index = + + m_max_keypool_index ;
2017-04-19 18:55:32 +02:00
2017-12-08 12:39:22 +01:00
CPubKey pubkey ( GenerateNewKey ( batch , internal ) ) ;
if ( ! batch . WritePool ( index , CKeyPool ( pubkey , internal ) ) ) {
2017-01-27 02:33:45 +01:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing generated key failed " ) ;
2017-07-15 00:36:58 +02:00
}
2017-04-19 18:55:32 +02:00
if ( internal ) {
2017-07-11 18:15:02 +02:00
setInternalKeyPool . insert ( index ) ;
2017-04-19 18:55:32 +02:00
} else {
2017-07-11 18:15:02 +02:00
setExternalKeyPool . insert ( index ) ;
2017-04-19 18:55:32 +02:00
}
2017-07-21 19:54:13 +02:00
m_pool_key_to_index [ pubkey . GetID ( ) ] = index ;
2017-07-17 10:16:36 +02:00
}
if ( missingInternal + missingExternal > 0 ) {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " keypool added %d keys (%d internal), size=%u (%u internal) \n " , missingInternal + missingExternal , missingInternal , setInternalKeyPool . size ( ) + setExternalKeyPool . size ( ) + set_pre_split_keypool . size ( ) , setInternalKeyPool . size ( ) ) ;
2011-06-26 19:23:24 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
return true ;
}
2018-05-17 03:56:41 +02:00
bool CWallet : : ReserveKeyFromKeyPool ( int64_t & nIndex , CKeyPool & keypool , bool fRequestedInternal )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
keypool . vchPubKey = CPubKey ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( ! IsLocked ( ) )
TopUpKeyPool ( ) ;
2011-06-26 19:23:24 +02:00
2017-04-19 18:55:32 +02:00
bool fReturningInternal = IsHDEnabled ( ) & & CanSupportFeature ( FEATURE_HD_SPLIT ) & & fRequestedInternal ;
2018-05-17 03:56:41 +02:00
bool use_split_keypool = set_pre_split_keypool . empty ( ) ;
std : : set < int64_t > & setKeyPool = use_split_keypool ? ( fReturningInternal ? setInternalKeyPool : setExternalKeyPool ) : set_pre_split_keypool ;
2017-04-19 18:55:32 +02:00
2011-06-26 19:23:24 +02:00
// Get the oldest key
2018-05-17 03:56:41 +02:00
if ( setKeyPool . empty ( ) ) {
return false ;
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2017-04-19 18:55:32 +02:00
auto it = setKeyPool . begin ( ) ;
nIndex = * it ;
setKeyPool . erase ( it ) ;
2017-12-08 12:39:22 +01:00
if ( ! batch . ReadPool ( nIndex , keypool ) ) {
2017-04-19 18:55:32 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
2017-01-10 16:45:30 +01:00
}
2017-04-19 18:55:32 +02:00
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
}
2018-04-21 09:10:12 +02:00
// If the key was pre-split keypool, we don't care about what type it is
2018-05-17 03:56:41 +02:00
if ( use_split_keypool & & keypool . fInternal ! = fReturningInternal ) {
2017-04-19 18:55:32 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : keypool entry misclassified " ) ;
}
2018-05-17 03:56:41 +02:00
if ( ! keypool . vchPubKey . IsValid ( ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : keypool entry invalid " ) ;
}
2017-04-19 18:55:32 +02:00
2017-07-21 19:54:13 +02:00
m_pool_key_to_index . erase ( keypool . vchPubKey . GetID ( ) ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " keypool reserve %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2018-05-17 03:56:41 +02:00
return true ;
2011-06-26 19:23:24 +02:00
}
2013-04-13 07:13:08 +02:00
void CWallet : : KeepKey ( int64_t nIndex )
2011-06-26 19:23:24 +02:00
{
// Remove from key pool
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
batch . ErasePool ( nIndex ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " keypool keep %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2017-07-21 19:54:13 +02:00
void CWallet : : ReturnKey ( int64_t nIndex , bool fInternal , const CPubKey & pubkey )
2011-06-26 19:23:24 +02:00
{
// Return to key pool
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
2017-04-19 18:55:32 +02:00
if ( fInternal ) {
setInternalKeyPool . insert ( nIndex ) ;
2018-04-21 09:10:12 +02:00
} else if ( ! set_pre_split_keypool . empty ( ) ) {
set_pre_split_keypool . insert ( nIndex ) ;
2017-04-19 18:55:32 +02:00
} else {
setExternalKeyPool . insert ( nIndex ) ;
}
2017-07-21 19:54:13 +02:00
m_pool_key_to_index [ pubkey . GetID ( ) ] = nIndex ;
2012-04-06 18:39:12 +02:00
}
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " keypool return %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2017-01-10 16:45:30 +01:00
bool CWallet : : GetKeyFromPool ( CPubKey & result , bool internal )
2011-06-26 19:23:24 +02:00
{
2017-05-05 08:53:39 +02:00
if ( IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
return false ;
}
2011-06-26 19:23:24 +02:00
CKeyPool keypool ;
2011-08-12 22:32:07 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2018-05-17 03:56:41 +02:00
int64_t nIndex ;
if ( ! ReserveKeyFromKeyPool ( nIndex , keypool , internal ) ) {
2011-09-01 16:58:08 +02:00
if ( IsLocked ( ) ) return false ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
result = GenerateNewKey ( batch , internal ) ;
2011-08-12 22:32:07 +02:00
return true ;
}
2011-09-01 16:58:08 +02:00
KeepKey ( nIndex ) ;
result = keypool . vchPubKey ;
2011-08-12 22:32:07 +02:00
}
return true ;
2011-06-26 19:23:24 +02:00
}
2017-12-08 12:39:22 +01:00
static int64_t GetOldestKeyTimeInPool ( const std : : set < int64_t > & setKeyPool , WalletBatch & batch ) {
2017-04-19 18:55:32 +02:00
if ( setKeyPool . empty ( ) ) {
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return GetTime ( ) ;
2017-04-19 18:55:32 +02:00
}
2016-04-05 10:45:11 +02:00
CKeyPool keypool ;
int64_t nIndex = * ( setKeyPool . begin ( ) ) ;
2017-12-08 12:39:22 +01:00
if ( ! batch . ReadPool ( nIndex , keypool ) ) {
2017-01-27 02:33:45 +01:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : read oldest key in keypool failed " ) ;
2017-04-19 19:11:16 +02:00
}
2016-04-05 10:45:11 +02:00
assert ( keypool . vchPubKey . IsValid ( ) ) ;
2011-06-26 19:23:24 +02:00
return keypool . nTime ;
}
2017-04-19 18:55:32 +02:00
int64_t CWallet : : GetOldestKeyPoolTime ( )
{
LOCK ( cs_wallet ) ;
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2017-04-19 18:55:32 +02:00
// load oldest key from keypool, get time and return
2017-12-08 12:39:22 +01:00
int64_t oldestKey = GetOldestKeyTimeInPool ( setExternalKeyPool , batch ) ;
2017-04-19 18:55:32 +02:00
if ( IsHDEnabled ( ) & & CanSupportFeature ( FEATURE_HD_SPLIT ) ) {
2017-12-08 12:39:22 +01:00
oldestKey = std : : max ( GetOldestKeyTimeInPool ( setInternalKeyPool , batch ) , oldestKey ) ;
2018-04-21 09:10:12 +02:00
if ( ! set_pre_split_keypool . empty ( ) ) {
oldestKey = std : : max ( GetOldestKeyTimeInPool ( set_pre_split_keypool , batch ) , oldestKey ) ;
}
2017-04-19 18:55:32 +02:00
}
return oldestKey ;
}
2014-04-23 00:46:19 +02:00
std : : map < CTxDestination , CAmount > CWallet : : GetAddressBalances ( )
2012-08-01 18:48:42 +02:00
{
2017-01-27 02:33:45 +01:00
std : : map < CTxDestination , CAmount > balances ;
2012-08-01 18:48:42 +02:00
{
LOCK ( cs_wallet ) ;
2017-06-01 17:48:29 +02:00
for ( const auto & walletEntry : mapWallet )
2012-08-01 18:48:42 +02:00
{
2017-06-01 17:48:29 +02:00
const CWalletTx * pcoin = & walletEntry . second ;
2012-08-01 18:48:42 +02:00
2016-11-12 10:05:09 +01:00
if ( ! pcoin - > IsTrusted ( ) )
2012-08-01 18:48:42 +02:00
continue ;
if ( pcoin - > IsCoinBase ( ) & & pcoin - > GetBlocksToMaturity ( ) > 0 )
continue ;
int nDepth = pcoin - > GetDepthInMainChain ( ) ;
2014-07-01 11:00:22 +02:00
if ( nDepth < ( pcoin - > IsFromMe ( ISMINE_ALL ) ? 0 : 1 ) )
2012-08-01 18:48:42 +02:00
continue ;
2016-11-12 01:54:51 +01:00
for ( unsigned int i = 0 ; i < pcoin - > tx - > vout . size ( ) ; i + + )
2012-08-01 18:48:42 +02:00
{
2012-08-20 19:43:33 +02:00
CTxDestination addr ;
2016-11-12 01:54:51 +01:00
if ( ! IsMine ( pcoin - > tx - > vout [ i ] ) )
2012-08-01 18:48:42 +02:00
continue ;
2016-11-12 01:54:51 +01:00
if ( ! ExtractDestination ( pcoin - > tx - > vout [ i ] . scriptPubKey , addr ) )
2012-08-20 19:43:33 +02:00
continue ;
2012-08-01 18:48:42 +02:00
2016-11-12 01:54:51 +01:00
CAmount n = IsSpent ( walletEntry . first , i ) ? 0 : pcoin - > tx - > vout [ i ] . nValue ;
2012-08-01 18:48:42 +02:00
if ( ! balances . count ( addr ) )
balances [ addr ] = 0 ;
balances [ addr ] + = n ;
}
}
}
return balances ;
}
2017-01-27 02:33:45 +01:00
std : : set < std : : set < CTxDestination > > CWallet : : GetAddressGroupings ( )
2012-08-01 18:48:42 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2017-01-27 02:33:45 +01:00
std : : set < std : : set < CTxDestination > > groupings ;
std : : set < CTxDestination > grouping ;
2012-08-01 18:48:42 +02:00
2017-06-01 17:48:29 +02:00
for ( const auto & walletEntry : mapWallet )
2012-08-01 18:48:42 +02:00
{
2017-06-01 17:48:29 +02:00
const CWalletTx * pcoin = & walletEntry . second ;
2012-08-01 18:48:42 +02:00
2016-11-12 01:54:51 +01:00
if ( pcoin - > tx - > vin . size ( ) > 0 )
2012-08-01 18:48:42 +02:00
{
2012-09-27 19:29:35 +02:00
bool any_mine = false ;
2012-08-01 18:48:42 +02:00
// group all input addresses with each other
2017-06-02 03:18:57 +02:00
for ( CTxIn txin : pcoin - > tx - > vin )
2012-08-20 19:43:33 +02:00
{
CTxDestination address ;
2012-09-27 19:29:35 +02:00
if ( ! IsMine ( txin ) ) /* If this input isn't mine, ignore it */
continue ;
2017-01-19 22:08:03 +01:00
if ( ! ExtractDestination ( mapWallet . at ( txin . prevout . hash ) . tx - > vout [ txin . prevout . n ] . scriptPubKey , address ) )
2012-08-20 19:43:33 +02:00
continue ;
grouping . insert ( address ) ;
2012-09-27 19:29:35 +02:00
any_mine = true ;
2012-08-20 19:43:33 +02:00
}
2012-08-01 18:48:42 +02:00
// group change with input addresses
2012-09-27 19:29:35 +02:00
if ( any_mine )
{
2017-06-02 03:18:57 +02:00
for ( CTxOut txout : pcoin - > tx - > vout )
2012-09-27 19:29:35 +02:00
if ( IsChange ( txout ) )
{
CTxDestination txoutAddr ;
if ( ! ExtractDestination ( txout . scriptPubKey , txoutAddr ) )
continue ;
grouping . insert ( txoutAddr ) ;
}
}
if ( grouping . size ( ) > 0 )
{
groupings . insert ( grouping ) ;
grouping . clear ( ) ;
}
2012-08-01 18:48:42 +02:00
}
// group lone addrs by themselves
2017-05-18 09:42:14 +02:00
for ( const auto & txout : pcoin - > tx - > vout )
if ( IsMine ( txout ) )
2012-08-01 18:48:42 +02:00
{
2012-08-20 19:43:33 +02:00
CTxDestination address ;
2017-05-18 09:42:14 +02:00
if ( ! ExtractDestination ( txout . scriptPubKey , address ) )
2012-08-20 19:43:33 +02:00
continue ;
grouping . insert ( address ) ;
2012-08-01 18:48:42 +02:00
groupings . insert ( grouping ) ;
grouping . clear ( ) ;
}
}
2017-01-27 02:33:45 +01:00
std : : set < std : : set < CTxDestination > * > uniqueGroupings ; // a set of pointers to groups of addresses
std : : map < CTxDestination , std : : set < CTxDestination > * > setmap ; // map addresses to the unique group containing it
2017-06-02 03:18:57 +02:00
for ( std : : set < CTxDestination > _grouping : groupings )
2012-08-01 18:48:42 +02:00
{
// make a set of all the groups hit by this new group
2017-01-27 02:33:45 +01:00
std : : set < std : : set < CTxDestination > * > hits ;
std : : map < CTxDestination , std : : set < CTxDestination > * > : : iterator it ;
2017-06-02 03:18:57 +02:00
for ( CTxDestination address : _grouping )
2012-08-01 18:48:42 +02:00
if ( ( it = setmap . find ( address ) ) ! = setmap . end ( ) )
hits . insert ( ( * it ) . second ) ;
// merge all hit groups into a new single group and delete old groups
2017-01-27 02:33:45 +01:00
std : : set < CTxDestination > * merged = new std : : set < CTxDestination > ( _grouping ) ;
2017-06-02 03:18:57 +02:00
for ( std : : set < CTxDestination > * hit : hits )
2012-08-01 18:48:42 +02:00
{
merged - > insert ( hit - > begin ( ) , hit - > end ( ) ) ;
uniqueGroupings . erase ( hit ) ;
delete hit ;
}
uniqueGroupings . insert ( merged ) ;
// update setmap
2017-06-02 03:18:57 +02:00
for ( CTxDestination element : * merged )
2012-08-01 18:48:42 +02:00
setmap [ element ] = merged ;
}
2017-01-27 02:33:45 +01:00
std : : set < std : : set < CTxDestination > > ret ;
2017-06-02 03:18:57 +02:00
for ( std : : set < CTxDestination > * uniqueGrouping : uniqueGroupings )
2012-08-01 18:48:42 +02:00
{
ret . insert ( * uniqueGrouping ) ;
delete uniqueGrouping ;
}
return ret ;
}
2017-10-20 19:27:55 +02:00
std : : set < CTxDestination > CWallet : : GetLabelAddresses ( const std : : string & label ) const
2013-07-16 01:01:09 +02:00
{
2014-11-28 19:11:49 +01:00
LOCK ( cs_wallet ) ;
2017-01-27 02:33:45 +01:00
std : : set < CTxDestination > result ;
2018-05-16 00:41:53 +02:00
for ( const std : : pair < const CTxDestination , CAddressBookData > & item : mapAddressBook )
2013-07-16 01:01:09 +02:00
{
const CTxDestination & address = item . first ;
2017-01-27 02:33:45 +01:00
const std : : string & strName = item . second . name ;
2017-10-20 19:27:55 +02:00
if ( strName = = label )
2013-07-16 01:01:09 +02:00
result . insert ( address ) ;
}
return result ;
}
2016-03-21 16:55:02 +01:00
void CWallet : : DeleteLabel ( const std : : string & label )
{
WalletBatch batch ( * database ) ;
batch . EraseAccount ( label ) ;
}
2017-01-10 16:45:30 +01:00
bool CReserveKey : : GetReservedKey ( CPubKey & pubkey , bool internal )
2011-06-26 19:23:24 +02:00
{
if ( nIndex = = - 1 )
{
CKeyPool keypool ;
2018-05-17 03:56:41 +02:00
if ( ! pwallet - > ReserveKeyFromKeyPool ( nIndex , keypool , internal ) ) {
2014-06-16 14:45:32 +02:00
return false ;
2011-07-14 03:28:31 +02:00
}
2018-05-17 03:56:41 +02:00
vchPubKey = keypool . vchPubKey ;
2017-04-19 18:55:32 +02:00
fInternal = keypool . fInternal ;
2011-06-26 19:23:24 +02:00
}
2012-05-14 19:07:52 +02:00
assert ( vchPubKey . IsValid ( ) ) ;
2013-04-25 19:30:28 +02:00
pubkey = vchPubKey ;
return true ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : KeepKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > KeepKey ( nIndex ) ;
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
vchPubKey = CPubKey ( ) ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : ReturnKey ( )
{
2017-04-19 19:11:16 +02:00
if ( nIndex ! = - 1 ) {
2017-07-21 19:54:13 +02:00
pwallet - > ReturnKey ( nIndex , fInternal , vchPubKey ) ;
2017-04-19 19:11:16 +02:00
}
2011-06-26 19:23:24 +02:00
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
vchPubKey = CPubKey ( ) ;
2011-06-26 19:23:24 +02:00
}
2011-07-07 15:22:54 +02:00
2017-07-18 21:49:56 +02:00
void CWallet : : MarkReserveKeysAsUsed ( int64_t keypool_id )
2017-04-19 18:55:32 +02:00
{
2017-07-18 21:49:56 +02:00
AssertLockHeld ( cs_wallet ) ;
bool internal = setInternalKeyPool . count ( keypool_id ) ;
2018-04-21 09:10:12 +02:00
if ( ! internal ) assert ( setExternalKeyPool . count ( keypool_id ) | | set_pre_split_keypool . count ( keypool_id ) ) ;
std : : set < int64_t > * setKeyPool = internal ? & setInternalKeyPool : ( set_pre_split_keypool . empty ( ) ? & setExternalKeyPool : & set_pre_split_keypool ) ;
2017-07-18 21:49:56 +02:00
auto it = setKeyPool - > begin ( ) ;
2017-04-19 18:55:32 +02:00
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * database ) ;
2017-07-18 21:49:56 +02:00
while ( it ! = std : : end ( * setKeyPool ) ) {
const int64_t & index = * ( it ) ;
if ( index > keypool_id ) break ; // set*KeyPool is ordered
2017-04-19 18:55:32 +02:00
2017-07-18 21:49:56 +02:00
CKeyPool keypool ;
2017-12-08 12:39:22 +01:00
if ( batch . ReadPool ( index , keypool ) ) { //TODO: This should be unnecessary
2017-07-18 21:49:56 +02:00
m_pool_key_to_index . erase ( keypool . vchPubKey . GetID ( ) ) ;
2017-04-19 18:55:32 +02:00
}
2017-12-01 01:49:16 +01:00
LearnAllRelatedScripts ( keypool . vchPubKey ) ;
2017-12-08 12:39:22 +01:00
batch . ErasePool ( index ) ;
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " keypool index %d removed \n " , index ) ;
2017-07-18 21:49:56 +02:00
it = setKeyPool - > erase ( it ) ;
2017-04-19 18:55:32 +02:00
}
}
2017-01-19 22:15:41 +01:00
void CWallet : : GetScriptForMining ( std : : shared_ptr < CReserveScript > & script )
2015-04-10 12:49:01 +02:00
{
2017-01-19 22:15:41 +01:00
std : : shared_ptr < CReserveKey > rKey = std : : make_shared < CReserveKey > ( this ) ;
2015-04-10 12:49:01 +02:00
CPubKey pubkey ;
2015-07-01 08:32:30 +02:00
if ( ! rKey - > GetReservedKey ( pubkey ) )
2015-04-10 12:49:01 +02:00
return ;
2015-07-01 08:32:30 +02:00
script = rKey ;
script - > reserveScript = CScript ( ) < < ToByteVector ( pubkey ) < < OP_CHECKSIG ;
2015-04-10 12:49:01 +02:00
}
2016-03-30 03:04:22 +02:00
void CWallet : : LockCoin ( const COutPoint & output )
2012-09-27 19:52:09 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . insert ( output ) ;
}
2016-03-30 03:04:22 +02:00
void CWallet : : UnlockCoin ( const COutPoint & output )
2012-09-27 19:52:09 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . erase ( output ) ;
}
void CWallet : : UnlockAllCoins ( )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . clear ( ) ;
}
bool CWallet : : IsLockedCoin ( uint256 hash , unsigned int n ) const
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
COutPoint outpt ( hash , n ) ;
return ( setLockedCoins . count ( outpt ) > 0 ) ;
}
2017-04-28 20:10:21 +02:00
void CWallet : : ListLockedCoins ( std : : vector < COutPoint > & vOutpts ) const
2012-09-27 19:52:09 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
for ( std : : set < COutPoint > : : iterator it = setLockedCoins . begin ( ) ;
it ! = setLockedCoins . end ( ) ; it + + ) {
COutPoint outpt = ( * it ) ;
vOutpts . push_back ( outpt ) ;
}
}
2014-10-26 08:03:12 +01:00
/** @} */ // end of Actions
2014-08-27 17:46:30 +02:00
2016-11-08 22:55:02 +01:00
void CWallet : : GetKeyBirthTimes ( std : : map < CTxDestination , int64_t > & mapKeyBirth ) const {
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2013-04-29 19:50:40 +02:00
mapKeyBirth . clear ( ) ;
// get birth times for keys with metadata
2016-11-08 22:55:02 +01:00
for ( const auto & entry : mapKeyMetadata ) {
if ( entry . second . nCreateTime ) {
mapKeyBirth [ entry . first ] = entry . second . nCreateTime ;
}
}
2013-04-29 19:50:40 +02:00
// map in which we'll infer heights of other keys
2016-08-13 19:21:13 +02:00
CBlockIndex * pindexMax = chainActive [ std : : max ( 0 , chainActive . Height ( ) - 144 ) ] ; // the tip can be reorganized; use a 144-block safety margin
2013-04-29 19:50:40 +02:00
std : : map < CKeyID , CBlockIndex * > mapKeyFirstBlock ;
2017-07-23 23:32:57 +02:00
for ( const CKeyID & keyid : GetKeys ( ) ) {
2013-04-29 19:50:40 +02:00
if ( mapKeyBirth . count ( keyid ) = = 0 )
mapKeyFirstBlock [ keyid ] = pindexMax ;
}
// if there are no such keys, we're done
if ( mapKeyFirstBlock . empty ( ) )
return ;
// find first block that affects those keys, if there are any left
std : : vector < CKeyID > vAffected ;
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapWallet ) {
2013-04-29 19:50:40 +02:00
// iterate over all wallet transactions...
2017-06-04 22:02:43 +02:00
const CWalletTx & wtx = entry . second ;
2018-01-12 01:23:09 +01:00
CBlockIndex * pindex = LookupBlockIndex ( wtx . hashBlock ) ;
if ( pindex & & chainActive . Contains ( pindex ) ) {
2013-04-29 19:50:40 +02:00
// ... which are already in a block
2018-01-12 01:23:09 +01:00
int nHeight = pindex - > nHeight ;
2017-06-02 03:18:57 +02:00
for ( const CTxOut & txout : wtx . tx - > vout ) {
2013-04-29 19:50:40 +02:00
// iterate over all their outputs
2014-08-27 17:46:30 +02:00
CAffectedKeysVisitor ( * this , vAffected ) . Process ( txout . scriptPubKey ) ;
2017-06-02 03:18:57 +02:00
for ( const CKeyID & keyid : vAffected ) {
2013-04-29 19:50:40 +02:00
// ... and all their affected keys
std : : map < CKeyID , CBlockIndex * > : : iterator rit = mapKeyFirstBlock . find ( keyid ) ;
if ( rit ! = mapKeyFirstBlock . end ( ) & & nHeight < rit - > second - > nHeight )
2018-01-12 01:23:09 +01:00
rit - > second = pindex ;
2013-04-29 19:50:40 +02:00
}
vAffected . clear ( ) ;
}
}
}
// Extract block timestamps for those keys
2017-06-04 22:02:43 +02:00
for ( const auto & entry : mapKeyFirstBlock )
mapKeyBirth [ entry . first ] = entry . second - > GetBlockTime ( ) - TIMESTAMP_WINDOW ; // block times can be 2h off
2013-04-29 19:50:40 +02:00
}
2013-11-18 16:55:54 +01:00
2016-12-19 16:51:45 +01:00
/**
* Compute smart timestamp for a transaction being added to the wallet .
*
* Logic :
* - If sending a transaction , assign its timestamp to the current time .
* - If receiving a transaction outside a block , assign its timestamp to the
* current time .
* - If receiving a block with a future timestamp , assign all its ( not already
* known ) transactions ' timestamps to the current time .
* - If receiving a block with a past timestamp , before the most recent known
* transaction ( that we care about ) , assign all its ( not already known )
* transactions ' timestamps to the same timestamp as that most - recent - known
* transaction .
* - If receiving a block with a past timestamp , but after the most recent known
* transaction , assign all its ( not already known ) transactions ' timestamps to
* the block time .
*
* For more information see CWalletTx : : nTimeSmart ,
* https : //bitcointalk.org/?topic=54527, or
* https : //github.com/bitcoin/bitcoin/pull/1393.
*/
2016-12-16 16:00:26 +01:00
unsigned int CWallet : : ComputeTimeSmart ( const CWalletTx & wtx ) const
{
unsigned int nTimeSmart = wtx . nTimeReceived ;
2017-02-10 21:00:30 +01:00
if ( ! wtx . hashUnset ( ) ) {
2018-03-13 23:33:17 +01:00
if ( const CBlockIndex * pindex = LookupBlockIndex ( wtx . hashBlock ) ) {
2016-12-16 16:00:26 +01:00
int64_t latestNow = wtx . nTimeReceived ;
int64_t latestEntry = 0 ;
2017-02-10 21:00:30 +01:00
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
int64_t latestTolerated = latestNow + 300 ;
const TxItems & txOrdered = wtxOrdered ;
for ( auto it = txOrdered . rbegin ( ) ; it ! = txOrdered . rend ( ) ; + + it ) {
CWalletTx * const pwtx = it - > second . first ;
if ( pwtx = = & wtx ) {
continue ;
}
CAccountingEntry * const pacentry = it - > second . second ;
int64_t nSmartTime ;
if ( pwtx ) {
nSmartTime = pwtx - > nTimeSmart ;
if ( ! nSmartTime ) {
nSmartTime = pwtx - > nTimeReceived ;
2016-12-16 16:00:26 +01:00
}
2017-02-10 21:00:30 +01:00
} else {
nSmartTime = pacentry - > nTime ;
}
if ( nSmartTime < = latestTolerated ) {
latestEntry = nSmartTime ;
if ( nSmartTime > latestNow ) {
latestNow = nSmartTime ;
2016-12-16 16:00:26 +01:00
}
2017-02-10 21:00:30 +01:00
break ;
2016-12-16 16:00:26 +01:00
}
}
2018-01-12 01:23:09 +01:00
int64_t blocktime = pindex - > GetBlockTime ( ) ;
2016-12-16 16:00:26 +01:00
nTimeSmart = std : : max ( latestEntry , std : : min ( blocktime , latestNow ) ) ;
2017-02-10 21:00:30 +01:00
} else {
2018-06-16 01:02:52 +02:00
WalletLogPrintf ( " %s: found %s in block %s not in index \n " , __func__ , wtx . GetHash ( ) . ToString ( ) , wtx . hashBlock . ToString ( ) ) ;
2016-12-16 16:00:26 +01:00
}
}
return nTimeSmart ;
}
2013-11-18 16:55:54 +01:00
bool CWallet : : AddDestData ( const CTxDestination & dest , const std : : string & key , const std : : string & value )
{
2014-01-14 05:05:43 +01:00
if ( boost : : get < CNoDestination > ( & dest ) )
return false ;
2013-11-18 16:55:54 +01:00
mapAddressBook [ dest ] . destdata . insert ( std : : make_pair ( key , value ) ) ;
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . WriteDestData ( EncodeDestination ( dest ) , key , value ) ;
2013-11-18 16:55:54 +01:00
}
bool CWallet : : EraseDestData ( const CTxDestination & dest , const std : : string & key )
{
if ( ! mapAddressBook [ dest ] . destdata . erase ( key ) )
return false ;
2017-12-08 12:39:22 +01:00
return WalletBatch ( * database ) . EraseDestData ( EncodeDestination ( dest ) , key ) ;
2013-11-18 16:55:54 +01:00
}
2018-07-27 08:22:42 +02:00
void CWallet : : LoadDestData ( const CTxDestination & dest , const std : : string & key , const std : : string & value )
2013-11-18 16:55:54 +01:00
{
mapAddressBook [ dest ] . destdata . insert ( std : : make_pair ( key , value ) ) ;
}
bool CWallet : : GetDestData ( const CTxDestination & dest , const std : : string & key , std : : string * value ) const
{
std : : map < CTxDestination , CAddressBookData > : : const_iterator i = mapAddressBook . find ( dest ) ;
if ( i ! = mapAddressBook . end ( ) )
{
CAddressBookData : : StringMap : : const_iterator j = i - > second . destdata . find ( key ) ;
if ( j ! = i - > second . destdata . end ( ) )
{
if ( value )
* value = j - > second ;
return true ;
}
}
return false ;
}
2014-08-21 05:04:43 +02:00
2017-04-28 20:10:21 +02:00
std : : vector < std : : string > CWallet : : GetDestValues ( const std : : string & prefix ) const
{
LOCK ( cs_wallet ) ;
std : : vector < std : : string > values ;
for ( const auto & address : mapAddressBook ) {
for ( const auto & data : address . second . destdata ) {
if ( ! data . first . compare ( 0 , prefix . size ( ) , prefix ) ) {
values . emplace_back ( data . second ) ;
}
}
}
return values ;
}
2018-04-21 09:10:12 +02:00
void CWallet : : MarkPreSplitKeys ( )
{
WalletBatch batch ( * database ) ;
for ( auto it = setExternalKeyPool . begin ( ) ; it ! = setExternalKeyPool . end ( ) ; ) {
int64_t index = * it ;
CKeyPool keypool ;
if ( ! batch . ReadPool ( index , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read keypool entry failed " ) ;
}
keypool . m_pre_split = true ;
if ( ! batch . WritePool ( index , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : writing modified keypool entry failed " ) ;
}
set_pre_split_keypool . insert ( index ) ;
it = setExternalKeyPool . erase ( it ) ;
}
}
2018-04-18 20:17:09 +02:00
bool CWallet : : Verify ( std : : string wallet_file , bool salvage_wallet , std : : string & error_string , std : : string & warning_string )
2018-04-18 19:11:28 +02:00
{
// Do some checking on wallet path. It should be either a:
//
// 1. Path where a directory can be created.
// 2. Path to an existing directory.
// 3. Path to a symlink to a directory.
// 4. For backwards compatibility, the name of a data file in -walletdir.
LOCK ( cs_wallets ) ;
fs : : path wallet_path = fs : : absolute ( wallet_file , GetWalletDir ( ) ) ;
fs : : file_type path_type = fs : : symlink_status ( wallet_path ) . type ( ) ;
if ( ! ( path_type = = fs : : file_not_found | | path_type = = fs : : directory_file | |
( path_type = = fs : : symlink_file & & fs : : is_directory ( wallet_path ) ) | |
( path_type = = fs : : regular_file & & fs : : path ( wallet_file ) . filename ( ) = = wallet_file ) ) ) {
2018-04-18 20:17:09 +02:00
error_string = strprintf (
" Invalid -wallet path '%s'. -wallet path should point to a directory where wallet.dat and "
2018-04-18 19:11:28 +02:00
" database/log.?????????? files can be stored, a location where such a directory could be created, "
2018-04-18 20:17:09 +02:00
" or (for backwards compatibility) the name of an existing data file in -walletdir (%s) " ,
wallet_file , GetWalletDir ( ) ) ;
return false ;
2018-04-18 19:11:28 +02:00
}
// Make sure that the wallet path doesn't clash with an existing wallet path
for ( auto wallet : GetWallets ( ) ) {
if ( fs : : absolute ( wallet - > GetName ( ) , GetWalletDir ( ) ) = = wallet_path ) {
2018-04-18 20:17:09 +02:00
error_string = strprintf ( " Error loading wallet %s. Duplicate -wallet filename specified. " , wallet_file ) ;
return false ;
2018-04-18 19:11:28 +02:00
}
}
2018-08-04 18:14:28 +02:00
try {
if ( ! WalletBatch : : VerifyEnvironment ( wallet_path , error_string ) ) {
return false ;
}
} catch ( const fs : : filesystem_error & e ) {
error_string = strprintf ( " Error loading wallet %s. %s " , wallet_file , e . what ( ) ) ;
2018-04-18 20:17:09 +02:00
return false ;
2018-04-18 19:11:28 +02:00
}
if ( salvage_wallet ) {
// Recover readable keypairs:
CWallet dummyWallet ( " dummy " , WalletDatabase : : CreateDummy ( ) ) ;
std : : string backup_filename ;
if ( ! WalletBatch : : Recover ( wallet_path , ( void * ) & dummyWallet , WalletBatch : : RecoverKeysOnlyFilter , backup_filename ) ) {
return false ;
}
}
2018-04-18 20:17:09 +02:00
return WalletBatch : : VerifyDatabaseFile ( wallet_path , warning_string , error_string ) ;
2018-04-18 19:11:28 +02:00
}
2017-05-05 08:53:39 +02:00
std : : shared_ptr < CWallet > CWallet : : CreateWalletFromFile ( const std : : string & name , const fs : : path & path , uint64_t wallet_creation_flags )
2016-02-22 12:07:55 +01:00
{
2017-11-14 03:25:46 +01:00
const std : : string & walletFile = name ;
2016-02-22 12:07:55 +01:00
// needed to restore wallet transaction meta data after -zapwallettxes
std : : vector < CWalletTx > vWtx ;
2017-08-01 21:17:40 +02:00
if ( gArgs . GetBoolArg ( " -zapwallettxes " , false ) ) {
2016-02-22 12:07:55 +01:00
uiInterface . InitMessage ( _ ( " Zapping all transactions from wallet... " ) ) ;
2017-12-08 12:39:22 +01:00
std : : unique_ptr < CWallet > tempWallet = MakeUnique < CWallet > ( name , WalletDatabase : : Create ( path ) ) ;
2016-02-22 12:07:55 +01:00
DBErrors nZapWalletRet = tempWallet - > ZapWalletTx ( vWtx ) ;
2018-03-09 15:03:40 +01:00
if ( nZapWalletRet ! = DBErrors : : LOAD_OK ) {
2016-09-09 10:44:47 +02:00
InitError ( strprintf ( _ ( " Error loading %s: Wallet corrupted " ) , walletFile ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-02-22 12:07:55 +01:00
}
}
2018-08-08 16:42:13 +02:00
uiInterface . InitMessage ( _ ( " Loading wallet... " ) ) ;
2016-02-22 12:07:55 +01:00
int64_t nStart = GetTimeMillis ( ) ;
bool fFirstRun = true ;
2018-04-28 23:36:43 +02:00
// TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared.
std : : shared_ptr < CWallet > walletInstance ( new CWallet ( name , WalletDatabase : : Create ( path ) ) , ReleaseWallet ) ;
2016-02-22 12:07:55 +01:00
DBErrors nLoadWalletRet = walletInstance - > LoadWallet ( fFirstRun ) ;
2018-03-09 15:03:40 +01:00
if ( nLoadWalletRet ! = DBErrors : : LOAD_OK )
2016-02-22 12:07:55 +01:00
{
2018-03-09 15:03:40 +01:00
if ( nLoadWalletRet = = DBErrors : : CORRUPT ) {
2016-09-09 10:44:47 +02:00
InitError ( strprintf ( _ ( " Error loading %s: Wallet corrupted " ) , walletFile ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
2018-03-09 15:03:40 +01:00
else if ( nLoadWalletRet = = DBErrors : : NONCRITICAL_ERROR )
2016-02-22 12:07:55 +01:00
{
2016-03-21 18:29:17 +01:00
InitWarning ( strprintf ( _ ( " Error reading %s! All keys read correctly, but transaction data "
2016-02-26 12:48:53 +01:00
" or address book entries might be missing or incorrect. " ) ,
2016-03-15 10:30:37 +01:00
walletFile ) ) ;
2016-02-22 12:07:55 +01:00
}
2018-03-09 15:03:40 +01:00
else if ( nLoadWalletRet = = DBErrors : : TOO_NEW ) {
2016-09-09 10:44:47 +02:00
InitError ( strprintf ( _ ( " Error loading %s: Wallet requires newer version of %s " ) , walletFile , _ ( PACKAGE_NAME ) ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
2018-03-09 15:03:40 +01:00
else if ( nLoadWalletRet = = DBErrors : : NEED_REWRITE )
2016-02-22 12:07:55 +01:00
{
2016-09-09 10:44:47 +02:00
InitError ( strprintf ( _ ( " Wallet needed to be rewritten: restart %s to complete " ) , _ ( PACKAGE_NAME ) ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
else {
InitError ( strprintf ( _ ( " Error loading %s " ) , walletFile ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-02-22 12:07:55 +01:00
}
}
2018-04-21 09:10:12 +02:00
int prev_version = walletInstance - > nWalletVersion ;
2017-08-01 21:17:40 +02:00
if ( gArgs . GetBoolArg ( " -upgradewallet " , fFirstRun ) )
2016-02-22 12:07:55 +01:00
{
2017-08-01 21:17:40 +02:00
int nMaxVersion = gArgs . GetArg ( " -upgradewallet " , 0 ) ;
2016-02-22 12:07:55 +01:00
if ( nMaxVersion = = 0 ) // the -upgradewallet without argument case
{
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " Performing wallet upgrade to %i \n " , FEATURE_LATEST ) ;
2018-06-19 00:21:32 +02:00
nMaxVersion = FEATURE_LATEST ;
2016-02-22 12:07:55 +01:00
walletInstance - > SetMinVersion ( FEATURE_LATEST ) ; // permanently upgrade the wallet immediately
}
else
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " Allowing wallet upgrade up to %i \n " , nMaxVersion ) ;
2016-02-22 12:07:55 +01:00
if ( nMaxVersion < walletInstance - > GetVersion ( ) )
2016-03-05 22:08:10 +01:00
{
2016-09-09 10:44:47 +02:00
InitError ( _ ( " Cannot downgrade wallet " ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-03-05 22:08:10 +01:00
}
2016-02-22 12:07:55 +01:00
walletInstance - > SetMaxVersion ( nMaxVersion ) ;
}
2018-03-31 19:37:27 +02:00
// Upgrade to HD if explicit upgrade
if ( gArgs . GetBoolArg ( " -upgradewallet " , false ) ) {
LOCK ( walletInstance - > cs_wallet ) ;
2018-04-28 05:32:59 +02:00
// Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT
int max_version = walletInstance - > nWalletVersion ;
if ( ! walletInstance - > CanSupportFeature ( FEATURE_HD_SPLIT ) & & max_version > = FEATURE_HD_SPLIT & & max_version < FEATURE_PRE_SPLIT_KEYPOOL ) {
InitError ( _ ( " Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified. " ) ) ;
return nullptr ;
}
2018-03-31 19:37:27 +02:00
bool hd_upgrade = false ;
2018-04-21 09:10:12 +02:00
bool split_upgrade = false ;
2018-03-31 19:37:27 +02:00
if ( walletInstance - > CanSupportFeature ( FEATURE_HD ) & & ! walletInstance - > IsHDEnabled ( ) ) {
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " Upgrading wallet to HD \n " ) ;
2018-03-31 19:37:27 +02:00
walletInstance - > SetMinVersion ( FEATURE_HD ) ;
// generate a new master key
2018-04-04 17:43:45 +02:00
CPubKey masterPubKey = walletInstance - > GenerateNewSeed ( ) ;
2018-07-27 08:22:42 +02:00
walletInstance - > SetHDSeed ( masterPubKey ) ;
2018-03-31 19:37:27 +02:00
hd_upgrade = true ;
}
// Upgrade to HD chain split if necessary
if ( walletInstance - > CanSupportFeature ( FEATURE_HD_SPLIT ) ) {
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " Upgrading wallet to use HD chain split \n " ) ;
2018-04-28 05:32:59 +02:00
walletInstance - > SetMinVersion ( FEATURE_PRE_SPLIT_KEYPOOL ) ;
2018-04-21 09:10:12 +02:00
split_upgrade = FEATURE_HD_SPLIT > prev_version ;
}
// Mark all keys currently in the keypool as pre-split
if ( split_upgrade ) {
walletInstance - > MarkPreSplitKeys ( ) ;
2018-03-31 19:37:27 +02:00
}
// Regenerate the keypool if upgraded to HD
if ( hd_upgrade ) {
2018-04-21 09:10:12 +02:00
if ( ! walletInstance - > TopUpKeyPool ( ) ) {
2018-07-27 00:07:37 +02:00
InitError ( _ ( " Unable to generate keys " ) ) ;
2018-03-31 19:37:27 +02:00
return nullptr ;
}
}
}
2016-02-22 12:07:55 +01:00
if ( fFirstRun )
{
2017-09-06 00:54:11 +02:00
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
2017-09-12 12:44:23 +02:00
if ( ! gArgs . GetBoolArg ( " -usehd " , true ) ) {
InitError ( strprintf ( _ ( " Error creating %s: You can't create non-HD wallets with this version. " ) , walletFile ) ) ;
return nullptr ;
}
2018-03-31 19:37:27 +02:00
walletInstance - > SetMinVersion ( FEATURE_LATEST ) ;
2017-03-24 10:53:35 +01:00
2017-05-05 08:53:39 +02:00
if ( ( wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
//selective allow to set flags
walletInstance - > SetWalletFlag ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ;
} else {
// generate a new seed
CPubKey seed = walletInstance - > GenerateNewSeed ( ) ;
2018-07-27 08:22:42 +02:00
walletInstance - > SetHDSeed ( seed ) ;
2017-05-05 08:53:39 +02:00
}
2017-07-29 02:00:49 +02:00
// Top up the keypool
2017-05-05 08:53:39 +02:00
if ( ! walletInstance - > IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) & & ! walletInstance - > TopUpKeyPool ( ) ) {
2018-07-27 00:07:37 +02:00
InitError ( _ ( " Unable to generate initial keys " ) ) ;
2017-10-09 14:26:53 +02:00
return nullptr ;
2016-02-22 12:07:55 +01:00
}
2018-04-27 20:01:02 +02:00
walletInstance - > ChainStateFlushed ( chainActive . GetLocator ( ) ) ;
2017-05-05 08:53:39 +02:00
} else if ( wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS ) {
// Make it impossible to disable private keys after creation
InitError ( strprintf ( _ ( " Error loading %s: Private keys can only be disabled during creation " ) , walletFile ) ) ;
return NULL ;
} else if ( walletInstance - > IsWalletFlagSet ( WALLET_FLAG_DISABLE_PRIVATE_KEYS ) ) {
LOCK ( walletInstance - > cs_KeyStore ) ;
if ( ! walletInstance - > mapKeys . empty ( ) | | ! walletInstance - > mapCryptedKeys . empty ( ) ) {
InitWarning ( strprintf ( _ ( " Warning: Private keys detected in wallet {%s} with disabled private keys " ) , walletFile ) ) ;
}
2018-02-11 03:06:35 +01:00
} else if ( gArgs . IsArgSet ( " -usehd " ) ) {
2017-09-12 12:44:23 +02:00
bool useHD = gArgs . GetBoolArg ( " -usehd " , true ) ;
2016-09-09 10:44:47 +02:00
if ( walletInstance - > IsHDEnabled ( ) & & ! useHD ) {
2017-09-12 12:44:23 +02:00
InitError ( strprintf ( _ ( " Error loading %s: You can't disable HD on an already existing HD wallet " ) , walletFile ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
if ( ! walletInstance - > IsHDEnabled ( ) & & useHD ) {
2017-06-20 00:57:31 +02:00
InitError ( strprintf ( _ ( " Error loading %s: You can't enable HD on an already existing non-HD wallet " ) , walletFile ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
2016-06-13 16:27:41 +02:00
}
2016-02-22 12:07:55 +01:00
2018-03-19 20:57:11 +01:00
if ( ! gArgs . GetArg ( " -addresstype " , " " ) . empty ( ) & & ! ParseOutputType ( gArgs . GetArg ( " -addresstype " , " " ) , walletInstance - > m_default_address_type ) ) {
2018-02-11 03:06:35 +01:00
InitError ( strprintf ( " Unknown address type '%s' " , gArgs . GetArg ( " -addresstype " , " " ) ) ) ;
return nullptr ;
}
2018-03-19 20:57:11 +01:00
if ( ! gArgs . GetArg ( " -changetype " , " " ) . empty ( ) & & ! ParseOutputType ( gArgs . GetArg ( " -changetype " , " " ) , walletInstance - > m_default_change_type ) ) {
2018-02-11 03:06:35 +01:00
InitError ( strprintf ( " Unknown change type '%s' " , gArgs . GetArg ( " -changetype " , " " ) ) ) ;
return nullptr ;
}
2018-04-07 18:12:46 +02:00
if ( gArgs . IsArgSet ( " -mintxfee " ) ) {
CAmount n = 0 ;
if ( ! ParseMoney ( gArgs . GetArg ( " -mintxfee " , " " ) , n ) | | 0 = = n ) {
InitError ( AmountErrMsg ( " mintxfee " , gArgs . GetArg ( " -mintxfee " , " " ) ) ) ;
return nullptr ;
}
if ( n > HIGH_TX_FEE_PER_KB ) {
InitWarning ( AmountHighWarn ( " -mintxfee " ) + " " +
_ ( " This is the minimum transaction fee you pay on every transaction. " ) ) ;
}
walletInstance - > m_min_fee = CFeeRate ( n ) ;
}
walletInstance - > m_allow_fallback_fee = Params ( ) . IsFallbackFeeEnabled ( ) ;
if ( gArgs . IsArgSet ( " -fallbackfee " ) ) {
CAmount nFeePerK = 0 ;
if ( ! ParseMoney ( gArgs . GetArg ( " -fallbackfee " , " " ) , nFeePerK ) ) {
InitError ( strprintf ( _ ( " Invalid amount for -fallbackfee=<amount>: '%s' " ) , gArgs . GetArg ( " -fallbackfee " , " " ) ) ) ;
return nullptr ;
}
if ( nFeePerK > HIGH_TX_FEE_PER_KB ) {
InitWarning ( AmountHighWarn ( " -fallbackfee " ) + " " +
_ ( " This is the transaction fee you may pay when fee estimates are not available. " ) ) ;
}
walletInstance - > m_fallback_fee = CFeeRate ( nFeePerK ) ;
walletInstance - > m_allow_fallback_fee = nFeePerK ! = 0 ; //disable fallback fee in case value was set to 0, enable if non-null value
}
if ( gArgs . IsArgSet ( " -discardfee " ) ) {
CAmount nFeePerK = 0 ;
if ( ! ParseMoney ( gArgs . GetArg ( " -discardfee " , " " ) , nFeePerK ) ) {
InitError ( strprintf ( _ ( " Invalid amount for -discardfee=<amount>: '%s' " ) , gArgs . GetArg ( " -discardfee " , " " ) ) ) ;
return nullptr ;
}
if ( nFeePerK > HIGH_TX_FEE_PER_KB ) {
InitWarning ( AmountHighWarn ( " -discardfee " ) + " " +
_ ( " This is the transaction fee you may discard if change is smaller than dust at this level " ) ) ;
}
walletInstance - > m_discard_rate = CFeeRate ( nFeePerK ) ;
}
if ( gArgs . IsArgSet ( " -paytxfee " ) ) {
CAmount nFeePerK = 0 ;
if ( ! ParseMoney ( gArgs . GetArg ( " -paytxfee " , " " ) , nFeePerK ) ) {
InitError ( AmountErrMsg ( " paytxfee " , gArgs . GetArg ( " -paytxfee " , " " ) ) ) ;
return nullptr ;
}
if ( nFeePerK > HIGH_TX_FEE_PER_KB ) {
InitWarning ( AmountHighWarn ( " -paytxfee " ) + " " +
_ ( " This is the transaction fee you will pay if you send a transaction. " ) ) ;
}
walletInstance - > m_pay_tx_fee = CFeeRate ( nFeePerK , 1000 ) ;
if ( walletInstance - > m_pay_tx_fee < : : minRelayTxFee ) {
InitError ( strprintf ( _ ( " Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) " ) ,
gArgs . GetArg ( " -paytxfee " , " " ) , : : minRelayTxFee . ToString ( ) ) ) ;
return nullptr ;
}
}
walletInstance - > m_confirm_target = gArgs . GetArg ( " -txconfirmtarget " , DEFAULT_TX_CONFIRM_TARGET ) ;
walletInstance - > m_spend_zero_conf_change = gArgs . GetBoolArg ( " -spendzeroconfchange " , DEFAULT_SPEND_ZEROCONF_CHANGE ) ;
walletInstance - > m_signal_rbf = gArgs . GetBoolArg ( " -walletrbf " , DEFAULT_WALLET_RBF ) ;
2018-08-08 16:42:13 +02:00
walletInstance - > WalletLogPrintf ( " Wallet completed loading in %15dms \n " , GetTimeMillis ( ) - nStart ) ;
2016-02-22 12:07:55 +01:00
2017-07-18 21:49:56 +02:00
// Try to top up keypool. No-op if the wallet is locked.
walletInstance - > TopUpKeyPool ( ) ;
2018-01-12 01:56:27 +01:00
LOCK ( cs_main ) ;
2017-01-18 17:59:10 +01:00
CBlockIndex * pindexRescan = chainActive . Genesis ( ) ;
2017-08-01 21:17:40 +02:00
if ( ! gArgs . GetBoolArg ( " -rescan " , false ) )
2016-02-22 12:07:55 +01:00
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * walletInstance - > database ) ;
2016-02-22 12:07:55 +01:00
CBlockLocator locator ;
2017-12-08 12:39:22 +01:00
if ( batch . ReadBestBlock ( locator ) )
2016-02-22 12:07:55 +01:00
pindexRescan = FindForkInGlobalIndex ( chainActive , locator ) ;
}
2017-01-18 00:06:16 +01:00
walletInstance - > m_last_block_processed = chainActive . Tip ( ) ;
2016-02-22 12:07:55 +01:00
if ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexRescan )
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
2017-06-20 00:57:31 +02:00
//this might happen if a user uses an old wallet within a pruned node
2016-02-22 12:07:55 +01:00
// or if he ran -disablewallet for a longer time, then decided to re-enable
if ( fPruneMode )
{
CBlockIndex * block = chainActive . Tip ( ) ;
while ( block & & block - > pprev & & ( block - > pprev - > nStatus & BLOCK_HAVE_DATA ) & & block - > pprev - > nTx > 0 & & pindexRescan ! = block )
block = block - > pprev ;
2016-09-09 10:44:47 +02:00
if ( pindexRescan ! = block ) {
InitError ( _ ( " Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node) " ) ) ;
2017-08-07 07:36:37 +02:00
return nullptr ;
2016-09-09 10:44:47 +02:00
}
2016-02-22 12:07:55 +01:00
}
uiInterface . InitMessage ( _ ( " Rescanning... " ) ) ;
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " Rescanning last %i blocks (from block %i)... \n " , chainActive . Height ( ) - pindexRescan - > nHeight , pindexRescan - > nHeight ) ;
2017-03-02 22:14:39 +01:00
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
while ( pindexRescan & & walletInstance - > nTimeFirstKey & & ( pindexRescan - > GetBlockTime ( ) < ( walletInstance - > nTimeFirstKey - TIMESTAMP_WINDOW ) ) ) {
pindexRescan = chainActive . Next ( pindexRescan ) ;
}
2016-02-22 12:07:55 +01:00
nStart = GetTimeMillis ( ) ;
2017-12-13 00:13:58 +01:00
{
2018-05-22 17:18:07 +02:00
WalletRescanReserver reserver ( walletInstance . get ( ) ) ;
2017-12-13 00:13:58 +01:00
if ( ! reserver . reserve ( ) ) {
InitError ( _ ( " Failed to rescan the wallet during initialization " ) ) ;
return nullptr ;
}
walletInstance - > ScanForWalletTransactions ( pindexRescan , nullptr , reserver , true ) ;
}
2018-08-08 16:42:13 +02:00
walletInstance - > WalletLogPrintf ( " Rescan completed in %15dms \n " , GetTimeMillis ( ) - nStart ) ;
2018-04-27 20:01:02 +02:00
walletInstance - > ChainStateFlushed ( chainActive . GetLocator ( ) ) ;
2017-12-08 12:39:22 +01:00
walletInstance - > database - > IncrementUpdateCounter ( ) ;
2016-02-22 12:07:55 +01:00
// Restore wallet transaction metadata after -zapwallettxes=1
2017-08-01 21:17:40 +02:00
if ( gArgs . GetBoolArg ( " -zapwallettxes " , false ) & & gArgs . GetArg ( " -zapwallettxes " , " 1 " ) ! = " 2 " )
2016-02-22 12:07:55 +01:00
{
2017-12-08 12:39:22 +01:00
WalletBatch batch ( * walletInstance - > database ) ;
2016-02-22 12:07:55 +01:00
2017-06-02 03:18:57 +02:00
for ( const CWalletTx & wtxOld : vWtx )
2016-02-22 12:07:55 +01:00
{
uint256 hash = wtxOld . GetHash ( ) ;
std : : map < uint256 , CWalletTx > : : iterator mi = walletInstance - > mapWallet . find ( hash ) ;
if ( mi ! = walletInstance - > mapWallet . end ( ) )
{
const CWalletTx * copyFrom = & wtxOld ;
CWalletTx * copyTo = & mi - > second ;
copyTo - > mapValue = copyFrom - > mapValue ;
copyTo - > vOrderForm = copyFrom - > vOrderForm ;
copyTo - > nTimeReceived = copyFrom - > nTimeReceived ;
copyTo - > nTimeSmart = copyFrom - > nTimeSmart ;
copyTo - > fFromMe = copyFrom - > fFromMe ;
copyTo - > strFromAccount = copyFrom - > strFromAccount ;
copyTo - > nOrderPos = copyFrom - > nOrderPos ;
2017-12-08 12:39:22 +01:00
batch . WriteTx ( * copyTo ) ;
2016-02-22 12:07:55 +01:00
}
}
}
}
2018-05-07 23:08:03 +02:00
2018-06-19 21:33:13 +02:00
uiInterface . LoadWallet ( walletInstance ) ;
2018-05-07 23:08:03 +02:00
// Register with the validation interface. It's ok to do this after rescan since we're still holding cs_main.
2018-05-22 17:18:07 +02:00
RegisterValidationInterface ( walletInstance . get ( ) ) ;
2018-05-07 23:08:03 +02:00
2017-08-01 21:17:40 +02:00
walletInstance - > SetBroadcastTransactions ( gArgs . GetBoolArg ( " -walletbroadcast " , DEFAULT_WALLETBROADCAST ) ) ;
2016-02-22 12:07:55 +01:00
2016-08-20 00:50:48 +02:00
{
LOCK ( walletInstance - > cs_wallet ) ;
2018-06-16 01:02:52 +02:00
walletInstance - > WalletLogPrintf ( " setKeyPool.size() = %u \n " , walletInstance - > GetKeyPoolSize ( ) ) ;
walletInstance - > WalletLogPrintf ( " mapWallet.size() = %u \n " , walletInstance - > mapWallet . size ( ) ) ;
walletInstance - > WalletLogPrintf ( " mapAddressBook.size() = %u \n " , walletInstance - > mapAddressBook . size ( ) ) ;
2016-08-20 00:50:48 +02:00
}
2016-09-09 10:44:47 +02:00
return walletInstance ;
}
2018-04-19 23:42:40 +02:00
void CWallet : : postInitProcess ( )
2016-10-20 09:22:13 +02:00
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions ( ) ;
}
2016-05-17 02:31:16 +02:00
bool CWallet : : BackupWallet ( const std : : string & strDest )
{
2017-12-08 12:39:22 +01:00
return database - > Backup ( strDest ) ;
2016-05-17 02:31:16 +02:00
}
2014-08-21 05:04:43 +02:00
CKeyPool : : CKeyPool ( )
{
nTime = GetTime ( ) ;
2017-01-16 11:10:12 +01:00
fInternal = false ;
2018-04-21 09:10:12 +02:00
m_pre_split = false ;
2014-08-21 05:04:43 +02:00
}
2017-01-10 16:45:30 +01:00
CKeyPool : : CKeyPool ( const CPubKey & vchPubKeyIn , bool internalIn )
2014-08-21 05:04:43 +02:00
{
nTime = GetTime ( ) ;
vchPubKey = vchPubKeyIn ;
2017-01-10 16:45:30 +01:00
fInternal = internalIn ;
2018-04-21 09:10:12 +02:00
m_pre_split = false ;
2014-08-21 05:04:43 +02:00
}
CWalletKey : : CWalletKey ( int64_t nExpires )
{
nTimeCreated = ( nExpires ? GetTime ( ) : 0 ) ;
nTimeExpires = nExpires ;
}
2014-08-28 17:15:21 +02:00
2016-12-30 10:35:43 +01:00
void CMerkleTx : : SetMerkleBranch ( const CBlockIndex * pindex , int posInBlock )
2014-08-28 17:15:21 +02:00
{
2014-08-29 20:24:16 +02:00
// Update the tx's hashBlock
2016-04-26 13:55:13 +02:00
hashBlock = pindex - > GetBlockHash ( ) ;
2014-08-28 17:15:21 +02:00
2016-04-26 13:55:13 +02:00
// set the position of the transaction in the block
nIndex = posInBlock ;
2014-08-28 17:15:21 +02:00
}
2018-07-11 06:22:10 +02:00
int CMerkleTx : : GetDepthInMainChain ( ) const
2014-08-28 17:15:21 +02:00
{
2016-01-07 22:31:27 +01:00
if ( hashUnset ( ) )
2014-08-28 17:15:21 +02:00
return 0 ;
2016-01-07 22:31:27 +01:00
2014-08-28 17:15:21 +02:00
AssertLockHeld ( cs_main ) ;
// Find the block it claims to be in
2018-01-12 01:23:09 +01:00
CBlockIndex * pindex = LookupBlockIndex ( hashBlock ) ;
2014-08-28 17:15:21 +02:00
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
return 0 ;
2015-11-26 18:42:07 +01:00
return ( ( nIndex = = - 1 ) ? ( - 1 ) : 1 ) * ( chainActive . Height ( ) - pindex - > nHeight + 1 ) ;
2014-08-28 17:15:21 +02:00
}
int CMerkleTx : : GetBlocksToMaturity ( ) const
{
if ( ! IsCoinBase ( ) )
return 0 ;
2018-07-13 18:41:42 +02:00
int chain_depth = GetDepthInMainChain ( ) ;
assert ( chain_depth > = 0 ) ; // coinbase tx should not be conflicted
return std : : max ( 0 , ( COINBASE_MATURITY + 1 ) - chain_depth ) ;
2014-08-28 17:15:21 +02:00
}
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
bool CWalletTx : : AcceptToMemoryPool ( const CAmount & nAbsurdFee , CValidationState & state )
2014-08-28 17:15:21 +02:00
{
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
// We must set fInMempool here - while it will be re-set to true by the
// entered-mempool callback, if we did not there would be a race where a
// user could call sendmoney in a loop and hit spurious out of funds errors
2018-03-18 15:26:45 +01:00
// because we think that this newly generated transaction's change is
// unavailable as we're not yet aware that it is in the mempool.
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
bool ret = : : AcceptToMemoryPool ( mempool , state , tx , nullptr /* pfMissingInputs */ ,
2017-09-12 18:30:26 +02:00
nullptr /* plTxnReplaced */ , false /* bypass_limits */ , nAbsurdFee ) ;
2017-12-11 16:38:16 +01:00
fInMempool | = ret ;
Use callbacks to cache whether wallet transactions are in mempool
This avoid calling out to mempool state during coin selection,
balance calculation, etc. In the next commit we ensure all wallet
callbacks from CValidationInterface happen in the same queue,
serialized with each other. This helps to avoid re-introducing one
of the issues described in #9584 [1] by further disconnecting
wallet from current chain/mempool state.
Thanks to @morcos for the suggestion to do this.
Note that there are several race conditions introduced here:
* If a user calls sendrawtransaction from RPC, adding a
transaction which is "trusted" (ie from them) and pays them
change, it may not be immediately used by coin selection until
the notification callbacks finish running. No such race is
introduced in normal transaction-sending RPCs as this case is
explicitly handled.
* Until Block{Connected,Disconnected} and
TransactionAddedToMempool calls also run in the CSceduler
background thread, there is a race where
TransactionAddedToMempool might be called after a
Block{Connected,Disconnected} call happens.
* Wallet will write a new best chain from the SetBestChain
callback prior to having processed the transaction from that
block.
[1] "you could go to select coins, need to use 0-conf change, but
such 0-conf change may have been included in a block who's
callbacks have not yet been processed - resulting in thinking they
are not in mempool and, thus, not selectable."
2017-01-20 22:38:07 +01:00
return ret ;
2014-08-28 17:15:21 +02:00
}
2017-12-01 01:49:11 +01:00
void CWallet : : LearnRelatedScripts ( const CPubKey & key , OutputType type )
{
2018-02-11 03:06:35 +01:00
if ( key . IsCompressed ( ) & & ( type = = OutputType : : P2SH_SEGWIT | | type = = OutputType : : BECH32 ) ) {
2017-12-01 01:49:11 +01:00
CTxDestination witdest = WitnessV0KeyHash ( key . GetID ( ) ) ;
CScript witprog = GetScriptForDestination ( witdest ) ;
// Make sure the resulting program is solvable.
assert ( IsSolvable ( * this , witprog ) ) ;
AddCScript ( witprog ) ;
}
}
void CWallet : : LearnAllRelatedScripts ( const CPubKey & key )
{
2018-02-11 03:06:35 +01:00
// OutputType::P2SH_SEGWIT always adds all necessary scripts for all types.
LearnRelatedScripts ( key , OutputType : : P2SH_SEGWIT ) ;
2017-12-01 01:49:11 +01:00
}
2018-07-19 04:43:03 +02:00
std : : vector < OutputGroup > CWallet : : GroupOutputs ( const std : : vector < COutput > & outputs , bool single_coin ) const {
std : : vector < OutputGroup > groups ;
std : : map < CTxDestination , OutputGroup > gmap ;
CTxDestination dst ;
for ( const auto & output : outputs ) {
if ( output . fSpendable ) {
CInputCoin input_coin = output . GetInputCoin ( ) ;
size_t ancestors , descendants ;
mempool . GetTransactionAncestry ( output . tx - > GetHash ( ) , ancestors , descendants ) ;
if ( ! single_coin & & ExtractDestination ( output . tx - > tx - > vout [ output . i ] . scriptPubKey , dst ) ) {
2018-07-30 16:43:16 +02:00
// Limit output groups to no more than 10 entries, to protect
// against inadvertently creating a too-large transaction
// when using -avoidpartialspends
2018-07-30 18:50:43 +02:00
if ( gmap [ dst ] . m_outputs . size ( ) > = OUTPUT_GROUP_MAX_ENTRIES ) {
2018-07-19 04:43:03 +02:00
groups . push_back ( gmap [ dst ] ) ;
gmap . erase ( dst ) ;
}
gmap [ dst ] . Insert ( input_coin , output . nDepth , output . tx - > IsFromMe ( ISMINE_ALL ) , ancestors , descendants ) ;
} else {
groups . emplace_back ( input_coin , output . nDepth , output . tx - > IsFromMe ( ISMINE_ALL ) , ancestors , descendants ) ;
}
}
}
if ( ! single_coin ) {
for ( const auto & it : gmap ) groups . push_back ( it . second ) ;
}
return groups ;
}