2011-08-09 13:27:58 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2015-12-13 14:51:43 +01:00
// Copyright (c) 2009-2015 The Bitcoin Core developers
2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash 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
2015-02-03 21:09:47 +01:00
# include "wallet/wallet.h"
2013-04-13 07:13:08 +02:00
2012-05-14 23:44:52 +02:00
# include "base58.h"
2014-05-05 20:54:00 +02:00
# include "checkpoints.h"
2015-07-05 14:17:46 +02:00
# include "chain.h"
2016-10-21 15:30:14 +02:00
# include "wallet/coincontrol.h"
2015-01-24 15:29:29 +01:00
# include "consensus/consensus.h"
2015-01-24 15:57:12 +01:00
# include "consensus/validation.h"
2015-07-05 14:30:07 +02:00
# include "key.h"
# include "keystore.h"
2017-08-09 02:19:06 +02:00
# include "validation.h"
2013-11-16 17:37:31 +01:00
# include "net.h"
2015-06-24 07:25:30 +02:00
# include "policy/policy.h"
2015-07-05 14:30:07 +02:00
# include "primitives/block.h"
# include "primitives/transaction.h"
2014-08-27 17:22:33 +02:00
# include "script/script.h"
# include "script/sign.h"
2014-06-19 15:08:37 +02:00
# include "timedata.h"
2015-07-05 14:17:46 +02:00
# include "txmempool.h"
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
# include "util.h"
2016-04-19 16:10:39 +02:00
# include "ui_interface.h"
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
# include "utilmoneystr.h"
2013-04-13 07:13:08 +02:00
2016-12-20 14:27:59 +01:00
# include "governance.h"
# include "instantx.h"
# include "keepass.h"
2017-05-05 13:26:27 +02:00
# include "privatesend-client.h"
2016-12-20 14:27:59 +01:00
# include "spork.h"
2014-10-01 08:50:24 +02:00
# include <assert.h>
2013-04-13 07:13:08 +02:00
2012-11-03 15:58:41 +01:00
# include <boost/algorithm/string/replace.hpp>
2015-02-04 21:19:27 +01:00
# include <boost/filesystem.hpp>
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
# include <boost/thread.hpp>
2011-06-26 19:23:24 +02:00
2014-12-06 20:41:53 +01:00
2011-06-26 19:23:24 +02:00
using namespace std ;
2016-04-02 11:06:56 +02:00
CWallet * pwalletMain = NULL ;
2015-12-19 14:27:15 +01:00
/** Transaction fee set by the user */
2014-04-10 20:14:18 +02:00
CFeeRate payTxFee ( DEFAULT_TRANSACTION_FEE ) ;
2015-05-18 08:51:16 +02:00
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET ;
2015-11-09 19:16:38 +01:00
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE ;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS ;
2011-06-26 19:23:24 +02:00
2016-03-11 08:37:26 +01:00
const char * DEFAULT_WALLET_DAT = " wallet.dat " ;
2014-10-26 08:03:12 +01:00
/**
2015-06-23 17:02:46 +02:00
* Fees smaller than this ( in duffs ) are considered zero fee ( for transaction creation )
2014-10-26 08:03:12 +01:00
* Override with - mintxfee
*/
2017-12-07 10:43:23 +01:00
CFeeRate CWallet : : minTxFee = CFeeRate ( DEFAULT_TRANSACTION_MINFEE ) ;
2016-01-05 19:10:19 +01:00
/**
* If fee estimation does not have enough data to provide estimates , use this fee instead .
* Has no effect if not using fee estimation
* Override with - fallbackfee
*/
2017-12-07 10:43:23 +01:00
CFeeRate CWallet : : fallbackFee = CFeeRate ( DEFAULT_FALLBACK_FEE ) ;
2014-07-03 20:25:32 +02:00
2016-01-07 22:31:12 +01:00
const uint256 CMerkleTx : : ABANDON_HASH ( uint256S ( " 0000000000000000000000000000000000000000000000000000000000000001 " ) ) ;
2011-06-26 19:23:24 +02:00
2014-10-26 08:03:12 +01:00
/** @defgroup mapWallet
*
* @ {
*/
2011-06-26 19:23:24 +02:00
2012-04-07 21:45:39 +02:00
struct CompareValueOnly
{
2014-04-23 00:46:19 +02:00
bool operator ( ) ( const pair < CAmount , pair < const CWalletTx * , unsigned int > > & t1 ,
const pair < CAmount , pair < const CWalletTx * , unsigned int > > & t2 ) const
2012-04-07 21:45:39 +02:00
{
return t1 . first < t2 . first ;
}
} ;
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-12-05 08:01:20 +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
}
2016-02-02 16:28:56 +01:00
int COutput : : Priority ( ) const
{
2017-06-30 20:30:16 +02:00
BOOST_FOREACH ( CAmount d , CPrivateSend : : GetStandardDenominations ( ) )
2016-12-05 08:01:20 +01:00
if ( tx - > tx - > vout [ i ] . nValue = = d ) return 10000 ;
if ( tx - > tx - > vout [ i ] . nValue < 1 * COIN ) return 20000 ;
2016-02-02 16:28:56 +01:00
//nondenom return largest first
2016-12-05 08:01:20 +01:00
return - ( tx - > tx - > vout [ i ] . nValue / COIN ) ;
2016-02-02 16:28:56 +01: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 ( ) )
return NULL ;
return & ( it - > second ) ;
}
2017-05-29 13:51:40 +02:00
CPubKey CWallet : : GenerateNewKey ( uint32_t nAccountIndex , bool fInternal )
2012-02-18 15:02:36 +01:00
{
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 ;
2013-06-20 01:13:55 +02:00
// Create new metadata
2013-04-13 07:13:08 +02:00
int64_t nCreationTime = GetTime ( ) ;
2017-05-29 13:51:40 +02:00
CKeyMetadata metadata ( nCreationTime ) ;
CPubKey pubkey ;
// use HD key derivation if HD was enabled during wallet creation
if ( IsHDEnabled ( ) ) {
DeriveNewChildKey ( metadata , secret , nAccountIndex , fInternal ) ;
pubkey = secret . GetPubKey ( ) ;
} else {
secret . MakeNewKey ( fCompressed ) ;
// Compressed public keys were introduced in version 0.6.0
if ( fCompressed )
SetMinVersion ( FEATURE_COMPRPUBKEY ) ;
pubkey = secret . GetPubKey ( ) ;
assert ( secret . VerifyPubKey ( pubkey ) ) ;
2013-06-20 01:13:55 +02:00
2017-05-29 13:51:40 +02:00
// Create new metadata
mapKeyMetadata [ pubkey . GetID ( ) ] = metadata ;
if ( ! nTimeFirstKey | | nCreationTime < nTimeFirstKey )
nTimeFirstKey = nCreationTime ;
if ( ! AddKeyPubKey ( secret , pubkey ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : AddKey failed " ) ;
}
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-05-29 13:51:40 +02:00
void CWallet : : DeriveNewChildKey ( const CKeyMetadata & metadata , CKey & secretRet , uint32_t nAccountIndex , bool fInternal )
{
CHDChain hdChainTmp ;
if ( ! GetHDChain ( hdChainTmp ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : GetHDChain failed " ) ;
}
if ( ! DecryptHDChain ( hdChainTmp ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : DecryptHDChainSeed failed " ) ;
// make sure seed matches this chain
if ( hdChainTmp . GetID ( ) ! = hdChainTmp . GetSeedHash ( ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : Wrong HD chain! " ) ;
CHDAccount acc ;
if ( ! hdChainTmp . GetAccount ( nAccountIndex , acc ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : Wrong HD account! " ) ;
// derive child key at next index, skip keys already known to the wallet
CExtKey childKey ;
uint32_t nChildIndex = fInternal ? acc . nInternalChainCounter : acc . nExternalChainCounter ;
do {
hdChainTmp . DeriveChildExtKey ( nAccountIndex , fInternal , nChildIndex , childKey ) ;
// increment childkey index
nChildIndex + + ;
} while ( HaveKey ( childKey . key . GetPubKey ( ) . GetID ( ) ) ) ;
secretRet = childKey . key ;
CPubKey pubkey = secretRet . GetPubKey ( ) ;
assert ( secretRet . VerifyPubKey ( pubkey ) ) ;
// store metadata
mapKeyMetadata [ pubkey . GetID ( ) ] = metadata ;
if ( ! nTimeFirstKey | | metadata . nCreateTime < nTimeFirstKey )
nTimeFirstKey = metadata . nCreateTime ;
// update the chain model in the database
CHDChain hdChainCurrent ;
GetHDChain ( hdChainCurrent ) ;
if ( fInternal ) {
acc . nInternalChainCounter = nChildIndex ;
}
else {
acc . nExternalChainCounter = nChildIndex ;
}
if ( ! hdChainCurrent . SetAccount ( nAccountIndex , acc ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetAccount failed " ) ;
if ( IsCrypted ( ) ) {
if ( ! SetCryptedHDChain ( hdChainCurrent , false ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetCryptedHDChain failed " ) ;
}
else {
if ( ! SetHDChain ( hdChainCurrent , false ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetHDChain failed " ) ;
}
if ( ! AddHDPubKey ( childKey . Neuter ( ) , fInternal ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : AddHDPubKey failed " ) ;
}
bool CWallet : : GetPubKey ( const CKeyID & address , CPubKey & vchPubKeyOut ) const
{
LOCK ( cs_wallet ) ;
std : : map < CKeyID , CHDPubKey > : : const_iterator mi = mapHdPubKeys . find ( address ) ;
if ( mi ! = mapHdPubKeys . end ( ) )
{
const CHDPubKey & hdPubKey = ( * mi ) . second ;
vchPubKeyOut = hdPubKey . extPubKey . pubkey ;
return true ;
}
else
return CCryptoKeyStore : : GetPubKey ( address , vchPubKeyOut ) ;
}
bool CWallet : : GetKey ( const CKeyID & address , CKey & keyOut ) const
{
LOCK ( cs_wallet ) ;
std : : map < CKeyID , CHDPubKey > : : const_iterator mi = mapHdPubKeys . find ( address ) ;
if ( mi ! = mapHdPubKeys . end ( ) )
{
// if the key has been found in mapHdPubKeys, derive it on the fly
const CHDPubKey & hdPubKey = ( * mi ) . second ;
CHDChain hdChainCurrent ;
if ( ! GetHDChain ( hdChainCurrent ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : GetHDChain failed " ) ;
if ( ! DecryptHDChain ( hdChainCurrent ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : DecryptHDChainSeed failed " ) ;
// make sure seed matches this chain
if ( hdChainCurrent . GetID ( ) ! = hdChainCurrent . GetSeedHash ( ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : Wrong HD chain! " ) ;
CExtKey extkey ;
hdChainCurrent . DeriveChildExtKey ( hdPubKey . nAccountIndex , hdPubKey . nChangeIndex ! = 0 , hdPubKey . extPubKey . nChild , extkey ) ;
keyOut = extkey . key ;
return true ;
}
else {
return CCryptoKeyStore : : GetKey ( address , keyOut ) ;
}
}
bool CWallet : : HaveKey ( const CKeyID & address ) const
{
LOCK ( cs_wallet ) ;
if ( mapHdPubKeys . count ( address ) > 0 )
return true ;
return CCryptoKeyStore : : HaveKey ( address ) ;
}
bool CWallet : : LoadHDPubKey ( const CHDPubKey & hdPubKey )
{
AssertLockHeld ( cs_wallet ) ;
mapHdPubKeys [ hdPubKey . extPubKey . pubkey . GetID ( ) ] = hdPubKey ;
return true ;
}
bool CWallet : : AddHDPubKey ( const CExtPubKey & extPubKey , bool fInternal )
{
AssertLockHeld ( cs_wallet ) ;
CHDChain hdChainCurrent ;
GetHDChain ( hdChainCurrent ) ;
CHDPubKey hdPubKey ;
hdPubKey . extPubKey = extPubKey ;
hdPubKey . hdchainID = hdChainCurrent . GetID ( ) ;
hdPubKey . nChangeIndex = fInternal ? 1 : 0 ;
mapHdPubKeys [ extPubKey . pubkey . GetID ( ) ] = hdPubKey ;
// check if we need to remove from watch-only
CScript script ;
script = GetScriptForDestination ( extPubKey . pubkey . GetID ( ) ) ;
if ( HaveWatchOnly ( script ) )
RemoveWatchOnly ( script ) ;
script = GetScriptForRawPubKey ( extPubKey . pubkey ) ;
if ( HaveWatchOnly ( script ) )
RemoveWatchOnly ( script ) ;
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . WriteHDPubKey ( hdPubKey , mapKeyMetadata [ extPubKey . pubkey . GetID ( ) ] ) ;
}
2013-06-20 01:13:55 +02:00
bool CWallet : : AddKeyPubKey ( 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
2013-05-01 06:52:05 +02:00
if ( ! CCryptoKeyStore : : AddKeyPubKey ( secret , pubkey ) )
2011-06-25 14:57:32 +02:00
return false ;
2014-07-26 21:05:11 +02:00
// check if we need to remove from watch-only
CScript script ;
script = GetScriptForDestination ( pubkey . GetID ( ) ) ;
2015-06-10 09:03:08 +02:00
if ( HaveWatchOnly ( script ) )
RemoveWatchOnly ( script ) ;
script = GetScriptForRawPubKey ( pubkey ) ;
2014-07-26 21:05:11 +02:00
if ( HaveWatchOnly ( script ) )
RemoveWatchOnly ( script ) ;
2011-06-26 19:23:24 +02:00
if ( ! fFileBacked )
return true ;
2013-05-01 06:52:05 +02:00
if ( ! IsCrypted ( ) ) {
2013-06-10 15:36:29 +02:00
return CWalletDB ( strWalletFile ) . WriteKey ( pubkey ,
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
}
2013-06-10 15:36:29 +02:00
bool CWallet : : AddCryptedKey ( const CPubKey & vchPubKey ,
2013-06-20 01:13:55 +02:00
const 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 ;
if ( ! fFileBacked )
return true ;
2011-07-08 15:08:27 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-07-08 15:08:27 +02:00
if ( pwalletdbEncryption )
2013-06-10 15:36:29 +02:00
return pwalletdbEncryption - > WriteCryptedKey ( vchPubKey ,
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
else
2013-06-10 15:36:29 +02:00
return CWalletDB ( strWalletFile ) . WriteCryptedKey ( vchPubKey ,
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
}
2011-10-10 21:51:07 +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
}
2013-06-20 01:13:55 +02:00
bool CWallet : : LoadKeyMetadata ( const CPubKey & pubkey , const CKeyMetadata & meta )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2013-06-20 01:13:55 +02:00
if ( meta . nCreateTime & & ( ! nTimeFirstKey | | meta . nCreateTime < nTimeFirstKey ) )
nTimeFirstKey = meta . nCreateTime ;
mapKeyMetadata [ pubkey . GetID ( ) ] = meta ;
return true ;
}
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 ) ;
}
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 ;
if ( ! fFileBacked )
return true ;
2012-01-05 03:40:52 +01:00
return CWalletDB ( strWalletFile ) . 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 )
{
2014-09-25 04:24:46 +02:00
std : : string strAddr = CBitcoinAddress ( CScriptID ( redeemScript ) ) . ToString ( ) ;
2014-06-10 09:42:42 +02:00
LogPrintf ( " %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 ) ;
return true ;
}
return CCryptoKeyStore : : AddCScript ( redeemScript ) ;
}
2014-06-09 21:11:59 +02:00
bool CWallet : : AddWatchOnly ( const CScript & dest )
2013-07-26 01:06:01 +02:00
{
if ( ! CCryptoKeyStore : : AddWatchOnly ( dest ) )
return false ;
nTimeFirstKey = 1 ; // No birthday information for watch-only keys.
2014-07-26 21:05:11 +02:00
NotifyWatchonlyChanged ( true ) ;
2013-07-26 01:06:01 +02:00
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . WriteWatchOnly ( dest ) ;
}
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 ) ;
if ( fFileBacked )
if ( ! CWalletDB ( strWalletFile ) . EraseWatchOnly ( dest ) )
return false ;
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 ) ;
}
2016-09-11 11:02:54 +02:00
bool CWallet : : Unlock ( const SecureString & strWalletPassphrase , bool fForMixingOnly )
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
{
2014-12-26 12:53:29 +01:00
SecureString strWalletPassphraseFinal ;
2016-09-11 11:02:54 +02:00
if ( ! IsLocked ( ) ) // was already fully unlocked, not only for mixing
2014-12-09 02:17:57 +01:00
return true ;
2014-12-26 12:53:29 +01:00
// Verify KeePassIntegration
2016-08-23 13:27:04 +02:00
if ( strWalletPassphrase = = " keepass " & & GetBoolArg ( " -keepass " , false ) ) {
2014-12-26 12:53:29 +01:00
try {
strWalletPassphraseFinal = keePassInt . retrievePassphrase ( ) ;
} catch ( std : : exception & e ) {
LogPrintf ( " CWallet::Unlock could not retrieve passphrase from KeePass: Error: %s \n " , e . what ( ) ) ;
return false ;
}
} else {
strWalletPassphraseFinal = strWalletPassphrase ;
}
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
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 ) ;
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
BOOST_FOREACH ( const MasterKeyMap : : value_type & pMasterKey , mapMasterKeys )
{
2016-08-23 13:27:04 +02:00
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphraseFinal , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
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 ;
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , vMasterKey ) )
2013-05-07 16:47:00 +02:00
continue ; // try another master key
2016-09-11 11:02:54 +02:00
if ( CCryptoKeyStore : : Unlock ( vMasterKey , fForMixingOnly ) ) {
2016-06-15 21:13:04 +02:00
if ( nWalletBackups = = - 2 ) {
TopUpKeyPool ( ) ;
LogPrintf ( " Keypool replenished, re-initializing automatic backups. \n " ) ;
nWalletBackups = GetArg ( " -createwalletbackups " , 10 ) ;
}
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 ;
2014-12-09 02:17:57 +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
}
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
{
2016-09-11 11:02:54 +02:00
bool fWasLocked = IsLocked ( true ) ;
2014-12-26 12:53:29 +01:00
bool bUseKeePass = false ;
SecureString strOldWalletPassphraseFinal ;
// Verify KeePassIntegration
if ( strOldWalletPassphrase = = " keepass " & & GetBoolArg ( " -keepass " , false ) ) {
bUseKeePass = true ;
try {
strOldWalletPassphraseFinal = keePassInt . retrievePassphrase ( ) ;
} catch ( std : : exception & e ) {
2016-08-23 13:27:04 +02:00
LogPrintf ( " CWallet::ChangeWalletPassphrase -- could not retrieve passphrase from KeePass: Error: %s \n " , e . what ( ) ) ;
2014-12-26 12:53:29 +01:00
return false ;
}
} else {
strOldWalletPassphraseFinal = strOldWalletPassphrase ;
}
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 ;
CKeyingMaterial vMasterKey ;
BOOST_FOREACH ( MasterKeyMap : : value_type & pMasterKey , mapMasterKeys )
{
2014-12-26 12:53:29 +01:00
if ( ! crypter . SetKeyFromPassphrase ( strOldWalletPassphraseFinal , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
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-08-26 20:37:23 +02: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 ;
if ( CCryptoKeyStore : : Unlock ( vMasterKey ) )
{
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 ) ;
pMasterKey . second . nDeriveIterations = pMasterKey . second . nDeriveIterations * ( 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ;
nStartTime = GetTimeMillis ( ) ;
crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) ;
pMasterKey . second . nDeriveIterations = ( pMasterKey . second . nDeriveIterations + pMasterKey . second . nDeriveIterations * 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) / 2 ;
if ( pMasterKey . second . nDeriveIterations < 25000 )
pMasterKey . second . nDeriveIterations = 25000 ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " 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 ;
if ( ! crypter . Encrypt ( vMasterKey , pMasterKey . second . vchCryptedKey ) )
return false ;
CWalletDB ( strWalletFile ) . WriteMasterKey ( pMasterKey . first , pMasterKey . second ) ;
if ( fWasLocked )
Lock ( ) ;
2014-12-26 12:53:29 +01:00
// Update KeePass if necessary
if ( bUseKeePass ) {
2016-08-23 13:27:04 +02:00
LogPrintf ( " CWallet::ChangeWalletPassphrase -- Updating KeePass with new passphrase " ) ;
2014-12-26 12:53:29 +01:00
try {
keePassInt . updatePassphrase ( strNewWalletPassphrase ) ;
} catch ( std : : exception & e ) {
2016-08-23 13:27:04 +02:00
LogPrintf ( " CWallet::ChangeWalletPassphrase -- could not update passphrase in KeePass: Error: %s \n " , e . what ( ) ) ;
2014-12-26 12:53:29 +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
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 ;
}
2012-04-15 22:10:54 +02:00
void CWallet : : SetBestChain ( const CBlockLocator & loc )
{
CWalletDB walletdb ( strWalletFile ) ;
walletdb . WriteBestBlock ( loc ) ;
}
2011-07-10 16:07:22 +02:00
2012-03-22 03:56:31 +01:00
bool CWallet : : SetMinVersion ( enum WalletFeature nVersion , CWalletDB * pwalletdbIn , 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 )
return true ;
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
if ( fFileBacked )
{
CWalletDB * pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB ( strWalletFile ) ;
if ( nWalletVersion > 40000 )
pwalletdb - > WriteMinVersion ( nWalletVersion ) ;
if ( ! pwalletdbIn )
delete pwalletdb ;
}
return true ;
}
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 ;
}
2014-02-14 02:12:51 +01:00
set < uint256 > CWallet : : GetConflicts ( const uint256 & txid ) const
{
set < uint256 > result ;
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
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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-27 13:25:42 +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 ;
}
2015-02-04 21:19:27 +01:00
void CWallet : : Flush ( bool shutdown )
{
bitdb . Flush ( shutdown ) ;
}
2016-04-02 11:06:56 +02:00
bool CWallet : : Verify ( )
{
2016-09-21 12:27:47 +02:00
if ( GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) )
return true ;
2016-05-10 15:15:40 +02:00
LogPrintf ( " Using BerkeleyDB version %s \n " , DbEnv : : version ( 0 , 0 , 0 ) ) ;
2016-04-02 11:06:56 +02:00
std : : string walletFile = GetArg ( " -wallet " , DEFAULT_WALLET_DAT ) ;
LogPrintf ( " Using wallet %s \n " , walletFile ) ;
uiInterface . InitMessage ( _ ( " Verifying wallet... " ) ) ;
// Wallet file must be a plain filename without a directory
if ( walletFile ! = boost : : filesystem : : basename ( walletFile ) + boost : : filesystem : : extension ( walletFile ) )
2016-04-19 16:10:39 +02:00
return InitError ( strprintf ( _ ( " Wallet %s resides outside data directory %s " ) , walletFile , GetDataDir ( ) . string ( ) ) ) ;
2016-04-02 11:06:56 +02:00
2015-02-04 21:19:27 +01:00
if ( ! bitdb . Open ( GetDataDir ( ) ) )
{
// try moving the database env out of the way
boost : : filesystem : : path pathDatabase = GetDataDir ( ) / " database " ;
boost : : filesystem : : path pathDatabaseBak = GetDataDir ( ) / strprintf ( " database.%d.bak " , GetTime ( ) ) ;
try {
boost : : filesystem : : rename ( pathDatabase , pathDatabaseBak ) ;
LogPrintf ( " Moved old %s to %s. Retrying. \n " , pathDatabase . string ( ) , pathDatabaseBak . string ( ) ) ;
} catch ( const boost : : filesystem : : filesystem_error & ) {
// failure is ok (well, not really, but it's not worse than what we started with)
}
// try again
if ( ! bitdb . Open ( GetDataDir ( ) ) ) {
// if it still fails, it probably means we can't even create the database env
2016-04-19 16:10:39 +02:00
return InitError ( strprintf ( _ ( " Error initializing wallet database environment %s! " ) , GetDataDir ( ) ) ) ;
2015-02-04 21:19:27 +01:00
}
}
if ( GetBoolArg ( " -salvagewallet " , false ) )
{
// Recover readable keypairs:
if ( ! CWalletDB : : Recover ( bitdb , walletFile , true ) )
return false ;
}
if ( boost : : filesystem : : exists ( GetDataDir ( ) / walletFile ) )
{
CDBEnv : : VerifyResult r = bitdb . Verify ( walletFile , CWalletDB : : Recover ) ;
if ( r = = CDBEnv : : RECOVER_OK )
{
2016-04-19 16:10:39 +02:00
InitWarning ( strprintf ( _ ( " Warning: Wallet file corrupt, data salvaged! "
2016-03-14 13:54:28 +01:00
" Original %s saved as %s in %s; if "
" your balance or transactions are incorrect you should "
" restore from a backup. " ) ,
2016-04-02 11:06:56 +02:00
walletFile , " wallet.{timestamp}.bak " , GetDataDir ( ) ) ) ;
2015-02-04 21:19:27 +01:00
}
if ( r = = CDBEnv : : RECOVER_FAIL )
2016-04-19 16:10:39 +02:00
return InitError ( strprintf ( _ ( " %s corrupt, salvage failed " ) , walletFile ) ) ;
2015-02-04 21:19:27 +01:00
}
return true ;
}
2014-02-15 22:38:28 +01:00
void CWallet : : SyncMetaData ( 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 ( ) ;
const CWalletTx * copyFrom = NULL ;
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 ;
int n = mapWallet [ hash ] . nOrderPos ;
if ( n < nMinOrderPos )
{
nMinOrderPos = n ;
copyFrom = & mapWallet [ hash ] ;
}
}
// 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 ;
CWalletTx * copyTo = & mapWallet [ hash ] ;
if ( copyFrom = = copyTo ) continue ;
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 ) ;
pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range ;
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:12 +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 )
{
mapTxSpends . insert ( make_pair ( outpoint , wtxid ) ) ;
2017-09-27 19:43:16 +02:00
setWalletUTXO . erase ( outpoint ) ;
2014-02-15 22:38:28 +01:00
pair < TxSpends : : iterator , TxSpends : : iterator > range ;
range = mapTxSpends . equal_range ( outpoint ) ;
SyncMetaData ( range ) ;
}
void CWallet : : AddToSpends ( const uint256 & wtxid )
{
assert ( mapWallet . count ( wtxid ) ) ;
CWalletTx & thisTx = mapWallet [ wtxid ] ;
if ( thisTx . IsCoinBase ( ) ) // Coinbases don't spend anything!
return ;
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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
2011-08-26 20:37:23 +02: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
2011-08-26 20:37:23 +02:00
vMasterKey . resize ( WALLET_CRYPTO_KEY_SIZE ) ;
2016-05-30 15:46:16 +02:00
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-05-30 15:46:16 +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 ) ;
kMasterKey . nDeriveIterations = 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 ) ;
kMasterKey . nDeriveIterations = ( kMasterKey . nDeriveIterations + 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
2013-09-18 12:38:08 +02:00
LogPrintf ( " 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 ;
if ( ! crypter . Encrypt ( vMasterKey , kMasterKey . vchCryptedKey ) )
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 ;
if ( fFileBacked )
{
2014-09-28 16:11:17 +02:00
assert ( ! pwalletdbEncryption ) ;
2011-07-08 15:08:27 +02:00
pwalletdbEncryption = new CWalletDB ( strWalletFile ) ;
2014-09-28 16:11:17 +02:00
if ( ! pwalletdbEncryption - > TxnBegin ( ) ) {
delete pwalletdbEncryption ;
pwalletdbEncryption = NULL ;
2012-05-14 07:11:11 +02:00
return false ;
2014-09-28 16:11:17 +02:00
}
2011-07-08 15:08:27 +02:00
pwalletdbEncryption - > 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
}
2017-05-29 13:51:40 +02:00
// must get current HD chain before EncryptKeys
CHDChain hdChainCurrent ;
GetHDChain ( hdChainCurrent ) ;
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 ( ! EncryptKeys ( vMasterKey ) )
2011-07-08 15:08:27 +02:00
{
2014-09-28 16:11:17 +02:00
if ( fFileBacked ) {
2011-07-08 15:08:27 +02:00
pwalletdbEncryption - > TxnAbort ( ) ;
2014-09-28 16:11:17 +02:00
delete pwalletdbEncryption ;
}
// 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
}
2017-05-29 13:51:40 +02:00
if ( ! hdChainCurrent . IsNull ( ) ) {
assert ( EncryptHDChain ( vMasterKey ) ) ;
CHDChain hdChainCrypted ;
assert ( GetHDChain ( hdChainCrypted ) ) ;
DBG (
printf ( " EncryptWallet -- current seed: '%s' \n " , HexStr ( hdChainCurrent . GetSeed ( ) ) . c_str ( ) ) ;
printf ( " EncryptWallet -- crypted seed: '%s' \n " , HexStr ( hdChainCrypted . GetSeed ( ) ) . c_str ( ) ) ;
) ;
// ids should match, seed hashes should not
assert ( hdChainCurrent . GetID ( ) = = hdChainCrypted . GetID ( ) ) ;
assert ( hdChainCurrent . GetSeedHash ( ) ! = hdChainCrypted . GetSeedHash ( ) ) ;
assert ( SetCryptedHDChain ( hdChainCrypted , false ) ) ;
}
2012-02-18 14:55:02 +01:00
// Encryption was introduced in version 0.4.0
2012-03-22 03:56:31 +01:00
SetMinVersion ( FEATURE_WALLETCRYPT , pwalletdbEncryption , true ) ;
2012-02-18 14:55:02 +01:00
2011-07-08 15:08:27 +02:00
if ( fFileBacked )
{
2014-09-28 16:11:17 +02:00
if ( ! pwalletdbEncryption - > TxnCommit ( ) ) {
delete pwalletdbEncryption ;
2014-10-26 08:03:12 +01:00
// We now have keys encrypted in memory, but not on disk...
2015-04-28 16:48:28 +02:00
// die to avoid confusion and let the user reload the unencrypted wallet.
2014-10-01 08:50:24 +02:00
assert ( false ) ;
2014-09-28 16:11:17 +02:00
}
2011-07-08 15:08:27 +02:00
2012-02-18 15:36:40 +01:00
delete pwalletdbEncryption ;
2011-07-08 15:08:27 +02:00
pwalletdbEncryption = NULL ;
}
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-11-17 20:01:25 +01:00
Lock ( ) ;
Unlock ( strWalletPassphrase ) ;
2017-05-29 13:51:40 +02:00
// if we are not using HD, generate new keypool
if ( IsHDEnabled ( ) ) {
TopUpKeyPool ( ) ;
}
else {
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.
2011-11-20 16:39:01 +01:00
CDB : : Rewrite ( strWalletFile ) ;
2012-05-05 16:07:14 +02:00
2014-12-26 12:53:29 +01:00
// Update KeePass if necessary
if ( GetBoolArg ( " -keepass " , false ) ) {
2016-08-23 13:27:04 +02:00
LogPrintf ( " CWallet::EncryptWallet -- Updating KeePass with new passphrase " ) ;
2014-12-26 12:53:29 +01:00
try {
keePassInt . updatePassphrase ( strWalletPassphrase ) ;
} catch ( std : : exception & e ) {
2016-08-23 13:27:04 +02:00
LogPrintf ( " CWallet::EncryptWallet -- could not update passphrase in KeePass: Error: %s \n " , e . what ( ) ) ;
2014-12-26 12:53:29 +01: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-20 12:46:59 +02:00
DBErrors CWallet : : ReorderTransactions ( )
{
2016-11-02 15:37:22 +01:00
LOCK ( cs_wallet ) ;
2016-09-20 12:46:59 +02:00
CWalletDB walletdb ( strWalletFile ) ;
2016-11-02 15:37:22 +01: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.
typedef pair < CWalletTx * , CAccountingEntry * > TxPair ;
typedef multimap < int64_t , TxPair > TxItems ;
TxItems txByTime ;
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
CWalletTx * wtx = & ( ( * it ) . second ) ;
txByTime . insert ( make_pair ( wtx - > nTimeReceived , TxPair ( wtx , ( CAccountingEntry * ) 0 ) ) ) ;
}
list < CAccountingEntry > acentries ;
walletdb . ListAccountCreditDebit ( " " , acentries ) ;
BOOST_FOREACH ( CAccountingEntry & entry , acentries )
{
txByTime . insert ( make_pair ( entry . nTime , TxPair ( ( CWalletTx * ) 0 , & entry ) ) ) ;
}
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 ;
int64_t & nOrderPos = ( pwtx ! = 0 ) ? pwtx - > nOrderPos : pacentry - > nOrderPos ;
if ( nOrderPos = = - 1 )
{
nOrderPos = nOrderPosNext + + ;
nOrderPosOffsets . push_back ( nOrderPos ) ;
if ( pwtx )
{
if ( ! walletdb . WriteTx ( * pwtx ) )
return DB_LOAD_FAIL ;
}
else
if ( ! walletdb . WriteAccountingEntry ( pacentry - > nEntryNo , * pacentry ) )
return DB_LOAD_FAIL ;
}
else
{
int64_t nOrderPosOff = 0 ;
BOOST_FOREACH ( const int64_t & nOffsetStart , nOrderPosOffsets )
{
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 )
{
if ( ! walletdb . WriteTx ( * pwtx ) )
return DB_LOAD_FAIL ;
}
else
if ( ! walletdb . WriteAccountingEntry ( pacentry - > nEntryNo , * pacentry ) )
return DB_LOAD_FAIL ;
}
}
walletdb . WriteOrderPosNext ( nOrderPosNext ) ;
return DB_LOAD_OK ;
2016-09-20 12:46:59 +02:00
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : IncOrderPosNext ( CWalletDB * pwalletdb )
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 + + ;
2012-11-13 23:52:37 +01:00
if ( pwalletdb ) {
pwalletdb - > WriteOrderPosNext ( nOrderPosNext ) ;
} else {
CWalletDB ( strWalletFile ) . WriteOrderPosNext ( nOrderPosNext ) ;
}
2012-09-08 06:55:36 +02:00
return nRet ;
}
2016-06-06 14:58:45 +02:00
bool CWallet : : AccountMove ( std : : string strFrom , std : : string strTo , CAmount nAmount , std : : string strComment )
{
CWalletDB walletdb ( strWalletFile ) ;
if ( ! walletdb . TxnBegin ( ) )
return false ;
int64_t nNow = GetAdjustedTime ( ) ;
// Debit
CAccountingEntry debit ;
debit . nOrderPos = IncOrderPosNext ( & walletdb ) ;
debit . strAccount = strFrom ;
debit . nCreditDebit = - nAmount ;
debit . nTime = nNow ;
debit . strOtherAccount = strTo ;
debit . strComment = strComment ;
2016-09-20 12:46:59 +02:00
AddAccountingEntry ( debit , & walletdb ) ;
2016-06-06 14:58:45 +02:00
// Credit
CAccountingEntry credit ;
credit . nOrderPos = IncOrderPosNext ( & walletdb ) ;
credit . strAccount = strTo ;
credit . nCreditDebit = nAmount ;
credit . nTime = nNow ;
credit . strOtherAccount = strFrom ;
credit . strComment = strComment ;
2016-09-20 12:46:59 +02:00
AddAccountingEntry ( credit , & walletdb ) ;
2016-06-06 14:58:45 +02:00
if ( ! walletdb . TxnCommit ( ) )
return false ;
return true ;
}
2016-06-06 16:27:48 +02:00
bool CWallet : : GetAccountPubkey ( CPubKey & pubKey , std : : string strAccount , bool bForceNew )
{
CWalletDB walletdb ( strWalletFile ) ;
CAccount account ;
walletdb . ReadAccount ( strAccount , account ) ;
if ( ! bForceNew ) {
if ( ! account . vchPubKey . IsValid ( ) )
bForceNew = true ;
else {
// Check if the current key has been used
CScript scriptPubKey = GetScriptForDestination ( account . vchPubKey . GetID ( ) ) ;
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ;
it ! = mapWallet . end ( ) & & account . vchPubKey . IsValid ( ) ;
+ + it )
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxOut & txout , ( * it ) . second . tx - > vout )
2016-06-06 16:27:48 +02:00
if ( txout . scriptPubKey = = scriptPubKey ) {
bForceNew = true ;
break ;
}
}
}
// Generate a new key
if ( bForceNew ) {
if ( ! GetKeyFromPool ( account . vchPubKey , false ) )
return false ;
SetAddressBook ( account . vchPubKey . GetID ( ) , strAccount , " receive " ) ;
walletdb . WriteAccount ( strAccount , account ) ;
}
pubKey = account . vchPubKey ;
return true ;
}
2011-07-13 11:56:38 +02:00
void CWallet : : MarkDirty ( )
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-07-13 11:56:38 +02:00
BOOST_FOREACH ( PAIRTYPE ( const uint256 , CWalletTx ) & item , mapWallet )
item . second . MarkDirty ( ) ;
}
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2011-07-13 11:56:38 +02:00
}
2016-08-01 01:57:52 +02:00
bool CWallet : : AddToWallet ( const CWalletTx & wtxIn , bool fFlushOnClose )
2011-06-26 19:23:24 +02:00
{
2016-08-01 01:57:52 +02:00
LOCK ( cs_wallet ) ;
CWalletDB walletdb ( strWalletFile , " r+ " , fFlushOnClose ) ;
2011-06-26 19:23:24 +02:00
uint256 hash = wtxIn . GetHash ( ) ;
2014-02-14 02:12:51 +01:00
2016-08-01 01:57:52 +02:00
// Inserts only if not already there, returns tx inserted or tx found
pair < map < uint256 , CWalletTx > : : iterator , bool > ret = mapWallet . insert ( make_pair ( hash , wtxIn ) ) ;
CWalletTx & wtx = ( * ret . first ) . second ;
wtx . BindWallet ( this ) ;
bool fInsertedNew = ret . second ;
if ( fInsertedNew )
2014-02-14 02:12:51 +01:00
{
2016-08-01 01:57:52 +02:00
wtx . nTimeReceived = GetAdjustedTime ( ) ;
wtx . nOrderPos = IncOrderPosNext ( & walletdb ) ;
2015-10-19 11:19:38 +02:00
wtxOrdered . insert ( make_pair ( wtx . nOrderPos , TxPair ( & wtx , ( CAccountingEntry * ) 0 ) ) ) ;
2012-05-28 20:45:12 +02:00
2016-08-01 01:57:52 +02:00
wtx . nTimeSmart = wtx . nTimeReceived ;
if ( ! wtxIn . hashUnset ( ) )
{
if ( mapBlockIndex . count ( wtxIn . hashBlock ) )
2012-05-28 20:45:12 +02:00
{
2016-08-01 01:57:52 +02:00
int64_t latestNow = wtx . nTimeReceived ;
int64_t latestEntry = 0 ;
2012-05-28 20:45:12 +02:00
{
2016-08-01 01:57:52 +02: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 ( TxItems : : const_reverse_iterator it = txOrdered . rbegin ( ) ; it ! = txOrdered . rend ( ) ; + + it )
2012-05-28 20:45:12 +02:00
{
2016-08-01 01:57:52 +02:00
CWalletTx * const pwtx = ( * it ) . second . first ;
if ( pwtx = = & wtx )
continue ;
CAccountingEntry * const pacentry = ( * it ) . second . second ;
int64_t nSmartTime ;
if ( pwtx )
2012-05-28 20:45:12 +02:00
{
2016-08-01 01:57:52 +02:00
nSmartTime = pwtx - > nTimeSmart ;
if ( ! nSmartTime )
nSmartTime = pwtx - > nTimeReceived ;
}
else
nSmartTime = pacentry - > nTime ;
if ( nSmartTime < = latestTolerated )
{
latestEntry = nSmartTime ;
if ( nSmartTime > latestNow )
latestNow = nSmartTime ;
break ;
2012-05-28 20:45:12 +02:00
}
}
}
2016-08-01 01:57:52 +02:00
int64_t blocktime = mapBlockIndex [ wtxIn . hashBlock ] - > GetBlockTime ( ) ;
wtx . nTimeSmart = std : : max ( latestEntry , std : : min ( blocktime , latestNow ) ) ;
2012-05-28 20:45:12 +02:00
}
2016-08-01 01:57:52 +02:00
else
LogPrintf ( " AddToWallet(): found %s in block %s not in index \n " ,
wtxIn . GetHash ( ) . ToString ( ) ,
wtxIn . hashBlock . ToString ( ) ) ;
}
AddToSpends ( hash ) ;
2016-12-05 08:01:20 +01:00
for ( int i = 0 ; i < wtx . tx - > vout . size ( ) ; + + i ) {
if ( IsMine ( wtx . tx - > vout [ i ] ) & & ! IsSpent ( hash , i ) ) {
2016-08-01 01:57:52 +02:00
setWalletUTXO . insert ( COutPoint ( hash , i ) ) ;
2017-09-27 19:43:16 +02:00
}
2012-05-28 01:06:09 +02:00
}
2016-08-01 01:57:52 +02:00
}
2011-06-26 19:23:24 +02:00
2016-08-01 01:57:52 +02:00
bool fUpdated = false ;
if ( ! fInsertedNew )
{
// Merge
if ( ! wtxIn . hashUnset ( ) & & wtxIn . hashBlock ! = wtx . hashBlock )
2011-06-26 19:23:24 +02:00
{
2016-08-01 01:57:52 +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 ;
}
if ( wtxIn . fFromMe & & wtxIn . fFromMe ! = wtx . fFromMe )
{
wtx . fFromMe = wtxIn . fFromMe ;
fUpdated = true ;
2011-06-26 19:23:24 +02:00
}
2016-08-01 01:57:52 +02:00
}
2011-06-26 19:23:24 +02:00
2016-08-01 01:57:52 +02:00
//// debug print
LogPrintf ( " AddToWallet %s %s%s \n " , wtxIn . GetHash ( ) . ToString ( ) , ( fInsertedNew ? " new " : " " ) , ( fUpdated ? " update " : " " ) ) ;
2011-06-26 19:23:24 +02:00
2016-08-01 01:57:52 +02:00
// Write to disk
if ( fInsertedNew | | fUpdated )
if ( ! walletdb . WriteTx ( wtx ) )
return false ;
2013-05-26 20:17:18 +02:00
2016-08-01 01:57:52 +02:00
// Break debit/credit balance caches:
wtx . MarkDirty ( ) ;
2011-06-26 19:23:24 +02:00
2016-08-01 01:57:52 +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-08-01 01:57:52 +02:00
// notify an external script when a wallet transaction comes in or is updated
std : : string strCmd = GetArg ( " -walletnotify " , " " ) ;
2012-11-03 15:58:41 +01:00
2016-08-01 01:57:52 +02:00
if ( ! strCmd . empty ( ) )
{
boost : : replace_all ( strCmd , " %s " , wtxIn . GetHash ( ) . GetHex ( ) ) ;
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
}
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
return true ;
}
2012-11-03 15:58:41 +01:00
2016-08-01 01:57:52 +02:00
bool CWallet : : LoadToWallet ( const CWalletTx & wtxIn )
{
uint256 hash = wtxIn . GetHash ( ) ;
2016-07-29 07:27:05 +02:00
2016-08-01 01:57:52 +02:00
mapWallet [ hash ] = wtxIn ;
CWalletTx & wtx = mapWallet [ hash ] ;
wtx . BindWallet ( this ) ;
wtxOrdered . insert ( make_pair ( wtx . nOrderPos , TxPair ( & wtx , ( CAccountingEntry * ) 0 ) ) ) ;
AddToSpends ( hash ) ;
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtx . tx - > vin ) {
2016-08-01 01:57:52 +02:00
if ( mapWallet . count ( txin . prevout . hash ) ) {
CWalletTx & prevtx = mapWallet [ txin . prevout . hash ] ;
if ( prevtx . nIndex = = - 1 & & ! prevtx . hashUnset ( ) ) {
MarkConflicted ( prevtx . hashBlock , wtx . GetHash ( ) ) ;
}
}
2012-05-05 16:07:14 +02:00
}
2016-08-01 01:57:52 +02:00
2011-06-26 19:23:24 +02:00
return true ;
}
2014-10-26 08:03:12 +01:00
/**
* Add a transaction to the wallet , or update it .
* pblock is optional , but should be provided if the transaction is known to be in a block .
* If fUpdate is true , existing transactions will be updated .
*/
2016-08-15 11:49:12 +02:00
bool CWallet : : AddToWalletIfInvolvingMe ( const CTransaction & tx , const CBlockIndex * pIndex , int posInBlock , bool fUpdate )
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
2016-08-15 11:49:12 +02:00
if ( posInBlock ! = - 1 ) {
2015-11-26 18:42:07 +01:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin ) {
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 ( ) ) {
2016-08-15 11:49:12 +02:00
LogPrintf ( " 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 ) ;
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 ;
if ( fExisted | | IsMine ( tx ) | | IsFromMe ( tx ) )
{
2016-12-05 08:01:20 +01:00
CWalletTx wtx ( this , MakeTransactionRef ( tx ) ) ;
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
2016-08-15 11:49:12 +02:00
if ( posInBlock ! = - 1 )
wtx . SetMerkleBranch ( pIndex , posInBlock ) ;
2014-08-31 05:55:27 +02:00
2016-08-01 01:57:52 +02:00
return AddToWallet ( wtx , false ) ;
2011-08-26 20:37:23 +02:00
}
2011-06-26 19:23:24 +02:00
}
return false ;
}
2016-01-07 22:31:12 +01:00
bool CWallet : : AbandonTransaction ( const uint256 & hashTx )
{
LOCK2 ( cs_main , cs_wallet ) ;
2016-12-19 09:43:05 +01:00
CWalletDB walletdb ( strWalletFile , " r+ " ) ;
2016-01-07 22:31:12 +01:00
std : : set < uint256 > todo ;
std : : set < uint256 > done ;
// Can't mark abandoned if confirmed or in mempool
assert ( mapWallet . count ( hashTx ) ) ;
CWalletTx & origtx = mapWallet [ hashTx ] ;
if ( origtx . GetDepthInMainChain ( ) > 0 | | origtx . InMempool ( ) ) {
return false ;
}
todo . insert ( hashTx ) ;
while ( ! todo . empty ( ) ) {
uint256 now = * todo . begin ( ) ;
todo . erase ( now ) ;
done . insert ( now ) ;
assert ( mapWallet . count ( now ) ) ;
CWalletTx & wtx = mapWallet [ now ] ;
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 ( ) ;
2016-05-10 15:51:11 +02:00
walletdb . WriteTx ( wtx ) ;
2016-01-07 22:31:12 +01:00
NotifyTransactionChanged ( this , wtx . GetHash ( ) , CT_UPDATED ) ;
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends : : const_iterator iter = mapTxSpends . lower_bound ( COutPoint ( hashTx , 0 ) ) ;
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
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtx . tx - > vin )
2016-01-07 22:31:12 +01:00
{
if ( mapWallet . count ( txin . prevout . hash ) )
mapWallet [ txin . prevout . hash ] . MarkDirty ( ) ;
}
}
}
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2016-01-07 22:31:12 +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 ;
2016-02-09 20:23:09 +01:00
if ( mapBlockIndex . count ( hashBlock ) ) {
CBlockIndex * pindex = mapBlockIndex [ hashBlock ] ;
if ( 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
CWalletDB walletdb ( strWalletFile , " r+ " , false ) ;
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 ) ;
assert ( mapWallet . count ( now ) ) ;
CWalletTx & wtx = mapWallet [ now ] ;
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 ( ) ;
2016-05-10 15:51:11 +02:00
walletdb . 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
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtx . tx - > vin )
2016-01-06 23:24:30 +01:00
{
if ( mapWallet . count ( txin . prevout . hash ) )
mapWallet [ txin . prevout . hash ] . MarkDirty ( ) ;
}
2015-11-26 18:42:07 +01:00
}
}
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2015-11-26 18:42:07 +01:00
}
2016-08-15 11:49:12 +02:00
void CWallet : : SyncTransaction ( const CTransaction & tx , const CBlockIndex * pindex , int posInBlock )
2014-02-15 22:38:28 +01:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2015-11-26 18:42:07 +01:00
2016-08-15 11:49:12 +02:00
if ( ! AddToWalletIfInvolvingMe ( tx , pindex , posInBlock , true ) )
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:
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
if ( mapWallet . count ( txin . prevout . hash ) )
mapWallet [ txin . prevout . hash ] . MarkDirty ( ) ;
}
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2013-10-19 18:34:06 +02:00
}
2011-06-26 19:23:24 +02: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 ) ;
2011-06-26 19:23:24 +02:00
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
2016-12-05 08:01:20 +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
}
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 ) ;
2011-06-26 19:23:24 +02:00
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
2016-12-05 08:01:20 +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 ;
}
2016-09-05 18:09:25 +02:00
// Recursively determine the rounds of a given input (How deep is the PrivateSend chain for a given input)
2017-09-11 16:13:48 +02:00
int CWallet : : GetRealOutpointPrivateSendRounds ( const COutPoint & outpoint , int nRounds ) const
2015-07-26 01:24:19 +02:00
{
static std : : map < uint256 , CMutableTransaction > mDenomWtxes ;
2016-09-05 18:09:25 +02:00
if ( nRounds > = 16 ) return 15 ; // 16 rounds max
2015-07-26 01:24:19 +02:00
2017-09-11 16:13:48 +02:00
uint256 hash = outpoint . hash ;
unsigned int nout = outpoint . n ;
2015-07-26 01:24:19 +02:00
const CWalletTx * wtx = GetWalletTx ( hash ) ;
if ( wtx ! = NULL )
{
std : : map < uint256 , CMutableTransaction > : : const_iterator mdwi = mDenomWtxes . find ( hash ) ;
2016-09-05 18:09:25 +02:00
if ( mdwi = = mDenomWtxes . end ( ) ) {
// not known yet, let's add it
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds INSERTING %s \n " , hash . ToString ( ) ) ;
2015-07-26 01:24:19 +02:00
mDenomWtxes [ hash ] = CMutableTransaction ( * wtx ) ;
2016-09-05 18:09:25 +02:00
} else if ( mDenomWtxes [ hash ] . vout [ nout ] . nRounds ! = - 10 ) {
// found and it's not an initial value, just return it
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
// bounds check
2016-12-05 08:01:20 +01:00
if ( nout > = wtx - > tx - > vout . size ( ) ) {
2015-07-26 01:24:19 +02:00
// should never actually hit this
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , - 4 ) ;
2015-07-26 01:24:19 +02:00
return - 4 ;
}
2016-12-05 08:01:20 +01:00
if ( CPrivateSend : : IsCollateralAmount ( wtx - > tx - > vout [ nout ] . nValue ) ) {
2015-07-26 01:24:19 +02:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 3 ;
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
//make sure the final output is non-denominate
2016-12-05 08:01:20 +01:00
if ( ! CPrivateSend : : IsDenominatedAmount ( wtx - > tx - > vout [ nout ] . nValue ) ) { //NOT DENOM
2015-07-26 01:24:19 +02:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 2 ;
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
bool fAllDenoms = true ;
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( CTxOut out , wtx - > tx - > vout ) {
2017-12-04 07:06:07 +01:00
fAllDenoms = fAllDenoms & & CPrivateSend : : IsDenominatedAmount ( out . nValue ) ;
2015-07-26 01:24:19 +02:00
}
2016-09-05 18:09:25 +02:00
2015-07-26 01:24:19 +02:00
// this one is denominated but there is another non-denominated output found in the same tx
2016-09-05 18:09:25 +02:00
if ( ! fAllDenoms ) {
2015-07-26 01:24:19 +02:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = 0 ;
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
int nShortest = - 10 ; // an initial value, should be no way to get this by calculations
bool fDenomFound = false ;
// only denoms here so let's look up
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( CTxIn txinNext , wtx - > tx - > vin ) {
2016-09-05 18:09:25 +02:00
if ( IsMine ( txinNext ) ) {
2017-09-11 16:13:48 +02:00
int n = GetRealOutpointPrivateSendRounds ( txinNext . prevout , nRounds + 1 ) ;
2015-07-26 01:24:19 +02:00
// denom found, find the shortest chain or initially assign nShortest with the first found value
2016-09-05 18:09:25 +02:00
if ( n > = 0 & & ( n < nShortest | | nShortest = = - 10 ) ) {
2015-07-26 01:24:19 +02:00
nShortest = n ;
fDenomFound = true ;
}
}
}
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = fDenomFound
? ( nShortest > = 15 ? 16 : nShortest + 1 ) // good, we a +1 to the shortest one but only 16 rounds max allowed
: 0 ; // too bad, we are the fist one in that chain
2017-09-11 16:13:48 +02:00
LogPrint ( " privatesend " , " GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
2016-09-05 18:09:25 +02:00
return nRounds - 1 ;
2015-07-26 01:24:19 +02:00
}
// respect current settings
2017-09-11 16:13:48 +02:00
int CWallet : : GetOutpointPrivateSendRounds ( const COutPoint & outpoint ) const
2016-09-05 18:09:25 +02:00
{
2015-07-29 17:06:45 +02:00
LOCK ( cs_wallet ) ;
2017-09-11 16:13:48 +02:00
int realPrivateSendRounds = GetRealOutpointPrivateSendRounds ( outpoint , 0 ) ;
2017-05-05 13:26:27 +02:00
return realPrivateSendRounds > privateSendClient . nPrivateSendRounds ? privateSendClient . nPrivateSendRounds : realPrivateSendRounds ;
2015-07-26 01:24:19 +02:00
}
2017-09-11 16:13:48 +02:00
bool CWallet : : IsDenominated ( const COutPoint & outpoint ) const
2014-12-09 02:17:57 +01:00
{
2016-09-05 18:09:25 +02:00
LOCK ( cs_wallet ) ;
2014-12-09 02:17:57 +01:00
2017-09-11 16:13:48 +02:00
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( outpoint . hash ) ;
2016-09-05 18:09:25 +02:00
if ( mi ! = mapWallet . end ( ) ) {
const CWalletTx & prev = ( * mi ) . second ;
2016-12-05 08:01:20 +01:00
if ( outpoint . n < prev . tx - > vout . size ( ) ) {
return CPrivateSend : : IsDenominatedAmount ( prev . tx - > vout [ outpoint . n ] . nValue ) ;
2015-07-26 01:24:19 +02:00
}
}
2016-09-05 18:09:25 +02:00
return false ;
}
2015-07-26 01:24:19 +02:00
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-22 09:58:00 +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-22 09:58:00 +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 ) ;
}
2017-05-29 13:51:40 +02:00
void CWallet : : GenerateNewHDChain ( )
{
CHDChain newHdChain ;
std : : string strSeed = GetArg ( " -hdseed " , " not hex " ) ;
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -hdseed " ) & & IsHex ( strSeed ) ) {
2017-05-29 13:51:40 +02:00
std : : vector < unsigned char > vchSeed = ParseHex ( strSeed ) ;
if ( ! newHdChain . SetSeed ( SecureVector ( vchSeed . begin ( ) , vchSeed . end ( ) ) , true ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetSeed failed " ) ;
}
else {
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -hdseed " ) & & ! IsHex ( strSeed ) )
2017-05-29 13:51:40 +02:00
LogPrintf ( " CWallet::GenerateNewHDChain -- Incorrect seed, generating random one instead \n " ) ;
// NOTE: empty mnemonic means "generate a new one for me"
std : : string strMnemonic = GetArg ( " -mnemonic " , " " ) ;
// NOTE: default mnemonic passphrase is an empty string
std : : string strMnemonicPassphrase = GetArg ( " -mnemonicpassphrase " , " " ) ;
SecureVector vchMnemonic ( strMnemonic . begin ( ) , strMnemonic . end ( ) ) ;
SecureVector vchMnemonicPassphrase ( strMnemonicPassphrase . begin ( ) , strMnemonicPassphrase . end ( ) ) ;
if ( ! newHdChain . SetMnemonic ( vchMnemonic , vchMnemonicPassphrase , true ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetMnemonic failed " ) ;
}
newHdChain . Debug ( __func__ ) ;
if ( ! SetHDChain ( newHdChain , false ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : SetHDChain failed " ) ;
// clean up
2016-12-27 19:11:21 +01:00
ForceRemoveArg ( " -hdseed " ) ;
ForceRemoveArg ( " -mnemonic " ) ;
ForceRemoveArg ( " -mnemonicpassphrase " ) ;
2017-05-29 13:51:40 +02:00
}
bool CWallet : : SetHDChain ( const CHDChain & chain , bool memonly )
{
LOCK ( cs_wallet ) ;
if ( ! CCryptoKeyStore : : SetHDChain ( chain ) )
return false ;
if ( ! memonly & & ! CWalletDB ( strWalletFile ) . WriteHDChain ( chain ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : WriteHDChain failed " ) ;
return true ;
}
bool CWallet : : SetCryptedHDChain ( const CHDChain & chain , bool memonly )
{
LOCK ( cs_wallet ) ;
if ( ! CCryptoKeyStore : : SetCryptedHDChain ( chain ) )
return false ;
if ( ! memonly ) {
if ( ! fFileBacked )
return false ;
if ( pwalletdbEncryption ) {
if ( ! pwalletdbEncryption - > WriteCryptedHDChain ( chain ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : WriteCryptedHDChain failed " ) ;
} else {
if ( ! CWalletDB ( strWalletFile ) . WriteCryptedHDChain ( chain ) )
throw std : : runtime_error ( std : : string ( __func__ ) + " : WriteCryptedHDChain failed " ) ;
}
}
return true ;
}
bool CWallet : : GetDecryptedHDChain ( CHDChain & hdChainRet )
{
LOCK ( cs_wallet ) ;
CHDChain hdChainTmp ;
if ( ! GetHDChain ( hdChainTmp ) ) {
return false ;
}
if ( ! DecryptHDChain ( hdChainTmp ) )
return false ;
// make sure seed matches this chain
if ( hdChainTmp . GetID ( ) ! = hdChainTmp . GetSeedHash ( ) )
return false ;
hdChainRet = hdChainTmp ;
return true ;
}
bool CWallet : : IsHDEnabled ( )
{
CHDChain hdChainCurrent ;
return GetHDChain ( hdChainCurrent ) ;
}
2015-02-04 23:19:29 +01:00
bool CWallet : : IsMine ( const CTransaction & tx ) const
{
BOOST_FOREACH ( const CTxOut & txout , tx . vout )
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 ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
nDebit + = GetDebit ( txin , filter ) ;
if ( ! MoneyRange ( nDebit ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
}
return nDebit ;
}
CAmount CWallet : : GetCredit ( const CTransaction & tx , const isminefilter & filter ) const
{
CAmount nCredit = 0 ;
BOOST_FOREACH ( const CTxOut & txout , tx . vout )
{
nCredit + = GetCredit ( txout , filter ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-22 09:58:00 +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 ;
BOOST_FOREACH ( const CTxOut & txout , tx . vout )
{
nChange + = GetChange ( txout ) ;
if ( ! MoneyRange ( nChange ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2015-02-04 23:19:29 +01:00
}
return nChange ;
}
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
}
int CWalletTx : : GetRequestCount ( ) const
{
// Returns -1 if it wasn't being tracked
int nRequests = - 1 ;
{
2012-04-06 18:39:12 +02:00
LOCK ( pwallet - > cs_wallet ) ;
2011-06-26 19:23:24 +02:00
if ( IsCoinBase ( ) )
{
// Generated block
2016-01-07 22:31:12 +01:00
if ( ! hashUnset ( ) )
2011-06-26 19:23:24 +02:00
{
map < uint256 , int > : : const_iterator mi = pwallet - > mapRequestCount . find ( hashBlock ) ;
if ( mi ! = pwallet - > mapRequestCount . end ( ) )
nRequests = ( * mi ) . second ;
}
}
else
{
// Did anyone request this transaction?
map < uint256 , int > : : const_iterator mi = pwallet - > mapRequestCount . find ( GetHash ( ) ) ;
if ( mi ! = pwallet - > mapRequestCount . end ( ) )
{
nRequests = ( * mi ) . second ;
// How about the block it's in?
2016-01-07 22:31:12 +01:00
if ( nRequests = = 0 & & ! hashUnset ( ) )
2011-06-26 19:23:24 +02:00
{
2016-09-27 13:25:42 +02:00
map < uint256 , int > : : const_iterator _mi = pwallet - > mapRequestCount . find ( hashBlock ) ;
if ( _mi ! = pwallet - > mapRequestCount . end ( ) )
nRequests = ( * _mi ) . second ;
2011-06-26 19:23:24 +02:00
else
nRequests = 1 ; // If it's in someone else's block it must have got out
}
}
}
}
return nRequests ;
}
2014-05-30 00:54:00 +02:00
void CWalletTx : : GetAmounts ( list < COutputEntry > & listReceived ,
2014-04-23 00:46:19 +02:00
list < COutputEntry > & listSent , CAmount & nFee , 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-12-05 08:01:20 +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-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; + + i )
2011-06-26 19:23:24 +02:00
{
2016-12-05 08:01:20 +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
if ( ! ExtractDestination ( txout . scriptPubKey , address ) & & ! txout . scriptPubKey . IsUnspendable ( ) )
2011-06-26 19:23:24 +02:00
{
2013-09-18 12:38:08 +02:00
LogPrintf ( " CWalletTx::GetAmounts: Unknown transaction type found, txid %s \n " ,
2014-01-16 16:15:27 +01:00
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
}
}
2014-04-23 00:46:19 +02:00
void CWalletTx : : GetAccountAmounts ( const string & strAccount , CAmount & nReceived ,
CAmount & nSent , CAmount & nFee , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
2012-06-02 04:33:28 +02:00
nReceived = nSent = nFee = 0 ;
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
CAmount allFee ;
2011-06-26 19:23:24 +02:00
string strSentAccount ;
2014-05-30 00:54:00 +02:00
list < COutputEntry > listReceived ;
list < COutputEntry > listSent ;
2014-04-08 15:23:50 +02:00
GetAmounts ( listReceived , listSent , allFee , strSentAccount , filter ) ;
2011-06-26 19:23:24 +02:00
if ( strAccount = = strSentAccount )
{
2014-05-30 00:54:00 +02:00
BOOST_FOREACH ( const COutputEntry & s , listSent )
nSent + = s . amount ;
2011-06-26 19:23:24 +02:00
nFee = allFee ;
}
{
2012-04-06 18:39:12 +02:00
LOCK ( pwallet - > cs_wallet ) ;
2014-05-30 00:54:00 +02:00
BOOST_FOREACH ( const COutputEntry & r , listReceived )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
if ( pwallet - > mapAddressBook . count ( r . destination ) )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
map < CTxDestination , CAddressBookData > : : const_iterator mi = pwallet - > mapAddressBook . find ( r . destination ) ;
2013-07-15 07:20:50 +02:00
if ( mi ! = pwallet - > mapAddressBook . end ( ) & & ( * mi ) . second . name = = strAccount )
2014-05-30 00:54:00 +02:00
nReceived + = r . amount ;
2011-06-26 19:23:24 +02:00
}
else if ( strAccount . empty ( ) )
{
2014-05-30 00:54:00 +02:00
nReceived + = r . amount ;
2011-06-26 19:23:24 +02:00
}
}
}
}
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 .
*/
2011-06-26 19:23:24 +02:00
int CWallet : : ScanForWalletTransactions ( CBlockIndex * pindexStart , bool fUpdate )
{
int ret = 0 ;
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
CBlockIndex * pindex = pindexStart ;
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-19 00:26:14 +01:00
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
2014-06-28 23:36:06 +02:00
while ( pindex & & nTimeFirstKey & & ( pindex - > GetBlockTime ( ) < ( nTimeFirstKey - 7200 ) ) )
2014-03-19 00:26:14 +01:00
pindex = chainActive . Next ( pindex ) ;
ShowProgress ( _ ( " Rescanning... " ) , 0 ) ; // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
2017-01-12 12:12:56 +01:00
double dProgressStart = GuessVerificationProgress ( chainParams . TxData ( ) , pindex ) ;
double dProgressTip = GuessVerificationProgress ( chainParams . TxData ( ) , chainActive . Tip ( ) ) ;
2011-06-26 19:23:24 +02:00
while ( pindex )
{
2014-03-19 00:26:14 +01:00
if ( pindex - > nHeight % 100 = = 0 & & dProgressTip - dProgressStart > 0.0 )
2017-01-12 12:12:56 +01:00
ShowProgress ( _ ( " Rescanning... " ) , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( GuessVerificationProgress ( chainParams . TxData ( ) , pindex ) - dProgressStart ) / ( dProgressTip - dProgressStart ) * 100 ) ) ) ) ;
2013-06-10 15:38:13 +02:00
2011-06-26 19:23:24 +02:00
CBlock block ;
2015-04-17 14:19:21 +02:00
ReadBlockFromDisk ( block , pindex , Params ( ) . GetConsensus ( ) ) ;
2016-08-15 11:49:12 +02:00
int posInBlock ;
for ( posInBlock = 0 ; posInBlock < ( int ) block . vtx . size ( ) ; posInBlock + + )
2011-06-26 19:23:24 +02:00
{
2016-11-21 10:51:32 +01:00
if ( AddToWalletIfInvolvingMe ( * block . vtx [ posInBlock ] , pindex , posInBlock , fUpdate ) )
2011-06-26 19:23:24 +02:00
ret + + ;
}
2013-10-10 23:07:44 +02:00
pindex = chainActive . Next ( pindex ) ;
2014-02-18 01:35:37 +01:00
if ( GetTime ( ) > = nNow + 60 ) {
nNow = GetTime ( ) ;
2017-01-12 12:12:56 +01:00
LogPrintf ( " Still rescanning. At block %d. Progress=%f \n " , pindex - > nHeight , GuessVerificationProgress ( chainParams . TxData ( ) , pindex ) ) ;
2014-02-18 01:35:37 +01:00
}
2011-06-26 19:23:24 +02:00
}
2014-03-19 00:26:14 +01:00
ShowProgress ( _ ( " Rescanning... " ) , 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
2014-02-15 22:38:28 +01:00
BOOST_FOREACH ( PAIRTYPE ( 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:12 +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
BOOST_FOREACH ( PAIRTYPE ( const int64_t , CWalletTx * ) & item , mapSorted )
{
CWalletTx & wtx = * ( item . second ) ;
LOCK ( mempool . cs ) ;
2016-10-28 13:49: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
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
bool CWalletTx : : RelayWalletTransaction ( CConnman * connman , std : : string strCommand )
2011-06-26 19:23:24 +02:00
{
2015-03-27 10:34:48 +01:00
assert ( pwallet - > GetBroadcastTransactions ( ) ) ;
2016-12-14 10:26:39 +01:00
if ( ! IsCoinBase ( ) & & ! isAbandoned ( ) & & GetDepthInMainChain ( ) = = 0 )
2011-06-26 19:23:24 +02:00
{
2016-12-14 10:26:39 +01:00
CValidationState state ;
/* GetDepthInMainChain already catches known conflicts. */
if ( InMempool ( ) | | AcceptToMemoryPool ( maxTxFee , state ) ) {
2012-11-01 15:52:25 +01:00
uint256 hash = GetHash ( ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " Relaying wtx %s \n " , hash . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
2017-01-29 09:22:14 +01:00
if ( strCommand = = NetMsgType : : TXLOCKREQUEST ) {
2017-09-15 20:05:13 +02:00
instantsend . ProcessTxLockRequest ( ( ( CTxLockRequest ) * this ) , * connman ) ;
2014-12-09 02:17:57 +01:00
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
if ( connman ) {
2016-05-16 22:47:29 +02:00
connman - > RelayTransaction ( ( CTransaction ) * this ) ;
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
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
}
2014-02-14 02:12:51 +01:00
set < uint256 > CWalletTx : : GetConflicts ( ) const
{
set < uint256 > result ;
if ( pwallet ! = NULL )
{
uint256 myHash = GetHash ( ) ;
result = pwallet - > GetConflicts ( myHash ) ;
result . erase ( myHash ) ;
}
return result ;
}
2014-12-19 02:00:01 +01:00
CAmount CWalletTx : : GetDebit ( const isminefilter & filter ) const
{
2016-12-05 08:01:20 +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
{
nDebitCached = pwallet - > GetDebit ( * this , ISMINE_SPENDABLE ) ;
fDebitCached = true ;
debit + = nDebitCached ;
}
}
if ( filter & ISMINE_WATCH_ONLY )
{
if ( fWatchDebitCached )
debit + = nWatchDebitCached ;
else
{
nWatchDebitCached = pwallet - > GetDebit ( * this , ISMINE_WATCH_ONLY ) ;
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 18:43:57 +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
{
nCreditCached = pwallet - > GetCredit ( * this , ISMINE_SPENDABLE ) ;
fCreditCached = true ;
credit + = nCreditCached ;
}
}
if ( filter & ISMINE_WATCH_ONLY )
{
if ( fWatchCreditCached )
credit + = nWatchCreditCached ;
else
{
nWatchCreditCached = pwallet - > GetCredit ( * this , ISMINE_WATCH_ONLY ) ;
fWatchCreditCached = true ;
credit + = nWatchCreditCached ;
}
}
return credit ;
}
CAmount CWalletTx : : GetImmatureCredit ( bool fUseCache ) const
{
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 & & IsInMainChain ( ) )
{
if ( fUseCache & & fImmatureCreditCached )
return nImmatureCreditCached ;
nImmatureCreditCached = pwallet - > GetCredit ( * this , ISMINE_SPENDABLE ) ;
fImmatureCreditCached = true ;
return nImmatureCreditCached ;
}
return 0 ;
}
CAmount CWalletTx : : GetAvailableCredit ( bool fUseCache ) const
{
if ( pwallet = = 0 )
return 0 ;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
if ( fUseCache & & fAvailableCreditCached )
return nAvailableCreditCached ;
CAmount nCredit = 0 ;
uint256 hashTx = GetHash ( ) ;
2016-12-05 08:01:20 +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-12-05 08:01:20 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2014-12-19 02:00:01 +01:00
nCredit + = pwallet - > GetCredit ( txout , ISMINE_SPENDABLE ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2014-12-19 02:00:01 +01:00
}
}
nAvailableCreditCached = nCredit ;
fAvailableCreditCached = true ;
return nCredit ;
}
CAmount CWalletTx : : GetImmatureWatchOnlyCredit ( const bool & fUseCache ) const
{
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 & & IsInMainChain ( ) )
{
if ( fUseCache & & fImmatureWatchCreditCached )
return nImmatureWatchCreditCached ;
nImmatureWatchCreditCached = pwallet - > GetCredit ( * this , ISMINE_WATCH_ONLY ) ;
fImmatureWatchCreditCached = true ;
return nImmatureWatchCreditCached ;
}
return 0 ;
}
CAmount CWalletTx : : GetAvailableWatchOnlyCredit ( const bool & fUseCache ) const
{
if ( pwallet = = 0 )
return 0 ;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
if ( fUseCache & & fAvailableWatchCreditCached )
return nAvailableWatchCreditCached ;
CAmount nCredit = 0 ;
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; i + + )
2014-12-19 02:00:01 +01:00
{
if ( ! pwallet - > IsSpent ( GetHash ( ) , i ) )
{
2016-12-05 08:01:20 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2014-12-19 02:00:01 +01:00
nCredit + = pwallet - > GetCredit ( txout , ISMINE_WATCH_ONLY ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2014-12-19 02:00:01 +01:00
}
}
nAvailableWatchCreditCached = nCredit ;
fAvailableWatchCreditCached = true ;
return nCredit ;
}
2016-02-02 16:28:56 +01:00
CAmount CWalletTx : : GetAnonymizedCredit ( bool fUseCache ) const
{
if ( pwallet = = 0 )
return 0 ;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
if ( fUseCache & & fAnonymizedCreditCached )
return nAnonymizedCreditCached ;
CAmount nCredit = 0 ;
uint256 hashTx = GetHash ( ) ;
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; i + + )
2016-02-02 16:28:56 +01:00
{
2016-12-05 08:01:20 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2017-09-11 16:13:48 +02:00
const COutPoint outpoint = COutPoint ( hashTx , i ) ;
2016-02-02 16:28:56 +01:00
2017-09-11 16:13:48 +02:00
if ( pwallet - > IsSpent ( hashTx , i ) | | ! pwallet - > IsDenominated ( outpoint ) ) continue ;
2016-02-02 16:28:56 +01:00
2017-09-11 16:13:48 +02:00
const int nRounds = pwallet - > GetOutpointPrivateSendRounds ( outpoint ) ;
2017-05-05 13:26:27 +02:00
if ( nRounds > = privateSendClient . nPrivateSendRounds ) {
2016-02-02 16:28:56 +01:00
nCredit + = pwallet - > GetCredit ( txout , ISMINE_SPENDABLE ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2016-02-02 16:28:56 +01:00
}
}
nAnonymizedCreditCached = nCredit ;
fAnonymizedCreditCached = true ;
return nCredit ;
}
CAmount CWalletTx : : GetDenominatedCredit ( bool unconfirmed , bool fUseCache ) const
{
if ( pwallet = = 0 )
return 0 ;
// Must wait until coinbase is safely deep enough in the chain before valuing it
if ( IsCoinBase ( ) & & GetBlocksToMaturity ( ) > 0 )
return 0 ;
int nDepth = GetDepthInMainChain ( false ) ;
if ( nDepth < 0 ) return 0 ;
2016-07-29 07:27:05 +02:00
bool isUnconfirmed = IsTrusted ( ) & & nDepth = = 0 ;
2016-02-02 16:28:56 +01:00
if ( unconfirmed ! = isUnconfirmed ) return 0 ;
if ( fUseCache ) {
if ( unconfirmed & & fDenomUnconfCreditCached )
return nDenomUnconfCreditCached ;
else if ( ! unconfirmed & & fDenomConfCreditCached )
return nDenomConfCreditCached ;
}
CAmount nCredit = 0 ;
uint256 hashTx = GetHash ( ) ;
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < tx - > vout . size ( ) ; i + + )
2016-02-02 16:28:56 +01:00
{
2016-12-05 08:01:20 +01:00
const CTxOut & txout = tx - > vout [ i ] ;
2016-02-02 16:28:56 +01:00
2016-12-05 08:01:20 +01:00
if ( pwallet - > IsSpent ( hashTx , i ) | | ! CPrivateSend : : IsDenominatedAmount ( tx - > vout [ i ] . nValue ) ) continue ;
2016-02-02 16:28:56 +01:00
nCredit + = pwallet - > GetCredit ( txout , ISMINE_SPENDABLE ) ;
if ( ! MoneyRange ( nCredit ) )
2016-08-22 09:58:00 +02:00
throw std : : runtime_error ( std : : string ( __func__ ) + " : value out of range " ) ;
2016-02-02 16:28:56 +01:00
}
if ( unconfirmed ) {
nDenomUnconfCreditCached = nCredit ;
fDenomUnconfCreditCached = true ;
} else {
nDenomConfCreditCached = nCredit ;
fDenomConfCreditCached = true ;
}
return nCredit ;
}
2014-12-19 02:00:01 +01:00
CAmount CWalletTx : : GetChange ( ) const
{
if ( fChangeCached )
return nChangeCached ;
nChangeCached = pwallet - > GetChange ( * this ) ;
fChangeCached = true ;
return nChangeCached ;
}
2015-11-30 16:15:15 +01:00
bool CWalletTx : : InMempool ( ) const
{
LOCK ( mempool . cs ) ;
if ( mempool . exists ( GetHash ( ) ) ) {
return true ;
}
return false ;
}
2014-12-19 02:00:01 +01:00
bool CWalletTx : : IsTrusted ( ) const
{
// Quick answer in most cases
2015-05-25 06:48:33 +02:00
if ( ! CheckFinalTx ( * this ) )
2014-12-19 02:00:01 +01:00
return false ;
int nDepth = GetDepthInMainChain ( ) ;
if ( nDepth > = 1 )
return true ;
if ( nDepth < 0 )
return false ;
if ( ! bSpendZeroConfChange | | ! IsFromMe ( ISMINE_ALL ) ) // using wtx's cached debit
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:
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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 ) ;
if ( parent = = NULL )
return false ;
2016-12-05 08:01:20 +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-12-05 08:01:20 +01:00
bool CWalletTx : : IsEquivalentTo ( const CWalletTx & _tx ) const
2015-07-02 20:57:39 +02:00
{
2016-12-05 08:01:20 +01:00
CMutableTransaction tx1 = * this - > tx ;
CMutableTransaction tx2 = * _tx . tx ;
2015-07-02 20:57:39 +02:00
for ( unsigned int i = 0 ; i < tx1 . vin . size ( ) ; i + + ) tx1 . vin [ i ] . scriptSig = CScript ( ) ;
for ( unsigned int i = 0 ; i < tx2 . vin . size ( ) ; i + + ) tx2 . vin [ i ] . scriptSig = CScript ( ) ;
return CTransaction ( tx1 ) = = CTransaction ( tx2 ) ;
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +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 ) ;
// Sort them in chronological order
multimap < unsigned int , CWalletTx * > mapSorted ;
BOOST_FOREACH ( PAIRTYPE ( const uint256 , CWalletTx ) & item , mapWallet )
{
CWalletTx & wtx = item . second ;
// Don't rebroadcast if newer than nTime:
if ( wtx . nTimeReceived > nTime )
continue ;
mapSorted . insert ( make_pair ( wtx . nTimeReceived , & wtx ) ) ;
}
BOOST_FOREACH ( PAIRTYPE ( const unsigned int , CWalletTx * ) & item , mapSorted )
{
CWalletTx & wtx = * item . second ;
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
if ( wtx . RelayWalletTransaction ( connman ) )
2015-03-23 18:47:18 +01:00
result . push_back ( wtx . GetHash ( ) ) ;
}
return result ;
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +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:
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
std : : vector < uint256 > relayed = ResendWalletTransactionsBefore ( nBestBlockTime - 5 * 60 , connman ) ;
2015-03-23 18:47:18 +01:00
if ( ! relayed . empty ( ) )
LogPrintf ( " %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
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetBalance ( ) 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 ) ;
2011-06-26 19:23:24 +02:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2014-02-13 01:23:06 +01:00
if ( pcoin - > IsTrusted ( ) )
2012-02-14 12:08:00 +01:00
nTotal + = pcoin - > GetAvailableCredit ( ) ;
2011-06-26 19:23:24 +02:00
}
}
return nTotal ;
}
2017-06-06 01:47:12 +02:00
CAmount CWallet : : GetAnonymizableBalance ( bool fSkipDenominated , bool fSkipUnconfirmed ) const
2015-04-30 00:06:24 +02:00
{
if ( fLiteMode ) return 0 ;
2016-07-29 07:27:05 +02:00
std : : vector < CompactTallyItem > vecTally ;
2017-06-06 01:47:12 +02:00
if ( ! SelectCoinsGrouppedByAddresses ( vecTally , fSkipDenominated , true , fSkipUnconfirmed ) ) return 0 ;
2016-07-29 07:27:05 +02:00
2015-04-30 00:06:24 +02:00
CAmount nTotal = 0 ;
2017-06-30 20:30:16 +02:00
const CAmount nSmallestDenom = CPrivateSend : : GetSmallestDenomination ( ) ;
const CAmount nMixingCollateral = CPrivateSend : : GetCollateralAmount ( ) ;
2016-07-29 07:27:05 +02:00
BOOST_FOREACH ( CompactTallyItem & item , vecTally ) {
2017-12-04 07:06:07 +01:00
bool fIsDenominated = CPrivateSend : : IsDenominatedAmount ( item . nAmount ) ;
2017-03-14 07:21:37 +01:00
if ( fSkipDenominated & & fIsDenominated ) continue ;
2017-06-30 20:30:16 +02:00
// assume that the fee to create denoms should be mixing collateral at max
if ( item . nAmount > = nSmallestDenom + ( fIsDenominated ? 0 : nMixingCollateral ) )
2016-07-29 07:27:05 +02:00
nTotal + = item . nAmount ;
2015-04-30 00:06:24 +02:00
}
return nTotal ;
}
2015-04-03 00:51:08 +02:00
CAmount CWallet : : GetAnonymizedBalance ( ) const
2014-12-09 02:17:57 +01:00
{
2015-03-15 19:19:25 +01:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2015-02-06 02:53:28 +01:00
2017-09-27 19:43:16 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
std : : set < uint256 > setWalletTxesCounted ;
for ( auto & outpoint : setWalletUTXO ) {
if ( setWalletTxesCounted . find ( outpoint . hash ) ! = setWalletTxesCounted . end ( ) ) continue ;
setWalletTxesCounted . insert ( outpoint . hash ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( outpoint . hash ) ; it ! = mapWallet . end ( ) & & it - > first = = outpoint . hash ; + + it ) {
if ( it - > second . IsTrusted ( ) )
nTotal + = it - > second . GetAnonymizedCredit ( ) ;
2014-12-09 02:17:57 +01:00
}
}
return nTotal ;
}
2015-07-07 09:21:13 +02:00
// Note: calculated including unconfirmed,
// that's ok as long as we use it for informational purposes only
2017-04-20 22:34:47 +02:00
float CWallet : : GetAverageAnonymizedRounds ( ) const
2014-12-09 02:17:57 +01:00
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2017-04-20 22:34:47 +02:00
int nTotal = 0 ;
int nCount = 0 ;
2014-12-09 02:17:57 +01:00
2017-09-27 19:43:16 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
for ( auto & outpoint : setWalletUTXO ) {
if ( ! IsDenominated ( outpoint ) ) continue ;
2014-12-09 02:17:57 +01:00
2017-09-27 19:43:16 +02:00
nTotal + = GetOutpointPrivateSendRounds ( outpoint ) ;
nCount + + ;
2014-12-09 02:17:57 +01:00
}
2017-04-20 22:34:47 +02:00
if ( nCount = = 0 ) return 0 ;
2014-12-09 02:17:57 +01:00
2017-04-20 22:34:47 +02:00
return ( float ) nTotal / nCount ;
2014-12-09 02:17:57 +01:00
}
2015-07-07 09:21:13 +02:00
// Note: calculated including unconfirmed,
// that's ok as long as we use it for informational purposes only
2015-04-03 00:51:08 +02:00
CAmount CWallet : : GetNormalizedAnonymizedBalance ( ) const
2015-01-28 08:35:17 +01:00
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2015-01-28 08:35:17 +01:00
2017-09-27 19:43:16 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
for ( auto & outpoint : setWalletUTXO ) {
map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( outpoint . hash ) ;
if ( it = = mapWallet . end ( ) ) continue ;
if ( ! IsDenominated ( outpoint ) ) continue ;
if ( it - > second . GetDepthInMainChain ( ) < 0 ) continue ;
2015-01-28 08:35:17 +01:00
2017-09-27 19:43:16 +02:00
int nRounds = GetOutpointPrivateSendRounds ( outpoint ) ;
2016-12-05 08:01:20 +01:00
nTotal + = it - > second . tx - > vout [ outpoint . n ] . nValue * nRounds / privateSendClient . nPrivateSendRounds ;
2015-01-28 08:35:17 +01:00
}
return nTotal ;
}
2016-07-15 12:21:20 +02:00
CAmount CWallet : : GetNeedsToBeAnonymizedBalance ( CAmount nMinBalance ) const
{
if ( fLiteMode ) return 0 ;
CAmount nAnonymizedBalance = GetAnonymizedBalance ( ) ;
2017-05-05 13:26:27 +02:00
CAmount nNeedsToAnonymizeBalance = privateSendClient . nPrivateSendAmount * COIN - nAnonymizedBalance ;
2016-07-15 12:21:20 +02:00
// try to overshoot target DS balance up to nMinBalance
nNeedsToAnonymizeBalance + = nMinBalance ;
CAmount nAnonymizableBalance = GetAnonymizableBalance ( ) ;
// anonymizable balance is way too small
if ( nAnonymizableBalance < nMinBalance ) return 0 ;
// not enough funds to anonymze amount we want, try the max we can
if ( nNeedsToAnonymizeBalance > nAnonymizableBalance ) nNeedsToAnonymizeBalance = nAnonymizableBalance ;
// we should never exceed the pool max
2017-06-30 20:30:16 +02:00
if ( nNeedsToAnonymizeBalance > CPrivateSend : : GetMaxPoolAmount ( ) ) nNeedsToAnonymizeBalance = CPrivateSend : : GetMaxPoolAmount ( ) ;
2016-07-15 12:21:20 +02:00
return nNeedsToAnonymizeBalance ;
}
2015-07-26 01:24:19 +02:00
CAmount CWallet : : GetDenominatedBalance ( bool unconfirmed ) const
2014-12-09 02:17:57 +01:00
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2014-12-09 02:17:57 +01:00
{
2015-02-12 14:26:32 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-09 02:17:57 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-07-26 01:24:19 +02:00
nTotal + = pcoin - > GetDenominatedCredit ( unconfirmed ) ;
2014-12-09 02:17:57 +01: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 ) ;
2011-07-11 20:42:10 +02:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2016-07-04 07:42:50 +02: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 ) ;
2012-02-14 12:08:00 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
2012-06-18 08:32:33 +02:00
const CWalletTx * pcoin = & ( * it ) . second ;
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 : : GetWatchOnlyBalance ( ) 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 ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) )
nTotal + = pcoin - > GetAvailableWatchOnlyCredit ( ) ;
}
}
2014-09-28 16:11:17 +02:00
2014-03-29 05:15:28 +01:00
return nTotal ;
}
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 ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2016-07-04 07:42:50 +02:00
if ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 & & pcoin - > InMempool ( ) )
2014-03-29 05:15:28 +01:00
nTotal + = pcoin - > GetAvailableWatchOnlyCredit ( ) ;
}
}
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 ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
nTotal + = pcoin - > GetImmatureWatchOnlyCredit ( ) ;
}
}
return nTotal ;
}
2016-09-05 18:09:25 +02:00
void CWallet : : AvailableCoins ( vector < COutput > & vCoins , bool fOnlyConfirmed , const CCoinControl * coinControl , bool fIncludeZeroValue , AvailableCoinsType nCoinType , bool fUseInstantSend ) const
2012-02-27 13:19:32 +01:00
{
vCoins . clear ( ) ;
{
2014-06-20 14:32:57 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2012-02-27 13:19:32 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
2014-02-15 22:38:28 +01:00
const uint256 & wtxid = it - > first ;
2012-02-27 13:19:32 +01:00
const CWalletTx * pcoin = & ( * it ) . second ;
2016-02-02 16:28:56 +01:00
if ( ! CheckFinalTx ( * pcoin ) )
2012-05-31 22:01:16 +02:00
continue ;
2014-02-13 01:23:06 +01:00
if ( fOnlyConfirmed & & ! pcoin - > IsTrusted ( ) )
2012-02-27 13:19:32 +01:00
continue ;
if ( pcoin - > IsCoinBase ( ) & & pcoin - > GetBlocksToMaturity ( ) > 0 )
continue ;
2015-02-01 18:11:49 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( false ) ;
2017-01-29 09:22:14 +01:00
// do not use IX for inputs that have less then INSTANTSEND_CONFIRMATIONS_REQUIRED blockchain confirmations
if ( fUseInstantSend & & nDepth < INSTANTSEND_CONFIRMATIONS_REQUIRED )
2014-02-12 19:43:07 +01:00
continue ;
2016-07-04 07:42:50 +02: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
2016-03-23 15:07:30 +01:00
if ( nDepth = = 0 & & ! pcoin - > InMempool ( ) )
continue ;
// 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
2016-07-04 07:42:50 +02:00
if ( nDepth = = 0 & & ! pcoin - > InMempool ( ) )
continue ;
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < pcoin - > tx - > vout . size ( ) ; i + + ) {
2014-12-09 02:17:57 +01:00
bool found = false ;
2016-09-05 18:09:25 +02:00
if ( nCoinType = = ONLY_DENOMINATED ) {
2016-12-05 08:01:20 +01:00
found = CPrivateSend : : IsDenominatedAmount ( pcoin - > tx - > vout [ i ] . nValue ) ;
2017-11-01 16:11:39 +01:00
} else if ( nCoinType = = ONLY_NONDENOMINATED ) {
2016-12-05 08:01:20 +01:00
if ( CPrivateSend : : IsCollateralAmount ( pcoin - > tx - > vout [ i ] . nValue ) ) continue ; // do not use collateral amounts
found = ! CPrivateSend : : IsDenominatedAmount ( pcoin - > tx - > vout [ i ] . nValue ) ;
2016-09-05 18:09:25 +02:00
} else if ( nCoinType = = ONLY_1000 ) {
2016-12-05 08:01:20 +01:00
found = pcoin - > tx - > vout [ i ] . nValue = = 1000 * COIN ;
2016-12-04 21:33:11 +01:00
} else if ( nCoinType = = ONLY_PRIVATESEND_COLLATERAL ) {
2016-12-05 08:01:20 +01:00
found = CPrivateSend : : IsCollateralAmount ( pcoin - > tx - > vout [ i ] . nValue ) ;
2014-12-09 02:17:57 +01:00
} else {
found = true ;
}
if ( ! found ) continue ;
2016-12-05 08:01:20 +01:00
isminetype mine = IsMine ( pcoin - > tx - > vout [ i ] ) ;
2014-07-01 11:00:22 +02:00
if ( ! ( IsSpent ( wtxid , i ) ) & & mine ! = ISMINE_NO & &
2016-09-05 18:09:25 +02:00
( ! IsLockedCoin ( ( * it ) . first , i ) | | nCoinType = = ONLY_1000 ) & &
2016-12-05 08:01:20 +01:00
( pcoin - > tx - > vout [ i ] . nValue > 0 | | fIncludeZeroValue ) & &
2017-09-09 09:04:02 +02:00
( ! coinControl | | ! coinControl - > HasSelected ( ) | | coinControl - > fAllowOtherInputs | | coinControl - > IsSelected ( COutPoint ( ( * it ) . first , i ) ) ) )
2016-02-02 16:28:56 +01:00
vCoins . push_back ( COutput ( pcoin , i , nDepth ,
( ( mine & ISMINE_SPENDABLE ) ! = ISMINE_NO ) | |
2017-09-09 09:04:02 +02:00
( coinControl & & coinControl - > fAllowWatchOnly & & ( mine & ISMINE_WATCH_SOLVABLE ) ! = ISMINE_NO ) ,
( mine & ( ISMINE_SPENDABLE | ISMINE_WATCH_SOLVABLE ) ) ! = ISMINE_NO ) ) ;
2012-09-27 19:52:09 +02:00
}
2012-02-27 13:19:32 +01:00
}
}
}
2014-04-23 00:46:19 +02:00
static void ApproximateBestSubset ( vector < pair < CAmount , pair < const CWalletTx * , unsigned int > > > vValue , const CAmount & nTotalLower , const CAmount & nTargetValue ,
2017-12-28 01:49:05 +01:00
vector < char > & vfBest , CAmount & nBest , bool fUseInstantSend = false , int iterations = 1000 )
2012-04-13 01:22:15 +02:00
{
vector < char > vfIncluded ;
vfBest . assign ( vValue . size ( ) , true ) ;
nBest = nTotalLower ;
2016-10-18 15:38:44 +02:00
FastRandomContext insecure_rand ;
2013-02-16 00:27:57 +01:00
2012-04-13 01:22:15 +02:00
for ( int nRep = 0 ; nRep < iterations & & nBest ! = nTargetValue ; nRep + + )
{
vfIncluded . assign ( vValue . size ( ) , false ) ;
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2012-04-13 01:22:15 +02:00
bool fReachedTarget = false ;
for ( int nPass = 0 ; nPass < 2 & & ! fReachedTarget ; nPass + + )
{
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
{
2017-11-03 21:04:47 +01:00
if ( fUseInstantSend & & nTotal + vValue [ i ] . first > sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) * COIN ) {
2017-10-25 16:57:56 +02:00
continue ;
}
2013-02-16 00:27:57 +01:00
//The solver here uses a randomized algorithm,
//the randomness serves no real security purpose but is just
//needed to prevent degenerate behavior and it is important
2014-10-26 08:03:12 +01:00
//that the rng is fast. We do not use a constant random sequence,
2013-02-16 00:27:57 +01:00
//because there may be some privacy improvement by making
//the selection random.
2016-10-18 15:38:44 +02:00
if ( nPass = = 0 ? insecure_rand . rand32 ( ) & 1 : ! vfIncluded [ i ] )
2012-04-13 01:22:15 +02:00
{
nTotal + = vValue [ i ] . first ;
vfIncluded [ i ] = true ;
if ( nTotal > = nTargetValue )
{
fReachedTarget = true ;
if ( nTotal < nBest )
{
nBest = nTotal ;
vfBest = vfIncluded ;
}
nTotal - = vValue [ i ] . first ;
vfIncluded [ i ] = false ;
}
}
}
}
}
}
2014-12-23 04:06:47 +01:00
// move denoms down
bool less_then_denom ( const COutput & out1 , const COutput & out2 )
{
const CWalletTx * pcoin1 = out1 . tx ;
const CWalletTx * pcoin2 = out2 . tx ;
bool found1 = false ;
bool found2 = false ;
2017-06-30 20:30:16 +02:00
BOOST_FOREACH ( CAmount d , CPrivateSend : : GetStandardDenominations ( ) ) // loop through predefined denoms
2014-12-23 04:06:47 +01:00
{
2016-12-05 08:01:20 +01:00
if ( pcoin1 - > tx - > vout [ out1 . i ] . nValue = = d ) found1 = true ;
if ( pcoin2 - > tx - > vout [ out2 . i ] . nValue = = d ) found2 = true ;
2014-12-23 04:06:47 +01:00
}
return ( ! found1 & & found2 ) ;
}
2016-12-20 13:12:46 +01:00
bool CWallet : : SelectCoinsMinConf ( const CAmount & nTargetValue , const int nConfMine , const int nConfTheirs , const uint64_t nMaxAncestors , vector < COutput > vCoins ,
2017-10-25 16:57:56 +02:00
set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet , bool fUseInstantSend ) const
2011-06-26 19:23:24 +02:00
{
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
// List of values less than target
2014-04-23 00:46:19 +02:00
pair < CAmount , pair < const CWalletTx * , unsigned int > > coinLowestLarger ;
2017-10-25 16:57:56 +02:00
coinLowestLarger . first = fUseInstantSend
2017-11-03 21:04:47 +01:00
? sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) * COIN
2017-10-25 16:57:56 +02:00
: std : : numeric_limits < CAmount > : : max ( ) ;
2011-06-26 19:23:24 +02:00
coinLowestLarger . second . first = NULL ;
2014-04-23 00:46:19 +02:00
vector < pair < CAmount , pair < const CWalletTx * , unsigned int > > > vValue ;
CAmount nTotalLower = 0 ;
2011-06-26 19:23:24 +02:00
2012-04-07 19:52:40 +02:00
random_shuffle ( vCoins . begin ( ) , vCoins . end ( ) , GetRandInt ) ;
2014-12-23 04:06:47 +01:00
// move denoms down on the list
sort ( vCoins . begin ( ) , vCoins . end ( ) , less_then_denom ) ;
// try to find nondenom first to prevent unneeded spending of mixed coins
for ( unsigned int tryDenom = 0 ; tryDenom < 2 ; tryDenom + + )
2011-06-26 19:23:24 +02:00
{
2016-09-05 18:09:25 +02:00
LogPrint ( " selectcoins " , " tryDenom: %d \n " , tryDenom ) ;
2015-02-03 22:00:54 +01:00
vValue . clear ( ) ;
2014-12-23 04:06:47 +01:00
nTotalLower = 0 ;
2015-04-03 00:51:08 +02:00
BOOST_FOREACH ( const COutput & output , vCoins )
2014-12-23 04:06:47 +01:00
{
2015-04-03 00:51:08 +02:00
if ( ! output . fSpendable )
continue ;
2013-07-26 01:06:01 +02:00
2014-12-23 04:06:47 +01:00
const CWalletTx * pcoin = output . tx ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
// if (fDebug) LogPrint("selectcoins", "value %s confirms %d\n", FormatMoney(pcoin->vout[output.i].nValue), output.nDepth);
2015-04-03 00:51:08 +02:00
if ( output . nDepth < ( pcoin - > IsFromMe ( ISMINE_ALL ) ? nConfMine : nConfTheirs ) )
2014-12-23 04:06:47 +01:00
continue ;
2011-06-26 19:23:24 +02:00
2016-12-20 13:12:46 +01:00
if ( ! mempool . TransactionWithinChainLimit ( pcoin - > GetHash ( ) , nMaxAncestors ) )
continue ;
2014-12-23 04:06:47 +01:00
int i = output . i ;
2016-12-05 08:01:20 +01:00
CAmount n = pcoin - > tx - > vout [ i ] . nValue ;
2017-12-04 07:06:07 +01:00
if ( tryDenom = = 0 & & CPrivateSend : : IsDenominatedAmount ( n ) ) continue ; // we don't want denom values on first run
2014-12-23 04:06:47 +01:00
2015-04-03 00:51:08 +02:00
pair < CAmount , pair < const CWalletTx * , unsigned int > > coin = make_pair ( n , make_pair ( pcoin , i ) ) ;
2014-12-23 04:06:47 +01:00
if ( n = = nTargetValue )
{
setCoinsRet . insert ( coin . second ) ;
nValueRet + = coin . first ;
return true ;
}
2016-02-02 16:28:56 +01:00
else if ( n < nTargetValue + MIN_CHANGE )
2014-12-23 04:06:47 +01:00
{
vValue . push_back ( coin ) ;
nTotalLower + = n ;
}
else if ( n < coinLowestLarger . first )
{
coinLowestLarger = coin ;
}
2012-02-27 13:19:32 +01:00
}
2014-12-23 04:06:47 +01:00
if ( nTotalLower = = nTargetValue )
2012-02-27 13:19:32 +01:00
{
2014-12-23 04:06:47 +01:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; + + i )
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
}
return true ;
2011-06-26 19:23:24 +02:00
}
2014-12-23 04:06:47 +01:00
if ( nTotalLower < nTargetValue )
2011-06-26 19:23:24 +02:00
{
2014-12-23 04:06:47 +01:00
if ( coinLowestLarger . second . first = = NULL ) // there is no input larger than nTargetValue
{
if ( tryDenom = = 0 )
// we didn't look at denom yet, let's do it
continue ;
else
// we looked at everything possible and didn't find anything, no luck
return false ;
}
setCoinsRet . insert ( coinLowestLarger . second ) ;
nValueRet + = coinLowestLarger . first ;
return true ;
2011-06-26 19:23:24 +02:00
}
2014-12-23 04:06:47 +01:00
// nTotalLower > nTargetValue
break ;
2011-06-26 19:23:24 +02:00
}
// Solve subset sum by stochastic approximation
2016-01-20 15:54:22 +01:00
std : : sort ( vValue . begin ( ) , vValue . end ( ) , CompareValueOnly ( ) ) ;
std : : reverse ( vValue . begin ( ) , vValue . end ( ) ) ;
2012-04-13 01:22:15 +02:00
vector < char > vfBest ;
2014-04-23 00:46:19 +02:00
CAmount nBest ;
2011-06-26 19:23:24 +02:00
2017-10-25 16:57:56 +02:00
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue , vfBest , nBest , fUseInstantSend ) ;
2015-09-13 23:23:59 +02:00
if ( nBest ! = nTargetValue & & nTotalLower > = nTargetValue + MIN_CHANGE )
2017-10-25 16:57:56 +02:00
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue + MIN_CHANGE , vfBest , nBest , fUseInstantSend ) ;
2011-06-26 19:23:24 +02:00
2012-04-13 01:22:15 +02:00
// If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
// or the next bigger coin is closer), return the bigger coin
if ( coinLowestLarger . second . first & &
2015-09-13 23:23:59 +02:00
( ( nBest ! = nTargetValue & & nBest < nTargetValue + MIN_CHANGE ) | | coinLowestLarger . first < = nBest ) )
2011-06-26 19:23:24 +02:00
{
setCoinsRet . insert ( coinLowestLarger . second ) ;
nValueRet + = coinLowestLarger . first ;
}
else {
2015-02-07 06:19:02 +01:00
string s = " CWallet::SelectCoinsMinConf best subset: " ;
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
2015-02-06 06:38:29 +01:00
{
2011-06-26 19:23:24 +02:00
if ( vfBest [ i ] )
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
2015-06-23 22:44:20 +02:00
s + = FormatMoney ( vValue [ i ] . first ) + " " ;
2011-06-26 19:23:24 +02:00
}
2015-02-06 06:38:29 +01:00
}
2016-10-22 18:52:14 +02:00
LogPrint ( " selectcoins " , " %s - total %s \n " , s , FormatMoney ( nBest ) ) ;
2011-06-26 19:23:24 +02:00
}
return true ;
}
2016-03-23 08:55:50 +01:00
bool CWallet : : SelectCoins ( const vector < COutput > & vAvailableCoins , const CAmount & nTargetValue , set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet , const CCoinControl * coinControl , AvailableCoinsType nCoinType , bool fUseInstantSend ) const
2011-06-26 19:23:24 +02:00
{
2015-03-24 16:11:00 +01:00
// Note: this function should never be used for "always free" tx types like dstx
2016-03-23 08:55:50 +01:00
vector < COutput > vCoins ( vAvailableCoins ) ;
2013-08-12 17:03:03 +02:00
2015-06-23 17:47:05 +02:00
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
2015-04-25 03:29:00 +02:00
if ( coinControl & & coinControl - > HasSelected ( ) & & ! coinControl - > fAllowOtherInputs )
2015-06-23 17:47:05 +02:00
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
if ( ! out . fSpendable )
continue ;
2016-10-16 21:23:17 +02:00
if ( nCoinType = = ONLY_DENOMINATED ) {
2017-09-11 16:13:48 +02:00
COutPoint outpoint = COutPoint ( out . tx - > GetHash ( ) , out . i ) ;
int nRounds = GetOutpointPrivateSendRounds ( outpoint ) ;
2015-06-23 17:47:05 +02:00
// make sure it's actually anonymized
2017-05-05 13:26:27 +02:00
if ( nRounds < privateSendClient . nPrivateSendRounds ) continue ;
2015-06-23 17:47:05 +02:00
}
2016-12-05 08:01:20 +01:00
nValueRet + = out . tx - > tx - > vout [ out . i ] . nValue ;
2015-06-23 17:47:05 +02:00
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
}
2017-01-29 09:22:14 +01:00
2015-06-23 17:47:05 +02:00
return ( nValueRet > = nTargetValue ) ;
}
2016-10-16 21:23:17 +02:00
//if we're doing only denominated, we need to round up to the nearest smallest denomination
if ( nCoinType = = ONLY_DENOMINATED ) {
2017-06-30 20:30:16 +02:00
std : : vector < CAmount > vecPrivateSendDenominations = CPrivateSend : : GetStandardDenominations ( ) ;
2016-10-16 21:23:17 +02:00
CAmount nSmallestDenom = vecPrivateSendDenominations . back ( ) ;
2014-12-09 02:17:57 +01:00
// Make outputs by looping through denominations, from large to small
2016-10-16 21:23:17 +02:00
BOOST_FOREACH ( CAmount nDenom , vecPrivateSendDenominations )
2014-12-09 02:17:57 +01:00
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
2016-10-16 21:23:17 +02:00
//make sure it's the denom we're looking for, round the amount up to smallest denom
2016-12-05 08:01:20 +01:00
if ( out . tx - > tx - > vout [ out . i ] . nValue = = nDenom & & nValueRet + nDenom < nTargetValue + nSmallestDenom ) {
2017-09-11 16:13:48 +02:00
COutPoint outpoint = COutPoint ( out . tx - > GetHash ( ) , out . i ) ;
int nRounds = GetOutpointPrivateSendRounds ( outpoint ) ;
2015-03-24 16:11:00 +01:00
// make sure it's actually anonymized
2017-05-05 13:26:27 +02:00
if ( nRounds < privateSendClient . nPrivateSendRounds ) continue ;
2016-10-16 21:23:17 +02:00
nValueRet + = nDenom ;
2015-03-24 16:11:00 +01:00
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
2014-12-09 02:17:57 +01:00
}
}
}
return ( nValueRet > = nTargetValue ) ;
}
2015-04-25 03:29:00 +02:00
// calculate value from preset inputs and store them
set < pair < const CWalletTx * , uint32_t > > setPresetCoins ;
CAmount nValueFromPresetInputs = 0 ;
std : : vector < COutPoint > vPresetInputs ;
if ( coinControl )
coinControl - > ListSelected ( vPresetInputs ) ;
BOOST_FOREACH ( const COutPoint & outpoint , vPresetInputs )
{
map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( outpoint . hash ) ;
if ( it ! = mapWallet . end ( ) )
{
const CWalletTx * pcoin = & it - > second ;
// Clearly invalid input, fail
2016-12-05 08:01:20 +01:00
if ( pcoin - > tx - > vout . size ( ) < = outpoint . n )
2015-04-25 03:29:00 +02:00
return false ;
2016-12-05 08:01:20 +01:00
nValueFromPresetInputs + = pcoin - > tx - > vout [ outpoint . n ] . nValue ;
2015-04-25 03:29:00 +02:00
setPresetCoins . insert ( make_pair ( pcoin , outpoint . n ) ) ;
} else
return false ; // TODO: Allow non-wallet inputs
}
// remove preset inputs from vCoins
for ( vector < COutput > : : iterator it = vCoins . begin ( ) ; it ! = vCoins . end ( ) & & coinControl & & coinControl - > HasSelected ( ) ; )
{
if ( setPresetCoins . count ( make_pair ( it - > tx , it - > i ) ) )
it = vCoins . erase ( it ) ;
else
+ + it ;
}
2016-12-20 13:12:46 +01:00
size_t nMaxChainLength = std : : min ( GetArg ( " -limitancestorcount " , DEFAULT_ANCESTOR_LIMIT ) , GetArg ( " -limitdescendantcount " , DEFAULT_DESCENDANT_LIMIT ) ) ;
bool fRejectLongChains = GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ;
2015-04-25 03:29:00 +02:00
bool res = nTargetValue < = nValueFromPresetInputs | |
2016-12-20 13:12:46 +01:00
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 1 , 6 , 0 , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) | |
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 1 , 1 , 0 , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) | |
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , 2 , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) ) | |
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , std : : min ( ( size_t ) 4 , nMaxChainLength / 3 ) , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) ) | |
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , nMaxChainLength / 2 , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) ) | |
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , nMaxChainLength , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) ) | |
( bSpendZeroConfChange & & ! fRejectLongChains & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , std : : numeric_limits < uint64_t > : : max ( ) , vCoins , setCoinsRet , nValueRet , fUseInstantSend ) ) ;
2014-12-09 02:17:57 +01:00
2015-04-25 03:29:00 +02:00
// because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
setCoinsRet . insert ( setPresetCoins . begin ( ) , setPresetCoins . end ( ) ) ;
// add preset inputs to the total value selected
nValueRet + = nValueFromPresetInputs ;
return res ;
2011-06-26 19:23:24 +02:00
}
2014-12-09 02:17:57 +01:00
struct CompareByPriority
{
bool operator ( ) ( const COutput & t1 ,
const COutput & t2 ) const
{
return t1 . Priority ( ) > t2 . Priority ( ) ;
}
} ;
2017-01-12 12:49:06 +01:00
bool CWallet : : FundTransaction ( CMutableTransaction & tx , CAmount & nFeeRet , bool overrideEstimatedFeeRate , const CFeeRate & specificFeeRate , int & nChangePosInOut , std : : string & strFailReason , bool includeWatching , bool lockUnspents , const std : : set < int > & setSubtractFeeFromOutputs , const CTxDestination & destChange )
2015-04-25 03:29:00 +02:00
{
vector < CRecipient > vecSend ;
// Turn the txout set into a CRecipient vector
2017-01-12 12:49:06 +01:00
for ( size_t idx = 0 ; idx < tx . vout . size ( ) ; idx + + )
2015-04-25 03:29:00 +02:00
{
2017-01-12 12:49:06 +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 ) ;
}
CCoinControl coinControl ;
2016-04-15 16:23:16 +02:00
coinControl . destChange = destChange ;
2015-04-25 03:29:00 +02:00
coinControl . fAllowOtherInputs = true ;
2015-04-24 06:42:49 +02:00
coinControl . fAllowWatchOnly = includeWatching ;
2016-06-03 15:31:49 +02:00
coinControl . fOverrideFeeRate = overrideEstimatedFeeRate ;
coinControl . nFeeRate = specificFeeRate ;
2015-04-25 03:29:00 +02:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
coinControl . Select ( txin . prevout ) ;
CReserveKey reservekey ( this ) ;
CWalletTx wtx ;
2016-04-15 16:23:16 +02:00
if ( ! CreateTransaction ( vecSend , wtx , reservekey , nFeeRet , nChangePosInOut , strFailReason , & coinControl , false ) )
2015-04-25 03:29:00 +02:00
return false ;
2016-04-15 16:23:16 +02:00
if ( nChangePosInOut ! = - 1 )
2016-12-05 08:01:20 +01:00
tx . vout . insert ( tx . vout . begin ( ) + nChangePosInOut , wtx . tx - > vout [ nChangePosInOut ] ) ;
2015-04-25 03:29:00 +02:00
2017-01-12 12:49:06 +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 + + )
tx . vout [ idx ] . nValue = wtx . tx - > vout [ idx ] . nValue ;
2015-04-25 03:29:00 +02:00
// Add new txins (keeping original txin scriptSig/order)
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtx . tx - > vin )
2015-04-25 03:29:00 +02:00
{
2017-09-09 09:04:02 +02:00
if ( ! coinControl . IsSelected ( txin . prevout ) )
2016-04-15 16:23:16 +02:00
{
2015-04-25 03:29:00 +02:00
tx . vin . push_back ( txin ) ;
2016-04-15 16:23:16 +02:00
if ( lockUnspents )
{
LOCK2 ( cs_main , cs_wallet ) ;
LockCoin ( txin . prevout ) ;
}
}
2015-04-25 03:29:00 +02:00
}
return true ;
}
2017-12-04 07:06:07 +01:00
bool CWallet : : SelectCoinsByDenominations ( int nDenom , CAmount nValueMin , CAmount nValueMax , std : : vector < CTxDSIn > & vecTxDSInRet , std : : vector < COutput > & vCoinsRet , CAmount & nValueRet , int nPrivateSendRoundsMin , int nPrivateSendRoundsMax )
2014-12-30 01:09:34 +01:00
{
2017-12-04 07:06:07 +01:00
vecTxDSInRet . clear ( ) ;
2016-10-16 21:23:17 +02:00
vCoinsRet . clear ( ) ;
2014-12-30 01:09:34 +01:00
nValueRet = 0 ;
vector < COutput > vCoins ;
2016-02-02 16:28:56 +01:00
AvailableCoins ( vCoins , true , NULL , false , ONLY_DENOMINATED ) ;
2014-12-30 01:09:34 +01:00
2016-10-16 21:23:17 +02:00
std : : random_shuffle ( vCoins . rbegin ( ) , vCoins . rend ( ) , GetRandInt ) ;
2014-12-30 01:09:34 +01:00
2016-09-05 18:09:25 +02:00
// ( bit on if present )
// bit 0 - 100DASH+1
// bit 1 - 10DASH+1
// bit 2 - 1DASH+1
// bit 3 - .1DASH+1
2016-10-16 21:23:17 +02:00
std : : vector < int > vecBits ;
2017-06-30 20:30:16 +02:00
if ( ! CPrivateSend : : GetDenominationsBits ( nDenom , vecBits ) ) {
2016-10-16 21:23:17 +02:00
return false ;
}
int nDenomResult = 0 ;
2014-12-30 01:09:34 +01:00
2017-06-30 20:30:16 +02:00
std : : vector < CAmount > vecPrivateSendDenominations = CPrivateSend : : GetStandardDenominations ( ) ;
2018-01-12 16:37:39 +01:00
FastRandomContext insecure_rand ;
2014-12-30 01:09:34 +01:00
BOOST_FOREACH ( const COutput & out , vCoins )
{
2015-04-07 03:45:30 +02:00
// masternode-like input should not be selected by AvailableCoins now anyway
//if(out.tx->vout[out.i].nValue == 1000*COIN) continue;
2016-12-05 08:01:20 +01:00
if ( nValueRet + out . tx - > tx - > vout [ out . i ] . nValue < = nValueMax ) {
2014-12-30 01:09:34 +01:00
2016-10-16 21:23:17 +02:00
CTxIn txin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
2014-12-30 01:09:34 +01:00
2017-09-11 16:13:48 +02:00
int nRounds = GetOutpointPrivateSendRounds ( txin . prevout ) ;
2016-09-05 18:09:25 +02:00
if ( nRounds > = nPrivateSendRoundsMax ) continue ;
if ( nRounds < nPrivateSendRoundsMin ) continue ;
2014-12-30 01:09:34 +01:00
2016-10-16 21:23:17 +02:00
BOOST_FOREACH ( int nBit , vecBits ) {
2016-12-05 08:01:20 +01:00
if ( out . tx - > tx - > vout [ out . i ] . nValue = = vecPrivateSendDenominations [ nBit ] ) {
2016-10-16 21:23:17 +02:00
if ( nValueRet > = nValueMin ) {
//randomly reduce the max amount we'll submit (for anonymity)
2018-01-12 16:37:39 +01:00
nValueMax - = insecure_rand . rand32 ( nValueMax / 5 ) ;
2016-10-16 21:23:17 +02:00
//on average use 50% of the inputs or less
2018-01-12 16:37:39 +01:00
int r = insecure_rand . rand32 ( vCoins . size ( ) ) ;
2017-12-04 07:06:07 +01:00
if ( ( int ) vecTxDSInRet . size ( ) > r ) return true ;
2016-10-16 21:23:17 +02:00
}
2016-12-05 08:01:20 +01:00
nValueRet + = out . tx - > tx - > vout [ out . i ] . nValue ;
vecTxDSInRet . push_back ( CTxDSIn ( txin , out . tx - > tx - > vout [ out . i ] . scriptPubKey ) ) ;
2016-10-16 21:23:17 +02:00
vCoinsRet . push_back ( out ) ;
nDenomResult | = 1 < < nBit ;
2015-01-19 22:25:03 +01:00
}
2014-12-30 01:09:34 +01:00
}
}
}
2016-10-16 21:23:17 +02:00
return nValueRet > = nValueMin & & nDenom = = nDenomResult ;
2014-12-30 01:09:34 +01:00
}
2016-07-15 12:21:20 +02:00
struct CompareByAmount
{
bool operator ( ) ( const CompactTallyItem & t1 ,
const CompactTallyItem & t2 ) const
{
return t1 . nAmount > t2 . nAmount ;
}
} ;
2017-06-06 01:47:12 +02:00
bool CWallet : : SelectCoinsGrouppedByAddresses ( std : : vector < CompactTallyItem > & vecTallyRet , bool fSkipDenominated , bool fAnonymizable , bool fSkipUnconfirmed ) const
2016-07-15 12:21:20 +02:00
{
LOCK2 ( cs_main , cs_wallet ) ;
isminefilter filter = ISMINE_SPENDABLE ;
2017-06-06 01:47:12 +02:00
// try to use cache for already confirmed anonymizable inputs
if ( fAnonymizable & & fSkipUnconfirmed ) {
2016-07-29 07:27:05 +02:00
if ( fSkipDenominated & & fAnonymizableTallyCachedNonDenom ) {
vecTallyRet = vecAnonymizableTallyCachedNonDenom ;
2017-06-06 01:47:12 +02:00
LogPrint ( " selectcoins " , " SelectCoinsGrouppedByAddresses - using cache for non-denom inputs %d \n " , vecTallyRet . size ( ) ) ;
2017-03-14 07:21:37 +01:00
return vecTallyRet . size ( ) > 0 ;
2016-07-29 07:27:05 +02:00
}
if ( ! fSkipDenominated & & fAnonymizableTallyCached ) {
vecTallyRet = vecAnonymizableTallyCached ;
2017-06-06 01:47:12 +02:00
LogPrint ( " selectcoins " , " SelectCoinsGrouppedByAddresses - using cache for all inputs %d \n " , vecTallyRet . size ( ) ) ;
2017-03-14 07:21:37 +01:00
return vecTallyRet . size ( ) > 0 ;
2016-07-29 07:27:05 +02:00
}
}
2017-06-30 20:30:16 +02:00
CAmount nSmallestDenom = CPrivateSend : : GetSmallestDenomination ( ) ;
2016-07-15 12:21:20 +02:00
// Tally
2017-09-27 19:43:16 +02:00
map < CTxDestination , CompactTallyItem > mapTally ;
std : : set < uint256 > setWalletTxesCounted ;
for ( auto & outpoint : setWalletUTXO ) {
if ( setWalletTxesCounted . find ( outpoint . hash ) ! = setWalletTxesCounted . end ( ) ) continue ;
setWalletTxesCounted . insert ( outpoint . hash ) ;
map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( outpoint . hash ) ;
if ( it = = mapWallet . end ( ) ) continue ;
2016-07-15 12:21:20 +02:00
const CWalletTx & wtx = ( * it ) . second ;
if ( wtx . IsCoinBase ( ) & & wtx . GetBlocksToMaturity ( ) > 0 ) continue ;
2017-06-06 01:47:12 +02:00
if ( fSkipUnconfirmed & & ! wtx . IsTrusted ( ) ) continue ;
2016-07-15 12:21:20 +02:00
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < wtx . tx - > vout . size ( ) ; i + + ) {
2017-09-27 19:43:16 +02:00
CTxDestination txdest ;
2016-12-05 08:01:20 +01:00
if ( ! ExtractDestination ( wtx . tx - > vout [ i ] . scriptPubKey , txdest ) ) continue ;
2016-07-15 12:21:20 +02:00
2017-09-27 19:43:16 +02:00
isminefilter mine = : : IsMine ( * this , txdest ) ;
2016-07-15 12:21:20 +02:00
if ( ! ( mine & filter ) ) continue ;
2017-09-27 19:43:16 +02:00
if ( IsSpent ( outpoint . hash , i ) | | IsLockedCoin ( outpoint . hash , i ) ) continue ;
2016-07-29 07:27:05 +02:00
2016-12-05 08:01:20 +01:00
if ( fSkipDenominated & & CPrivateSend : : IsDenominatedAmount ( wtx . tx - > vout [ i ] . nValue ) ) continue ;
2016-07-15 12:21:20 +02:00
2016-07-29 07:27:05 +02:00
if ( fAnonymizable ) {
// ignore collaterals
2016-12-05 08:01:20 +01:00
if ( CPrivateSend : : IsCollateralAmount ( wtx . tx - > vout [ i ] . nValue ) ) continue ;
if ( fMasterNode & & wtx . tx - > vout [ i ] . nValue = = 1000 * COIN ) continue ;
2016-07-29 07:27:05 +02:00
// ignore outputs that are 10 times smaller then the smallest denomination
// otherwise they will just lead to higher fee / lower priority
2016-12-05 08:01:20 +01:00
if ( wtx . tx - > vout [ i ] . nValue < = nSmallestDenom / 10 ) continue ;
2016-07-29 07:27:05 +02:00
// ignore anonymized
2017-09-27 19:43:16 +02:00
if ( GetOutpointPrivateSendRounds ( COutPoint ( outpoint . hash , i ) ) > = privateSendClient . nPrivateSendRounds ) continue ;
2016-07-29 07:27:05 +02:00
}
2017-09-27 19:43:16 +02:00
CompactTallyItem & item = mapTally [ txdest ] ;
item . txdest = txdest ;
2016-12-05 08:01:20 +01:00
item . nAmount + = wtx . tx - > vout [ i ] . nValue ;
2017-09-27 19:43:16 +02:00
item . vecTxIn . push_back ( CTxIn ( outpoint . hash , i ) ) ;
2016-07-15 12:21:20 +02:00
}
}
// construct resulting vector
2016-07-29 07:27:05 +02:00
vecTallyRet . clear ( ) ;
2017-09-27 19:43:16 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , CompactTallyItem ) & item , mapTally ) {
2017-06-30 20:30:16 +02:00
if ( fAnonymizable & & item . second . nAmount < nSmallestDenom ) continue ;
2016-07-15 12:21:20 +02:00
vecTallyRet . push_back ( item . second ) ;
2017-03-14 07:21:37 +01:00
}
2016-07-15 12:21:20 +02:00
// order by amounts per address, from smallest to largest
sort ( vecTallyRet . rbegin ( ) , vecTallyRet . rend ( ) , CompareByAmount ( ) ) ;
2017-06-06 01:47:12 +02:00
// cache already confirmed anonymizable entries for later use
if ( fAnonymizable & & fSkipUnconfirmed ) {
2016-07-29 07:27:05 +02:00
if ( fSkipDenominated ) {
vecAnonymizableTallyCachedNonDenom = vecTallyRet ;
fAnonymizableTallyCachedNonDenom = true ;
} else {
vecAnonymizableTallyCached = vecTallyRet ;
fAnonymizableTallyCached = true ;
}
}
2016-07-15 12:21:20 +02:00
// debug
2017-09-27 19:43:16 +02:00
if ( LogAcceptCategory ( " selectcoins " ) ) {
std : : string strMessage = " SelectCoinsGrouppedByAddresses - vecTallyRet: \n " ;
BOOST_FOREACH ( CompactTallyItem & item , vecTallyRet )
strMessage + = strprintf ( " %s %f \n " , CBitcoinAddress ( item . txdest ) . ToString ( ) . c_str ( ) , float ( item . nAmount ) / COIN ) ;
LogPrint ( " selectcoins " , " %s " , strMessage ) ;
}
2016-07-15 12:21:20 +02:00
2017-03-14 07:21:37 +01:00
return vecTallyRet . size ( ) > 0 ;
2016-07-15 12:21:20 +02:00
}
2016-09-05 18:09:25 +02:00
bool CWallet : : SelectCoinsDark ( CAmount nValueMin , CAmount nValueMax , std : : vector < CTxIn > & vecTxInRet , CAmount & nValueRet , int nPrivateSendRoundsMin , int nPrivateSendRoundsMax ) const
2014-12-09 02:17:57 +01:00
{
CCoinControl * coinControl = NULL ;
2016-09-05 18:09:25 +02:00
vecTxInRet . clear ( ) ;
2014-12-30 01:09:34 +01:00
nValueRet = 0 ;
2014-12-09 02:17:57 +01:00
vector < COutput > vCoins ;
2017-11-01 16:11:39 +01:00
AvailableCoins ( vCoins , true , coinControl , false , nPrivateSendRoundsMin < 0 ? ONLY_NONDENOMINATED : ONLY_DENOMINATED ) ;
2014-12-09 02:17:57 +01:00
2015-02-18 13:31:40 +01:00
//order the array so largest nondenom are first, then denominations, then very small inputs.
2014-12-09 02:17:57 +01:00
sort ( vCoins . rbegin ( ) , vCoins . rend ( ) , CompareByPriority ( ) ) ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
2017-03-14 07:21:37 +01:00
//do not allow inputs less than 1/10th of minimum value
2016-12-05 08:01:20 +01:00
if ( out . tx - > tx - > vout [ out . i ] . nValue < nValueMin / 10 ) continue ;
2015-04-30 00:06:24 +02:00
//do not allow collaterals to be selected
2016-12-05 08:01:20 +01:00
if ( CPrivateSend : : IsCollateralAmount ( out . tx - > tx - > vout [ out . i ] . nValue ) ) continue ;
if ( fMasterNode & & out . tx - > tx - > vout [ out . i ] . nValue = = 1000 * COIN ) continue ; //masternode input
2014-12-09 02:17:57 +01:00
2016-12-05 08:01:20 +01:00
if ( nValueRet + out . tx - > tx - > vout [ out . i ] . nValue < = nValueMax ) {
2016-09-05 18:09:25 +02:00
CTxIn txin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
2014-12-09 02:17:57 +01:00
2017-09-11 16:13:48 +02:00
int nRounds = GetOutpointPrivateSendRounds ( txin . prevout ) ;
2016-09-05 18:09:25 +02:00
if ( nRounds > = nPrivateSendRoundsMax ) continue ;
if ( nRounds < nPrivateSendRoundsMin ) continue ;
2014-12-09 02:17:57 +01:00
2016-12-05 08:01:20 +01:00
nValueRet + = out . tx - > tx - > vout [ out . i ] . nValue ;
2016-09-05 18:09:25 +02:00
vecTxInRet . push_back ( txin ) ;
2014-12-09 02:17:57 +01:00
}
}
2017-03-14 07:21:37 +01:00
return nValueRet > = nValueMin ;
2014-12-09 02:17:57 +01:00
}
2017-12-04 07:06:07 +01:00
bool CWallet : : GetCollateralTxDSIn ( CTxDSIn & txdsinRet , CAmount & nValueRet ) const
2014-12-09 02:17:57 +01:00
{
vector < COutput > vCoins ;
2015-01-29 23:15:04 +01:00
AvailableCoins ( vCoins ) ;
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( const COutput & out , vCoins )
{
2016-12-05 08:01:20 +01:00
if ( CPrivateSend : : IsCollateralAmount ( out . tx - > tx - > vout [ out . i ] . nValue ) )
2015-01-27 05:13:34 +01:00
{
2016-12-05 08:01:20 +01:00
txdsinRet = CTxDSIn ( CTxIn ( out . tx - > tx - > GetHash ( ) , out . i ) , out . tx - > tx - > vout [ out . i ] . scriptPubKey ) ;
nValueRet = out . tx - > tx - > vout [ out . i ] . nValue ;
2014-12-09 02:17:57 +01:00
return true ;
}
}
return false ;
}
2017-09-11 16:13:48 +02:00
bool CWallet : : GetMasternodeOutpointAndKeys ( COutPoint & outpointRet , CPubKey & pubKeyRet , CKey & keyRet , std : : string strTxHash , std : : string strOutputIndex )
2016-07-15 08:33:16 +02:00
{
// wait for reindex and/or import to finish
if ( fImporting | | fReindex ) return false ;
// Find possible candidates
std : : vector < COutput > vPossibleCoins ;
AvailableCoins ( vPossibleCoins , true , NULL , false , ONLY_1000 ) ;
if ( vPossibleCoins . empty ( ) ) {
2017-09-11 16:13:48 +02:00
LogPrintf ( " CWallet::GetMasternodeOutpointAndKeys -- Could not locate any valid masternode vin \n " ) ;
2016-07-15 08:33:16 +02:00
return false ;
}
if ( strTxHash . empty ( ) ) // No output specified, select the first one
2017-09-11 16:13:48 +02:00
return GetOutpointAndKeysFromOutput ( vPossibleCoins [ 0 ] , outpointRet , pubKeyRet , keyRet ) ;
2016-07-15 08:33:16 +02:00
// Find specific vin
uint256 txHash = uint256S ( strTxHash ) ;
int nOutputIndex = atoi ( strOutputIndex . c_str ( ) ) ;
BOOST_FOREACH ( COutput & out , vPossibleCoins )
if ( out . tx - > GetHash ( ) = = txHash & & out . i = = nOutputIndex ) // found it!
2017-09-11 16:13:48 +02:00
return GetOutpointAndKeysFromOutput ( out , outpointRet , pubKeyRet , keyRet ) ;
2016-07-15 08:33:16 +02:00
2017-09-11 16:13:48 +02:00
LogPrintf ( " CWallet::GetMasternodeOutpointAndKeys -- Could not locate specified masternode vin \n " ) ;
2016-07-15 08:33:16 +02:00
return false ;
}
2017-09-11 16:13:48 +02:00
bool CWallet : : GetOutpointAndKeysFromOutput ( const COutput & out , COutPoint & outpointRet , CPubKey & pubKeyRet , CKey & keyRet )
2016-07-15 08:33:16 +02:00
{
// wait for reindex and/or import to finish
if ( fImporting | | fReindex ) return false ;
CScript pubScript ;
2017-09-11 16:13:48 +02:00
outpointRet = COutPoint ( out . tx - > GetHash ( ) , out . i ) ;
2016-12-05 08:01:20 +01:00
pubScript = out . tx - > tx - > vout [ out . i ] . scriptPubKey ; // the inputs PubKey
2016-07-15 08:33:16 +02:00
CTxDestination address1 ;
ExtractDestination ( pubScript , address1 ) ;
CBitcoinAddress address2 ( address1 ) ;
CKeyID keyID ;
if ( ! address2 . GetKeyID ( keyID ) ) {
2017-09-11 16:13:48 +02:00
LogPrintf ( " CWallet::GetOutpointAndKeysFromOutput -- Address does not refer to a key \n " ) ;
2016-07-15 08:33:16 +02:00
return false ;
}
if ( ! GetKey ( keyID , keyRet ) ) {
2017-09-11 16:13:48 +02:00
LogPrintf ( " CWallet::GetOutpointAndKeysFromOutput -- Private key for address is not known \n " ) ;
2016-07-15 08:33:16 +02:00
return false ;
}
pubKeyRet = keyRet . GetPubKey ( ) ;
return true ;
}
2016-01-24 05:21:14 +01:00
int CWallet : : CountInputsWithAmount ( CAmount nInputAmount )
2014-12-09 02:17:57 +01:00
{
2016-01-24 05:21:14 +01:00
CAmount nTotal = 0 ;
2014-12-09 02:17:57 +01:00
{
2016-11-28 15:21:50 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-09 02:17:57 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) ) {
2015-02-06 02:53:28 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( false ) ;
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < pcoin - > tx - > vout . size ( ) ; i + + ) {
2017-09-09 09:04:02 +02:00
COutput out = COutput ( pcoin , i , nDepth , true , true ) ;
2017-09-11 16:13:48 +02:00
COutPoint outpoint = COutPoint ( out . tx - > GetHash ( ) , out . i ) ;
2014-12-09 02:17:57 +01:00
2016-12-05 08:01:20 +01:00
if ( out . tx - > tx - > vout [ out . i ] . nValue ! = nInputAmount ) continue ;
if ( ! CPrivateSend : : IsDenominatedAmount ( pcoin - > tx - > vout [ i ] . nValue ) ) continue ;
if ( IsSpent ( out . tx - > GetHash ( ) , i ) | | IsMine ( pcoin - > tx - > vout [ i ] ) ! = ISMINE_SPENDABLE | | ! IsDenominated ( outpoint ) ) continue ;
2014-12-09 02:17:57 +01:00
2015-02-06 02:53:28 +01:00
nTotal + + ;
2014-12-09 02:17:57 +01:00
}
}
}
}
return nTotal ;
}
2015-08-16 02:29:16 +02:00
bool CWallet : : HasCollateralInputs ( bool fOnlyConfirmed ) const
2014-12-09 02:17:57 +01:00
{
vector < COutput > vCoins ;
2016-12-04 21:33:11 +01:00
AvailableCoins ( vCoins , fOnlyConfirmed , NULL , false , ONLY_PRIVATESEND_COLLATERAL ) ;
2014-12-09 02:17:57 +01:00
2016-12-04 21:33:11 +01:00
return ! vCoins . empty ( ) ;
2014-12-09 02:17:57 +01:00
}
2015-07-10 00:08:26 +02:00
bool CWallet : : CreateCollateralTransaction ( CMutableTransaction & txCollateral , std : : string & strReason )
2014-12-09 02:17:57 +01:00
{
txCollateral . vin . clear ( ) ;
txCollateral . vout . clear ( ) ;
CReserveKey reservekey ( this ) ;
2016-09-05 18:09:25 +02:00
CAmount nValue = 0 ;
2017-12-04 07:06:07 +01:00
CTxDSIn txdsinCollateral ;
2014-12-09 02:17:57 +01:00
2017-12-04 07:06:07 +01:00
if ( ! GetCollateralTxDSIn ( txdsinCollateral , nValue ) ) {
2016-09-05 18:09:25 +02:00
strReason = " PrivateSend requires a collateral transaction and could not locate an acceptable input! " ;
2014-12-09 02:17:57 +01:00
return false ;
}
// make our change address
CScript scriptChange ;
CPubKey vchPubKey ;
2017-05-29 13:51:40 +02:00
assert ( reservekey . GetReservedKey ( vchPubKey , true ) ) ; // should never fail, as we just unlocked
2015-04-03 00:51:08 +02:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
reservekey . KeepKey ( ) ;
2017-12-04 07:06:07 +01:00
txCollateral . vin . push_back ( txdsinCollateral ) ;
2014-12-09 02:17:57 +01:00
2016-10-26 01:33:52 +02:00
//pay collateral charge in fees
2017-06-30 20:30:16 +02:00
CTxOut txout = CTxOut ( nValue - CPrivateSend : : GetCollateralAmount ( ) , scriptChange ) ;
2016-10-26 01:33:52 +02:00
txCollateral . vout . push_back ( txout ) ;
2011-06-26 19:23:24 +02:00
2017-12-04 07:06:07 +01:00
if ( ! SignSignature ( * this , txdsinCollateral . prevPubKey , txCollateral , 0 , int ( SIGHASH_ALL | SIGHASH_ANYONECANPAY ) ) ) {
2016-10-26 01:33:52 +02:00
strReason = " Unable to sign collateral transaction! " ;
return false ;
2014-12-09 02:17:57 +01:00
}
return true ;
}
2016-12-05 08:01:20 +01:00
bool CWallet : : GetBudgetSystemCollateralTX ( CTransactionRef & tx , uint256 hash , CAmount amount , bool fUseInstantSend )
2015-07-12 19:34:21 +02:00
{
CWalletTx wtx ;
2016-09-05 01:44:10 +02:00
if ( GetBudgetSystemCollateralTX ( wtx , hash , amount , fUseInstantSend ) ) {
2016-12-05 08:01:20 +01:00
tx = wtx . tx ;
2015-07-12 19:34:21 +02:00
return true ;
}
return false ;
}
2016-09-05 01:44:10 +02:00
bool CWallet : : GetBudgetSystemCollateralTX ( CWalletTx & tx , uint256 hash , CAmount amount , bool fUseInstantSend )
2015-07-10 00:08:26 +02:00
{
// make our change address
2016-12-20 00:05:24 +01:00
CReserveKey reservekey ( this ) ;
2015-07-10 00:08:26 +02:00
CScript scriptChange ;
scriptChange < < OP_RETURN < < ToByteVector ( hash ) ;
2016-01-24 05:21:14 +01:00
CAmount nFeeRet = 0 ;
2016-02-02 16:28:56 +01:00
int nChangePosRet = - 1 ;
2015-07-10 00:08:26 +02:00
std : : string strFail = " " ;
2016-02-02 16:28:56 +01:00
vector < CRecipient > vecSend ;
2016-09-05 01:44:10 +02:00
vecSend . push_back ( ( CRecipient ) { scriptChange , amount , false } ) ;
2015-07-10 00:08:26 +02:00
CCoinControl * coinControl = NULL ;
2016-09-02 14:17:32 +02:00
bool success = CreateTransaction ( vecSend , tx , reservekey , nFeeRet , nChangePosRet , strFail , coinControl , true , ALL_COINS , fUseInstantSend ) ;
2015-07-10 00:08:26 +02:00
if ( ! success ) {
2016-09-05 18:09:25 +02:00
LogPrintf ( " CWallet::GetBudgetSystemCollateralTX -- Error: %s \n " , strFail ) ;
2015-07-10 00:08:26 +02:00
return false ;
}
return true ;
}
2016-09-05 18:09:25 +02:00
bool CWallet : : ConvertList ( std : : vector < CTxIn > vecTxIn , std : : vector < CAmount > & vecAmounts )
2014-12-09 02:17:57 +01:00
{
2016-09-05 18:09:25 +02:00
BOOST_FOREACH ( CTxIn txin , vecTxIn ) {
if ( mapWallet . count ( txin . prevout . hash ) ) {
CWalletTx & wtx = mapWallet [ txin . prevout . hash ] ;
2016-12-05 08:01:20 +01:00
if ( txin . prevout . n < wtx . tx - > vout . size ( ) ) {
vecAmounts . push_back ( wtx . tx - > vout [ txin . prevout . n ] . nValue ) ;
2014-12-09 02:17:57 +01:00
}
} else {
2016-09-05 18:09:25 +02:00
LogPrintf ( " CWallet::ConvertList -- Couldn't find transaction \n " ) ;
2014-12-09 02:17:57 +01:00
}
}
return true ;
}
2011-06-26 19:23:24 +02:00
2015-04-25 03:29:00 +02:00
bool CWallet : : CreateTransaction ( const vector < CRecipient > & vecSend , CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet ,
2016-04-15 16:23:16 +02:00
int & nChangePosInOut , std : : string & strFailReason , const CCoinControl * coinControl , bool sign , AvailableCoinsType nCoinType , bool fUseInstantSend )
2011-06-26 19:23:24 +02:00
{
2017-01-29 09:22:14 +01:00
CAmount nFeePay = fUseInstantSend ? CTxLockRequest ( ) . GetMinFee ( ) : 0 ;
2015-07-10 00:08:26 +02:00
2014-04-23 00:46:19 +02:00
CAmount nValue = 0 ;
2016-04-15 16:23:16 +02:00
int nChangePosRequest = nChangePosInOut ;
2014-07-23 14:34:36 +02:00
unsigned int nSubtractFeeFromAmount = 0 ;
2017-01-05 22:28:24 +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-23 08:42:02 +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-23 08:42:02 +01:00
if ( vecSend . empty ( ) )
2013-04-25 23:31:22 +02:00
{
2016-11-23 08:42:02 +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-05-27 21:44:57 +02:00
wtxNew . fTimeReceivedIsTxTime = true ;
2011-06-28 23:45:22 +02:00
wtxNew . BindWallet ( this ) ;
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.
2016-03-21 21:23:45 +01:00
2016-12-08 21:03:57 +01:00
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 ) ;
2011-06-26 19:23:24 +02:00
{
2017-01-05 22:28:24 +01:00
set < pair < const CWalletTx * , unsigned int > > setCoins ;
std : : vector < CTxDSIn > vecTxDSInTmp ;
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
{
2016-03-23 08:55:50 +01:00
std : : vector < COutput > vAvailableCoins ;
AvailableCoins ( vAvailableCoins , true , coinControl , false , nCoinType , fUseInstantSend ) ;
2014-11-02 00:14:47 +01:00
nFeeRet = 0 ;
2015-07-17 17:32:50 +02:00
if ( nFeePay > 0 ) nFeeRet = nFeePay ;
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-04-15 16:23:16 +02:00
nChangePosInOut = nChangePosRequest ;
2014-06-07 13:53:27 +02:00
txNew . vin . clear ( ) ;
txNew . vout . clear ( ) ;
2011-06-26 19:23:24 +02:00
wtxNew . fFromMe = true ;
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 ;
2011-06-26 19:23:24 +02:00
double dPriority = 0 ;
// vouts to the payees
2017-01-05 22:28:24 +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 )
{
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 ;
}
}
2014-07-03 20:25:32 +02:00
if ( txout . IsDust ( : : minRelayTxFee ) )
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
2014-04-23 00:46:19 +02:00
CAmount nValueIn = 0 ;
2017-01-05 22:28:24 +01:00
setCoins . clear ( ) ;
2016-03-23 08:55:50 +01:00
if ( ! SelectCoins ( vAvailableCoins , nValueToSelect , setCoins , nValueIn , coinControl , nCoinType , fUseInstantSend ) )
2013-04-25 23:31:22 +02:00
{
2017-11-01 16:11:39 +01:00
if ( nCoinType = = ONLY_NONDENOMINATED ) {
strFailReason = _ ( " Unable to locate enough PrivateSend non-denominated funds for this transaction. " ) ;
2017-01-29 09:22:14 +01:00
} else if ( nCoinType = = ONLY_DENOMINATED ) {
2016-05-09 21:08:13 +02:00
strFailReason = _ ( " Unable to locate enough PrivateSend denominated funds for this transaction. " ) ;
strFailReason + = " " + _ ( " PrivateSend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins. " ) ;
2017-01-29 09:22:14 +01:00
} else if ( nValueIn < nValueToSelect ) {
strFailReason = _ ( " Insufficient funds. " ) ;
2017-09-14 13:41:58 +02:00
if ( fUseInstantSend ) {
2017-01-29 09:22:14 +01:00
// could be not true but most likely that's the reason
strFailReason + = " " + strprintf ( _ ( " InstantSend requires inputs with at least %d confirmations, you might need to wait a few minutes and try again. " ) , INSTANTSEND_CONFIRMATIONS_REQUIRED ) ;
}
2015-02-04 16:30:00 +01:00
}
2014-12-09 02:17:57 +01:00
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2017-09-14 13:41:58 +02:00
if ( fUseInstantSend & & nValueIn > sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) * COIN ) {
strFailReason + = " " + strprintf ( _ ( " InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH. " ) , sporkManager . GetSporkValue ( SPORK_5_INSTANTSEND_MAX_VALUE ) ) ;
return false ;
}
2014-12-09 02:17:57 +01:00
2017-01-05 22:28:24 +01:00
for ( const auto & pcoin : setCoins )
2011-06-26 19:23:24 +02:00
{
2016-12-05 08:01:20 +01:00
CAmount nCredit = pcoin . first - > tx - > vout [ pcoin . second ] . nValue ;
2015-01-16 18:17:57 +01:00
//The coin age after the next block (depth+1) is used instead of the current,
2012-12-26 18:45:42 +01:00
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
2015-01-16 18:17:57 +01:00
//But mempool inputs might still be in the mempool, so their age stays 0
int age = pcoin . first - > GetDepthInMainChain ( ) ;
2015-11-26 18:42:07 +01:00
assert ( age > = 0 ) ;
2015-01-16 18:17:57 +01:00
if ( age ! = 0 )
age + = 1 ;
dPriority + = ( double ) nCredit * age ;
2011-06-26 19:23:24 +02:00
}
2015-03-18 19:22:49 +01:00
const CAmount nChange = nValueIn - nValueToSelect ;
2016-03-06 15:50:14 +01:00
CTxOut newTxOut ;
2015-01-27 15:29:25 +01:00
2011-07-24 16:37:09 +02:00
if ( nChange > 0 )
2011-06-26 19:23:24 +02:00
{
2013-08-12 17:03:03 +02:00
2016-02-02 16:28:56 +01:00
//over pay for denominated transactions
2016-09-05 18:09:25 +02:00
if ( nCoinType = = ONLY_DENOMINATED ) {
2016-02-02 16:28:56 +01:00
nFeeRet + = nChange ;
wtxNew . mapValue [ " DS " ] = " 1 " ;
// recheck skipped denominations during next mixing
2017-05-05 13:26:27 +02:00
privateSendClient . ClearSkippedDenominations ( ) ;
2016-02-02 16:28:56 +01:00
} else {
2013-08-12 17:03:03 +02:00
2016-02-02 16:28:56 +01:00
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-dash-address
CScript scriptChange ;
2013-08-12 17:03:03 +02:00
2016-02-02 16:28:56 +01:00
// coin control: send change to custom address
if ( coinControl & & ! boost : : get < CNoDestination > ( & coinControl - > destChange ) )
scriptChange = GetScriptForDestination ( coinControl - > destChange ) ;
2011-06-26 19:23:24 +02:00
2016-02-02 16:28:56 +01:00
// no coin control: send change to newly generated address
else
{
// 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
CPubKey vchPubKey ;
2017-05-29 13:51:40 +02:00
if ( ! reservekey . GetReservedKey ( vchPubKey , true ) )
2017-04-11 12:53:54 +02:00
{
strFailReason = _ ( " Keypool ran out, please call keypoolrefill first " ) ;
return false ;
}
2016-02-02 16:28:56 +01:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
}
2013-04-25 00:27:00 +02:00
2016-03-06 15:50:14 +01:00
newTxOut = CTxOut ( nChange , scriptChange ) ;
2013-04-25 00:27:00 +02:00
2016-02-02 16:28:56 +01:00
// We do not move dust-change to fees, because the sender would end up paying more than requested.
// This would be against the purpose of the all-inclusive feature.
// So instead we raise the change and deduct from the recipient.
if ( nSubtractFeeFromAmount > 0 & & newTxOut . IsDust ( : : minRelayTxFee ) )
2014-07-23 14:34:36 +02:00
{
2016-02-02 16:28:56 +01:00
CAmount nDust = newTxOut . GetDustThreshold ( : : minRelayTxFee ) - newTxOut . nValue ;
newTxOut . nValue + = nDust ; // raise change until no more dust
for ( unsigned int i = 0 ; i < vecSend . size ( ) ; i + + ) // subtract from first recipient
2014-07-23 14:34:36 +02:00
{
2016-02-02 16:28:56 +01:00
if ( vecSend [ i ] . fSubtractFeeFromAmount )
2014-07-23 14:34:36 +02:00
{
2016-02-02 16:28:56 +01:00
txNew . vout [ i ] . nValue - = nDust ;
if ( txNew . vout [ i ] . IsDust ( : : minRelayTxFee ) )
{
strFailReason = _ ( " The transaction amount is too small to send after the fee has been deducted " ) ;
return false ;
}
break ;
2014-07-23 14:34:36 +02:00
}
}
}
2016-02-02 16:28:56 +01:00
// Never create dust outputs; if we would, just
// add the dust to the fee.
if ( newTxOut . IsDust ( : : minRelayTxFee ) )
{
2016-04-15 16:23:16 +02:00
nChangePosInOut = - 1 ;
2016-02-02 16:28:56 +01:00
nFeeRet + = nChange ;
reservekey . ReturnKey ( ) ;
}
else
{
2016-04-15 16:23:16 +02:00
if ( nChangePosInOut = = - 1 )
{
// Insert change txn at random position:
nChangePosInOut = GetRandInt ( txNew . vout . size ( ) + 1 ) ;
}
2016-06-09 07:28:00 +02:00
else if ( ( unsigned int ) nChangePosInOut > txNew . vout . size ( ) )
2016-04-15 16:23:16 +02:00
{
strFailReason = _ ( " Change index out of range " ) ;
return false ;
}
vector < CTxOut > : : iterator position = txNew . vout . begin ( ) + nChangePosInOut ;
2016-02-02 16:28:56 +01:00
txNew . vout . insert ( position , newTxOut ) ;
}
2013-04-25 00:27:00 +02:00
}
2011-06-26 19:23:24 +02:00
}
else
reservekey . ReturnKey ( ) ;
// Fill vin
2013-08-25 20:13:25 +02:00
//
// Note how the sequence number is set to max()-1 so that the
// nLockTime set above actually works.
2017-01-05 22:28:24 +01:00
vecTxDSInTmp . clear ( ) ;
for ( const auto & coin : setCoins ) {
2016-09-05 18:09:25 +02:00
CTxIn txin = CTxIn ( coin . first - > GetHash ( ) , coin . second , CScript ( ) ,
2016-02-14 22:03:55 +01:00
std : : numeric_limits < unsigned int > : : max ( ) - 1 ) ;
2016-12-05 08:01:20 +01:00
vecTxDSInTmp . push_back ( CTxDSIn ( txin , coin . first - > tx - > vout [ coin . second ] . scriptPubKey ) ) ;
2016-09-05 18:09:25 +02:00
txNew . vin . push_back ( txin ) ;
2016-02-14 22:03:55 +01:00
}
2011-06-26 19:23:24 +02:00
2017-07-10 16:42:59 +02:00
sort ( txNew . vin . begin ( ) , txNew . vin . end ( ) , CompareInputBIP69 ( ) ) ;
2017-12-04 07:06:07 +01:00
sort ( vecTxDSInTmp . begin ( ) , vecTxDSInTmp . end ( ) , CompareInputBIP69 ( ) ) ;
2017-07-10 16:42:59 +02:00
sort ( txNew . vout . begin ( ) , txNew . vout . end ( ) , CompareOutputBIP69 ( ) ) ;
2015-08-21 03:28:17 +02:00
2016-03-06 15:50:14 +01:00
// If there was change output added before, we must update its position now
2016-04-15 16:23:16 +02:00
if ( nChangePosInOut ! = - 1 ) {
2016-03-06 15:50:14 +01:00
int i = 0 ;
BOOST_FOREACH ( const CTxOut & txOut , txNew . vout )
{
if ( txOut = = newTxOut )
{
2016-04-15 16:23:16 +02:00
nChangePosInOut = i ;
2016-03-06 15:50:14 +01:00
break ;
}
i + + ;
}
}
2017-01-05 22:28:24 +01:00
// Fill in dummy signatures for fee calculation.
2011-06-26 19:23:24 +02:00
int nIn = 0 ;
2017-12-04 07:06:07 +01:00
for ( const auto & txdsin : vecTxDSInTmp )
2015-04-25 03:29:00 +02:00
{
2017-12-04 07:06:07 +01:00
const CScript & scriptPubKey = txdsin . prevPubKey ;
2015-04-25 03:29:00 +02:00
CScript & scriptSigRes = txNew . vin [ nIn ] . scriptSig ;
2017-01-05 22:28:24 +01:00
if ( ! ProduceSignature ( DummySignatureCreator ( this ) , scriptPubKey , scriptSigRes ) )
2013-04-25 23:31:22 +02:00
{
strFailReason = _ ( " Signing transaction failed " ) ;
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2015-04-25 03:29:00 +02:00
nIn + + ;
}
unsigned int nBytes = : : GetSerializeSize ( txNew , SER_NETWORK , PROTOCOL_VERSION ) ;
2017-01-05 22:28:24 +01:00
CTransaction txNewConst ( txNew ) ;
dPriority = txNewConst . ComputePriority ( dPriority , nBytes ) ;
2014-06-07 13:53:27 +02:00
2017-01-05 22:28:24 +01:00
// Remove scriptSigs to eliminate the fee calculation dummy signatures
for ( auto & txin : txNew . vin ) {
txin . scriptSig = CScript ( ) ;
2013-04-25 23:31:22 +02:00
}
2015-04-25 03:29:00 +02:00
2016-10-28 14:08:39 +02:00
// Allow to override the default confirmation target over the CoinControl instance
int currentConfirmationTarget = nTxConfirmTarget ;
if ( coinControl & & coinControl - > nConfirmTarget > 0 )
currentConfirmationTarget = coinControl - > nConfirmTarget ;
2014-12-16 10:43:40 +01:00
// Can we complete this as a free transaction?
2017-12-13 13:43:05 +01:00
// Note: InstantSend transaction can't be a free one
if ( ! fUseInstantSend & & fSendFreeTransactions & & nBytes < = MAX_FREE_TRANSACTION_CREATE_SIZE )
2011-06-26 19:23:24 +02:00
{
2014-12-16 10:43:40 +01:00
// Not enough fee: enough priority?
2016-10-28 14:08:39 +02:00
double dPriorityNeeded = mempool . estimateSmartPriority ( currentConfirmationTarget ) ;
2015-11-16 21:15:32 +01:00
// Require at least hard-coded AllowFree.
if ( dPriority > = dPriorityNeeded & & AllowFree ( dPriority ) )
2014-12-16 10:43:40 +01:00
break ;
// Small enough, and priority high enough, to send for free
2016-02-02 16:28:56 +01:00
// if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
// break;
2014-12-16 10:43:40 +01:00
}
2016-10-28 14:08:39 +02:00
CAmount nFeeNeeded = max ( nFeePay , GetMinimumFee ( nBytes , currentConfirmationTarget , mempool ) ) ;
2015-11-25 13:04:52 +01:00
if ( coinControl & & nFeeNeeded > 0 & & coinControl - > nMinimumTotalFee > nFeeNeeded ) {
nFeeNeeded = coinControl - > nMinimumTotalFee ;
}
2017-01-29 09:22:14 +01:00
if ( fUseInstantSend ) {
nFeeNeeded = std : : max ( nFeeNeeded , CTxLockRequest ( txNew ) . GetMinFee ( ) ) ;
}
2016-06-03 15:31:49 +02:00
if ( coinControl & & coinControl - > fOverrideFeeRate )
nFeeNeeded = coinControl - > nFeeRate . GetFee ( nBytes ) ;
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-09 17:20:41 +01:00
if ( nFeeRet > = nFeeNeeded ) {
// Reduce fee to only the needed amount if we have change
// output to increase. 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.
// TODO: The case where nSubtractFeeFromAmount > 0 remains
// to be addressed because it requires returning the fee to
// the payees and not the change output.
// TODO: The case where there is no change output remains
// to be addressed so we avoid creating too small an output.
if ( nFeeRet > nFeeNeeded & & nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
CAmount extraFeePaid = nFeeRet - nFeeNeeded ;
vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
change_position - > nValue + = extraFeePaid ;
nFeeRet - = extraFeePaid ;
}
2014-12-16 10:43:40 +01:00
break ; // Done, enough fee included.
2017-01-09 17:20:41 +01:00
}
// Try to reduce change to include necessary fee
if ( nChangePosInOut ! = - 1 & & nSubtractFeeFromAmount = = 0 ) {
CAmount additionalFeeNeeded = nFeeNeeded - nFeeRet ;
vector < CTxOut > : : iterator change_position = txNew . vout . begin ( ) + nChangePosInOut ;
// 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
}
}
2011-06-26 19:23:24 +02:00
2014-05-27 21:44:57 +02:00
// Include more fee and try again.
nFeeRet = nFeeNeeded ;
continue ;
2011-06-26 19:23:24 +02:00
}
}
2017-01-05 22:28:24 +01:00
if ( sign )
{
CTransaction txNewConst ( txNew ) ;
int nIn = 0 ;
for ( const auto & txdsin : vecTxDSInTmp )
{
const CScript & scriptPubKey = txdsin . prevPubKey ;
CScript & scriptSigRes = txNew . vin [ nIn ] . scriptSig ;
if ( ! ProduceSignature ( TransactionSignatureCreator ( this , & txNewConst , nIn , SIGHASH_ALL ) , scriptPubKey , scriptSigRes ) )
{
strFailReason = _ ( " Signing transaction failed " ) ;
return false ;
}
nIn + + ;
}
}
// Embed the constructed transaction data in wtxNew.
wtxNew . SetTx ( MakeTransactionRef ( std : : move ( txNew ) ) ) ;
2011-06-26 19:23:24 +02:00
}
2016-12-20 13:12:46 +01:00
if ( GetBoolArg ( " -walletrejectlongchains " , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ) {
// Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp ;
2017-01-05 23:14:23 +01:00
CTxMemPoolEntry entry ( wtxNew . tx , 0 , 0 , 0 , 0 , 0 , false , 0 , lp ) ;
2016-12-20 13:12:46 +01:00
CTxMemPool : : setEntries setAncestors ;
size_t nLimitAncestors = GetArg ( " -limitancestorcount " , DEFAULT_ANCESTOR_LIMIT ) ;
size_t nLimitAncestorSize = GetArg ( " -limitancestorsize " , DEFAULT_ANCESTOR_SIZE_LIMIT ) * 1000 ;
size_t nLimitDescendants = GetArg ( " -limitdescendantcount " , DEFAULT_DESCENDANT_LIMIT ) ;
size_t nLimitDescendantSize = GetArg ( " -limitdescendantsize " , DEFAULT_DESCENDANT_SIZE_LIMIT ) * 1000 ;
std : : string errString ;
if ( ! mempool . CalculateMemPoolAncestors ( entry , setAncestors , nLimitAncestors , nLimitAncestorSize , nLimitDescendants , nLimitDescendantSize , errString ) ) {
strFailReason = _ ( " Transaction has too long of a mempool chain " ) ;
return false ;
}
}
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
*/
2016-10-28 13:49:04 +02:00
bool CWallet : : CommitTransaction ( CWalletTx & wtxNew , CReserveKey & reservekey , CConnman * connman , CValidationState & state , std : : string strCommand )
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2016-12-05 08:01:20 +01:00
LogPrintf ( " CommitTransaction: \n %s " , wtxNew . tx - > ToString ( ) ) ;
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-08-01 01:57:52 +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
2015-02-06 05:25:46 +01:00
set < uint256 > updated_hahes ;
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtxNew . tx - > vin )
2011-06-26 19:23:24 +02:00
{
2015-02-06 05:25:46 +01:00
// notify only once
if ( updated_hahes . find ( txin . prevout . hash ) ! = updated_hahes . end ( ) ) continue ;
2011-06-26 19:23:24 +02:00
CWalletTx & coin = mapWallet [ txin . prevout . hash ] ;
2011-06-28 23:45:22 +02:00
coin . BindWallet ( this ) ;
2015-02-06 05:25:46 +01:00
NotifyTransactionChanged ( this , txin . prevout . hash , CT_UPDATED ) ;
updated_hahes . insert ( txin . prevout . hash ) ;
2011-06-26 19:23:24 +02:00
}
}
// Track how many getdata requests our transaction gets
2011-08-26 20:37:23 +02:00
mapRequestCount [ wtxNew . GetHash ( ) ] = 0 ;
2011-06-26 19:23:24 +02: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
2016-10-28 13:49:04 +02:00
if ( ! wtxNew . AcceptToMemoryPool ( maxTxFee , state ) ) {
2016-12-13 12:15:25 +01:00
LogPrintf ( " CommitTransaction(): Transaction cannot be broadcast immediately, %s \n " , state . GetRejectReason ( ) ) ;
// TODO: if we expect the failure to be long term or permanent, instead delete wtx from the wallet and return failure.
} else {
wtxNew . RelayWalletTransaction ( connman , strCommand ) ;
2015-03-27 10:34:48 +01:00
}
2011-06-26 19:23:24 +02:00
}
}
return true ;
}
2016-09-20 12:46:59 +02:00
void CWallet : : ListAccountCreditDebit ( const std : : string & strAccount , std : : list < CAccountingEntry > & entries ) {
CWalletDB walletdb ( strWalletFile ) ;
return walletdb . ListAccountCreditDebit ( strAccount , entries ) ;
}
bool CWallet : : AddAccountingEntry ( const CAccountingEntry & acentry )
{
CWalletDB walletdb ( strWalletFile ) ;
return AddAccountingEntry ( acentry , & walletdb ) ;
}
bool CWallet : : AddAccountingEntry ( const CAccountingEntry & acentry , CWalletDB * pwalletdb )
2015-10-19 11:19:38 +02:00
{
2016-09-20 12:46:59 +02:00
if ( ! pwalletdb - > WriteAccountingEntry_Backend ( acentry ) )
2015-10-19 11:19:38 +02:00
return false ;
laccentries . push_back ( acentry ) ;
CAccountingEntry & entry = laccentries . back ( ) ;
wtxOrdered . insert ( make_pair ( entry . nOrderPos , TxPair ( ( CWalletTx * ) 0 , & entry ) ) ) ;
return true ;
}
2015-10-25 02:47:04 +02:00
CAmount CWallet : : GetRequiredFee ( unsigned int nTxBytes )
{
return std : : max ( minTxFee . GetFee ( nTxBytes ) , : : minRelayTxFee . GetFee ( nTxBytes ) ) ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetMinimumFee ( unsigned int nTxBytes , unsigned int nConfirmTarget , const CTxMemPool & pool )
2014-05-27 21:44:57 +02:00
{
// payTxFee is user-set "I want to pay this much"
2014-04-23 00:46:19 +02:00
CAmount nFeeNeeded = payTxFee . GetFee ( nTxBytes ) ;
2014-05-27 21:44:57 +02:00
// User didn't set: use -txconfirmtarget to estimate...
2015-11-16 21:15:32 +01:00
if ( nFeeNeeded = = 0 ) {
int estimateFoundTarget = nConfirmTarget ;
nFeeNeeded = pool . estimateSmartFee ( nConfirmTarget , & estimateFoundTarget ) . GetFee ( nTxBytes ) ;
2016-01-05 19:10:19 +01:00
// ... unless we don't have enough mempool data for estimatefee, then use fallbackFee
if ( nFeeNeeded = = 0 )
nFeeNeeded = fallbackFee . GetFee ( nTxBytes ) ;
}
// prevent user from paying a fee below minRelayTxFee or minTxFee
nFeeNeeded = std : : max ( nFeeNeeded , GetRequiredFee ( nTxBytes ) ) ;
2014-12-16 10:43:40 +01:00
// But always obey the maximum
if ( nFeeNeeded > maxTxFee )
nFeeNeeded = maxTxFee ;
2014-05-27 21:44:57 +02:00
return nFeeNeeded ;
}
2012-09-18 20:30:47 +02:00
DBErrors CWallet : : LoadWallet ( bool & fFirstRunRet )
2011-06-26 19:23:24 +02:00
{
if ( ! fFileBacked )
2012-09-05 10:32:13 +02:00
return DB_LOAD_OK ;
2011-06-26 19:23:24 +02:00
fFirstRunRet = false ;
2012-09-18 20:30:47 +02:00
DBErrors nLoadWalletRet = CWalletDB ( strWalletFile , " cr+ " ) . LoadWallet ( this ) ;
2011-11-11 03:12:46 +01:00
if ( nLoadWalletRet = = DB_NEED_REWRITE )
2011-11-10 21:29:23 +01:00
{
2011-11-11 03:12:46 +01:00
if ( CDB : : Rewrite ( strWalletFile , " \x04 pool " ) )
{
2013-12-19 09:58:06 +01:00
LOCK ( cs_wallet ) ;
2017-05-29 13:51:40 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2016-09-05 18:09:25 +02:00
nKeysLeftSinceAutoBackup = 0 ;
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
}
2017-09-27 19:43:16 +02:00
{
LOCK2 ( cs_main , cs_wallet ) ;
for ( auto & pair : mapWallet ) {
2016-12-05 08:01:20 +01:00
for ( int i = 0 ; i < pair . second . tx - > vout . size ( ) ; + + i ) {
if ( IsMine ( pair . second . tx - > vout [ i ] ) & & ! IsSpent ( pair . first , i ) ) {
2017-09-27 19:43:16 +02:00
setWalletUTXO . insert ( COutPoint ( pair . first , i ) ) ;
}
}
}
}
2011-07-05 03:06:19 +02:00
if ( nLoadWalletRet ! = DB_LOAD_OK )
return nLoadWalletRet ;
2012-05-14 19:07:52 +02:00
fFirstRunRet = ! vchDefaultKey . IsValid ( ) ;
2011-06-26 19:23:24 +02:00
2014-03-19 00:26:14 +01:00
uiInterface . LoadWallet ( this ) ;
2011-07-13 07:07:49 +02:00
return DB_LOAD_OK ;
2011-06-26 19:23:24 +02:00
}
2016-03-29 11:14:47 +02:00
DBErrors CWallet : : ZapSelectTx ( vector < uint256 > & vHashIn , vector < uint256 > & vHashOut )
{
if ( ! fFileBacked )
return DB_LOAD_OK ;
DBErrors nZapSelectTxRet = CWalletDB ( strWalletFile , " cr+ " ) . ZapSelectTx ( this , vHashIn , vHashOut ) ;
if ( nZapSelectTxRet = = DB_NEED_REWRITE )
{
if ( CDB : : Rewrite ( strWalletFile , " \x04 pool " ) )
{
LOCK ( cs_wallet ) ;
2017-09-15 12:08:47 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2016-03-29 11:14:47 +02: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.
}
}
if ( nZapSelectTxRet ! = DB_LOAD_OK )
return nZapSelectTxRet ;
MarkDirty ( ) ;
return DB_LOAD_OK ;
}
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
{
if ( ! fFileBacked )
return DB_LOAD_OK ;
2014-02-14 18:27:15 +01:00
DBErrors nZapWalletTxRet = CWalletDB ( strWalletFile , " cr+ " ) . ZapWalletTx ( this , vWtx ) ;
2014-02-14 17:33:07 +01:00
if ( nZapWalletTxRet = = DB_NEED_REWRITE )
{
if ( CDB : : Rewrite ( strWalletFile , " \x04 pool " ) )
{
LOCK ( cs_wallet ) ;
2017-05-29 13:51:40 +02:00
setInternalKeyPool . clear ( ) ;
setExternalKeyPool . clear ( ) ;
2016-09-05 18:09:25 +02:00
nKeysLeftSinceAutoBackup = 0 ;
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
}
}
if ( nZapWalletTxRet ! = DB_LOAD_OK )
return nZapWalletTxRet ;
return DB_LOAD_OK ;
}
2013-07-22 08:50:39 +02:00
bool CWallet : : SetAddressBook ( const CTxDestination & address , const string & strName , const 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 ) ) ;
2011-07-07 15:22:54 +02:00
if ( ! fFileBacked )
return false ;
2013-07-22 08:50:39 +02:00
if ( ! strPurpose . empty ( ) & & ! CWalletDB ( strWalletFile ) . WritePurpose ( CBitcoinAddress ( address ) . ToString ( ) , strPurpose ) )
return false ;
2012-05-14 23:44:52 +02:00
return CWalletDB ( strWalletFile ) . WriteName ( CBitcoinAddress ( address ) . ToString ( ) , 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
if ( fFileBacked )
2013-11-18 16:55:54 +01:00
{
2014-02-18 18:11:46 +01:00
// Delete destdata tuples associated with address
std : : string strAddress = CBitcoinAddress ( address ) . ToString ( ) ;
BOOST_FOREACH ( const PAIRTYPE ( string , string ) & item , mapAddressBook [ address ] . destdata )
{
CWalletDB ( strWalletFile ) . 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
2011-07-07 15:22:54 +02:00
if ( ! fFileBacked )
return false ;
2013-07-22 08:50:39 +02:00
CWalletDB ( strWalletFile ) . ErasePurpose ( CBitcoinAddress ( address ) . ToString ( ) ) ;
2012-05-14 23:44:52 +02:00
return CWalletDB ( strWalletFile ) . EraseName ( CBitcoinAddress ( address ) . ToString ( ) ) ;
2011-07-07 15:22:54 +02:00
}
2012-05-14 19:07:52 +02:00
bool CWallet : : SetDefaultKey ( const CPubKey & vchPubKey )
2011-07-07 15:22:54 +02:00
{
if ( fFileBacked )
{
if ( ! CWalletDB ( strWalletFile ) . WriteDefaultKey ( vchPubKey ) )
return false ;
}
vchDefaultKey = vchPubKey ;
return true ;
}
2014-10-26 08:03:12 +01:00
/**
* Mark old keypool keys as used ,
* and generate all new keys
*/
2011-11-17 20:01:25 +01:00
bool CWallet : : NewKeyPool ( )
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-11-17 20:01:25 +01:00
CWalletDB walletdb ( strWalletFile ) ;
2017-05-29 13:51:40 +02:00
BOOST_FOREACH ( int64_t nIndex , setInternalKeyPool ) {
2011-11-17 20:01:25 +01:00
walletdb . ErasePool ( nIndex ) ;
2017-05-29 13:51:40 +02:00
}
setInternalKeyPool . clear ( ) ;
BOOST_FOREACH ( int64_t nIndex , setExternalKeyPool ) {
walletdb . ErasePool ( nIndex ) ;
}
setExternalKeyPool . clear ( ) ;
2017-05-05 13:26:27 +02:00
privateSendClient . fEnablePrivateSend = false ;
2016-09-05 18:09:25 +02:00
nKeysLeftSinceAutoBackup = 0 ;
2011-11-17 20:01:25 +01:00
2017-05-29 13:51:40 +02:00
if ( ! TopUpKeyPool ( ) )
2011-11-17 20:01:25 +01:00
return false ;
2017-05-29 13:51:40 +02:00
LogPrintf ( " CWallet::NewKeyPool rewrote keypool \n " ) ;
2011-11-17 20:01:25 +01:00
}
return true ;
}
2017-05-29 13:51:40 +02:00
size_t CWallet : : KeypoolCountExternalKeys ( )
{
AssertLockHeld ( cs_wallet ) ; // setExternalKeyPool
return setExternalKeyPool . size ( ) ;
}
size_t CWallet : : KeypoolCountInternalKeys ( )
{
AssertLockHeld ( cs_wallet ) ; // setInternalKeyPool
return setInternalKeyPool . size ( ) ;
}
2013-06-25 22:07:29 +02:00
bool CWallet : : TopUpKeyPool ( unsigned int kpSize )
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2016-09-11 11:02:54 +02:00
if ( IsLocked ( 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
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
2015-10-04 13:55:33 +02:00
nTargetSize = max ( GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2013-06-25 22:07:29 +02:00
2017-05-29 13:51:40 +02:00
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
int64_t amountExternal = setExternalKeyPool . size ( ) ;
int64_t amountInternal = setInternalKeyPool . size ( ) ;
int64_t missingExternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - amountExternal , ( int64_t ) 0 ) ;
int64_t missingInternal = std : : max ( std : : max ( ( int64_t ) nTargetSize , ( int64_t ) 1 ) - amountInternal , ( int64_t ) 0 ) ;
if ( ! IsHDEnabled ( ) )
{
// don't create extra internal keys
missingInternal = 0 ;
} else {
nTargetSize * = 2 ;
}
bool fInternal = false ;
CWalletDB walletdb ( strWalletFile ) ;
for ( int64_t i = missingInternal + missingExternal ; i - - ; )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nEnd = 1 ;
2017-05-29 13:51:40 +02:00
if ( i < missingInternal ) {
fInternal = true ;
}
if ( ! setInternalKeyPool . empty ( ) ) {
nEnd = * ( - - setInternalKeyPool . end ( ) ) + 1 ;
}
if ( ! setExternalKeyPool . empty ( ) ) {
nEnd = std : : max ( nEnd , * ( - - setExternalKeyPool . end ( ) ) + 1 ) ;
}
// TODO: implement keypools for all accounts?
if ( ! walletdb . WritePool ( nEnd , CKeyPool ( GenerateNewKey ( 0 , fInternal ) , fInternal ) ) )
2016-08-22 09:58:00 +02:00
throw runtime_error ( std : : string ( __func__ ) + " : writing generated key failed " ) ;
2017-05-29 13:51:40 +02:00
if ( fInternal ) {
setInternalKeyPool . insert ( nEnd ) ;
} else {
setExternalKeyPool . insert ( nEnd ) ;
}
LogPrintf ( " keypool added key %d, size=%u, internal=%d \n " , nEnd , setInternalKeyPool . size ( ) + setExternalKeyPool . size ( ) , fInternal ) ;
2015-02-15 00:20:58 +01:00
double dProgress = 100.f * nEnd / ( nTargetSize + 1 ) ;
2014-12-02 12:43:06 +01:00
std : : string strMsg = strprintf ( _ ( " Loading wallet... (%3.2f %%) " ) , dProgress ) ;
2014-12-02 09:48:47 +01:00
uiInterface . InitMessage ( strMsg ) ;
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 ;
}
2017-05-29 13:51:40 +02:00
void CWallet : : ReserveKeyFromKeyPool ( int64_t & nIndex , CKeyPool & keypool , bool fInternal )
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 ) ;
2016-09-11 11:02:54 +02:00
if ( ! IsLocked ( 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
TopUpKeyPool ( ) ;
2011-06-26 19:23:24 +02:00
2017-05-29 13:51:40 +02:00
fInternal = fInternal & & IsHDEnabled ( ) ;
std : : set < int64_t > & setKeyPool = fInternal ? setInternalKeyPool : setExternalKeyPool ;
2011-06-26 19:23:24 +02:00
// Get the oldest key
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 ( setKeyPool . empty ( ) )
return ;
CWalletDB walletdb ( strWalletFile ) ;
2017-05-29 13:51:40 +02:00
nIndex = * setKeyPool . begin ( ) ;
setKeyPool . erase ( nIndex ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
}
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
}
if ( keypool . fInternal ! = fInternal ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : keypool entry misclassified " ) ;
}
2012-05-14 19:07:52 +02:00
assert ( keypool . vchPubKey . IsValid ( ) ) ;
2014-02-24 09:08:56 +01:00
LogPrintf ( " keypool reserve %d \n " , nIndex ) ;
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
if ( fFileBacked )
{
CWalletDB walletdb ( strWalletFile ) ;
2011-08-26 20:37:23 +02:00
walletdb . ErasePool ( nIndex ) ;
2016-06-15 21:13:04 +02:00
nKeysLeftSinceAutoBackup = nWalletBackups ? nKeysLeftSinceAutoBackup - 1 : 0 ;
2011-06-26 19:23:24 +02:00
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " keypool keep %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2017-05-29 13:51:40 +02:00
void CWallet : : ReturnKey ( int64_t nIndex , bool fInternal )
2011-06-26 19:23:24 +02:00
{
// Return to key pool
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
2017-05-29 13:51:40 +02:00
if ( fInternal ) {
setInternalKeyPool . insert ( nIndex ) ;
} else {
setExternalKeyPool . insert ( nIndex ) ;
}
2012-04-06 18:39:12 +02:00
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " keypool return %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2017-05-29 13:51:40 +02:00
bool CWallet : : GetKeyFromPool ( CPubKey & result , bool fInternal )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nIndex = 0 ;
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 ) ;
2017-05-29 13:51:40 +02:00
ReserveKeyFromKeyPool ( nIndex , keypool , fInternal ) ;
2011-09-01 16:58:08 +02:00
if ( nIndex = = - 1 )
2011-08-12 22:32:07 +02:00
{
2016-09-11 11:02:54 +02:00
if ( IsLocked ( true ) ) return false ;
2017-05-29 13:51:40 +02:00
// TODO: implement keypool for all accouts?
result = GenerateNewKey ( 0 , fInternal ) ;
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-05-29 13:51:40 +02:00
static int64_t GetOldestKeyInPool ( const std : : set < int64_t > & setKeyPool , CWalletDB & walletdb ) {
CKeyPool keypool ;
int64_t nIndex = * ( setKeyPool . begin ( ) ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : read oldest key in keypool failed " ) ;
}
assert ( keypool . vchPubKey . IsValid ( ) ) ;
return keypool . nTime ;
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetOldestKeyPoolTime ( )
2011-06-26 19:23:24 +02:00
{
2017-05-29 13:51:40 +02:00
LOCK ( cs_wallet ) ;
// if the keypool is empty, return <NOW>
if ( setExternalKeyPool . empty ( ) & & setInternalKeyPool . 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-05-29 13:51:40 +02:00
CWalletDB walletdb ( strWalletFile ) ;
int64_t oldestKey = - 1 ;
// load oldest key from keypool, get time and return
if ( ! setInternalKeyPool . empty ( ) ) {
oldestKey = std : : max ( GetOldestKeyInPool ( setInternalKeyPool , walletdb ) , oldestKey ) ;
}
if ( ! setExternalKeyPool . empty ( ) ) {
oldestKey = std : : max ( GetOldestKeyInPool ( setExternalKeyPool , walletdb ) , oldestKey ) ;
}
return oldestKey ;
2011-06-26 19:23:24 +02:00
}
2014-04-23 00:46:19 +02:00
std : : map < CTxDestination , CAmount > CWallet : : GetAddressBalances ( )
2012-08-01 18:48:42 +02:00
{
2014-04-23 00:46:19 +02:00
map < CTxDestination , CAmount > balances ;
2012-08-01 18:48:42 +02:00
{
LOCK ( cs_wallet ) ;
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
2016-11-23 07:24:38 +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-12-05 08:01:20 +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-12-05 08:01:20 +01:00
if ( ! IsMine ( pcoin - > tx - > vout [ i ] ) )
2012-08-01 18:48:42 +02:00
continue ;
2016-12-05 08:01:20 +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-12-05 08:01:20 +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 ;
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > CWallet : : GetAddressGroupings ( )
2012-08-01 18:48:42 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > groupings ;
set < CTxDestination > grouping ;
2012-08-01 18:48:42 +02:00
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
2016-12-05 08:01:20 +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
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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 ;
2016-12-05 08:01:20 +01:00
if ( ! ExtractDestination ( mapWallet [ 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 )
{
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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
2016-12-05 08:01:20 +01:00
for ( unsigned int i = 0 ; i < pcoin - > tx - > vout . size ( ) ; i + + )
if ( IsMine ( pcoin - > tx - > vout [ i ] ) )
2012-08-01 18:48:42 +02:00
{
2012-08-20 19:43:33 +02:00
CTxDestination address ;
2016-12-05 08:01:20 +01:00
if ( ! ExtractDestination ( pcoin - > tx - > vout [ i ] . 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 ( ) ;
}
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > * > uniqueGroupings ; // a set of pointers to groups of addresses
map < CTxDestination , set < CTxDestination > * > setmap ; // map addresses to the unique group containing it
2016-09-27 13:25:42 +02:00
BOOST_FOREACH ( set < CTxDestination > _grouping , groupings )
2012-08-01 18:48:42 +02:00
{
// make a set of all the groups hit by this new group
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > * > hits ;
map < CTxDestination , set < CTxDestination > * > : : iterator it ;
2016-09-27 13:25:42 +02:00
BOOST_FOREACH ( 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
2016-09-27 13:25:42 +02:00
set < CTxDestination > * merged = new set < CTxDestination > ( _grouping ) ;
2012-08-20 19:43:33 +02:00
BOOST_FOREACH ( 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
2012-08-20 19:43:33 +02:00
BOOST_FOREACH ( CTxDestination element , * merged )
2012-08-01 18:48:42 +02:00
setmap [ element ] = merged ;
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > ret ;
BOOST_FOREACH ( set < CTxDestination > * uniqueGrouping , uniqueGroupings )
2012-08-01 18:48:42 +02:00
{
ret . insert ( * uniqueGrouping ) ;
delete uniqueGrouping ;
}
return ret ;
}
2016-05-25 18:06:23 +02:00
CAmount CWallet : : GetAccountBalance ( const std : : string & strAccount , int nMinDepth , const isminefilter & filter , bool fAddLockConf )
{
CWalletDB walletdb ( strWalletFile ) ;
return GetAccountBalance ( walletdb , strAccount , nMinDepth , filter , fAddLockConf ) ;
}
CAmount CWallet : : GetAccountBalance ( CWalletDB & walletdb , const std : : string & strAccount , int nMinDepth , const isminefilter & filter , bool fAddLockConf )
{
CAmount nBalance = 0 ;
// Tally wallet transactions
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx & wtx = ( * it ) . second ;
if ( ! CheckFinalTx ( wtx ) | | wtx . GetBlocksToMaturity ( ) > 0 | | wtx . GetDepthInMainChain ( fAddLockConf ) < 0 )
continue ;
CAmount nReceived , nSent , nFee ;
wtx . GetAccountAmounts ( strAccount , nReceived , nSent , nFee , filter ) ;
if ( nReceived ! = 0 & & wtx . GetDepthInMainChain ( fAddLockConf ) > = nMinDepth )
nBalance + = nReceived ;
nBalance - = nSent + nFee ;
}
// Tally internal accounting entries
nBalance + = walletdb . GetAccountCreditDebit ( strAccount ) ;
return nBalance ;
}
2015-05-31 15:36:44 +02:00
std : : set < CTxDestination > CWallet : : GetAccountAddresses ( const std : : string & strAccount ) const
2013-07-16 01:01:09 +02:00
{
2014-11-28 19:11:49 +01:00
LOCK ( cs_wallet ) ;
2013-07-16 01:01:09 +02:00
set < CTxDestination > result ;
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , CAddressBookData ) & item , mapAddressBook )
{
const CTxDestination & address = item . first ;
const string & strName = item . second . name ;
if ( strName = = strAccount )
result . insert ( address ) ;
}
return result ;
}
2017-05-29 13:51:40 +02:00
bool CReserveKey : : GetReservedKey ( CPubKey & pubkey , bool fInternalIn )
2011-06-26 19:23:24 +02:00
{
if ( nIndex = = - 1 )
{
CKeyPool keypool ;
2017-05-29 13:51:40 +02:00
pwallet - > ReserveKeyFromKeyPool ( nIndex , keypool , fInternalIn ) ;
if ( nIndex ! = - 1 ) {
2011-07-14 03:11:40 +02:00
vchPubKey = keypool . vchPubKey ;
2017-05-29 13:51:40 +02:00
}
2013-04-25 19:30:28 +02:00
else {
2014-06-16 14:45:32 +02:00
return false ;
2011-07-14 03:28:31 +02:00
}
2017-05-29 13:51:40 +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 ( )
{
2017-05-29 13:51:40 +02:00
if ( nIndex ! = - 1 ) {
2011-06-26 19:23:24 +02:00
pwallet - > KeepKey ( nIndex ) ;
2017-05-29 13:51:40 +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
}
void CReserveKey : : ReturnKey ( )
{
2017-05-29 13:51:40 +02:00
if ( nIndex ! = - 1 ) {
pwallet - > ReturnKey ( nIndex , fInternal ) ;
}
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-05-29 13:51:40 +02:00
static void LoadReserveKeysToSet ( std : : set < CKeyID > & setAddress , const std : : set < int64_t > & setKeyPool , CWalletDB & walletdb )
2011-07-11 21:49:45 +02:00
{
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( const int64_t & id , setKeyPool )
2011-07-11 21:49:45 +02:00
{
CKeyPool keypool ;
if ( ! walletdb . ReadPool ( id , keypool ) )
2016-08-22 09:58:00 +02:00
throw runtime_error ( std : : string ( __func__ ) + " : read failed " ) ;
2012-05-14 19:07:52 +02:00
assert ( keypool . vchPubKey . IsValid ( ) ) ;
2012-05-14 23:44:52 +02:00
CKeyID keyID = keypool . vchPubKey . GetID ( ) ;
setAddress . insert ( keyID ) ;
2011-07-11 21:49:45 +02:00
}
}
2012-05-05 16:07:14 +02:00
2017-05-29 13:51:40 +02:00
void CWallet : : GetAllReserveKeys ( std : : set < CKeyID > & setAddress ) const
{
setAddress . clear ( ) ;
CWalletDB walletdb ( strWalletFile ) ;
LOCK2 ( cs_main , cs_wallet ) ;
LoadReserveKeysToSet ( setAddress , setInternalKeyPool , walletdb ) ;
LoadReserveKeysToSet ( setAddress , setExternalKeyPool , walletdb ) ;
BOOST_FOREACH ( const CKeyID & keyID , setAddress ) {
if ( ! HaveKey ( keyID ) ) {
throw std : : runtime_error ( std : : string ( __func__ ) + " : unknown key in key pool " ) ;
}
}
}
2015-02-02 13:06:43 +01:00
bool CWallet : : UpdatedTransaction ( const uint256 & hashTx )
2012-05-05 16:07:14 +02:00
{
{
LOCK ( cs_wallet ) ;
// Only notify UI if this transaction is in this wallet
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( hashTx ) ;
2015-02-02 13:06:43 +01:00
if ( mi ! = mapWallet . end ( ) ) {
2012-05-05 16:07:14 +02:00
NotifyTransactionChanged ( this , hashTx , CT_UPDATED ) ;
2015-02-02 13:06:43 +01:00
return true ;
}
2012-05-05 16:07:14 +02:00
}
2015-02-02 13:06:43 +01:00
return false ;
2012-05-05 16:07:14 +02:00
}
2012-09-27 19:52:09 +02:00
2015-07-01 08:32:30 +02:00
void CWallet : : GetScriptForMining ( boost : : shared_ptr < CReserveScript > & script )
2015-04-10 12:49:01 +02:00
{
2015-07-01 08:32:30 +02:00
boost : : shared_ptr < CReserveKey > rKey ( new CReserveKey ( this ) ) ;
2015-04-10 12:49:01 +02:00
CPubKey pubkey ;
2017-05-29 13:51:40 +02:00
if ( ! rKey - > GetReservedKey ( pubkey , false ) )
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-04-15 16:23:16 +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-06-13 08:39:28 +02:00
std : : map < uint256 , CWalletTx > : : iterator it = mapWallet . find ( output . hash ) ;
if ( it ! = mapWallet . end ( ) ) it - > second . MarkDirty ( ) ; // recalculate all credits for this tx
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2012-09-27 19:52:09 +02:00
}
2016-04-15 16:23:16 +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 ) ;
2016-06-13 08:39:28 +02:00
std : : map < uint256 , CWalletTx > : : iterator it = mapWallet . find ( output . hash ) ;
if ( it ! = mapWallet . end ( ) ) it - > second . MarkDirty ( ) ; // recalculate all credits for this tx
2016-07-29 07:27:05 +02:00
fAnonymizableTallyCached = false ;
fAnonymizableTallyCachedNonDenom = false ;
2012-09-27 19:52:09 +02:00
}
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 ) ;
}
void CWallet : : ListLockedCoins ( std : : vector < COutPoint > & vOutpts )
{
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
class CAffectedKeysVisitor : public boost : : static_visitor < void > {
private :
const CKeyStore & keystore ;
std : : vector < CKeyID > & vKeys ;
public :
CAffectedKeysVisitor ( const CKeyStore & keystoreIn , std : : vector < CKeyID > & vKeysIn ) : keystore ( keystoreIn ) , vKeys ( vKeysIn ) { }
void Process ( const CScript & script ) {
txnouttype type ;
std : : vector < CTxDestination > vDest ;
int nRequired ;
if ( ExtractDestinations ( script , type , vDest , nRequired ) ) {
BOOST_FOREACH ( 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 ) ;
}
void operator ( ) ( const CNoDestination & none ) { }
} ;
2013-04-13 07:13:08 +02:00
void CWallet : : GetKeyBirthTimes ( std : : map < CKeyID , 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
for ( std : : map < CKeyID , CKeyMetadata > : : const_iterator it = mapKeyMetadata . begin ( ) ; it ! = mapKeyMetadata . end ( ) ; it + + )
if ( it - > second . nCreateTime )
mapKeyBirth [ it - > first ] = it - > second . nCreateTime ;
// map in which we'll infer heights of other keys
2016-08-17 12:50:28 +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 ;
std : : set < CKeyID > setKeys ;
GetKeys ( setKeys ) ;
BOOST_FOREACH ( const CKeyID & keyid , setKeys ) {
if ( mapKeyBirth . count ( keyid ) = = 0 )
mapKeyFirstBlock [ keyid ] = pindexMax ;
}
setKeys . clear ( ) ;
// 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 ;
for ( std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; it + + ) {
// iterate over all wallet transactions...
const CWalletTx & wtx = ( * it ) . second ;
2014-09-04 02:02:44 +02:00
BlockMap : : const_iterator blit = mapBlockIndex . find ( wtx . hashBlock ) ;
2013-10-10 23:07:44 +02:00
if ( blit ! = mapBlockIndex . end ( ) & & chainActive . Contains ( blit - > second ) ) {
2013-04-29 19:50:40 +02:00
// ... which are already in a block
int nHeight = blit - > second - > nHeight ;
2016-12-05 08:01:20 +01:00
BOOST_FOREACH ( 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 ) ;
2013-04-29 19:50:40 +02:00
BOOST_FOREACH ( const CKeyID & keyid , vAffected ) {
// ... and all their affected keys
std : : map < CKeyID , CBlockIndex * > : : iterator rit = mapKeyFirstBlock . find ( keyid ) ;
if ( rit ! = mapKeyFirstBlock . end ( ) & & nHeight < rit - > second - > nHeight )
rit - > second = blit - > second ;
}
vAffected . clear ( ) ;
}
}
}
// Extract block timestamps for those keys
for ( std : : map < CKeyID , CBlockIndex * > : : const_iterator it = mapKeyFirstBlock . begin ( ) ; it ! = mapKeyFirstBlock . end ( ) ; it + + )
2014-06-28 23:36:06 +02:00
mapKeyBirth [ it - > first ] = it - > second - > GetBlockTime ( ) - 7200 ; // block times can be 2h off
2013-04-29 19:50:40 +02:00
}
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 ) ) ;
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . WriteDestData ( CBitcoinAddress ( dest ) . ToString ( ) , key , value ) ;
}
bool CWallet : : EraseDestData ( const CTxDestination & dest , const std : : string & key )
{
if ( ! mapAddressBook [ dest ] . destdata . erase ( key ) )
return false ;
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . EraseDestData ( CBitcoinAddress ( dest ) . ToString ( ) , key ) ;
}
bool CWallet : : LoadDestData ( const CTxDestination & dest , const std : : string & key , const std : : string & value )
{
mapAddressBook [ dest ] . destdata . insert ( std : : make_pair ( key , value ) ) ;
return true ;
}
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
2016-03-11 08:37:26 +01:00
std : : string CWallet : : GetWalletHelpString ( bool showDebug )
{
std : : string strUsage = HelpMessageGroup ( _ ( " Wallet options: " ) ) ;
strUsage + = HelpMessageOpt ( " -disablewallet " , _ ( " Do not load the wallet and disable wallet RPC calls " ) ) ;
strUsage + = HelpMessageOpt ( " -keypool=<n> " , strprintf ( _ ( " Set key pool size to <n> (default: %u) " ) , DEFAULT_KEYPOOL_SIZE ) ) ;
strUsage + = HelpMessageOpt ( " -fallbackfee=<amt> " , strprintf ( _ ( " A fee rate (in %s/kB) that will be used when fee estimation has insufficient data (default: %s) " ) ,
CURRENCY_UNIT , FormatMoney ( DEFAULT_FALLBACK_FEE ) ) ) ;
strUsage + = HelpMessageOpt ( " -mintxfee=<amt> " , strprintf ( _ ( " Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s) " ) ,
CURRENCY_UNIT , FormatMoney ( DEFAULT_TRANSACTION_MINFEE ) ) ) ;
strUsage + = HelpMessageOpt ( " -paytxfee=<amt> " , strprintf ( _ ( " Fee (in %s/kB) to add to transactions you send (default: %s) " ) ,
CURRENCY_UNIT , FormatMoney ( payTxFee . GetFeePerK ( ) ) ) ) ;
strUsage + = HelpMessageOpt ( " -rescan " , _ ( " Rescan the block chain for missing wallet transactions on startup " ) ) ;
2016-03-14 13:54:28 +01:00
strUsage + = HelpMessageOpt ( " -salvagewallet " , _ ( " Attempt to recover private keys from a corrupt wallet on startup " ) ) ;
2016-03-17 16:20:27 +01:00
if ( showDebug )
strUsage + = HelpMessageOpt ( " -sendfreetransactions " , strprintf ( _ ( " Send transactions as zero-fee transactions if possible (default: %u) " ) , DEFAULT_SEND_FREE_TRANSACTIONS ) ) ;
2016-03-11 08:37:26 +01:00
strUsage + = HelpMessageOpt ( " -spendzeroconfchange " , strprintf ( _ ( " Spend unconfirmed change when sending transactions (default: %u) " ) , DEFAULT_SPEND_ZEROCONF_CHANGE ) ) ;
strUsage + = HelpMessageOpt ( " -txconfirmtarget=<n> " , strprintf ( _ ( " If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u) " ) , DEFAULT_TX_CONFIRM_TARGET ) ) ;
2016-06-23 12:58:08 +02:00
strUsage + = HelpMessageOpt ( " -usehd " , _ ( " Use hierarchical deterministic key generation (HD) after BIP39/BIP44. Only has effect during wallet creation/first start " ) + " " + strprintf ( _ ( " (default: %u) " ) , DEFAULT_USE_HD_WALLET ) ) ;
2016-03-11 08:37:26 +01:00
strUsage + = HelpMessageOpt ( " -mnemonic " , _ ( " User defined mnemonic for HD wallet (bip39). Only has effect during wallet creation/first start (default: randomly generated) " ) ) ;
2016-06-23 12:58:08 +02:00
strUsage + = HelpMessageOpt ( " -mnemonicpassphrase " , _ ( " User defined mnemonic passphrase for HD wallet (BIP39). Only has effect during wallet creation/first start (default: empty string) " ) ) ;
2016-03-11 08:37:26 +01:00
strUsage + = HelpMessageOpt ( " -hdseed " , _ ( " User defined seed for HD wallet (should be in hex). Only has effect during wallet creation/first start (default: randomly generated) " ) ) ;
strUsage + = HelpMessageOpt ( " -upgradewallet " , _ ( " Upgrade wallet to latest format on startup " ) ) ;
strUsage + = HelpMessageOpt ( " -wallet=<file> " , _ ( " Specify wallet file (within data directory) " ) + " " + strprintf ( _ ( " (default: %s) " ) , DEFAULT_WALLET_DAT ) ) ;
strUsage + = HelpMessageOpt ( " -walletbroadcast " , _ ( " Make the wallet broadcast transactions " ) + " " + strprintf ( _ ( " (default: %u) " ) , DEFAULT_WALLETBROADCAST ) ) ;
strUsage + = HelpMessageOpt ( " -walletnotify=<cmd> " , _ ( " Execute command when a wallet transaction changes (%s in cmd is replaced by TxID) " ) ) ;
strUsage + = HelpMessageOpt ( " -zapwallettxes=<mode> " , _ ( " Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup " ) +
" " + _ ( " (1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data) " ) ) ;
strUsage + = HelpMessageOpt ( " -createwalletbackups=<n> " , strprintf ( _ ( " Number of automatic wallet backups (default: %u) " ) , nWalletBackups ) ) ;
strUsage + = HelpMessageOpt ( " -walletbackupsdir=<dir> " , _ ( " Specify full path to directory for automatic wallet backups (must exist) " ) ) ;
strUsage + = HelpMessageOpt ( " -keepass " , strprintf ( _ ( " Use KeePass 2 integration using KeePassHttp plugin (default: %u) " ) , 0 ) ) ;
strUsage + = HelpMessageOpt ( " -keepassport=<port> " , strprintf ( _ ( " Connect to KeePassHttp on port <port> (default: %u) " ) , DEFAULT_KEEPASS_HTTP_PORT ) ) ;
strUsage + = HelpMessageOpt ( " -keepasskey=<key> " , _ ( " KeePassHttp key for AES encrypted communication with KeePass " ) ) ;
strUsage + = HelpMessageOpt ( " -keepassid=<name> " , _ ( " KeePassHttp id for the established association " ) ) ;
strUsage + = HelpMessageOpt ( " -keepassname=<name> " , _ ( " Name to construct url for KeePass entry that stores the wallet passphrase " ) ) ;
if ( showDebug )
{
strUsage + = HelpMessageGroup ( _ ( " Wallet debugging/testing options: " ) ) ;
strUsage + = HelpMessageOpt ( " -dblogsize=<n> " , strprintf ( " Flush wallet database activity from memory to disk log every <n> megabytes (default: %u) " , DEFAULT_WALLET_DBLOGSIZE ) ) ;
strUsage + = HelpMessageOpt ( " -flushwallet " , strprintf ( " Run a thread to flush wallet periodically (default: %u) " , DEFAULT_FLUSHWALLET ) ) ;
strUsage + = HelpMessageOpt ( " -privdb " , strprintf ( " Sets the DB_PRIVATE flag in the wallet db environment (default: %u) " , DEFAULT_WALLET_PRIVDB ) ) ;
2016-12-20 13:12:46 +01:00
strUsage + = HelpMessageOpt ( " -walletrejectlongchains " , strprintf ( _ ( " Wallet will not create transactions that violate mempool chain limits (default: %u " ) , DEFAULT_WALLET_REJECT_LONG_CHAINS ) ) ;
2016-03-11 08:37:26 +01:00
}
return strUsage ;
}
2017-01-03 23:10:41 +01:00
CWallet * CWallet : : CreateWalletFromFile ( const std : : string walletFile )
2016-03-14 11:34:43 +01:00
{
// needed to restore wallet transaction meta data after -zapwallettxes
std : : vector < CWalletTx > vWtx ;
if ( GetBoolArg ( " -zapwallettxes " , false ) ) {
uiInterface . InitMessage ( _ ( " Zapping all transactions from wallet... " ) ) ;
2016-04-02 11:06:56 +02:00
CWallet * tempWallet = new CWallet ( walletFile ) ;
2016-03-14 11:34:43 +01:00
DBErrors nZapWalletRet = tempWallet - > ZapWalletTx ( vWtx ) ;
if ( nZapWalletRet ! = DB_LOAD_OK ) {
2017-01-03 23:10:41 +01:00
InitError ( strprintf ( _ ( " Error loading %s: Wallet corrupted " ) , walletFile ) ) ;
return NULL ;
2016-03-14 11:34:43 +01:00
}
delete tempWallet ;
tempWallet = NULL ;
}
uiInterface . InitMessage ( _ ( " Loading wallet... " ) ) ;
int64_t nStart = GetTimeMillis ( ) ;
bool fFirstRun = true ;
2016-04-02 11:06:56 +02:00
CWallet * walletInstance = new CWallet ( walletFile ) ;
2016-03-14 11:34:43 +01:00
DBErrors nLoadWalletRet = walletInstance - > LoadWallet ( fFirstRun ) ;
if ( nLoadWalletRet ! = DB_LOAD_OK )
{
2017-01-03 23:10:41 +01:00
if ( nLoadWalletRet = = DB_CORRUPT ) {
InitError ( strprintf ( _ ( " Error loading %s: Wallet corrupted " ) , walletFile ) ) ;
return NULL ;
}
2016-03-14 11:34:43 +01:00
else if ( nLoadWalletRet = = DB_NONCRITICAL_ERROR )
{
2016-04-19 16:10:39 +02:00
InitWarning ( strprintf ( _ ( " Error reading %s! All keys read correctly, but transaction data "
2016-03-14 13:54:28 +01:00
" or address book entries might be missing or incorrect. " ) ,
2016-04-02 11:06:56 +02:00
walletFile ) ) ;
2016-03-14 11:34:43 +01:00
}
2017-01-03 23:10:41 +01:00
else if ( nLoadWalletRet = = DB_TOO_NEW ) {
InitError ( strprintf ( _ ( " Error loading %s: Wallet requires newer version of %s " ) , walletFile , _ ( PACKAGE_NAME ) ) ) ;
return NULL ;
}
2016-03-14 11:34:43 +01:00
else if ( nLoadWalletRet = = DB_NEED_REWRITE )
{
2017-01-03 23:10:41 +01:00
InitError ( strprintf ( _ ( " Wallet needed to be rewritten: restart %s to complete " ) , _ ( PACKAGE_NAME ) ) ) ;
return NULL ;
}
else {
InitError ( strprintf ( _ ( " Error loading %s " ) , walletFile ) ) ;
return NULL ;
2016-03-14 11:34:43 +01:00
}
}
if ( GetBoolArg ( " -upgradewallet " , fFirstRun ) )
{
int nMaxVersion = GetArg ( " -upgradewallet " , 0 ) ;
if ( nMaxVersion = = 0 ) // the -upgradewallet without argument case
{
LogPrintf ( " Performing wallet upgrade to %i \n " , FEATURE_LATEST ) ;
nMaxVersion = CLIENT_VERSION ;
walletInstance - > SetMinVersion ( FEATURE_LATEST ) ; // permanently upgrade the wallet immediately
}
else
LogPrintf ( " Allowing wallet upgrade up to %i \n " , nMaxVersion ) ;
if ( nMaxVersion < walletInstance - > GetVersion ( ) )
{
2017-01-03 23:10:41 +01:00
InitError ( _ ( " Cannot downgrade wallet " ) ) ;
return NULL ;
2016-03-14 11:34:43 +01:00
}
walletInstance - > SetMaxVersion ( nMaxVersion ) ;
}
if ( fFirstRun )
{
// Create new keyUser and set as default key
2017-09-15 12:29:12 +02:00
if ( GetBoolArg ( " -usehd " , DEFAULT_USE_HD_WALLET ) & & ! walletInstance - > IsHDEnabled ( ) ) {
if ( GetArg ( " -mnemonicpassphrase " , " " ) . size ( ) > 256 ) {
2017-01-03 23:10:41 +01:00
InitError ( _ ( " Mnemonic passphrase is too long, must be at most 256 characters " ) ) ;
return NULL ;
2017-09-15 12:29:12 +02:00
}
2016-03-14 11:34:43 +01:00
// generate a new master key
2017-09-15 12:29:12 +02:00
walletInstance - > GenerateNewHDChain ( ) ;
2016-03-14 11:34:43 +01:00
// ensure this wallet.dat can only be opened by clients supporting HD
2017-12-20 06:57:47 +01:00
walletInstance - > SetMinVersion ( FEATURE_HD ) ;
2016-03-14 11:34:43 +01:00
}
CPubKey newDefaultKey ;
if ( walletInstance - > GetKeyFromPool ( newDefaultKey , false ) ) {
walletInstance - > SetDefaultKey ( newDefaultKey ) ;
2017-01-03 23:10:41 +01:00
if ( ! walletInstance - > SetAddressBook ( walletInstance - > vchDefaultKey . GetID ( ) , " " , " receive " ) ) {
InitError ( _ ( " Cannot write default address " ) + = " \n " ) ;
return NULL ;
}
2016-03-14 11:34:43 +01:00
}
walletInstance - > SetBestChain ( chainActive . GetLocator ( ) ) ;
// Try to create wallet backup right after new wallet was created
std : : string strBackupWarning ;
std : : string strBackupError ;
2017-09-15 12:29:12 +02:00
if ( ! AutoBackupWallet ( walletInstance , " " , strBackupWarning , strBackupError ) ) {
if ( ! strBackupWarning . empty ( ) ) {
2017-09-15 14:16:23 +02:00
InitWarning ( strBackupWarning ) ;
2017-09-15 12:29:12 +02:00
}
if ( ! strBackupError . empty ( ) ) {
2017-01-03 23:10:41 +01:00
InitError ( strBackupError ) ;
return NULL ;
2017-09-15 12:29:12 +02:00
}
2016-03-14 11:34:43 +01:00
}
}
2016-12-27 19:11:21 +01:00
else if ( IsArgSet ( " -usehd " ) ) {
2016-03-14 11:34:43 +01:00
bool useHD = GetBoolArg ( " -usehd " , DEFAULT_USE_HD_WALLET ) ;
2017-09-15 12:29:12 +02:00
if ( walletInstance - > IsHDEnabled ( ) & & ! useHD ) {
2017-01-03 23:10:41 +01:00
InitError ( strprintf ( _ ( " Error loading %s: You can't disable HD on a already existing HD wallet " ) ,
walletInstance - > strWalletFile ) ) ;
return NULL ;
2017-09-15 12:29:12 +02:00
}
if ( ! walletInstance - > IsHDEnabled ( ) & & useHD ) {
2017-01-03 23:10:41 +01:00
InitError ( strprintf ( _ ( " Error loading %s: You can't enable HD on a already existing non-HD wallet " ) ,
walletInstance - > strWalletFile ) ) ;
return NULL ;
2017-09-15 12:29:12 +02:00
}
2016-03-14 11:34:43 +01:00
}
// Warn user every time he starts non-encrypted HD wallet
2017-09-15 12:29:12 +02:00
if ( GetBoolArg ( " -usehd " , DEFAULT_USE_HD_WALLET ) & & ! walletInstance - > IsLocked ( ) ) {
2017-09-15 14:16:23 +02:00
InitWarning ( _ ( " Make sure to encrypt your wallet and delete all non-encrypted backups after you verified that wallet works! " ) ) ;
2016-03-14 11:34:43 +01:00
}
LogPrintf ( " wallet %15dms \n " , GetTimeMillis ( ) - nStart ) ;
RegisterValidationInterface ( walletInstance ) ;
CBlockIndex * pindexRescan = chainActive . Tip ( ) ;
if ( GetBoolArg ( " -rescan " , false ) )
pindexRescan = chainActive . Genesis ( ) ;
else
{
2016-04-02 11:06:56 +02:00
CWalletDB walletdb ( walletFile ) ;
2016-03-14 11:34:43 +01:00
CBlockLocator locator ;
if ( walletdb . ReadBestBlock ( locator ) )
pindexRescan = FindForkInGlobalIndex ( chainActive , locator ) ;
else
pindexRescan = chainActive . Genesis ( ) ;
}
if ( chainActive . Tip ( ) & & chainActive . Tip ( ) ! = pindexRescan )
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
//this might happen if a user uses a old wallet within a pruned node
// 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 ;
2017-01-03 23:10:41 +01: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) " ) ) ;
return NULL ;
}
2016-03-14 11:34:43 +01:00
}
uiInterface . InitMessage ( _ ( " Rescanning... " ) ) ;
LogPrintf ( " Rescanning last %i blocks (from block %i)... \n " , chainActive . Height ( ) - pindexRescan - > nHeight , pindexRescan - > nHeight ) ;
nStart = GetTimeMillis ( ) ;
walletInstance - > ScanForWalletTransactions ( pindexRescan , true ) ;
LogPrintf ( " rescan %15dms \n " , GetTimeMillis ( ) - nStart ) ;
walletInstance - > SetBestChain ( chainActive . GetLocator ( ) ) ;
nWalletDBUpdated + + ;
// Restore wallet transaction metadata after -zapwallettxes=1
if ( GetBoolArg ( " -zapwallettxes " , false ) & & GetArg ( " -zapwallettxes " , " 1 " ) ! = " 2 " )
{
2016-04-02 11:06:56 +02:00
CWalletDB walletdb ( walletFile ) ;
2016-03-14 11:34:43 +01:00
BOOST_FOREACH ( const CWalletTx & wtxOld , vWtx )
{
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 ;
2016-05-10 15:51:11 +02:00
walletdb . WriteTx ( * copyTo ) ;
2016-03-14 11:34:43 +01:00
}
}
}
}
walletInstance - > SetBroadcastTransactions ( GetBoolArg ( " -walletbroadcast " , DEFAULT_WALLETBROADCAST ) ) ;
2016-08-24 10:32:59 +02:00
{
LOCK ( walletInstance - > cs_wallet ) ;
LogPrintf ( " setExternalKeyPool.size() = %u \n " , walletInstance - > KeypoolCountExternalKeys ( ) ) ;
LogPrintf ( " setInternalKeyPool.size() = %u \n " , walletInstance - > KeypoolCountInternalKeys ( ) ) ;
LogPrintf ( " mapWallet.size() = %u \n " , walletInstance - > mapWallet . size ( ) ) ;
LogPrintf ( " mapAddressBook.size() = %u \n " , walletInstance - > mapAddressBook . size ( ) ) ;
}
2017-01-03 23:10:41 +01:00
return walletInstance ;
}
bool CWallet : : InitLoadWallet ( )
{
if ( GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) ) {
pwalletMain = NULL ;
LogPrintf ( " Wallet disabled! \n " ) ;
return true ;
}
std : : string walletFile = GetArg ( " -wallet " , DEFAULT_WALLET_DAT ) ;
CWallet * const pwallet = CreateWalletFromFile ( walletFile ) ;
if ( ! pwallet ) {
return false ;
}
pwalletMain = pwallet ;
2016-08-24 10:32:59 +02:00
2016-04-02 11:06:56 +02:00
return true ;
}
2017-01-03 23:10:41 +01:00
std : : atomic < bool > CWallet : : fFlushThreadRunning ( false ) ;
2016-11-02 21:37:28 +01:00
void CWallet : : postInitProcess ( boost : : thread_group & threadGroup )
{
// Add wallet transactions that aren't already in a block to mempool
// Do this here as mempool requires genesis block to be loaded
ReacceptWalletTransactions ( ) ;
// Run a thread to flush wallet periodically
2017-01-03 23:10:41 +01:00
if ( ! CWallet : : fFlushThreadRunning . exchange ( true ) ) {
threadGroup . create_thread ( ThreadFlushWalletDB ) ;
}
2016-11-02 21:37:28 +01:00
}
2016-04-02 11:06:56 +02:00
bool CWallet : : ParameterInteraction ( )
{
2016-09-21 12:27:47 +02:00
if ( GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) )
return true ;
2016-09-20 12:45:28 +02:00
if ( GetBoolArg ( " -blocksonly " , DEFAULT_BLOCKSONLY ) & & SoftSetBoolArg ( " -walletbroadcast " , false ) ) {
LogPrintf ( " %s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0 \n " , __func__ ) ;
}
2016-11-23 07:17:47 +01:00
if ( GetBoolArg ( " -salvagewallet " , false ) & & SoftSetBoolArg ( " -rescan " , true ) ) {
// Rewrite just private keys: rescan to find transactions
LogPrintf ( " %s: parameter interaction: -salvagewallet=1 -> setting -rescan=1 \n " , __func__ ) ;
}
// -zapwallettx implies a rescan
if ( GetBoolArg ( " -zapwallettxes " , false ) & & SoftSetBoolArg ( " -rescan " , true ) ) {
LogPrintf ( " %s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1 \n " , __func__ ) ;
}
2016-09-20 12:45:28 +02:00
if ( GetBoolArg ( " -sysperms " , false ) )
return InitError ( " -sysperms is not allowed in combination with enabled wallet functionality " ) ;
if ( GetArg ( " -prune " , 0 ) & & GetBoolArg ( " -rescan " , false ) )
return InitError ( _ ( " Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again. " ) ) ;
2016-09-26 13:55:04 +02:00
if ( : : minRelayTxFee . GetFeePerK ( ) > HIGH_TX_FEE_PER_KB )
InitWarning ( AmountHighWarn ( " -minrelaytxfee " ) + " " +
_ ( " The wallet will avoid paying less than the minimum relay fee. " ) ) ;
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -mintxfee " ) )
2016-04-02 11:06:56 +02:00
{
CAmount n = 0 ;
2016-12-27 19:11:21 +01:00
if ( ! ParseMoney ( GetArg ( " -mintxfee " , " " ) , n ) | | 0 = = n )
return InitError ( AmountErrMsg ( " mintxfee " , GetArg ( " -mintxfee " , " " ) ) ) ;
2016-09-26 13:55:04 +02:00
if ( n > HIGH_TX_FEE_PER_KB )
InitWarning ( AmountHighWarn ( " -mintxfee " ) + " " +
_ ( " This is the minimum transaction fee you pay on every transaction. " ) ) ;
CWallet : : minTxFee = CFeeRate ( n ) ;
2016-04-02 11:06:56 +02:00
}
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -fallbackfee " ) )
2016-04-02 11:06:56 +02:00
{
CAmount nFeePerK = 0 ;
2016-12-27 19:11:21 +01:00
if ( ! ParseMoney ( GetArg ( " -fallbackfee " , " " ) , nFeePerK ) )
return InitError ( strprintf ( _ ( " Invalid amount for -fallbackfee=<amount>: '%s' " ) , GetArg ( " -fallbackfee " , " " ) ) ) ;
2016-04-02 11:06:56 +02:00
if ( nFeePerK > HIGH_TX_FEE_PER_KB )
2016-09-26 13:55:04 +02:00
InitWarning ( AmountHighWarn ( " -fallbackfee " ) + " " +
_ ( " This is the transaction fee you may pay when fee estimates are not available. " ) ) ;
2016-04-02 11:06:56 +02:00
CWallet : : fallbackFee = CFeeRate ( nFeePerK ) ;
}
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -paytxfee " ) )
2016-04-02 11:06:56 +02:00
{
CAmount nFeePerK = 0 ;
2016-12-27 19:11:21 +01:00
if ( ! ParseMoney ( GetArg ( " -paytxfee " , " " ) , nFeePerK ) )
return InitError ( AmountErrMsg ( " paytxfee " , GetArg ( " -paytxfee " , " " ) ) ) ;
2016-04-02 11:06:56 +02:00
if ( nFeePerK > HIGH_TX_FEE_PER_KB )
2016-09-26 13:55:04 +02:00
InitWarning ( AmountHighWarn ( " -paytxfee " ) + " " +
_ ( " This is the transaction fee you will pay if you send a transaction. " ) ) ;
2016-04-02 11:06:56 +02:00
payTxFee = CFeeRate ( nFeePerK , 1000 ) ;
if ( payTxFee < : : minRelayTxFee )
{
2016-04-19 16:10:39 +02:00
return InitError ( strprintf ( _ ( " Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s) " ) ,
2016-12-27 19:11:21 +01:00
GetArg ( " -paytxfee " , " " ) , : : minRelayTxFee . ToString ( ) ) ) ;
2016-04-02 11:06:56 +02:00
}
}
2016-12-27 19:11:21 +01:00
if ( IsArgSet ( " -maxtxfee " ) )
2016-04-02 11:06:56 +02:00
{
CAmount nMaxFee = 0 ;
2016-12-27 19:11:21 +01:00
if ( ! ParseMoney ( GetArg ( " -maxtxfee " , " " ) , nMaxFee ) )
return InitError ( AmountErrMsg ( " maxtxfee " , GetArg ( " -maxtxfee " , " " ) ) ) ;
2016-04-02 11:06:56 +02:00
if ( nMaxFee > HIGH_MAX_TX_FEE )
2016-04-19 16:10:39 +02:00
InitWarning ( _ ( " -maxtxfee is set very high! Fees this large could be paid on a single transaction. " ) ) ;
2016-04-02 11:06:56 +02:00
maxTxFee = nMaxFee ;
if ( CFeeRate ( maxTxFee , 1000 ) < : : minRelayTxFee )
{
2016-04-19 16:10:39 +02:00
return InitError ( strprintf ( _ ( " Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions) " ) ,
2016-12-27 19:11:21 +01:00
GetArg ( " -maxtxfee " , " " ) , : : minRelayTxFee . ToString ( ) ) ) ;
2016-04-02 11:06:56 +02:00
}
}
nTxConfirmTarget = GetArg ( " -txconfirmtarget " , DEFAULT_TX_CONFIRM_TARGET ) ;
bSpendZeroConfChange = GetBoolArg ( " -spendzeroconfchange " , DEFAULT_SPEND_ZEROCONF_CHANGE ) ;
fSendFreeTransactions = GetBoolArg ( " -sendfreetransactions " , DEFAULT_SEND_FREE_TRANSACTIONS ) ;
2016-12-20 11:28:55 +01:00
if ( fSendFreeTransactions & & GetArg ( " -limitfreerelay " , DEFAULT_LIMITFREERELAY ) < = 0 )
return InitError ( " Creation of free transactions with their relay disabled is not supported. " ) ;
2018-01-18 17:55:51 +01:00
if ( IsArgSet ( " -walletbackupsdir " ) ) {
if ( ! boost : : filesystem : : is_directory ( GetArg ( " -walletbackupsdir " , " " ) ) ) {
LogPrintf ( " %s: Warning: incorrect parameter -walletbackupsdir, path must exist! Using default path. \n " , __func__ ) ;
InitWarning ( " Warning: incorrect parameter -walletbackupsdir, path must exist! Using default path. \n " ) ;
ForceRemoveArg ( " -walletbackupsdir " ) ;
}
}
2016-04-02 11:06:56 +02:00
return true ;
2016-03-14 11:34:43 +01:00
}
2018-01-11 18:39:50 +01:00
bool CWallet : : InitAutoBackup ( )
{
if ( GetBoolArg ( " -disablewallet " , DEFAULT_DISABLE_WALLET ) )
return true ;
std : : string strWarning ;
std : : string strError ;
nWalletBackups = GetArg ( " -createwalletbackups " , 10 ) ;
nWalletBackups = std : : max ( 0 , std : : min ( 10 , nWalletBackups ) ) ;
std : : string strWalletFile = GetArg ( " -wallet " , DEFAULT_WALLET_DAT ) ;
if ( ! AutoBackupWallet ( NULL , strWalletFile , strWarning , strError ) ) {
if ( ! strWarning . empty ( ) )
InitWarning ( strWarning ) ;
if ( ! strError . empty ( ) )
return InitError ( strError ) ;
}
return true ;
}
2016-05-25 18:06:23 +02:00
bool CWallet : : BackupWallet ( const std : : string & strDest )
{
if ( ! fFileBacked )
return false ;
while ( true )
{
{
LOCK ( bitdb . cs_db ) ;
if ( ! bitdb . mapFileUseCount . count ( strWalletFile ) | | bitdb . mapFileUseCount [ strWalletFile ] = = 0 )
{
// Flush log data to the dat file
bitdb . CloseDb ( strWalletFile ) ;
bitdb . CheckpointLSN ( strWalletFile ) ;
bitdb . mapFileUseCount . erase ( strWalletFile ) ;
// Copy wallet file
boost : : filesystem : : path pathSrc = GetDataDir ( ) / strWalletFile ;
boost : : filesystem : : path pathDest ( strDest ) ;
if ( boost : : filesystem : : is_directory ( pathDest ) )
pathDest / = strWalletFile ;
try {
# if BOOST_VERSION >= 104000
boost : : filesystem : : copy_file ( pathSrc , pathDest , boost : : filesystem : : copy_option : : overwrite_if_exists ) ;
# else
boost : : filesystem : : copy_file ( pathSrc , pathDest ) ;
# endif
LogPrintf ( " copied %s to %s \n " , strWalletFile , pathDest . string ( ) ) ;
return true ;
} catch ( const boost : : filesystem : : filesystem_error & e ) {
LogPrintf ( " error copying %s to %s - %s \n " , strWalletFile , pathDest . string ( ) , e . what ( ) ) ;
return false ;
}
}
}
MilliSleep ( 100 ) ;
}
return false ;
}
2017-09-15 21:54:00 +02:00
// This should be called carefully:
// either supply "wallet" (if already loaded) or "strWalletFile" (if wallet wasn't loaded yet)
bool AutoBackupWallet ( CWallet * wallet , std : : string strWalletFile , std : : string & strBackupWarning , std : : string & strBackupError )
{
namespace fs = boost : : filesystem ;
strBackupWarning = strBackupError = " " ;
if ( nWalletBackups > 0 )
{
fs : : path backupsDir = GetBackupsDir ( ) ;
if ( ! fs : : exists ( backupsDir ) )
{
// Always create backup folder to not confuse the operating system's file browser
LogPrintf ( " Creating backup folder %s \n " , backupsDir . string ( ) ) ;
if ( ! fs : : create_directories ( backupsDir ) ) {
// smth is wrong, we shouldn't continue until it's resolved
strBackupError = strprintf ( _ ( " Wasn't able to create wallet backup folder %s! " ) , backupsDir . string ( ) ) ;
LogPrintf ( " %s \n " , strBackupError ) ;
nWalletBackups = - 1 ;
return false ;
}
2018-01-18 17:55:51 +01:00
} else if ( ! fs : : is_directory ( backupsDir ) ) {
// smth is wrong, we shouldn't continue until it's resolved
strBackupError = strprintf ( _ ( " %s is not a valid backup folder! " ) , backupsDir . string ( ) ) ;
LogPrintf ( " %s \n " , strBackupError ) ;
nWalletBackups = - 1 ;
return false ;
2017-09-15 21:54:00 +02:00
}
// Create backup of the ...
std : : string dateTimeStr = DateTimeStrFormat ( " .%Y-%m-%d-%H-%M " , GetTime ( ) ) ;
if ( wallet )
{
// ... opened wallet
LOCK2 ( cs_main , wallet - > cs_wallet ) ;
strWalletFile = wallet - > strWalletFile ;
fs : : path backupFile = backupsDir / ( strWalletFile + dateTimeStr ) ;
if ( ! wallet - > BackupWallet ( backupFile . string ( ) ) ) {
strBackupWarning = strprintf ( _ ( " Failed to create backup %s! " ) , backupFile . string ( ) ) ;
LogPrintf ( " %s \n " , strBackupWarning ) ;
nWalletBackups = - 1 ;
return false ;
}
// Update nKeysLeftSinceAutoBackup using current external keypool size
wallet - > nKeysLeftSinceAutoBackup = wallet - > KeypoolCountExternalKeys ( ) ;
LogPrintf ( " nKeysLeftSinceAutoBackup: %d \n " , wallet - > nKeysLeftSinceAutoBackup ) ;
if ( wallet - > IsLocked ( true ) ) {
strBackupWarning = _ ( " Wallet is locked, can't replenish keypool! Automatic backups and mixing are disabled, please unlock your wallet to replenish keypool. " ) ;
LogPrintf ( " %s \n " , strBackupWarning ) ;
nWalletBackups = - 2 ;
return false ;
}
} else {
// ... strWalletFile file
fs : : path sourceFile = GetDataDir ( ) / strWalletFile ;
fs : : path backupFile = backupsDir / ( strWalletFile + dateTimeStr ) ;
sourceFile . make_preferred ( ) ;
backupFile . make_preferred ( ) ;
if ( fs : : exists ( backupFile ) )
{
strBackupWarning = _ ( " Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this. " ) ;
LogPrintf ( " %s \n " , strBackupWarning ) ;
return false ;
}
if ( fs : : exists ( sourceFile ) ) {
try {
fs : : copy_file ( sourceFile , backupFile ) ;
LogPrintf ( " Creating backup of %s -> %s \n " , sourceFile . string ( ) , backupFile . string ( ) ) ;
} catch ( fs : : filesystem_error & error ) {
strBackupWarning = strprintf ( _ ( " Failed to create backup, error: %s " ) , error . what ( ) ) ;
LogPrintf ( " %s \n " , strBackupWarning ) ;
nWalletBackups = - 1 ;
return false ;
}
}
}
// Keep only the last 10 backups, including the new one of course
typedef std : : multimap < std : : time_t , fs : : path > folder_set_t ;
folder_set_t folder_set ;
fs : : directory_iterator end_iter ;
backupsDir . make_preferred ( ) ;
// Build map of backup files for current(!) wallet sorted by last write time
fs : : path currentFile ;
for ( fs : : directory_iterator dir_iter ( backupsDir ) ; dir_iter ! = end_iter ; + + dir_iter )
{
// Only check regular files
if ( fs : : is_regular_file ( dir_iter - > status ( ) ) )
{
currentFile = dir_iter - > path ( ) . filename ( ) ;
// Only add the backups for the current wallet, e.g. wallet.dat.*
if ( dir_iter - > path ( ) . stem ( ) . string ( ) = = strWalletFile )
{
folder_set . insert ( folder_set_t : : value_type ( fs : : last_write_time ( dir_iter - > path ( ) ) , * dir_iter ) ) ;
}
}
}
// Loop backward through backup files and keep the N newest ones (1 <= N <= 10)
int counter = 0 ;
BOOST_REVERSE_FOREACH ( PAIRTYPE ( const std : : time_t , fs : : path ) file , folder_set )
{
counter + + ;
if ( counter > nWalletBackups )
{
// More than nWalletBackups backups: delete oldest one(s)
try {
fs : : remove ( file . second ) ;
LogPrintf ( " Old backup deleted: %s \n " , file . second ) ;
} catch ( fs : : filesystem_error & error ) {
strBackupWarning = strprintf ( _ ( " Failed to delete backup, error: %s " ) , error . what ( ) ) ;
LogPrintf ( " %s \n " , strBackupWarning ) ;
return false ;
}
}
}
return true ;
}
LogPrintf ( " Automatic wallet backups are disabled! \n " ) ;
return false ;
}
2014-08-21 05:04:43 +02:00
CKeyPool : : CKeyPool ( )
{
nTime = GetTime ( ) ;
2017-05-29 13:51:40 +02:00
fInternal = false ;
2014-08-21 05:04:43 +02:00
}
2017-05-29 13:51:40 +02:00
CKeyPool : : CKeyPool ( const CPubKey & vchPubKeyIn , bool fInternalIn )
2014-08-21 05:04:43 +02:00
{
nTime = GetTime ( ) ;
vchPubKey = vchPubKeyIn ;
2017-05-29 13:51:40 +02:00
fInternal = fInternalIn ;
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
2017-01-03 09:31:45 +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-08-15 11:49:12 +02:00
hashBlock = pindex - > GetBlockHash ( ) ;
2014-08-28 17:15:21 +02:00
2016-08-15 11:49:12 +02:00
// set the position of the transaction in the block
nIndex = posInBlock ;
2014-08-28 17:15:21 +02:00
}
2016-02-02 16:28:56 +01:00
int CMerkleTx : : GetDepthInMainChain ( const CBlockIndex * & pindexRet , bool enableIX ) const
2014-08-28 17:15:21 +02:00
{
2016-03-21 21:23:45 +01:00
int nResult ;
2016-01-07 22:31:12 +01:00
2016-03-21 21:23:45 +01:00
if ( hashUnset ( ) )
nResult = 0 ;
else {
AssertLockHeld ( cs_main ) ;
2014-08-28 17:15:21 +02:00
2016-03-21 21:23:45 +01:00
// Find the block it claims to be in
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
if ( mi = = mapBlockIndex . end ( ) )
nResult = 0 ;
else {
CBlockIndex * pindex = ( * mi ) . second ;
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
nResult = 0 ;
else {
pindexRet = pindex ;
nResult = ( ( nIndex = = - 1 ) ? ( - 1 ) : 1 ) * ( chainActive . Height ( ) - pindex - > nHeight + 1 ) ;
if ( nResult = = 0 & & ! mempool . exists ( GetHash ( ) ) )
return - 1 ; // Not in chain, not in mempool
2015-04-03 00:51:08 +02:00
}
}
}
2017-01-29 09:22:14 +01:00
if ( enableIX & & nResult < 6 & & instantsend . IsLockedInstantSendTransaction ( GetHash ( ) ) )
2016-05-25 07:25:16 +02:00
return nInstantSendDepth + nResult ;
2016-03-21 21:23:45 +01:00
2014-08-28 17:15:21 +02:00
return nResult ;
}
int CMerkleTx : : GetBlocksToMaturity ( ) const
{
if ( ! IsCoinBase ( ) )
return 0 ;
return max ( 0 , ( COINBASE_MATURITY + 1 ) - GetDepthInMainChain ( ) ) ;
}
2016-10-28 13:49:04 +02:00
bool CMerkleTx : : AcceptToMemoryPool ( const CAmount & nAbsurdFee , CValidationState & state )
2014-08-28 17:15:21 +02:00
{
2017-01-04 12:22:49 +01:00
return : : AcceptToMemoryPool ( mempool , state , tx , true , NULL , false , nAbsurdFee ) ;
2014-08-28 17:15:21 +02:00
}