2011-08-09 13:27:58 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2014-12-17 02:47:57 +01:00
// Copyright (c) 2009-2014 The Bitcoin Core developers
2014-10-26 08:03:12 +01:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2011-06-26 19:23:24 +02:00
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"
2013-08-12 17:03:03 +02:00
# include "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"
2015-02-05 01:21:11 +01:00
# include "main.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"
# include "utilmoneystr.h"
2013-04-13 07:13:08 +02:00
2014-10-01 08:50:24 +02:00
# include <assert.h>
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
using namespace std ;
2014-10-26 08:03:12 +01:00
/**
* Settings
*/
2014-04-10 20:14:18 +02:00
CFeeRate payTxFee ( DEFAULT_TRANSACTION_FEE ) ;
2014-12-16 10:43:40 +01:00
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE ;
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
2015-04-28 16:48:28 +02:00
/**
* Fees smaller than this ( in satoshi ) are considered zero fee ( for transaction creation )
2014-10-26 08:03:12 +01:00
* Override with - mintxfee
*/
2015-09-13 23:23:59 +02:00
CFeeRate CWallet : : minTxFee = CFeeRate ( DEFAULT_TRANSACTION_MINFEE ) ;
2014-07-03 20:25:32 +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
{
2014-09-08 12:25:52 +02:00
return strprintf ( " COutput(%s, %d, %d) [ % s ] " , tx->GetHash().ToString(), i, nDepth, FormatMoney(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
}
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 ) ;
}
2012-05-14 19:07:52 +02:00
CPubKey CWallet : : GenerateNewKey ( )
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 ;
secret . MakeNewKey ( fCompressed ) ;
2012-02-18 15:06:32 +01:00
// Compressed public keys were introduced in version 0.6.0
if ( fCompressed )
2012-03-22 03:56:31 +01:00
SetMinVersion ( FEATURE_COMPRPUBKEY ) ;
2012-02-18 15:06:32 +01:00
2013-05-01 06:52:05 +02:00
CPubKey pubkey = secret . GetPubKey ( ) ;
2014-11-06 10:17:48 +01:00
assert ( secret . VerifyPubKey ( pubkey ) ) ;
2013-06-20 01:13:55 +02:00
// Create new metadata
2013-04-13 07:13:08 +02:00
int64_t nCreationTime = GetTime ( ) ;
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ pubkey . GetID ( ) ] = CKeyMetadata ( nCreationTime ) ;
if ( ! nTimeFirstKey | | nCreationTime < nTimeFirstKey )
nTimeFirstKey = nCreationTime ;
2013-05-01 06:52:05 +02:00
if ( ! AddKeyPubKey ( secret , pubkey ) )
2015-01-08 11:44:25 +01:00
throw std : : runtime_error ( " CWallet::GenerateNewKey(): 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
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 ) ;
}
2011-11-26 07:02:04 +01:00
bool CWallet : : Unlock ( const SecureString & strWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
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 )
{
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
return false ;
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , vMasterKey ) )
2013-05-07 16:47:00 +02:00
continue ; // try another master 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 ( CCryptoKeyStore : : Unlock ( vMasterKey ) )
return true ;
}
2012-04-06 18:39:12 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
}
2011-11-26 07:02:04 +01:00
bool CWallet : : ChangeWalletPassphrase ( const SecureString & strOldWalletPassphrase , const SecureString & strNewWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
bool fWasLocked = IsLocked ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
Lock ( ) ;
CCrypter crypter ;
CKeyingMaterial vMasterKey ;
BOOST_FOREACH ( MasterKeyMap : : value_type & pMasterKey , mapMasterKeys )
{
if ( ! crypter . SetKeyFromPassphrase ( strOldWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
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 ( ) ;
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-07-17 14:09:46 +02:00
set < uint256 > CWallet : : GetConflicts ( const uint256 & txid ) const
2014-02-14 02:12:51 +01:00
{
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
BOOST_FOREACH ( const CTxIn & txin , wtx . vin )
{
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 ) ;
for ( TxSpends : : const_iterator it = range . first ; it ! = range . second ; + + it )
2014-07-17 14:09:46 +02:00
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 ) ;
}
2015-03-21 18:40:51 +01:00
bool CWallet : : Verify ( const string & walletFile , string & warningString , string & errorString )
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
string msg = strprintf ( _ ( " Error initializing wallet database environment %s! " ) , GetDataDir ( ) ) ;
errorString + = msg ;
return true ;
}
}
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 )
{
warningString + = strprintf ( _ ( " Warning: wallet.dat corrupt, data salvaged! "
" Original wallet.dat saved as wallet.{timestamp}.bak in %s; if "
" your balance or transactions are incorrect you should "
" restore from a backup. " ) , GetDataDir ( ) ) ;
}
if ( r = = CDBEnv : : RECOVER_FAIL )
errorString + = _ ( " wallet.dat corrupt, salvage failed " ) ;
}
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 ) ;
if ( mit ! = mapWallet . end ( ) & & mit - > second . GetDepthInMainChain ( ) > = 0 )
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 ) ) ;
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 ;
BOOST_FOREACH ( const CTxIn & txin , thisTx . vin )
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 ;
RandAddSeedPerfmon ( ) ;
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 ) ;
2014-11-07 13:42:52 +01:00
GetRandBytes ( & 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 ;
RandAddSeedPerfmon ( ) ;
2014-06-24 14:27:32 +02:00
2011-08-26 20:37:23 +02:00
kMasterKey . vchSalt . resize ( WALLET_CRYPTO_SALT_SIZE ) ;
2014-11-07 13:42:52 +01:00
GetRandBytes ( & 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
}
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
}
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 ) ;
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
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
}
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 ;
}
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 ( ) ;
}
}
2014-08-31 05:55:27 +02:00
bool CWallet : : AddToWallet ( const CWalletTx & wtxIn , bool fFromLoadWallet , CWalletDB * pwalletdb )
2011-06-26 19:23:24 +02:00
{
uint256 hash = wtxIn . GetHash ( ) ;
2014-02-14 02:12:51 +01:00
if ( fFromLoadWallet )
{
mapWallet [ hash ] = wtxIn ;
2015-10-19 11:19:38 +02:00
CWalletTx & wtx = mapWallet [ hash ] ;
wtx . BindWallet ( this ) ;
wtxOrdered . insert ( make_pair ( wtx . nOrderPos , TxPair ( & wtx , ( CAccountingEntry * ) 0 ) ) ) ;
2014-02-15 22:38:28 +01:00
AddToSpends ( hash ) ;
2015-11-26 18:42:07 +01:00
BOOST_FOREACH ( const CTxIn & txin , wtx . vin ) {
if ( mapWallet . count ( txin . prevout . hash ) ) {
CWalletTx & prevtx = mapWallet [ txin . prevout . hash ] ;
if ( prevtx . nIndex = = - 1 & & ! prevtx . hashBlock . IsNull ( ) ) {
MarkConflicted ( prevtx . hashBlock , wtx . GetHash ( ) ) ;
}
}
}
2014-02-14 02:12:51 +01:00
}
else
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
// 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 ;
2011-06-28 23:45:22 +02:00
wtx . BindWallet ( this ) ;
2011-06-26 19:23:24 +02:00
bool fInsertedNew = ret . second ;
if ( fInsertedNew )
2012-05-28 01:06:09 +02:00
{
2011-06-26 19:23:24 +02:00
wtx . nTimeReceived = GetAdjustedTime ( ) ;
2014-08-31 05:55:27 +02:00
wtx . nOrderPos = IncOrderPosNext ( pwalletdb ) ;
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
wtx . nTimeSmart = wtx . nTimeReceived ;
2014-12-15 09:11:16 +01:00
if ( ! wtxIn . hashBlock . IsNull ( ) )
2012-05-28 20:45:12 +02:00
{
if ( mapBlockIndex . count ( wtxIn . hashBlock ) )
{
2014-06-28 23:36:06 +02:00
int64_t latestNow = wtx . nTimeReceived ;
int64_t latestEntry = 0 ;
2012-05-28 20:45:12 +02:00
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
2013-04-13 07:13:08 +02:00
int64_t latestTolerated = latestNow + 300 ;
2015-10-19 11:19:38 +02:00
const TxItems & txOrdered = wtxOrdered ;
for ( TxItems : : const_reverse_iterator it = txOrdered . rbegin ( ) ; it ! = txOrdered . rend ( ) ; + + it )
2012-05-28 20:45:12 +02:00
{
CWalletTx * const pwtx = ( * it ) . second . first ;
if ( pwtx = = & wtx )
continue ;
CAccountingEntry * const pacentry = ( * it ) . second . second ;
2013-04-13 07:13:08 +02:00
int64_t nSmartTime ;
2012-05-28 20:45:12 +02:00
if ( pwtx )
{
nSmartTime = pwtx - > nTimeSmart ;
if ( ! nSmartTime )
nSmartTime = pwtx - > nTimeReceived ;
}
else
nSmartTime = pacentry - > nTime ;
if ( nSmartTime < = latestTolerated )
{
latestEntry = nSmartTime ;
if ( nSmartTime > latestNow )
latestNow = nSmartTime ;
break ;
}
}
}
2014-06-28 23:36:06 +02:00
int64_t blocktime = mapBlockIndex [ wtxIn . hashBlock ] - > GetBlockTime ( ) ;
2012-05-28 20:45:12 +02:00
wtx . nTimeSmart = std : : max ( latestEntry , std : : min ( blocktime , latestNow ) ) ;
}
else
2015-01-08 11:44:25 +01:00
LogPrintf ( " AddToWallet(): found %s in block %s not in index \n " ,
2014-01-16 16:15:27 +01:00
wtxIn . GetHash ( ) . ToString ( ) ,
wtxIn . hashBlock . ToString ( ) ) ;
2012-05-28 20:45:12 +02:00
}
2014-02-15 22:38:28 +01:00
AddToSpends ( hash ) ;
2012-05-28 01:06:09 +02:00
}
2011-06-26 19:23:24 +02:00
bool fUpdated = false ;
if ( ! fInsertedNew )
{
// Merge
2014-12-15 09:11:16 +01:00
if ( ! wtxIn . hashBlock . IsNull ( ) & & wtxIn . hashBlock ! = wtx . hashBlock )
2011-06-26 19:23:24 +02:00
{
wtx . hashBlock = wtxIn . hashBlock ;
fUpdated = true ;
}
2015-08-11 21:03:31 +02:00
if ( wtxIn . nIndex ! = - 1 & & ( wtxIn . nIndex ! = wtx . nIndex ) )
2011-06-26 19:23:24 +02:00
{
wtx . nIndex = wtxIn . nIndex ;
fUpdated = true ;
}
if ( wtxIn . fFromMe & & wtxIn . fFromMe ! = wtx . fFromMe )
{
wtx . fFromMe = wtxIn . fFromMe ;
fUpdated = true ;
}
}
//// debug print
2014-01-16 16:15:27 +01:00
LogPrintf ( " AddToWallet %s %s%s \n " , wtxIn . GetHash ( ) . ToString ( ) , ( fInsertedNew ? " new " : " " ) , ( fUpdated ? " update " : " " ) ) ;
2011-06-26 19:23:24 +02:00
// Write to disk
if ( fInsertedNew | | fUpdated )
2014-08-31 05:55:27 +02:00
if ( ! wtx . WriteToDisk ( pwalletdb ) )
2011-06-26 19:23:24 +02:00
return false ;
2013-05-26 20:17:18 +02:00
2014-02-15 22:38:28 +01:00
// Break debit/credit balance caches:
wtx . MarkDirty ( ) ;
2011-06-26 19:23:24 +02:00
2012-05-05 16:07:14 +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
// notify an external script when a wallet transaction comes in or is updated
std : : string strCmd = GetArg ( " -walletnotify " , " " ) ;
if ( ! strCmd . empty ( ) )
{
boost : : replace_all ( strCmd , " %s " , wtxIn . GetHash ( ) . GetHex ( ) ) ;
boost : : thread t ( runCommand , strCmd ) ; // thread runs free
}
2012-05-05 16:07:14 +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 .
*/
2014-06-09 10:02:00 +02:00
bool CWallet : : AddToWalletIfInvolvingMe ( const CTransaction & tx , const CBlock * pblock , 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
if ( pblock ) {
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 ( ) ) {
LogPrintf ( " Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i) \n " , tx . GetHash ( ) . ToString ( ) , pblock - > GetHash ( ) . ToString ( ) , range . first - > second . ToString ( ) , range . first - > first . hash . ToString ( ) , range . first - > first . n ) ;
MarkConflicted ( pblock - > GetHash ( ) , range . first - > second ) ;
}
range . first + + ;
}
}
}
2014-09-06 21:59:59 +02:00
bool fExisted = mapWallet . count ( tx . GetHash ( ) ) ! = 0 ;
2011-08-26 20:37:23 +02:00
if ( fExisted & & ! fUpdate ) return false ;
2014-07-17 14:09:46 +02:00
if ( fExisted | | IsMine ( tx ) | | IsFromMe ( tx ) )
2011-08-26 20:37:23 +02:00
{
CWalletTx wtx ( this , 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
if ( pblock )
2014-08-29 20:24:16 +02:00
wtx . SetMerkleBranch ( * pblock ) ;
2014-08-31 05:55:27 +02:00
// Do not flush the wallet here for performance reasons
// this is safe, as in case of a crash, we rescan the necessary blocks on startup through our SetBestChain-mechanism
CWalletDB walletdb ( strWalletFile , " r+ " , false ) ;
return AddToWallet ( wtx , false , & walletdb ) ;
2011-08-26 20:37:23 +02:00
}
2011-06-26 19:23:24 +02:00
}
return false ;
}
2015-11-26 18:42:07 +01:00
void CWallet : : MarkConflicted ( const uint256 & hashBlock , const uint256 & hashTx )
{
LOCK2 ( cs_main , cs_wallet ) ;
CBlockIndex * pindex ;
assert ( mapBlockIndex . count ( hashBlock ) ) ;
pindex = mapBlockIndex [ hashBlock ] ;
int conflictconfirms = 0 ;
if ( chainActive . Contains ( pindex ) ) {
conflictconfirms = - ( chainActive . Height ( ) - pindex - > nHeight + 1 ) ;
}
assert ( conflictconfirms < 0 ) ;
// Do not flush the wallet here for performance reasons
CWalletDB walletdb ( strWalletFile , " r+ " , false ) ;
std : : deque < uint256 > todo ;
std : : set < uint256 > done ;
todo . push_back ( hashTx ) ;
while ( ! todo . empty ( ) ) {
uint256 now = todo . front ( ) ;
todo . pop_front ( ) ;
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 ( ) ;
wtx . WriteToDisk ( & walletdb ) ;
// 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 ) ) {
todo . push_back ( iter - > second ) ;
}
iter + + ;
}
}
}
}
2014-06-09 10:02:00 +02:00
void CWallet : : SyncTransaction ( const CTransaction & tx , const CBlock * pblock )
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
2014-06-09 10:02:00 +02:00
if ( ! AddToWalletIfInvolvingMe ( tx , pblock , 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 ( ) ;
}
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 ;
if ( txin . prevout . n < prev . vout . size ( ) )
2013-07-26 01:06:01 +02:00
return IsMine ( prev . 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 ;
if ( txin . prevout . n < prev . vout . size ( ) )
2014-04-08 15:23:50 +02:00
if ( IsMine ( prev . vout [ txin . prevout . n ] ) & filter )
2011-06-26 19:23:24 +02:00
return prev . vout [ txin . prevout . n ] . nValue ;
}
}
return 0 ;
}
2015-02-04 23:19:29 +01:00
isminetype CWallet : : IsMine ( const CTxOut & txout ) const
{
return : : IsMine ( * this , txout . scriptPubKey ) ;
}
CAmount CWallet : : GetCredit ( const CTxOut & txout , const isminefilter & filter ) const
{
if ( ! MoneyRange ( txout . nValue ) )
throw std : : runtime_error ( " CWallet::GetCredit(): value out of range " ) ;
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 ) )
throw std : : runtime_error ( " CWallet::GetChange(): value out of range " ) ;
return ( IsChange ( txout ) ? txout . nValue : 0 ) ;
}
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 ) )
throw std : : runtime_error ( " CWallet::GetDebit(): value out of range " ) ;
}
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 ) )
throw std : : runtime_error ( " CWallet::GetCredit(): value out of range " ) ;
}
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 ) )
throw std : : runtime_error ( " CWallet::GetChange(): value out of range " ) ;
}
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
2014-12-15 09:11:16 +01:00
if ( ! hashBlock . IsNull ( ) )
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?
2014-12-15 09:11:16 +01:00
if ( nRequests = = 0 & & ! hashBlock . IsNull ( ) )
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
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
{
2014-04-23 00:46:19 +02:00
CAmount nValueOut = GetValueOut ( ) ;
2011-06-26 19:23:24 +02:00
nFee = nDebit - nValueOut ;
}
2011-10-03 19:05:43 +02:00
// Sent/received.
2014-07-18 13:24:38 +02:00
for ( unsigned int i = 0 ; i < vout . size ( ) ; + + i )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
const CTxOut & txout = 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 ;
if ( ! ExtractDestination ( txout . scriptPubKey , address ) )
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
}
}
}
}
2013-10-19 18:42:14 +02:00
2014-08-31 05:55:27 +02:00
bool CWalletTx : : WriteToDisk ( CWalletDB * pwalletdb )
2011-06-26 19:23:24 +02:00
{
2014-08-31 05:55:27 +02:00
return pwalletdb - > WriteTx ( GetHash ( ) , * this ) ;
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
2015-04-23 00:19:11 +02:00
double dProgressStart = Checkpoints : : GuessVerificationProgress ( chainParams . Checkpoints ( ) , pindex , false ) ;
double dProgressTip = Checkpoints : : GuessVerificationProgress ( chainParams . Checkpoints ( ) , chainActive . Tip ( ) , false ) ;
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 )
2015-04-23 00:19:11 +02:00
ShowProgress ( _ ( " Rescanning... " ) , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( Checkpoints : : GuessVerificationProgress ( chainParams . Checkpoints ( ) , pindex , false ) - 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 ( ) ) ;
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( CTransaction & tx , block . vtx )
{
2014-06-09 10:02:00 +02:00
if ( AddToWalletIfInvolvingMe ( tx , & block , 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 ( ) ;
2015-04-23 00:19:11 +02:00
LogPrintf ( " Still rescanning. At block %d. Progress=%f \n " , pindex - > nHeight , Checkpoints : : GuessVerificationProgress ( chainParams . Checkpoints ( ) , 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 ( ) ;
2015-11-26 18:42:07 +01:00
if ( ! wtx . IsCoinBase ( ) & & nDepth = = 0 ) {
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 ) ;
wtx . AcceptToMemoryPool ( false ) ;
}
2011-06-26 19:23:24 +02:00
}
2015-03-23 18:47:18 +01:00
bool CWalletTx : : RelayWalletTransaction ( )
2011-06-26 19:23:24 +02:00
{
2015-03-27 10:34:48 +01:00
assert ( pwallet - > GetBroadcastTransactions ( ) ) ;
2011-06-26 19:23:24 +02:00
if ( ! IsCoinBase ( ) )
{
2012-11-01 15:52:25 +01:00
if ( GetDepthInMainChain ( ) = = 0 ) {
2014-06-09 10:02:00 +02:00
LogPrintf ( " Relaying wtx %s \n " , GetHash ( ) . ToString ( ) ) ;
RelayTransaction ( ( CTransaction ) * this ) ;
2015-03-23 18:47:18 +01: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-07-17 14:09:46 +02:00
set < uint256 > CWalletTx : : GetConflicts ( ) const
2014-02-14 02:12:51 +01:00
{
set < uint256 > result ;
if ( pwallet ! = NULL )
{
uint256 myHash = GetHash ( ) ;
2014-07-17 14:09:46 +02:00
result = pwallet - > GetConflicts ( myHash ) ;
2014-02-14 02:12:51 +01:00
result . erase ( myHash ) ;
}
return result ;
}
2014-12-19 02:00:01 +01:00
CAmount CWalletTx : : GetDebit ( const isminefilter & filter ) const
{
if ( vin . empty ( ) )
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 ;
int64_t credit = 0 ;
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 ( ) ;
for ( unsigned int i = 0 ; i < vout . size ( ) ; i + + )
{
if ( ! pwallet - > IsSpent ( hashTx , i ) )
{
const CTxOut & txout = vout [ i ] ;
nCredit + = pwallet - > GetCredit ( txout , ISMINE_SPENDABLE ) ;
if ( ! MoneyRange ( nCredit ) )
throw std : : runtime_error ( " CWalletTx::GetAvailableCredit() : value out of range " ) ;
}
}
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 ;
for ( unsigned int i = 0 ; i < vout . size ( ) ; i + + )
{
if ( ! pwallet - > IsSpent ( GetHash ( ) , i ) )
{
const CTxOut & txout = vout [ i ] ;
nCredit + = pwallet - > GetCredit ( txout , ISMINE_WATCH_ONLY ) ;
if ( ! MoneyRange ( nCredit ) )
throw std : : runtime_error ( " CWalletTx::GetAvailableCredit() : value out of range " ) ;
}
}
nAvailableWatchCreditCached = nCredit ;
fAvailableWatchCreditCached = true ;
return nCredit ;
}
CAmount CWalletTx : : GetChange ( ) const
{
if ( fChangeCached )
return nChangeCached ;
nChangeCached = pwallet - > GetChange ( * this ) ;
fChangeCached = true ;
return nChangeCached ;
}
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.
{
LOCK ( mempool . cs ) ;
if ( ! mempool . exists ( GetHash ( ) ) ) {
return false ;
}
}
2014-12-19 02:00:01 +01:00
// Trusted if all inputs are from us and are in the mempool:
BOOST_FOREACH ( const CTxIn & txin , vin )
{
// Transactions not sent by us: not trusted
const CWalletTx * parent = pwallet - > GetWalletTx ( txin . prevout . hash ) ;
if ( parent = = NULL )
return false ;
const CTxOut & parentOut = parent - > vout [ txin . prevout . n ] ;
if ( pwallet - > IsMine ( parentOut ) ! = ISMINE_SPENDABLE )
return false ;
}
return true ;
}
2015-07-02 20:57:39 +02:00
bool CWalletTx : : IsEquivalentTo ( const CWalletTx & tx ) const
{
CMutableTransaction tx1 = * this ;
CMutableTransaction tx2 = tx ;
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 ) ;
}
2015-03-23 18:47:18 +01:00
std : : vector < uint256 > CWallet : : ResendWalletTransactionsBefore ( int64_t nTime )
{
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 ;
if ( wtx . RelayWalletTransaction ( ) )
result . push_back ( wtx . GetHash ( ) ) ;
}
return result ;
}
void CWallet : : ResendWalletTransactions ( int64_t nBestBlockTime )
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:
std : : vector < uint256 > relayed = ResendWalletTransactionsBefore ( nBestBlockTime - 5 * 60 ) ;
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 ;
}
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 ;
2015-05-25 06:48:33 +02:00
if ( ! CheckFinalTx ( * pcoin ) | | ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 ) )
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 ;
2015-05-25 06:48:33 +02:00
if ( ! CheckFinalTx ( * pcoin ) | | ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 ) )
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 ;
}
2015-04-20 19:13:18 +02:00
void CWallet : : AvailableCoins ( vector < COutput > & vCoins , bool fOnlyConfirmed , const CCoinControl * coinControl , bool fIncludeZeroValue ) 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 ;
2015-05-25 06:48:33 +02: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 ;
2014-02-12 19:43:07 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( ) ;
if ( nDepth < 0 )
continue ;
2012-09-27 19:52:09 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
2013-07-26 01:06:01 +02:00
isminetype mine = IsMine ( pcoin - > vout [ i ] ) ;
2014-07-01 11:00:22 +02:00
if ( ! ( IsSpent ( wtxid , i ) ) & & mine ! = ISMINE_NO & &
2015-04-20 19:13:18 +02:00
! IsLockedCoin ( ( * it ) . first , i ) & & ( pcoin - > vout [ i ] . nValue > 0 | | fIncludeZeroValue ) & &
2015-04-25 03:29:00 +02:00
( ! coinControl | | ! coinControl - > HasSelected ( ) | | coinControl - > fAllowOtherInputs | | coinControl - > IsSelected ( ( * it ) . first , i ) ) )
2015-04-24 06:42:49 +02:00
vCoins . push_back ( COutput ( pcoin , i , nDepth ,
( ( mine & ISMINE_SPENDABLE ) ! = ISMINE_NO ) | |
2015-08-08 18:27:19 +02:00
( coinControl & & coinControl - > fAllowWatchOnly & & ( mine & 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 ,
vector < char > & vfBest , CAmount & nBest , int iterations = 1000 )
2012-04-13 01:22:15 +02:00
{
vector < char > vfIncluded ;
vfBest . assign ( vValue . size ( ) , true ) ;
nBest = nTotalLower ;
2013-02-16 00:27:57 +01:00
seed_insecure_rand ( ) ;
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 + + )
{
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.
if ( nPass = = 0 ? insecure_rand ( ) & 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-04-23 00:46:19 +02:00
bool CWallet : : SelectCoinsMinConf ( const CAmount & nTargetValue , int nConfMine , int nConfTheirs , vector < COutput > vCoins ,
set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet ) 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 ;
coinLowestLarger . first = 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 ) ;
2013-07-26 01:06:01 +02:00
BOOST_FOREACH ( const COutput & output , vCoins )
2011-06-26 19:23:24 +02:00
{
2013-07-26 01:06:01 +02:00
if ( ! output . fSpendable )
continue ;
2012-02-27 13:19:32 +01:00
const CWalletTx * pcoin = output . tx ;
2011-06-26 19:23:24 +02:00
2014-07-01 11:00:22 +02:00
if ( output . nDepth < ( pcoin - > IsFromMe ( ISMINE_ALL ) ? nConfMine : nConfTheirs ) )
2012-02-27 13:19:32 +01:00
continue ;
2011-06-26 19:23:24 +02:00
2012-02-27 13:19:32 +01:00
int i = output . i ;
2014-04-23 00:46:19 +02:00
CAmount n = pcoin - > vout [ i ] . nValue ;
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
pair < CAmount , pair < const CWalletTx * , unsigned int > > coin = make_pair ( n , make_pair ( pcoin , i ) ) ;
2011-06-26 19:23:24 +02:00
2012-02-27 13:19:32 +01:00
if ( n = = nTargetValue )
{
setCoinsRet . insert ( coin . second ) ;
nValueRet + = coin . first ;
return true ;
}
2015-09-13 23:23:59 +02:00
else if ( n < nTargetValue + MIN_CHANGE )
2012-02-27 13:19:32 +01:00
{
vValue . push_back ( coin ) ;
nTotalLower + = n ;
}
else if ( n < coinLowestLarger . first )
{
coinLowestLarger = coin ;
2011-06-26 19:23:24 +02:00
}
}
2012-04-13 01:22:15 +02:00
if ( nTotalLower = = nTargetValue )
2011-06-26 19:23:24 +02:00
{
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; + + i )
2011-06-26 19:23:24 +02:00
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
}
return true ;
}
2012-04-13 01:22:15 +02:00
if ( nTotalLower < nTargetValue )
2011-06-26 19:23:24 +02:00
{
if ( coinLowestLarger . second . first = = NULL )
return false ;
setCoinsRet . insert ( coinLowestLarger . second ) ;
nValueRet + = coinLowestLarger . first ;
return true ;
}
// Solve subset sum by stochastic approximation
2012-04-07 21:45:39 +02:00
sort ( vValue . rbegin ( ) , vValue . rend ( ) , CompareValueOnly ( ) ) ;
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
2015-09-13 23:23:59 +02:00
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue , vfBest , nBest ) ;
if ( nBest ! = nTargetValue & & nTotalLower > = nTargetValue + MIN_CHANGE )
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue + MIN_CHANGE , vfBest , nBest ) ;
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 {
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
2011-06-26 19:23:24 +02:00
if ( vfBest [ i ] )
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
}
2013-09-19 14:47:21 +02:00
LogPrint ( " selectcoins " , " SelectCoins() best subset: " ) ;
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
2011-06-26 19:23:24 +02:00
if ( vfBest [ i ] )
2014-01-16 16:15:27 +01:00
LogPrint ( " selectcoins " , " %s " , FormatMoney ( vValue [ i ] . first ) ) ;
LogPrint ( " selectcoins " , " total %s \n " , FormatMoney ( nBest ) ) ;
2011-06-26 19:23:24 +02:00
}
return true ;
}
2014-04-23 00:46:19 +02:00
bool CWallet : : SelectCoins ( const CAmount & nTargetValue , set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet , const CCoinControl * coinControl ) const
2011-06-26 19:23:24 +02:00
{
2012-02-27 13:19:32 +01:00
vector < COutput > vCoins ;
2013-08-12 17:03:03 +02:00
AvailableCoins ( vCoins , true , coinControl ) ;
// 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 )
2013-08-12 17:03:03 +02:00
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
2015-04-25 03:29:00 +02:00
if ( ! out . fSpendable )
continue ;
2013-08-12 17:03:03 +02:00
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
}
return ( nValueRet > = nTargetValue ) ;
}
2012-02-27 13:19:32 +01:00
2015-04-25 03:29:00 +02:00
// calculate value from preset inputs and store them
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
if ( pcoin - > vout . size ( ) < = outpoint . n )
return false ;
nValueFromPresetInputs + = pcoin - > vout [ outpoint . n ] . nValue ;
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 ;
}
bool res = nTargetValue < = nValueFromPresetInputs | |
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 1 , 6 , vCoins , setCoinsRet , nValueRet ) | |
SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 1 , 1 , vCoins , setCoinsRet , nValueRet ) | |
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue - nValueFromPresetInputs , 0 , 1 , vCoins , setCoinsRet , nValueRet ) ) ;
// 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
}
2015-04-24 06:42:49 +02:00
bool CWallet : : FundTransaction ( CMutableTransaction & tx , CAmount & nFeeRet , int & nChangePosRet , std : : string & strFailReason , bool includeWatching )
2015-04-25 03:29:00 +02:00
{
vector < CRecipient > vecSend ;
// Turn the txout set into a CRecipient vector
BOOST_FOREACH ( const CTxOut & txOut , tx . vout )
{
CRecipient recipient = { txOut . scriptPubKey , txOut . nValue , false } ;
vecSend . push_back ( recipient ) ;
}
CCoinControl coinControl ;
coinControl . fAllowOtherInputs = true ;
2015-04-24 06:42:49 +02:00
coinControl . fAllowWatchOnly = includeWatching ;
2015-04-25 03:29:00 +02:00
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
coinControl . Select ( txin . prevout ) ;
CReserveKey reservekey ( this ) ;
CWalletTx wtx ;
if ( ! CreateTransaction ( vecSend , wtx , reservekey , nFeeRet , nChangePosRet , strFailReason , & coinControl , false ) )
return false ;
if ( nChangePosRet ! = - 1 )
tx . vout . insert ( tx . vout . begin ( ) + nChangePosRet , wtx . vout [ nChangePosRet ] ) ;
// Add new txins (keeping original txin scriptSig/order)
BOOST_FOREACH ( const CTxIn & txin , wtx . vin )
{
bool found = false ;
BOOST_FOREACH ( const CTxIn & origTxIn , tx . vin )
{
if ( txin . prevout . hash = = origTxIn . prevout . hash & & txin . prevout . n = = origTxIn . prevout . n )
{
found = true ;
break ;
}
}
if ( ! found )
tx . vin . push_back ( txin ) ;
}
return true ;
}
bool CWallet : : CreateTransaction ( const vector < CRecipient > & vecSend , CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet ,
int & nChangePosRet , std : : string & strFailReason , const CCoinControl * coinControl , bool sign )
2011-06-26 19:23:24 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nValue = 0 ;
2014-07-23 14:34:36 +02:00
unsigned int nSubtractFeeFromAmount = 0 ;
BOOST_FOREACH ( const CRecipient & 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
{
strFailReason = _ ( " Transaction amounts must be positive " ) ;
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
}
if ( vecSend . empty ( ) | | nValue < 0 )
2013-04-25 23:31:22 +02:00
{
strFailReason = _ ( " Transaction amounts must be positive " ) ;
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.
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
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
{
2014-11-02 00:14:47 +01:00
nFeeRet = 0 ;
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
{
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
nChangePosRet = - 1 ;
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
2014-07-23 14:34:36 +02:00
BOOST_FOREACH ( const CRecipient & 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
set < pair < const CWalletTx * , unsigned int > > setCoins ;
2014-04-23 00:46:19 +02:00
CAmount nValueIn = 0 ;
2015-03-18 19:22:49 +01:00
if ( ! SelectCoins ( nValueToSelect , setCoins , nValueIn , coinControl ) )
2013-04-25 23:31:22 +02:00
{
strFailReason = _ ( " Insufficient funds " ) ;
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
BOOST_FOREACH ( PAIRTYPE ( const CWalletTx * , unsigned int ) pcoin , setCoins )
{
2014-04-23 00:46:19 +02:00
CAmount nCredit = pcoin . first - > 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 ;
2011-07-24 16:37:09 +02:00
if ( nChange > 0 )
2011-06-26 19:23:24 +02:00
{
2011-09-28 18:30:06 +02:00
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
2011-06-26 19:23:24 +02:00
CScript scriptChange ;
2013-08-12 17:03:03 +02:00
// coin control: send change to custom address
if ( coinControl & & ! boost : : get < CNoDestination > ( & coinControl - > destChange ) )
2014-09-11 19:15:29 +02:00
scriptChange = GetScriptForDestination ( coinControl - > destChange ) ;
2013-08-12 17:03:03 +02: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 ;
2013-12-02 20:33:44 +01:00
bool ret ;
ret = reservekey . GetReservedKey ( vchPubKey ) ;
assert ( ret ) ; // should never fail, as we just unlocked
2013-08-12 17:03:03 +02:00
2014-09-11 19:15:29 +02:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2013-08-12 17:03:03 +02:00
}
2011-06-26 19:23:24 +02:00
2013-04-25 00:27:00 +02:00
CTxOut newTxOut ( nChange , scriptChange ) ;
2014-07-23 14:34:36 +02: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 ) )
{
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
{
if ( vecSend [ i ] . fSubtractFeeFromAmount )
{
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 ;
}
}
}
2013-04-25 00:27:00 +02:00
// Never create dust outputs; if we would, just
// add the dust to the fee.
2014-07-03 20:25:32 +02:00
if ( newTxOut . IsDust ( : : minRelayTxFee ) )
2013-04-25 00:27:00 +02:00
{
nFeeRet + = nChange ;
reservekey . ReturnKey ( ) ;
}
else
{
// Insert change txn at random position:
2014-07-23 14:34:36 +02:00
nChangePosRet = GetRandInt ( txNew . vout . size ( ) + 1 ) ;
vector < CTxOut > : : iterator position = txNew . vout . begin ( ) + nChangePosRet ;
2014-06-07 13:53:27 +02: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.
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
2013-08-25 20:13:25 +02:00
txNew . vin . push_back ( CTxIn ( coin . first - > GetHash ( ) , coin . second , CScript ( ) ,
std : : numeric_limits < unsigned int > : : max ( ) - 1 ) ) ;
2011-06-26 19:23:24 +02:00
// Sign
int nIn = 0 ;
2015-04-25 03:29:00 +02:00
CTransaction txNewConst ( txNew ) ;
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
2015-04-25 03:29:00 +02:00
{
bool signSuccess ;
const CScript & scriptPubKey = coin . first - > vout [ coin . second ] . scriptPubKey ;
CScript & scriptSigRes = txNew . vin [ nIn ] . scriptSig ;
if ( sign )
signSuccess = ProduceSignature ( TransactionSignatureCreator ( this , & txNewConst , nIn , SIGHASH_ALL ) , scriptPubKey , scriptSigRes ) ;
else
signSuccess = ProduceSignature ( DummySignatureCreator ( this ) , scriptPubKey , scriptSigRes ) ;
if ( ! signSuccess )
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 ) ;
// Remove scriptSigs if we used dummy signatures for fee calculation
if ( ! sign ) {
BOOST_FOREACH ( CTxIn & vin , txNew . vin )
vin . scriptSig = CScript ( ) ;
}
2011-06-26 19:23:24 +02:00
2014-06-07 13:53:27 +02:00
// Embed the constructed transaction data in wtxNew.
* static_cast < CTransaction * > ( & wtxNew ) = CTransaction ( txNew ) ;
2011-06-26 19:23:24 +02:00
// Limit size
2013-02-04 22:56:26 +01:00
if ( nBytes > = MAX_STANDARD_TX_SIZE )
2013-04-25 23:31:22 +02:00
{
strFailReason = _ ( " Transaction too large " ) ;
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
2013-11-11 08:35:14 +01:00
dPriority = wtxNew . ComputePriority ( dPriority , nBytes ) ;
2011-06-26 19:23:24 +02:00
2014-12-16 10:43:40 +01:00
// Can we complete this as a free transaction?
if ( fSendFreeTransactions & & nBytes < = MAX_FREE_TRANSACTION_CREATE_SIZE )
{
// Not enough fee: enough priority?
2015-11-16 21:15:32 +01:00
double dPriorityNeeded = mempool . estimateSmartPriority ( nTxConfirmTarget ) ;
// Require at least hard-coded AllowFree.
if ( dPriority > = dPriorityNeeded & & AllowFree ( dPriority ) )
2014-12-16 10:43:40 +01:00
break ;
}
2014-05-27 21:44:57 +02:00
2014-12-16 10:43:40 +01:00
CAmount nFeeNeeded = GetMinimumFee ( nBytes , nTxConfirmTarget , mempool ) ;
2015-11-25 13:04:52 +01:00
if ( coinControl & & nFeeNeeded > 0 & & coinControl - > nMinimumTotalFee > nFeeNeeded ) {
nFeeNeeded = coinControl - > nMinimumTotalFee ;
}
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
}
2014-12-16 10:43:40 +01:00
if ( nFeeRet > = nFeeNeeded )
break ; // Done, enough fee included.
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
}
}
}
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
*/
2011-06-26 19:23:24 +02:00
bool CWallet : : CommitTransaction ( CWalletTx & wtxNew , CReserveKey & reservekey )
{
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " CommitTransaction: \n %s " , wtxNew . ToString ( ) ) ;
2011-06-26 19:23:24 +02:00
{
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
// maybe makes sense; please don't do it anywhere else.
2014-08-31 05:55:27 +02:00
CWalletDB * pwalletdb = fFileBacked ? new CWalletDB ( strWalletFile , " r+ " ) : NULL ;
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.
2014-08-31 05:55:27 +02:00
AddToWallet ( wtxNew , false , pwalletdb ) ;
2011-06-26 19:23:24 +02:00
2014-02-15 22:38:28 +01:00
// Notify that old coins are spent
2011-06-26 19:23:24 +02:00
set < CWalletTx * > setCoins ;
BOOST_FOREACH ( const CTxIn & txin , wtxNew . vin )
{
CWalletTx & coin = mapWallet [ txin . prevout . hash ] ;
2011-06-28 23:45:22 +02:00
coin . BindWallet ( this ) ;
2012-05-05 16:07:14 +02:00
NotifyTransactionChanged ( this , coin . GetHash ( ) , CT_UPDATED ) ;
2011-06-26 19:23:24 +02:00
}
if ( fFileBacked )
delete pwalletdb ;
}
// 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
if ( ! wtxNew . AcceptToMemoryPool ( false ) )
{
// This must not fail. The transaction has already been signed and recorded.
2015-07-31 16:41:06 +02:00
LogPrintf ( " CommitTransaction(): Error: Transaction not valid \n " ) ;
2015-03-27 10:34:48 +01:00
return false ;
}
wtxNew . RelayWalletTransaction ( ) ;
2011-06-26 19:23:24 +02:00
}
}
return true ;
}
2015-10-19 11:19:38 +02:00
bool CWallet : : AddAccountingEntry ( const CAccountingEntry & acentry , CWalletDB & pwalletdb )
{
if ( ! pwalletdb . WriteAccountingEntry_Backend ( acentry ) )
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 ) ;
// ... unless we don't have enough mempool data for our desired target
// so we make sure we're paying at least minTxFee
if ( nFeeNeeded = = 0 | | ( unsigned int ) estimateFoundTarget > nConfirmTarget )
nFeeNeeded = std : : max ( nFeeNeeded , GetRequiredFee ( nTxBytes ) ) ;
}
2014-12-16 10:43:40 +01:00
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
if ( nFeeNeeded < : : minRelayTxFee . GetFee ( nTxBytes ) )
nFeeNeeded = : : minRelayTxFee . GetFee ( nTxBytes ) ;
// But always obey the maximum
if ( nFeeNeeded > maxTxFee )
nFeeNeeded = maxTxFee ;
2014-05-27 21:44:57 +02:00
return nFeeNeeded ;
}
2011-06-26 19:23:24 +02:00
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 ) ;
2011-11-11 03:12:46 +01:00
setKeyPool . clear ( ) ;
// 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
}
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
}
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 ) ;
setKeyPool . clear ( ) ;
// 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 ) ;
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( int64_t nIndex , setKeyPool )
2011-11-17 20:01:25 +01:00
walletdb . ErasePool ( nIndex ) ;
setKeyPool . clear ( ) ;
if ( IsLocked ( ) )
return false ;
2015-06-27 21:21:41 +02:00
int64_t nKeys = max ( GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2011-11-17 20:01:25 +01:00
for ( int i = 0 ; i < nKeys ; i + + )
{
2013-04-13 07:13:08 +02:00
int64_t nIndex = i + 1 ;
2011-11-17 20:01:25 +01:00
walletdb . WritePool ( nIndex , CKeyPool ( GenerateNewKey ( ) ) ) ;
setKeyPool . insert ( nIndex ) ;
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " CWallet::NewKeyPool wrote %d new keys \n " , nKeys ) ;
2011-11-17 20:01:25 +01:00
}
return true ;
}
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 ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( IsLocked ( ) )
return false ;
2011-06-26 19:23:24 +02:00
CWalletDB walletdb ( strWalletFile ) ;
// Top up key pool
2013-06-25 22:07:29 +02:00
unsigned int nTargetSize ;
if ( kpSize > 0 )
nTargetSize = kpSize ;
else
2015-06-27 21:21:41 +02:00
nTargetSize = max ( GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2013-06-25 22:07:29 +02:00
2012-04-22 19:22:39 +02:00
while ( setKeyPool . size ( ) < ( nTargetSize + 1 ) )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nEnd = 1 ;
2011-06-26 19:23:24 +02:00
if ( ! setKeyPool . empty ( ) )
nEnd = * ( - - setKeyPool . end ( ) ) + 1 ;
if ( ! walletdb . WritePool ( nEnd , CKeyPool ( GenerateNewKey ( ) ) ) )
2015-01-08 11:44:25 +01:00
throw runtime_error ( " TopUpKeyPool() : writing generated key failed " ) ;
2011-06-26 19:23:24 +02:00
setKeyPool . insert ( nEnd ) ;
2014-05-06 15:25:01 +02:00
LogPrintf ( " keypool added key %d, size=%u \n " , nEnd , setKeyPool . size ( ) ) ;
2011-06-26 19:23:24 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
return true ;
}
2013-04-13 07:13:08 +02:00
void CWallet : : ReserveKeyFromKeyPool ( int64_t & nIndex , CKeyPool & keypool )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
keypool . vchPubKey = CPubKey ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( ! IsLocked ( ) )
TopUpKeyPool ( ) ;
2011-06-26 19:23:24 +02:00
// 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 ) ;
2011-06-26 19:23:24 +02:00
nIndex = * ( setKeyPool . begin ( ) ) ;
setKeyPool . erase ( setKeyPool . begin ( ) ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) )
2015-01-08 11:44:25 +01:00
throw runtime_error ( " ReserveKeyFromKeyPool() : read failed " ) ;
2012-05-14 19:07:52 +02:00
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) )
2015-01-08 11:44:25 +01:00
throw runtime_error ( " ReserveKeyFromKeyPool() : unknown key in key pool " ) ;
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 ) ;
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
}
2013-04-13 07:13:08 +02:00
void CWallet : : ReturnKey ( int64_t nIndex )
2011-06-26 19:23:24 +02:00
{
// Return to key pool
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
2011-06-26 19:23:24 +02:00
setKeyPool . 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
}
2013-08-23 21:54:50 +02:00
bool CWallet : : GetKeyFromPool ( CPubKey & result )
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 ) ;
2011-09-01 16:58:08 +02:00
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
if ( nIndex = = - 1 )
2011-08-12 22:32:07 +02:00
{
2011-09-01 16:58:08 +02:00
if ( IsLocked ( ) ) return false ;
result = GenerateNewKey ( ) ;
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
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetOldestKeyPoolTime ( )
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 ;
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
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 ( nIndex = = - 1 )
return GetTime ( ) ;
2011-06-26 19:23:24 +02:00
ReturnKey ( nIndex ) ;
return keypool . nTime ;
}
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 ;
2015-05-25 06:48:33 +02:00
if ( ! CheckFinalTx ( * pcoin ) | | ! 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 ;
2012-08-20 19:43:33 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
2012-08-01 18:48:42 +02:00
{
2012-08-20 19:43:33 +02:00
CTxDestination addr ;
2012-08-01 18:48:42 +02:00
if ( ! IsMine ( pcoin - > vout [ i ] ) )
continue ;
2012-08-20 19:43:33 +02:00
if ( ! ExtractDestination ( pcoin - > vout [ i ] . scriptPubKey , addr ) )
continue ;
2012-08-01 18:48:42 +02:00
2014-04-23 00:46:19 +02:00
CAmount n = IsSpent ( walletEntry . first , i ) ? 0 : pcoin - > 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 ;
2012-09-27 19:29:35 +02:00
if ( pcoin - > 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
BOOST_FOREACH ( CTxIn txin , pcoin - > 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 ;
2012-08-20 19:43:33 +02:00
if ( ! ExtractDestination ( mapWallet [ txin . prevout . hash ] . vout [ txin . prevout . n ] . scriptPubKey , address ) )
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 )
{
BOOST_FOREACH ( CTxOut txout , pcoin - > vout )
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
2012-08-20 19:43:33 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
2012-08-01 18:48:42 +02:00
if ( IsMine ( pcoin - > vout [ i ] ) )
{
2012-08-20 19:43:33 +02:00
CTxDestination address ;
if ( ! ExtractDestination ( pcoin - > vout [ i ] . scriptPubKey , address ) )
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
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 ;
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
2012-08-20 19:43:33 +02:00
set < CTxDestination > * merged = new set < CTxDestination > ( grouping ) ;
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 ;
}
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 ;
}
2013-04-25 19:30:28 +02:00
bool CReserveKey : : GetReservedKey ( CPubKey & pubkey )
2011-06-26 19:23:24 +02:00
{
if ( nIndex = = - 1 )
{
CKeyPool keypool ;
pwallet - > ReserveKeyFromKeyPool ( nIndex , keypool ) ;
2011-07-14 03:11:40 +02:00
if ( nIndex ! = - 1 )
vchPubKey = keypool . vchPubKey ;
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
}
2011-06-26 19:23:24 +02:00
}
2012-05-14 19:07:52 +02:00
assert ( vchPubKey . IsValid ( ) ) ;
2013-04-25 19:30:28 +02:00
pubkey = vchPubKey ;
return true ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : KeepKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > KeepKey ( nIndex ) ;
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
vchPubKey = CPubKey ( ) ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : ReturnKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > ReturnKey ( nIndex ) ;
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
2013-04-29 19:50:40 +02:00
void CWallet : : GetAllReserveKeys ( set < CKeyID > & setAddress ) const
2011-07-11 21:49:45 +02:00
{
setAddress . clear ( ) ;
CWalletDB walletdb ( strWalletFile ) ;
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
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 ) )
2015-01-08 11:44:25 +01:00
throw runtime_error ( " GetAllReserveKeyHashes() : 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 ( ) ;
if ( ! HaveKey ( keyID ) )
2015-01-08 11:44:25 +01:00
throw runtime_error ( " GetAllReserveKeyHashes() : unknown key in key pool " ) ;
2012-05-14 23:44:52 +02:00
setAddress . insert ( keyID ) ;
2011-07-11 21:49:45 +02:00
}
}
2012-05-05 16:07:14 +02:00
void CWallet : : UpdatedTransaction ( const uint256 & hashTx )
{
{
LOCK ( cs_wallet ) ;
// Only notify UI if this transaction is in this wallet
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( hashTx ) ;
if ( mi ! = mapWallet . end ( ) )
NotifyTransactionChanged ( this , hashTx , CT_UPDATED ) ;
}
}
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 ;
2015-07-01 08:32:30 +02:00
if ( ! rKey - > GetReservedKey ( pubkey ) )
2015-04-10 12:49:01 +02:00
return ;
2015-07-01 08:32:30 +02:00
script = rKey ;
script - > reserveScript = CScript ( ) < < ToByteVector ( pubkey ) < < OP_CHECKSIG ;
2015-04-10 12:49:01 +02:00
}
2012-09-27 19:52:09 +02:00
void CWallet : : LockCoin ( COutPoint & output )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . insert ( output ) ;
}
void CWallet : : UnlockCoin ( COutPoint & output )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . erase ( output ) ;
}
void CWallet : : UnlockAllCoins ( )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . clear ( ) ;
}
bool CWallet : : IsLockedCoin ( uint256 hash , unsigned int n ) const
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
COutPoint outpt ( hash , n ) ;
return ( setLockedCoins . count ( outpt ) > 0 ) ;
}
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
2013-10-10 23:07:44 +02:00
CBlockIndex * pindexMax = chainActive [ std : : max ( 0 , chainActive . Height ( ) - 144 ) ] ; // the tip can be reorganised; 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 ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout ) {
// 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
CKeyPool : : CKeyPool ( )
{
nTime = GetTime ( ) ;
}
CKeyPool : : CKeyPool ( const CPubKey & vchPubKeyIn )
{
nTime = GetTime ( ) ;
vchPubKey = vchPubKeyIn ;
}
CWalletKey : : CWalletKey ( int64_t nExpires )
{
nTimeCreated = ( nExpires ? GetTime ( ) : 0 ) ;
nTimeExpires = nExpires ;
}
2014-08-28 17:15:21 +02:00
2014-08-29 20:24:16 +02:00
int CMerkleTx : : SetMerkleBranch ( const CBlock & block )
2014-08-28 17:15:21 +02:00
{
AssertLockHeld ( cs_main ) ;
CBlock blockTmp ;
2014-08-29 20:24:16 +02:00
// Update the tx's hashBlock
hashBlock = block . GetHash ( ) ;
2014-08-28 17:15:21 +02:00
2014-08-29 20:24:16 +02:00
// Locate the transaction
for ( nIndex = 0 ; nIndex < ( int ) block . vtx . size ( ) ; nIndex + + )
if ( block . vtx [ nIndex ] = = * ( CTransaction * ) this )
break ;
if ( nIndex = = ( int ) block . vtx . size ( ) )
{
nIndex = - 1 ;
2015-01-08 11:44:25 +01:00
LogPrintf ( " ERROR: SetMerkleBranch(): couldn't find tx in block \n " ) ;
2014-08-29 20:24:16 +02:00
return 0 ;
2014-08-28 17:15:21 +02:00
}
// Is the tx in a block that's in the main chain
2014-09-04 02:02:44 +02:00
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
2014-08-28 17:15:21 +02:00
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
2014-08-29 20:24:16 +02:00
const CBlockIndex * pindex = ( * mi ) . second ;
2014-08-28 17:15:21 +02:00
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
return 0 ;
return chainActive . Height ( ) - pindex - > nHeight + 1 ;
}
2015-11-26 18:42:07 +01:00
int CMerkleTx : : GetDepthInMainChain ( const CBlockIndex * & pindexRet ) const
2014-08-28 17:15:21 +02:00
{
2015-11-26 18:42:07 +01:00
if ( hashBlock . IsNull ( ) )
2014-08-28 17:15:21 +02:00
return 0 ;
AssertLockHeld ( cs_main ) ;
// Find the block it claims to be in
2014-09-04 02:02:44 +02:00
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
2014-08-28 17:15:21 +02:00
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
CBlockIndex * pindex = ( * mi ) . second ;
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
return 0 ;
pindexRet = pindex ;
2015-11-26 18:42:07 +01:00
return ( ( nIndex = = - 1 ) ? ( - 1 ) : 1 ) * ( chainActive . Height ( ) - pindex - > nHeight + 1 ) ;
2014-08-28 17:15:21 +02:00
}
int CMerkleTx : : GetBlocksToMaturity ( ) const
{
if ( ! IsCoinBase ( ) )
return 0 ;
return max ( 0 , ( COINBASE_MATURITY + 1 ) - GetDepthInMainChain ( ) ) ;
}
2015-01-31 03:54:55 +01:00
bool CMerkleTx : : AcceptToMemoryPool ( bool fLimitFree , bool fRejectAbsurdFee )
2014-08-28 17:15:21 +02:00
{
CValidationState state ;
2015-10-02 23:20:38 +02:00
return : : AcceptToMemoryPool ( mempool , state , * this , fLimitFree , NULL , false , fRejectAbsurdFee ) ;
2014-08-28 17:15:21 +02:00
}