2011-08-09 13:27:58 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2014-02-08 22:50:24 +01:00
// Copyright (c) 2009-2014 The Bitcoin developers
2015-01-15 11:31:35 +01:00
// Copyright (c) 2014-2015 The Darkcoin developers
2011-06-26 19:23:24 +02:00
// Distributed under the MIT/X11 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
2012-04-15 23:39:49 +02:00
# include "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"
2013-08-12 17:03:03 +02:00
# include "coincontrol.h"
2013-11-16 17:37:31 +01:00
# include "net.h"
2014-12-06 20:41:53 +01:00
# include "darksend.h"
2014-12-26 12:53:29 +01:00
# include "keepass.h"
2013-04-13 07:13:08 +02:00
2012-11-03 15:58:41 +01:00
# include <boost/algorithm/string/replace.hpp>
2013-04-13 07:13:08 +02:00
# include <openssl/rand.h>
2011-06-26 19:23:24 +02:00
2014-12-06 20:41:53 +01:00
2011-06-26 19:23:24 +02:00
using namespace std ;
2013-12-13 16:14:48 +01:00
// Settings
2014-05-05 20:54:00 +02:00
int64_t nTransactionFee = DEFAULT_TRANSACTION_FEE ;
2014-02-11 12:49:33 +01:00
bool bSpendZeroConfChange = true ;
2011-06-26 19:23:24 +02:00
//////////////////////////////////////////////////////////////////////////////
//
// mapWallet
//
2012-04-07 21:45:39 +02:00
struct CompareValueOnly
{
2013-04-13 07:13:08 +02:00
bool operator ( ) ( const pair < int64_t , pair < const CWalletTx * , unsigned int > > & t1 ,
const pair < int64_t , pair < const CWalletTx * , unsigned int > > & t2 ) const
2012-04-07 21:45:39 +02:00
{
return t1 . first < t2 . first ;
}
} ;
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
2012-02-18 15:02:36 +01:00
RandAddSeedPerfmon ( ) ;
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 ( ) ;
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 ) )
2012-02-18 15:02:36 +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 ;
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 )
{
std : : string strAddr = CBitcoinAddress ( redeemScript . GetID ( ) ) . ToString ( ) ;
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-12-09 02:17:57 +01:00
bool CWallet : : Unlock ( const SecureString & strWalletPassphrase , bool anonymizeOnly )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2014-12-26 12:53:29 +01:00
SecureString strWalletPassphraseFinal ;
2014-12-09 02:17:57 +01:00
if ( ! IsLocked ( ) )
{
fWalletUnlockAnonymizeOnly = anonymizeOnly ;
return true ;
}
2014-12-26 12:53:29 +01:00
// Verify KeePassIntegration
if ( strWalletPassphrase = = " keepass " & & GetBoolArg ( " -keepass " , false ) ) {
try {
strWalletPassphraseFinal = keePassInt . retrievePassphrase ( ) ;
} catch ( std : : exception & e ) {
LogPrintf ( " CWallet::Unlock could not retrieve passphrase from KeePass: Error: %s \n " , e . what ( ) ) ;
return false ;
}
} else {
strWalletPassphraseFinal = strWalletPassphrase ;
}
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
CKeyingMaterial vMasterKey ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
BOOST_FOREACH ( const MasterKeyMap : : value_type & pMasterKey , mapMasterKeys )
{
2014-12-26 12:53:29 +01:00
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphraseFinal , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , vMasterKey ) )
2013-05-07 16:47:00 +02:00
continue ; // try another master key
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 ) )
2014-12-09 02:17:57 +01:00
{
fWalletUnlockAnonymizeOnly = anonymizeOnly ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return true ;
2014-12-09 02:17:57 +01:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2012-04-06 18:39:12 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
}
2011-11-26 07:02:04 +01:00
bool CWallet : : ChangeWalletPassphrase ( const SecureString & strOldWalletPassphrase , const SecureString & strNewWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
bool fWasLocked = IsLocked ( ) ;
2014-12-26 12:53:29 +01:00
bool bUseKeePass = false ;
SecureString strOldWalletPassphraseFinal ;
// Verify KeePassIntegration
if ( strOldWalletPassphrase = = " keepass " & & GetBoolArg ( " -keepass " , false ) ) {
bUseKeePass = true ;
try {
strOldWalletPassphraseFinal = keePassInt . retrievePassphrase ( ) ;
} catch ( std : : exception & e ) {
LogPrintf ( " CWallet::ChangeWalletPassphrase could not retrieve passphrase from KeePass: Error: %s \n " , e . what ( ) ) ;
return false ;
}
} else {
strOldWalletPassphraseFinal = strOldWalletPassphrase ;
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
Lock ( ) ;
CCrypter crypter ;
CKeyingMaterial vMasterKey ;
BOOST_FOREACH ( MasterKeyMap : : value_type & pMasterKey , mapMasterKeys )
{
2014-12-26 12:53:29 +01:00
if ( ! crypter . SetKeyFromPassphrase ( strOldWalletPassphraseFinal , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
2011-08-26 20:37:23 +02:00
if ( ! crypter . Decrypt ( pMasterKey . second . vchCryptedKey , vMasterKey ) )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
if ( CCryptoKeyStore : : Unlock ( vMasterKey ) )
{
2013-04-13 07:13:08 +02:00
int64_t nStartTime = GetTimeMillis ( ) ;
2011-06-28 15:31:09 +02:00
crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) ;
pMasterKey . second . nDeriveIterations = pMasterKey . second . nDeriveIterations * ( 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) ;
nStartTime = GetTimeMillis ( ) ;
crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) ;
pMasterKey . second . nDeriveIterations = ( pMasterKey . second . nDeriveIterations + pMasterKey . second . nDeriveIterations * 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) / 2 ;
if ( pMasterKey . second . nDeriveIterations < 25000 )
pMasterKey . second . nDeriveIterations = 25000 ;
2013-09-18 12:38:08 +02:00
LogPrintf ( " Wallet passphrase changed to an nDeriveIterations of %i \n " , pMasterKey . second . nDeriveIterations ) ;
2011-06-28 15:31:09 +02:00
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( ! crypter . SetKeyFromPassphrase ( strNewWalletPassphrase , pMasterKey . second . vchSalt , pMasterKey . second . nDeriveIterations , pMasterKey . second . nDerivationMethod ) )
return false ;
if ( ! crypter . Encrypt ( vMasterKey , pMasterKey . second . vchCryptedKey ) )
return false ;
CWalletDB ( strWalletFile ) . WriteMasterKey ( pMasterKey . first , pMasterKey . second ) ;
if ( fWasLocked )
Lock ( ) ;
2014-12-26 12:53:29 +01:00
// Update KeePass if necessary
if ( bUseKeePass ) {
LogPrintf ( " CWallet::ChangeWalletPassphrase - Updating KeePass with new passphrase " ) ;
try {
keePassInt . updatePassphrase ( strNewWalletPassphrase ) ;
} catch ( std : : exception & e ) {
LogPrintf ( " CWallet::ChangeWalletPassphrase - could not update passphrase in KeePass: Error: %s \n " , e . what ( ) ) ;
return false ;
}
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return true ;
}
}
}
2011-08-26 20:37:23 +02:00
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
return false ;
}
2012-04-15 22:10:54 +02:00
void CWallet : : SetBestChain ( const CBlockLocator & loc )
{
CWalletDB walletdb ( strWalletFile ) ;
walletdb . WriteBestBlock ( loc ) ;
}
2011-07-10 16:07:22 +02:00
2012-03-22 03:56:31 +01:00
bool CWallet : : SetMinVersion ( enum WalletFeature nVersion , CWalletDB * pwalletdbIn , bool fExplicit )
2012-02-18 14:55:02 +01:00
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // nWalletVersion
2012-02-18 14:55:02 +01:00
if ( nWalletVersion > = nVersion )
return true ;
2012-03-22 03:56:31 +01:00
// when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
if ( fExplicit & & nVersion > nWalletMaxVersion )
nVersion = FEATURE_LATEST ;
2012-02-18 14:55:02 +01:00
nWalletVersion = nVersion ;
2012-03-22 03:56:31 +01:00
if ( nVersion > nWalletMaxVersion )
nWalletMaxVersion = nVersion ;
2012-02-18 14:55:02 +01:00
if ( fFileBacked )
{
CWalletDB * pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB ( strWalletFile ) ;
if ( nWalletVersion > 40000 )
pwalletdb - > WriteMinVersion ( nWalletVersion ) ;
if ( ! pwalletdbIn )
delete pwalletdb ;
}
return true ;
}
2012-03-22 03:56:31 +01:00
bool CWallet : : SetMaxVersion ( int nVersion )
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // nWalletVersion, nWalletMaxVersion
2012-03-22 03:56:31 +01:00
// cannot downgrade below current version
if ( nWalletVersion > nVersion )
return false ;
nWalletMaxVersion = nVersion ;
return true ;
}
2014-02-14 02:12:51 +01:00
set < uint256 > CWallet : : GetConflicts ( const uint256 & txid ) const
{
set < uint256 > result ;
AssertLockHeld ( cs_wallet ) ;
std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( txid ) ;
if ( it = = mapWallet . end ( ) )
return result ;
const CWalletTx & wtx = it - > second ;
2014-02-15 22:38:28 +01:00
std : : pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range ;
2014-02-14 02:12:51 +01:00
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-02-14 02:12:51 +01:00
result . insert ( it - > second ) ;
}
return result ;
}
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 ;
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-02-15 22:38:28 +01:00
// Outpoint is spent if any non-conflicted transaction
// spends it:
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 ) ;
RAND_bytes ( & 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 ;
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
RandAddSeedPerfmon ( ) ;
kMasterKey . vchSalt . resize ( WALLET_CRYPTO_SALT_SIZE ) ;
RAND_bytes ( & 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 )
{
2011-07-08 15:08:27 +02:00
pwalletdbEncryption = new CWalletDB ( strWalletFile ) ;
2012-05-14 07:11:11 +02:00
if ( ! pwalletdbEncryption - > TxnBegin ( ) )
return false ;
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
{
if ( fFileBacked )
pwalletdbEncryption - > TxnAbort ( ) ;
exit ( 1 ) ; //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
}
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 )
{
if ( ! pwalletdbEncryption - > TxnCommit ( ) )
exit ( 1 ) ; //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
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
2014-12-26 12:53:29 +01:00
// Update KeePass if necessary
if ( GetBoolArg ( " -keepass " , false ) ) {
LogPrintf ( " CWallet::EncryptWallet - Updating KeePass with new passphrase " ) ;
try {
keePassInt . updatePassphrase ( strWalletPassphrase ) ;
} catch ( std : : exception & e ) {
LogPrintf ( " CWallet::EncryptWallet - could not update passphrase in KeePass: Error: %s \n " , e . what ( ) ) ;
}
}
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 ;
}
2012-09-02 00:07:47 +02:00
CWallet : : TxItems CWallet : : OrderedTxItems ( std : : list < CAccountingEntry > & acentries , std : : string strAccount )
2012-05-28 20:45:12 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2012-05-28 20:45:12 +02:00
CWalletDB walletdb ( strWalletFile ) ;
// First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
TxItems txOrdered ;
// Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry
// would make this much faster for applications that do this a lot.
for ( map < uint256 , CWalletTx > : : iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
CWalletTx * wtx = & ( ( * it ) . second ) ;
txOrdered . insert ( make_pair ( wtx - > nOrderPos , TxPair ( wtx , ( CAccountingEntry * ) 0 ) ) ) ;
}
2012-09-02 00:07:47 +02:00
acentries . clear ( ) ;
2012-05-28 20:45:12 +02:00
walletdb . ListAccountCreditDebit ( strAccount , acentries ) ;
BOOST_FOREACH ( CAccountingEntry & entry , acentries )
{
txOrdered . insert ( make_pair ( entry . nOrderPos , TxPair ( ( CWalletTx * ) 0 , & entry ) ) ) ;
}
return txOrdered ;
}
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-02-14 02:12:51 +01:00
bool CWallet : : AddToWallet ( const CWalletTx & wtxIn , bool fFromLoadWallet )
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 ;
2014-02-18 15:23:24 +01:00
mapWallet [ hash ] . BindWallet ( this ) ;
2014-02-15 22:38:28 +01:00
AddToSpends ( hash ) ;
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 ( ) ;
2012-09-08 06:55:36 +02:00
wtx . nOrderPos = IncOrderPosNext ( ) ;
2012-05-28 20:45:12 +02:00
wtx . nTimeSmart = wtx . nTimeReceived ;
if ( wtxIn . hashBlock ! = 0 )
{
if ( mapBlockIndex . count ( wtxIn . hashBlock ) )
{
unsigned int latestNow = wtx . nTimeReceived ;
unsigned int latestEntry = 0 ;
{
// 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 ;
2012-09-02 00:07:47 +02:00
std : : list < CAccountingEntry > acentries ;
TxItems txOrdered = OrderedTxItems ( acentries ) ;
2012-05-28 20:45:12 +02:00
for ( TxItems : : reverse_iterator it = txOrdered . rbegin ( ) ; it ! = txOrdered . rend ( ) ; + + it )
{
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 ;
}
}
}
unsigned int & blocktime = mapBlockIndex [ wtxIn . hashBlock ] - > nTime ;
wtx . nTimeSmart = std : : max ( latestEntry , std : : min ( blocktime , latestNow ) ) ;
}
else
2013-09-18 12:38:08 +02: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
if ( wtxIn . hashBlock ! = 0 & & wtxIn . hashBlock ! = wtx . hashBlock )
{
wtx . hashBlock = wtxIn . hashBlock ;
fUpdated = true ;
}
if ( wtxIn . nIndex ! = - 1 & & ( wtxIn . vMerkleBranch ! = wtx . vMerkleBranch | | wtxIn . nIndex ! = wtx . nIndex ) )
{
wtx . vMerkleBranch = wtxIn . vMerkleBranch ;
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 )
if ( ! wtx . WriteToDisk ( ) )
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 ;
}
2011-11-07 00:05:42 +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.
2013-10-19 18:34:06 +02:00
bool CWallet : : AddToWalletIfInvolvingMe ( const uint256 & hash , 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 ) ;
2011-08-26 20:37:23 +02:00
bool fExisted = mapWallet . count ( hash ) ;
if ( fExisted & & ! fUpdate ) return false ;
if ( fExisted | | IsMine ( tx ) | | IsFromMe ( tx ) )
{
CWalletTx wtx ( this , tx ) ;
// Get merkle branch if transaction was found in a block
if ( pblock )
wtx . SetMerkleBranch ( pblock ) ;
return AddToWallet ( wtx ) ;
}
2011-06-26 19:23:24 +02:00
}
return false ;
}
2014-02-15 22:38:28 +01:00
void CWallet : : SyncTransaction ( const uint256 & hash , const CTransaction & tx , const CBlock * pblock )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-09 12:41:22 +01:00
if ( ! AddToWalletIfInvolvingMe ( hash , 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
}
void CWallet : : EraseFromWallet ( const uint256 & hash )
2011-06-26 19:23:24 +02:00
{
if ( ! fFileBacked )
2013-10-19 18:34:06 +02:00
return ;
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
if ( mapWallet . erase ( hash ) )
CWalletDB ( strWalletFile ) . EraseTx ( hash ) ;
}
2013-10-19 18:34:06 +02:00
return ;
2011-06-26 19:23:24 +02:00
}
bool CWallet : : IsMine ( const CTxIn & txin ) const
{
{
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 ( ) )
if ( IsMine ( prev . vout [ txin . prevout . n ] ) )
return true ;
}
}
return false ;
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetDebit ( 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 ( ) )
if ( IsMine ( prev . vout [ txin . prevout . n ] ) )
return prev . vout [ txin . prevout . n ] . nValue ;
}
}
return 0 ;
}
2014-12-09 02:17:57 +01:00
int64_t CWallet : : IsDenominated ( const CTxIn & txin ) const
{
{
LOCK ( cs_wallet ) ;
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 ( ) ) {
BOOST_FOREACH ( int64_t d , darkSendDenominations ) {
if ( prev . vout [ txin . prevout . n ] . nValue = = d ) {
return true ;
}
}
}
}
}
return 0 ;
}
2011-10-03 19:05:43 +02:00
bool CWallet : : IsChange ( const CTxOut & txout ) const
{
2012-05-14 23:44:52 +02:00
CTxDestination address ;
2011-11-08 19:20:29 +01:00
// TODO: fix handling of 'change' outputs. The assumption is that any
// payment to a TX_PUBKEYHASH that is mine but isn't in the address book
// 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).
2012-05-14 23:44:52 +02:00
if ( ExtractDestination ( txout . scriptPubKey , address ) & & : : IsMine ( * this , address ) )
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 ;
}
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
if ( hashBlock ! = 0 )
{
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?
if ( nRequests = = 0 & & hashBlock ! = 0 )
{
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 ;
}
2013-04-13 07:13:08 +02:00
void CWalletTx : : GetAmounts ( list < pair < CTxDestination , int64_t > > & listReceived ,
list < pair < CTxDestination , int64_t > > & listSent , int64_t & nFee , string & strSentAccount ) 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:
2013-04-13 07:13:08 +02:00
int64_t nDebit = GetDebit ( ) ;
2011-06-26 19:23:24 +02:00
if ( nDebit > 0 ) // debit>0 means we signed/sent this transaction
{
2013-11-11 07:03:51 +01:00
int64_t nValueOut = GetValueOut ( ) ;
2011-06-26 19:23:24 +02:00
nFee = nDebit - nValueOut ;
}
2011-10-03 19:05:43 +02:00
// Sent/received.
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( const CTxOut & txout , vout )
{
2012-09-22 05:20:14 +02:00
bool fIsMine ;
// 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 ;
fIsMine = pwallet - > IsMine ( txout ) ;
}
else if ( ! ( fIsMine = pwallet - > IsMine ( txout ) ) )
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
}
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 )
listSent . push_back ( make_pair ( address , txout . nValue ) ) ;
2012-09-22 05:20:14 +02:00
// If we are receiving the output, add it as a "received" entry
if ( fIsMine )
2011-06-26 19:23:24 +02:00
listReceived . push_back ( make_pair ( address , txout . nValue ) ) ;
}
}
2013-04-13 07:13:08 +02:00
void CWalletTx : : GetAccountAmounts ( const string & strAccount , int64_t & nReceived ,
int64_t & nSent , int64_t & nFee ) 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
2013-04-13 07:13:08 +02:00
int64_t allFee ;
2011-06-26 19:23:24 +02:00
string strSentAccount ;
2013-04-13 07:13:08 +02:00
list < pair < CTxDestination , int64_t > > listReceived ;
list < pair < CTxDestination , int64_t > > listSent ;
2012-06-02 04:33:28 +02:00
GetAmounts ( listReceived , listSent , allFee , strSentAccount ) ;
2011-06-26 19:23:24 +02:00
if ( strAccount = = strSentAccount )
{
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64_t ) & s , listSent )
2011-06-26 19:23:24 +02:00
nSent + = s . second ;
nFee = allFee ;
}
{
2012-04-06 18:39:12 +02:00
LOCK ( pwallet - > cs_wallet ) ;
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , int64_t ) & r , listReceived )
2011-06-26 19:23:24 +02:00
{
if ( pwallet - > mapAddressBook . count ( r . first ) )
{
2013-07-15 07:20:50 +02:00
map < CTxDestination , CAddressBookData > : : const_iterator mi = pwallet - > mapAddressBook . find ( r . first ) ;
if ( mi ! = pwallet - > mapAddressBook . end ( ) & & ( * mi ) . second . name = = strAccount )
2011-06-26 19:23:24 +02:00
nReceived + = r . second ;
}
else if ( strAccount . empty ( ) )
{
nReceived + = r . second ;
}
}
}
}
2013-10-19 18:42:14 +02:00
2011-06-26 19:23:24 +02:00
bool CWalletTx : : WriteToDisk ( )
{
return CWalletDB ( pwallet - > strWalletFile ) . WriteTx ( GetHash ( ) , * this ) ;
}
2011-11-07 00:05:42 +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 ( ) ;
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)
while ( pindex & & nTimeFirstKey & & ( pindex - > nTime < ( nTimeFirstKey - 7200 ) ) )
pindex = chainActive . Next ( pindex ) ;
ShowProgress ( _ ( " Rescanning... " ) , 0 ) ; // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
double dProgressStart = Checkpoints : : GuessVerificationProgress ( pindex , false ) ;
double dProgressTip = Checkpoints : : GuessVerificationProgress ( 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 )
ShowProgress ( _ ( " Rescanning... " ) , std : : max ( 1 , std : : min ( 99 , ( int ) ( ( Checkpoints : : GuessVerificationProgress ( pindex , false ) - dProgressStart ) / ( dProgressTip - dProgressStart ) * 100 ) ) ) ) ;
2013-06-10 15:38:13 +02:00
2011-06-26 19:23:24 +02:00
CBlock block ;
2013-06-24 03:10:02 +02:00
ReadBlockFromDisk ( block , pindex ) ;
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( CTransaction & tx , block . vtx )
{
2012-07-08 00:06:34 +02:00
if ( AddToWalletIfInvolvingMe ( tx . GetHash ( ) , 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 ( ) ;
LogPrintf ( " Still rescanning. At block %d. Progress=%f \n " , pindex - > nHeight , Checkpoints : : GuessVerificationProgress ( pindex ) ) ;
}
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 ( )
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
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 ( ) ;
if ( ! wtx . IsCoinBase ( ) & & nDepth < 0 )
2011-06-26 19:23:24 +02:00
{
2014-02-15 22:38:28 +01:00
// Try to add to memory pool
LOCK ( mempool . cs ) ;
wtx . AcceptToMemoryPool ( false ) ;
2011-06-26 19:23:24 +02:00
}
}
}
2014-12-09 02:17:57 +01:00
void CWalletTx : : RelayWalletTransaction ( std : : string strCommand )
2011-06-26 19:23:24 +02:00
{
if ( ! IsCoinBase ( ) )
{
2012-11-01 15:52:25 +01:00
if ( GetDepthInMainChain ( ) = = 0 ) {
uint256 hash = GetHash ( ) ;
2014-01-16 16:15:27 +01:00
LogPrintf ( " Relaying wtx %s \n " , hash . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
if ( strCommand = = " txlreq " ) {
RelayTransactionLockReq ( ( CTransaction ) * this , hash , true ) ;
} else {
RelayTransaction ( ( CTransaction ) * this , hash ) ;
}
2011-06-26 19:23:24 +02:00
}
}
}
2014-02-14 02:12:51 +01:00
set < uint256 > CWalletTx : : GetConflicts ( ) const
{
set < uint256 > result ;
if ( pwallet ! = NULL )
{
uint256 myHash = GetHash ( ) ;
result = pwallet - > GetConflicts ( myHash ) ;
result . erase ( myHash ) ;
}
return result ;
}
2011-06-26 19:23:24 +02:00
void CWallet : : ResendWalletTransactions ( )
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
2013-04-19 23:28:25 +02:00
if ( GetTime ( ) < nNextResend )
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
2013-04-19 23:28:25 +02:00
if ( nTimeBestReceived < 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
// Rebroadcast any of our txes that aren't in a block yet
2013-09-18 12:38:08 +02:00
LogPrintf ( " ResendWalletTransactions() \n " ) ;
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
// 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 until it's had plenty of time that
// it should have gotten in already by now.
2013-04-13 07:13:08 +02:00
if ( nTimeBestReceived - ( int64_t ) wtx . nTimeReceived > 5 * 60 )
2011-06-26 19:23:24 +02:00
mapSorted . insert ( make_pair ( wtx . nTimeReceived , & wtx ) ) ;
}
BOOST_FOREACH ( PAIRTYPE ( const unsigned int , CWalletTx * ) & item , mapSorted )
{
CWalletTx & wtx = * item . second ;
2012-07-06 16:33:34 +02:00
wtx . RelayWalletTransaction ( ) ;
2011-06-26 19:23:24 +02:00
}
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Actions
//
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetBalance ( ) const
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t 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-12-09 02:17:57 +01:00
int64_t CWallet : : GetAnonymizedBalance ( ) const
{
int64_t nTotal = 0 ;
{
LOCK ( cs_wallet ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) ) {
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
COutput out = COutput ( pcoin , i , pcoin - > GetDepthInMainChain ( ) ) ;
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
if ( IsSpent ( out . tx - > GetHash ( ) , i ) | | ! IsMine ( pcoin - > vout [ i ] ) | | ! IsDenominated ( vin ) ) continue ;
int rounds = GetInputDarksendRounds ( vin ) ;
if ( rounds > = nDarksendRounds ) {
nTotal + = pcoin - > vout [ i ] . nValue ;
}
}
}
}
}
return nTotal ;
}
double CWallet : : GetAverageAnonymizedRounds ( ) const
{
double fTotal = 0 ;
double fCount = 0 ;
{
LOCK ( cs_wallet ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-01-02 23:20:30 +01:00
2014-12-09 02:17:57 +01:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
COutput out = COutput ( pcoin , i , pcoin - > GetDepthInMainChain ( ) ) ;
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
if ( IsSpent ( out . tx - > GetHash ( ) , i ) | | ! IsMine ( pcoin - > vout [ i ] ) | | ! IsDenominated ( vin ) ) continue ;
int rounds = GetInputDarksendRounds ( vin ) ;
fTotal + = ( float ) rounds ;
fCount + = 1 ;
}
}
}
if ( fCount = = 0 ) return 0 ;
return fTotal / fCount ;
}
int64_t CWallet : : GetDenominatedBalance ( bool onlyDenom , bool onlyUnconfirmed ) const
{
int64_t nTotal = 0 ;
{
LOCK ( cs_wallet ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
2015-01-02 23:20:30 +01:00
{
COutput out = COutput ( pcoin , i , pcoin - > GetDepthInMainChain ( ) ) ;
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
bool unconfirmed = ( ! IsFinalTx ( * pcoin ) | | ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 ) ) ;
if ( IsSpent ( out . tx - > GetHash ( ) , i ) ) continue ;
if ( ! IsMine ( pcoin - > vout [ i ] ) ) continue ;
if ( onlyUnconfirmed ! = unconfirmed ) continue ;
int rounds = GetInputDarksendRounds ( vin ) ;
if ( onlyDenom ! = ( rounds > = 0 ) ) continue ;
nTotal + = pcoin - > vout [ i ] . nValue ;
2014-12-09 02:17:57 +01:00
}
}
}
2015-01-02 23:20:30 +01:00
2014-12-09 02:17:57 +01:00
return nTotal ;
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetUnconfirmedBalance ( ) const
2011-07-11 20:42:10 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t 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 ;
2014-02-14 02:12:51 +01:00
if ( ! IsFinalTx ( * pcoin ) | | ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 ) )
2012-02-14 12:08:00 +01:00
nTotal + = pcoin - > GetAvailableCredit ( ) ;
}
}
return nTotal ;
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetImmatureBalance ( ) const
2012-02-14 12:08:00 +01:00
{
2013-04-13 07:13:08 +02:00
int64_t 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
2012-04-13 01:22:15 +02:00
// populate vCoins with vector of spendable COutputs
2014-12-09 02:17:57 +01:00
void CWallet : : AvailableCoins ( vector < COutput > & vCoins , bool fOnlyConfirmed , const CCoinControl * coinControl , AvailableCoinsType coin_type ) 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 ;
2013-01-08 13:17:15 +01:00
if ( ! IsFinalTx ( * 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 + + ) {
2014-12-09 02:17:57 +01:00
bool found = false ;
if ( coin_type = = ONLY_DENOMINATED ) {
//should make this a vector
COutput out = COutput ( pcoin , i , pcoin - > GetDepthInMainChain ( ) ) ;
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
int rounds = GetInputDarksendRounds ( vin ) ;
2015-01-15 15:41:56 +01:00
if ( rounds > = 0 ) found = true ;
2014-12-09 02:17:57 +01:00
} else if ( coin_type = = ONLY_NONDENOMINATED ) {
found = true ;
BOOST_FOREACH ( int64_t d , darkSendDenominations )
if ( pcoin - > vout [ i ] . nValue = = d )
found = false ;
} else {
found = true ;
}
if ( ! found ) continue ;
2014-02-15 22:38:28 +01:00
if ( ! ( IsSpent ( wtxid , i ) ) & & IsMine ( pcoin - > vout [ i ] ) & &
2013-08-12 17:03:03 +02:00
! IsLockedCoin ( ( * it ) . first , i ) & & pcoin - > vout [ i ] . nValue > 0 & &
( ! coinControl | | ! coinControl - > HasSelected ( ) | | coinControl - > IsSelected ( ( * it ) . first , i ) ) )
2014-02-12 19:43:07 +01:00
vCoins . push_back ( COutput ( pcoin , i , nDepth ) ) ;
2012-09-27 19:52:09 +02:00
}
2012-02-27 13:19:32 +01:00
}
}
}
2013-04-13 07:13:08 +02:00
static void ApproximateBestSubset ( vector < pair < int64_t , pair < const CWalletTx * , unsigned int > > > vValue , int64_t nTotalLower , int64_t nTargetValue ,
vector < char > & vfBest , int64_t & 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 ) ;
2013-04-13 07:13:08 +02:00
int64_t 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
//that the rng fast. We do not use a constant random sequence,
//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-12-09 02:17:57 +01:00
2014-12-23 04:06:47 +01:00
// TODO: find appropriate place for this sort function
// move denoms down
bool less_then_denom ( const COutput & out1 , const COutput & out2 )
{
const CWalletTx * pcoin1 = out1 . tx ;
const CWalletTx * pcoin2 = out2 . tx ;
bool found1 = false ;
bool found2 = false ;
BOOST_FOREACH ( int64_t d , darkSendDenominations ) // loop through predefined denoms
{
if ( pcoin1 - > vout [ out1 . i ] . nValue = = d ) found1 = true ;
if ( pcoin2 - > vout [ out2 . i ] . nValue = = d ) found2 = true ;
}
return ( ! found1 & & found2 ) ;
}
2013-04-13 07:13:08 +02:00
bool CWallet : : SelectCoinsMinConf ( int64_t nTargetValue , int nConfMine , int nConfTheirs , vector < COutput > vCoins ,
set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , int64_t & nValueRet ) const
2011-06-26 19:23:24 +02:00
{
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
// List of values less than target
2013-04-13 07:13:08 +02:00
pair < int64_t , pair < const CWalletTx * , unsigned int > > coinLowestLarger ;
coinLowestLarger . first = std : : numeric_limits < int64_t > : : max ( ) ;
2011-06-26 19:23:24 +02:00
coinLowestLarger . second . first = NULL ;
2013-04-13 07:13:08 +02:00
vector < pair < int64_t , pair < const CWalletTx * , unsigned int > > > vValue ;
int64_t nTotalLower = 0 ;
2011-06-26 19:23:24 +02:00
2012-04-07 19:52:40 +02:00
random_shuffle ( vCoins . begin ( ) , vCoins . end ( ) , GetRandInt ) ;
2014-12-23 04:06:47 +01:00
// move denoms down on the list
sort ( vCoins . begin ( ) , vCoins . end ( ) , less_then_denom ) ;
// try to find nondenom first to prevent unneeded spending of mixed coins
for ( unsigned int tryDenom = 0 ; tryDenom < 2 ; tryDenom + + )
2011-06-26 19:23:24 +02:00
{
2014-12-23 04:06:47 +01:00
if ( fDebug ) LogPrint ( " selectcoins " , " tryDenom: %d \n " , tryDenom ) ;
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
nTotalLower = 0 ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
BOOST_FOREACH ( COutput output , vCoins )
{
const CWalletTx * pcoin = output . tx ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
// if (fDebug) LogPrint("selectcoins", "value %s confirms %d\n", FormatMoney(pcoin->vout[output.i].nValue), output.nDepth);
if ( output . nDepth < ( pcoin - > IsFromMe ( ) ? nConfMine : nConfTheirs ) )
continue ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
int i = output . i ;
int64_t n = pcoin - > vout [ i ] . nValue ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
if ( tryDenom = = 0 ) // first run?
{
bool found = false ;
BOOST_FOREACH ( int64_t d , darkSendDenominations ) // loop through predefined denoms
if ( n = = d )
found = true ;
if ( found ) continue ; // we don't want denom values on first run
}
pair < int64_t , pair < const CWalletTx * , unsigned int > > coin = make_pair ( n , make_pair ( pcoin , i ) ) ;
if ( n = = nTargetValue )
{
setCoinsRet . insert ( coin . second ) ;
nValueRet + = coin . first ;
return true ;
}
else if ( n < nTargetValue + CENT )
{
vValue . push_back ( coin ) ;
nTotalLower + = n ;
}
else if ( n < coinLowestLarger . first )
{
coinLowestLarger = coin ;
}
2012-02-27 13:19:32 +01:00
}
2014-12-23 04:06:47 +01:00
if ( nTotalLower = = nTargetValue )
2012-02-27 13:19:32 +01:00
{
2014-12-23 04:06:47 +01:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; + + i )
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
}
return true ;
2011-06-26 19:23:24 +02:00
}
2014-12-23 04:06:47 +01:00
if ( nTotalLower < nTargetValue )
2011-06-26 19:23:24 +02:00
{
2014-12-23 04:06:47 +01:00
if ( coinLowestLarger . second . first = = NULL ) // there is no input larger than nTargetValue
{
if ( tryDenom = = 0 )
// we didn't look at denom yet, let's do it
continue ;
else
// we looked at everything possible and didn't find anything, no luck
return false ;
}
setCoinsRet . insert ( coinLowestLarger . second ) ;
nValueRet + = coinLowestLarger . first ;
return true ;
2011-06-26 19:23:24 +02:00
}
2014-12-23 04:06:47 +01:00
// nTotalLower > nTargetValue
break ;
2011-06-26 19:23:24 +02:00
}
// Solve subset sum by stochastic approximation
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 ;
2013-04-13 07:13:08 +02:00
int64_t nBest ;
2011-06-26 19:23:24 +02:00
2012-04-13 01:22:15 +02:00
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue , vfBest , nBest , 1000 ) ;
if ( nBest ! = nTargetValue & & nTotalLower > = nTargetValue + CENT )
ApproximateBestSubset ( vValue , nTotalLower , nTargetValue + CENT , vfBest , nBest , 1000 ) ;
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 & &
( ( nBest ! = nTargetValue & & nBest < nTargetValue + CENT ) | | 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-12-09 02:17:57 +01:00
bool CWallet : : SelectCoins ( int64_t nTargetValue , set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , int64_t & nValueRet , const CCoinControl * coinControl , AvailableCoinsType coin_type ) 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 ) ;
2014-12-09 02:17:57 +01:00
//if we're doing only denominated, we need to round up to the nearest .1DRK
if ( coin_type = = ONLY_DENOMINATED ) {
// denominate our funds
std : : vector < CTxOut > vOut ;
// Make outputs by looping through denominations, from large to small
BOOST_FOREACH ( int64_t v , darkSendDenominations )
{
int added = 0 ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
if ( out . tx - > vout [ out . i ] . nValue = = v //make sure it's the denom we're looking for
& & nValueRet + out . tx - > vout [ out . i ] . nValue < nTargetValue + ( 0.1 * COIN ) + 1 //round the amount up to .1DRK over
& & added < = 50 ) { //don't add more than 50 of one denom type
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
added + + ;
}
}
}
return ( nValueRet > = nTargetValue ) ;
}
2013-08-12 17:03:03 +02:00
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if ( coinControl & & coinControl - > HasSelected ( ) )
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
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
return ( SelectCoinsMinConf ( nTargetValue , 1 , 6 , vCoins , setCoinsRet , nValueRet ) | |
SelectCoinsMinConf ( nTargetValue , 1 , 1 , vCoins , setCoinsRet , nValueRet ) | |
2014-02-11 12:49:33 +01:00
( bSpendZeroConfChange & & SelectCoinsMinConf ( nTargetValue , 0 , 1 , vCoins , setCoinsRet , nValueRet ) ) ) ;
2011-06-26 19:23:24 +02:00
}
2014-12-09 02:17:57 +01:00
struct CompareByPriority
{
bool operator ( ) ( const COutput & t1 ,
const COutput & t2 ) const
{
return t1 . Priority ( ) > t2 . Priority ( ) ;
}
} ;
2015-01-20 16:59:37 +01:00
bool CWallet : : SelectCoinsByDenominations ( int nDenom , int64_t nValueMin , int64_t nValueMax , std : : vector < CTxIn > & setCoinsRet , vector < COutput > & setCoinsRet2 , int64_t & nValueRet , int nDarksendRoundsMin , int nDarksendRoundsMax )
2014-12-30 01:09:34 +01:00
{
CCoinControl * coinControl = NULL ;
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
2015-01-20 16:59:37 +01:00
setCoinsRet2 . clear ( ) ;
2014-12-30 01:09:34 +01:00
vector < COutput > vCoins ;
AvailableCoins ( vCoins , false , coinControl , ALL_COINS ) ;
//order the array so fees are first, then denominated money, then the rest.
std : : random_shuffle ( vCoins . rbegin ( ) , vCoins . rend ( ) ) ;
//keep track of each denomination that we have
2014-12-30 19:13:28 +01:00
bool fFound100 = false ;
bool fFound10 = false ;
bool fFound1 = false ;
bool fFoundDot1 = false ;
2014-12-30 01:09:34 +01:00
//Check to see if any of the denomination are off, in that case mark them as fulfilled
if ( ! ( nDenom & ( 1 < < 0 ) ) ) fFound100 = true ;
if ( ! ( nDenom & ( 1 < < 1 ) ) ) fFound10 = true ;
if ( ! ( nDenom & ( 1 < < 2 ) ) ) fFound1 = true ;
if ( ! ( nDenom & ( 1 < < 3 ) ) ) fFoundDot1 = true ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
//there's no reason to allow inputs less than 1 COIN into DS (other than denominations smaller than that amount)
if ( out . tx - > vout [ out . i ] . nValue < 1 * COIN & & out . tx - > vout [ out . i ] . nValue ! = ( .1 * COIN ) + 1 ) continue ;
if ( fMasterNode & & out . tx - > vout [ out . i ] . nValue = = 1000 * COIN ) continue ; //masternode input
if ( nValueRet + out . tx - > vout [ out . i ] . nValue < = nValueMax ) {
bool fAccepted = false ;
// Function returns as follows:
//
// bit 0 - 100DRK+1 ( bit on if present )
// bit 1 - 10DRK+1
// bit 2 - 1DRK+1
// bit 3 - .1DRK+1
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
int rounds = GetInputDarksendRounds ( vin ) ;
if ( rounds > = nDarksendRoundsMax ) continue ;
if ( rounds < nDarksendRoundsMin ) continue ;
2015-01-15 15:41:56 +01:00
if ( fFound100 & & fFound10 & & fFound1 & & fFoundDot1 ) { //if fulfilled
2015-01-19 22:25:03 +01:00
//we can return this for submission
if ( nValueRet > = nValueMin ) {
//random reduce the max amount we'll submit for anonymity
nValueMax - = ( rand ( ) % ( nValueMax / 5 ) ) ;
2015-01-20 10:42:15 +01:00
//on average use 50% of the inputs or less
int r = ( rand ( ) % ( int ) vCoins . size ( ) ) ;
if ( ( int ) setCoinsRet . size ( ) > r ) return true ;
2015-01-19 22:25:03 +01:00
}
2014-12-30 01:09:34 +01:00
//Denomination criterion has been met, we can take any matching denominations
if ( ( nDenom & ( 1 < < 0 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 100 * COIN ) + 1 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 1 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 10 * COIN ) + 1 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 2 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 1 * COIN ) + 1 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 3 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( .1 * COIN ) + 1 ) ) { fAccepted = true ; }
} else {
//Criterion has not been satisfied, we will only take 1 of each until it is.
2014-12-30 19:13:28 +01:00
if ( ( nDenom & ( 1 < < 0 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 100 * COIN ) + 1 ) ) { fAccepted = true ; fFound100 = true ; }
else if ( ( nDenom & ( 1 < < 1 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 10 * COIN ) + 1 ) ) { fAccepted = true ; fFound10 = true ; }
else if ( ( nDenom & ( 1 < < 2 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 1 * COIN ) + 1 ) ) { fAccepted = true ; fFound1 = true ; }
else if ( ( nDenom & ( 1 < < 3 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( .1 * COIN ) + 1 ) ) { fAccepted = true ; fFoundDot1 = true ; }
2014-12-30 01:09:34 +01:00
}
if ( ! fAccepted ) continue ;
vin . prevPubKey = out . tx - > vout [ out . i ] . scriptPubKey ; // the inputs PubKey
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . push_back ( vin ) ;
2015-01-20 16:59:37 +01:00
setCoinsRet2 . push_back ( out ) ;
2014-12-30 01:09:34 +01:00
}
}
2015-01-15 15:41:56 +01:00
return ( nValueRet > = nValueMin & & fFound100 & & fFound10 & & fFound1 & & fFoundDot1 ) ;
2014-12-30 01:09:34 +01:00
}
2014-12-30 20:42:34 +01:00
bool CWallet : : SelectCoinsDark ( int64_t nValueMin , int64_t nValueMax , std : : vector < CTxIn > & setCoinsRet , int64_t & nValueRet , int nDarksendRoundsMin , int nDarksendRoundsMax ) const
2014-12-09 02:17:57 +01:00
{
CCoinControl * coinControl = NULL ;
2014-12-30 01:09:34 +01:00
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
2014-12-09 02:17:57 +01:00
vector < COutput > vCoins ;
2015-01-15 15:41:56 +01:00
AvailableCoins ( vCoins , false , coinControl , nDarksendRoundsMin < 0 ? ONLY_NONDENOMINATED : ONLY_DENOMINATED ) ;
2014-12-09 02:17:57 +01:00
set < pair < const CWalletTx * , unsigned int > > setCoinsRet2 ;
//order the array so fees are first, then denominated money, then the rest.
sort ( vCoins . rbegin ( ) , vCoins . rend ( ) , CompareByPriority ( ) ) ;
//the first thing we get is a fee input, then we'll use as many denominated as possible. then the rest
BOOST_FOREACH ( const COutput & out , vCoins )
{
//there's no reason to allow inputs less than 1 COIN into DS (other than denominations smaller than that amount)
2014-12-26 04:58:39 +01:00
if ( out . tx - > vout [ out . i ] . nValue < 1 * COIN & & out . tx - > vout [ out . i ] . nValue ! = ( .1 * COIN ) + 1 ) continue ;
2014-12-09 02:17:57 +01:00
if ( fMasterNode & & out . tx - > vout [ out . i ] . nValue = = 1000 * COIN ) continue ; //masternode input
if ( nValueRet + out . tx - > vout [ out . i ] . nValue < = nValueMax ) {
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
int rounds = GetInputDarksendRounds ( vin ) ;
if ( rounds > = nDarksendRoundsMax ) continue ;
if ( rounds < nDarksendRoundsMin ) continue ;
vin . prevPubKey = out . tx - > vout [ out . i ] . scriptPubKey ; // the inputs PubKey
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . push_back ( vin ) ;
setCoinsRet2 . insert ( make_pair ( out . tx , out . i ) ) ;
}
}
// if it's more than min, we're good to return
if ( nValueRet > = nValueMin ) return true ;
return false ;
}
bool CWallet : : SelectCoinsCollateral ( std : : vector < CTxIn > & setCoinsRet , int64_t & nValueRet ) const
{
CCoinControl * coinControl = NULL ;
vector < COutput > vCoins ;
//printf(" selecting coins for collateral\n");
AvailableCoins ( vCoins , false , coinControl , ALL_COINS ) ;
//printf("found coins %d\n", (int)vCoins.size());
set < pair < const CWalletTx * , unsigned int > > setCoinsRet2 ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
// collateral inputs will always be a multiple of DARSEND_COLLATERAL, up to five
if (
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 5 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 4 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 3 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 2 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 1 ) + DARKSEND_FEE
) {
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
vin . prevPubKey = out . tx - > vout [ out . i ] . scriptPubKey ; // the inputs PubKey
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . push_back ( vin ) ;
setCoinsRet2 . insert ( make_pair ( out . tx , out . i ) ) ;
return true ;
}
}
return false ;
}
int CWallet : : CountInputsWithAmount ( int64_t nInputAmount )
{
int64_t nTotal = 0 ;
{
LOCK ( cs_wallet ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) ) {
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
COutput out = COutput ( pcoin , i , pcoin - > GetDepthInMainChain ( ) ) ;
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
if ( out . tx - > vout [ out . i ] . nValue ! = nInputAmount ) continue ;
if ( IsSpent ( out . tx - > GetHash ( ) , i ) | | ! IsMine ( pcoin - > vout [ i ] ) | | ! IsDenominated ( vin ) ) continue ;
int rounds = GetInputDarksendRounds ( vin ) ;
if ( rounds > = nDarksendRounds ) {
nTotal + + ;
}
}
}
}
}
return nTotal ;
}
bool CWallet : : HasDarksendFeeInputs ( ) const
{
CCoinControl * coinControl = NULL ;
vector < COutput > vCoins ;
AvailableCoins ( vCoins , false , coinControl , ALL_COINS ) ;
bool found_collateral = false ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
if (
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 5 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 4 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 3 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 2 ) + DARKSEND_FEE | |
out . tx - > vout [ out . i ] . nValue = = ( DARKSEND_COLLATERAL * 1 ) + DARKSEND_FEE
) found_collateral = true ;
}
return found_collateral ;
}
bool CWallet : : SelectCoinsWithoutDenomination ( int64_t nTargetValue , set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , int64_t & nValueRet ) const
{
CCoinControl * coinControl = NULL ;
vector < COutput > vCoins ;
AvailableCoins ( vCoins , true , coinControl , ONLY_NONDENOMINATED ) ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
}
return ( nValueRet > = nTargetValue ) ;
}
bool CWallet : : CreateCollateralTransaction ( CTransaction & txCollateral , std : : string strReason )
{
/*
To doublespend a collateral transaction , it will require a fee higher than this . So there ' s
still a significant cost .
*/
int64_t nFeeRet = 0.001 * COIN ;
txCollateral . vin . clear ( ) ;
txCollateral . vout . clear ( ) ;
CReserveKey reservekey ( this ) ;
int64_t nValueIn2 = 0 ;
std : : vector < CTxIn > vCoinsCollateral ;
if ( ! SelectCoinsCollateral ( vCoinsCollateral , nValueIn2 ) )
{
strReason = " Error: Darksend requires a collateral transaction and could not locate an acceptable input! " ;
return false ;
}
// make our change address
CScript scriptChange ;
CPubKey vchPubKey ;
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
reservekey . KeepKey ( ) ;
BOOST_FOREACH ( CTxIn v , vCoinsCollateral )
txCollateral . vin . push_back ( v ) ;
2011-06-26 19:23:24 +02:00
2014-12-09 02:17:57 +01:00
if ( nValueIn2 - DARKSEND_COLLATERAL - nFeeRet > 0 ) {
//pay collateral charge in fees
CTxOut vout3 = CTxOut ( nValueIn2 - DARKSEND_COLLATERAL , scriptChange ) ;
txCollateral . vout . push_back ( vout3 ) ;
}
int vinNumber = 0 ;
BOOST_FOREACH ( CTxIn v , txCollateral . vin ) {
if ( ! SignSignature ( * this , v . prevPubKey , txCollateral , vinNumber , int ( SIGHASH_ALL | SIGHASH_ANYONECANPAY ) ) ) {
BOOST_FOREACH ( CTxIn v , vCoinsCollateral )
UnlockCoin ( v . prevout ) ;
2011-06-26 19:23:24 +02:00
2014-12-09 02:17:57 +01:00
strReason = " CDarkSendPool::Sign - Unable to sign collateral transaction! \n " ;
return false ;
}
vinNumber + + ;
}
return true ;
}
bool CWallet : : ConvertList ( std : : vector < CTxIn > vCoins , std : : vector < int64_t > & vecAmounts )
{
BOOST_FOREACH ( CTxIn i , vCoins ) {
if ( mapWallet . count ( i . prevout . hash ) )
{
CWalletTx & wtx = mapWallet [ i . prevout . hash ] ;
if ( i . prevout . n < wtx . vout . size ( ) ) {
vecAmounts . push_back ( wtx . vout [ i . prevout . n ] . nValue ) ;
}
} else {
LogPrintf ( " ConvertList -- Couldn't find transaction \n " ) ;
}
}
return true ;
}
2011-06-26 19:23:24 +02:00
2013-04-13 07:13:08 +02:00
bool CWallet : : CreateTransaction ( const vector < pair < CScript , int64_t > > & vecSend ,
2014-12-09 02:17:57 +01:00
CWalletTx & wtxNew , CReserveKey & reservekey , int64_t & nFeeRet , std : : string & strFailReason , const CCoinControl * coinControl , AvailableCoinsType coin_type )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nValue = 0 ;
BOOST_FOREACH ( const PAIRTYPE ( CScript , int64_t ) & s , vecSend )
2011-06-26 19:23:24 +02:00
{
if ( 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
nValue + = s . second ;
}
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
2011-06-28 23:45:22 +02:00
wtxNew . BindWallet ( this ) ;
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
{
nFeeRet = nTransactionFee ;
2013-07-31 06:06:44 +02:00
while ( true )
2011-06-26 19:23:24 +02:00
{
wtxNew . vin . clear ( ) ;
wtxNew . vout . clear ( ) ;
wtxNew . fFromMe = true ;
2013-04-13 07:13:08 +02:00
int64_t nTotalValue = nValue + nFeeRet ;
2011-06-26 19:23:24 +02:00
double dPriority = 0 ;
// vouts to the payees
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CScript , int64_t ) & s , vecSend )
2013-04-25 00:27:00 +02:00
{
CTxOut txout ( s . second , s . first ) ;
2013-01-08 13:17:15 +01:00
if ( txout . IsDust ( CTransaction : : nMinRelayTxFee ) )
2013-04-25 23:31:22 +02:00
{
strFailReason = _ ( " Transaction amount too small " ) ;
2013-04-25 00:27:00 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2013-04-25 00:27:00 +02:00
wtxNew . vout . push_back ( txout ) ;
}
2011-06-26 19:23:24 +02:00
// Choose coins to use
set < pair < const CWalletTx * , unsigned int > > setCoins ;
2013-04-13 07:13:08 +02:00
int64_t nValueIn = 0 ;
2014-12-09 02:17:57 +01:00
if ( ! SelectCoins ( nTotalValue , setCoins , nValueIn , coinControl , coin_type ) )
2013-04-25 23:31:22 +02:00
{
2014-12-09 02:17:57 +01:00
if ( coin_type = = ALL_COINS )
strFailReason = _ ( " Insufficient funds " ) ;
else if ( coin_type = = ONLY_NONDENOMINATED )
strFailReason = _ ( " Unable to locate enough Darksend non-denominated funds for this transaction " ) ;
else
strFailReason = _ ( " Unable to locate enough Darksend denominated funds for this transaction " ) ;
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
2014-12-09 02:17:57 +01:00
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( PAIRTYPE ( const CWalletTx * , unsigned int ) pcoin , setCoins )
{
2013-04-13 07:13:08 +02:00
int64_t nCredit = pcoin . first - > vout [ pcoin . second ] . nValue ;
2012-12-26 18:45:42 +01:00
//The priority after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
dPriority + = ( double ) nCredit * ( pcoin . first - > GetDepthInMainChain ( ) + 1 ) ;
2011-06-26 19:23:24 +02:00
}
2013-04-13 07:13:08 +02:00
int64_t nChange = nValueIn - nValue - nFeeRet ;
2013-09-18 03:48:41 +02:00
// The following if statement should be removed once enough miners
// have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids
// creating free transactions that have change outputs less than
2014-12-12 12:44:25 +01:00
// CENT darkcoins.
2013-04-26 02:11:27 +02:00
if ( nFeeRet < CTransaction : : nMinTxFee & & nChange > 0 & & nChange < CENT )
2011-07-24 16:37:09 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nMoveToFee = min ( nChange , CTransaction : : nMinTxFee - nFeeRet ) ;
2011-07-24 16:37:09 +02:00
nChange - = nMoveToFee ;
nFeeRet + = nMoveToFee ;
}
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
2014-12-12 12:44:25 +01:00
// change transaction isn't always pay-to-darkcoin-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 ) )
scriptChange . SetDestination ( coinControl - > destChange ) ;
// 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
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
}
2011-06-26 19:23:24 +02:00
2013-04-25 00:27:00 +02:00
CTxOut newTxOut ( nChange , scriptChange ) ;
// Never create dust outputs; if we would, just
// add the dust to the fee.
2013-01-08 13:17:15 +01:00
if ( newTxOut . IsDust ( CTransaction : : nMinRelayTxFee ) )
2013-04-25 00:27:00 +02:00
{
nFeeRet + = nChange ;
reservekey . ReturnKey ( ) ;
}
else
{
// Insert change txn at random position:
vector < CTxOut > : : iterator position = wtxNew . vout . begin ( ) + GetRandInt ( wtxNew . vout . size ( ) + 1 ) ;
wtxNew . vout . insert ( position , newTxOut ) ;
}
2011-06-26 19:23:24 +02:00
}
else
reservekey . ReturnKey ( ) ;
// Fill vin
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
wtxNew . vin . push_back ( CTxIn ( coin . first - > GetHash ( ) , coin . second ) ) ;
// Sign
int nIn = 0 ;
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
if ( ! SignSignature ( * this , * coin . first , wtxNew , nIn + + ) )
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
}
2011-06-26 19:23:24 +02:00
// Limit size
2012-04-16 14:56:45 +02:00
unsigned int nBytes = : : GetSerializeSize ( * ( CTransaction * ) & wtxNew , SER_NETWORK , PROTOCOL_VERSION ) ;
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
}
2013-11-11 08:35:14 +01:00
dPriority = wtxNew . ComputePriority ( dPriority , nBytes ) ;
2011-06-26 19:23:24 +02:00
// Check that enough fee is included
2013-04-13 07:13:08 +02:00
int64_t nPayFee = nTransactionFee * ( 1 + ( int64_t ) nBytes / 1000 ) ;
2013-01-08 13:17:15 +01:00
bool fAllowFree = AllowFree ( dPriority ) ;
2013-08-12 16:59:09 +02:00
int64_t nMinFee = GetMinFee ( wtxNew , nBytes , fAllowFree , GMF_SEND ) ;
2011-06-26 19:23:24 +02:00
if ( nFeeRet < max ( nPayFee , nMinFee ) )
{
nFeeRet = max ( nPayFee , nMinFee ) ;
continue ;
}
wtxNew . fTimeReceivedIsTxTime = true ;
break ;
}
}
}
return true ;
}
2013-04-13 07:13:08 +02:00
bool CWallet : : CreateTransaction ( CScript scriptPubKey , int64_t nValue ,
2013-08-12 17:03:03 +02:00
CWalletTx & wtxNew , CReserveKey & reservekey , int64_t & nFeeRet , std : : string & strFailReason , const CCoinControl * coinControl )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
vector < pair < CScript , int64_t > > vecSend ;
2011-06-26 19:23:24 +02:00
vecSend . push_back ( make_pair ( scriptPubKey , nValue ) ) ;
2013-08-12 17:03:03 +02:00
return CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRet , strFailReason , coinControl ) ;
2011-06-26 19:23:24 +02:00
}
// Call after CreateTransaction unless you want to abort
2014-12-09 02:17:57 +01:00
bool CWallet : : CommitTransaction ( CWalletTx & wtxNew , CReserveKey & reservekey , std : : string strCommand )
2011-06-26 19:23:24 +02:00
{
{
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.
CWalletDB * pwalletdb = fFileBacked ? new CWalletDB ( strWalletFile , " r " ) : NULL ;
// 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.
AddToWallet ( wtxNew ) ;
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
// Broadcast
2013-06-13 22:28:03 +02:00
if ( ! wtxNew . AcceptToMemoryPool ( false ) )
2011-06-26 19:23:24 +02:00
{
// This must not fail. The transaction has already been signed and recorded.
2013-09-18 12:38:08 +02:00
LogPrintf ( " CommitTransaction() : Error: Transaction not valid " ) ;
2011-06-26 19:23:24 +02:00
return false ;
}
2014-12-09 02:17:57 +01:00
wtxNew . RelayWalletTransaction ( strCommand ) ;
2011-06-26 19:23:24 +02:00
}
return true ;
}
2014-12-09 02:17:57 +01:00
string CWallet : : SendMoney ( CScript scriptPubKey , int64_t nValue , CWalletTx & wtxNew , AvailableCoinsType coin_type )
2011-06-26 19:23:24 +02:00
{
CReserveKey reservekey ( this ) ;
2013-04-13 07:13:08 +02:00
int64_t nFeeRequired ;
2014-12-09 02:17:57 +01:00
CCoinControl * coinControl = NULL ;
2011-08-26 20:37:23 +02:00
if ( IsLocked ( ) )
2011-06-26 19:23:24 +02:00
{
2012-09-18 18:26:02 +02:00
string strError = _ ( " Error: Wallet locked, unable to create transaction! " ) ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " SendMoney() : %s \n " , strError . c_str ( ) ) ;
2011-08-26 20:37:23 +02:00
return strError ;
}
2014-12-09 02:17:57 +01:00
if ( fWalletUnlockAnonymizeOnly )
{
string strError = _ ( " Error: Wallet unlocked for anonymization only, unable to create transaction. " ) ;
LogPrintf ( " SendMoney() : %s \n " , strError . c_str ( ) ) ;
return strError ;
}
CWalletTx wtx ;
std : : vector < std : : pair < CScript , int64_t > > vecSend ;
vecSend . push_back ( make_pair ( scriptPubKey , nValue ) ) ;
string strError = " " ;
if ( ! CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRequired , strError , coinControl , coin_type ) )
2011-08-26 20:37:23 +02:00
{
if ( nValue + nFeeRequired > GetBalance ( ) )
2014-01-16 16:15:27 +01:00
strError = strprintf ( _ ( " Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds! " ) , FormatMoney ( nFeeRequired ) ) ;
LogPrintf ( " SendMoney() : %s \n " , strError ) ;
2011-08-26 20:37:23 +02:00
return strError ;
2011-06-26 19:23:24 +02:00
}
if ( ! CommitTransaction ( wtxNew , reservekey ) )
2012-09-18 18:26:02 +02:00
return _ ( " Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. " ) ;
2011-06-26 19:23:24 +02:00
return " " ;
}
2014-12-09 02:17:57 +01:00
string CWallet : : SendMoneyToDestination ( const CTxDestination & address , int64_t nValue , CWalletTx & wtxNew , AvailableCoinsType coin_type )
2011-06-26 19:23:24 +02:00
{
// Check amount
if ( nValue < = 0 )
return _ ( " Invalid amount " ) ;
if ( nValue + nTransactionFee > GetBalance ( ) )
return _ ( " Insufficient funds " ) ;
2014-12-12 12:44:25 +01:00
// Parse Darkcoin address
2011-06-26 19:23:24 +02:00
CScript scriptPubKey ;
2012-05-14 23:44:52 +02:00
scriptPubKey . SetDestination ( address ) ;
2011-06-26 19:23:24 +02:00
2014-12-09 02:17:57 +01:00
return SendMoney ( scriptPubKey , nValue , wtxNew , coin_type ) ;
}
int64_t CWallet : : GetTotalValue ( std : : vector < CTxIn > vCoins ) {
int64_t nTotalValue = 0 ;
CWalletTx wtx ;
BOOST_FOREACH ( CTxIn i , vCoins ) {
if ( mapWallet . count ( i . prevout . hash ) )
{
CWalletTx & wtx = mapWallet [ i . prevout . hash ] ;
if ( i . prevout . n < wtx . vout . size ( ) ) {
nTotalValue + = wtx . vout [ i . prevout . n ] . nValue ;
}
} else {
LogPrintf ( " GetTotalValue -- Couldn't find transaction \n " ) ;
}
}
return nTotalValue ;
2011-06-26 19:23:24 +02:00
}
2014-12-30 01:09:34 +01:00
string CWallet : : PrepareDarksendDenominate ( int minRounds , int maxRounds )
2014-12-09 02:17:57 +01:00
{
if ( IsLocked ( ) )
return _ ( " Error: Wallet locked, unable to create transaction! " ) ;
2014-12-30 01:09:34 +01:00
if ( darkSendPool . GetState ( ) ! = POOL_STATUS_ERROR & & darkSendPool . GetState ( ) ! = POOL_STATUS_SUCCESS )
if ( darkSendPool . GetMyTransactionCount ( ) > 0 )
2014-12-09 02:17:57 +01:00
return _ ( " Error: You already have pending entries in the Darksend pool " ) ;
// ** find the coins we'll use
std : : vector < CTxIn > vCoins ;
2015-01-20 16:59:37 +01:00
std : : vector < COutput > vCoins2 ;
2014-12-09 02:17:57 +01:00
int64_t nValueIn = 0 ;
CReserveKey reservekey ( this ) ;
2014-12-30 20:42:34 +01:00
/*
Select the coins we ' ll use
2015-01-15 15:41:56 +01:00
if minRounds > = 0 it means only denominated inputs are going in and coming out
2014-12-30 20:42:34 +01:00
*/
if ( minRounds > = 0 ) {
2015-01-20 16:59:37 +01:00
if ( ! SelectCoinsByDenominations ( darkSendPool . sessionDenom , 0.1 * COIN , DARKSEND_POOL_MAX , vCoins , vCoins2 , nValueIn , minRounds , maxRounds ) )
2014-12-30 20:42:34 +01:00
return _ ( " Insufficient funds " ) ;
}
2014-12-09 02:17:57 +01:00
// calculate total value out
int64_t nTotalValue = GetTotalValue ( vCoins ) ;
2014-12-30 01:09:34 +01:00
LogPrintf ( " PrepareDarksendDenominate - preparing darksend denominate . Got: %d \n " , nTotalValue ) ;
2014-12-09 02:17:57 +01:00
//--------------
BOOST_FOREACH ( CTxIn v , vCoins )
LockCoin ( v . prevout ) ;
// denominate our funds
int64_t nValueLeft = nTotalValue ;
std : : vector < CTxOut > vOut ;
2011-06-26 19:23:24 +02:00
2014-12-30 22:00:19 +01:00
// Make outputs by looping through denominations, from small to large
2014-12-30 20:42:34 +01:00
2015-01-20 16:59:37 +01:00
BOOST_FOREACH ( const COutput & out , vCoins2 ) {
2014-12-09 02:17:57 +01:00
CScript scriptChange ;
CPubKey vchPubKey ;
2015-01-20 16:59:37 +01:00
//use a unique change address
2014-12-09 02:17:57 +01:00
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
reservekey . KeepKey ( ) ;
2015-01-20 16:59:37 +01:00
CTxOut o ( out . tx - > vout [ out . i ] . nValue , scriptChange ) ;
2014-12-09 02:17:57 +01:00
vOut . push_back ( o ) ;
2015-01-20 16:59:37 +01:00
//increment outputs and subtract denomination amount
nValueLeft - = out . tx - > vout [ out . i ] . nValue ;
if ( nValueLeft = = 0 ) break ;
2014-12-09 02:17:57 +01:00
}
2015-01-20 16:59:37 +01:00
// if we have anything left over, send it back as change
if ( nValueLeft ! = 0 )
return " Error: change left-over in pool. Must use denominations only " ;
2014-12-09 02:17:57 +01:00
darkSendPool . SendDarksendDenominate ( vCoins , vOut , nValueIn ) ;
return " " ;
}
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
// the requires a new key.
}
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 17:33:07 +01:00
DBErrors CWallet : : ZapWalletTx ( )
{
if ( ! fFileBacked )
return DB_LOAD_OK ;
DBErrors nZapWalletTxRet = CWalletDB ( strWalletFile , " cr+ " ) . ZapWalletTx ( this ) ;
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
// the requires a new key.
}
}
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 ;
}
2013-08-29 16:19:43 +02:00
NotifyAddressBookChanged ( this , address , strName , : : IsMine ( * this , address ) ,
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
}
2013-08-29 16:19:43 +02:00
NotifyAddressBookChanged ( this , address , " " , : : IsMine ( * this , address ) , " " , 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
}
2014-12-09 02:17:57 +01:00
bool CWallet : : GetTransaction ( const uint256 & hashTx , CWalletTx & wtx )
{
{
LOCK ( cs_wallet ) ;
map < uint256 , CWalletTx > : : iterator mi = mapWallet . find ( hashTx ) ;
if ( mi ! = mapWallet . end ( ) )
{
wtx = ( * mi ) . second ;
return true ;
}
}
return false ;
}
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 ;
}
2011-11-17 20:01:25 +01:00
//
// Mark old keypool keys as used,
// and generate all new keys
//
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 ;
2014-12-02 09:48:47 +01:00
int64_t nKeys = max ( GetArg ( " -keypool " , 1000 ) , ( 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
2014-12-02 09:48:47 +01:00
nTargetSize = max ( GetArg ( " -keypool " , 1000 ) , ( 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 ( ) ) ) )
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
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 ( ) ) ;
2014-12-02 12:43:06 +01:00
double dProgress = nEnd / 10.f ;
std : : string strMsg = strprintf ( _ ( " Loading wallet... (%3.2f %%) " ) , dProgress ) ;
2014-12-02 09:48:47 +01:00
uiInterface . InitMessage ( strMsg ) ;
2011-06-26 19:23:24 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
return true ;
}
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 ) )
throw runtime_error ( " ReserveKeyFromKeyPool() : read failed " ) ;
2012-05-14 19:07:52 +02:00
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) )
2011-06-26 19:23:24 +02: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
int64_t CWallet : : AddReserveKey ( const CKeyPool & keypool )
2011-07-11 21:49:45 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-07-11 21:49:45 +02:00
CWalletDB walletdb ( strWalletFile ) ;
2013-04-13 07:13:08 +02:00
int64_t nIndex = 1 + * ( - - setKeyPool . end ( ) ) ;
2011-07-11 21:49:45 +02:00
if ( ! walletdb . WritePool ( nIndex , keypool ) )
throw runtime_error ( " AddReserveKey() : writing added key failed " ) ;
setKeyPool . insert ( nIndex ) ;
return nIndex ;
}
return - 1 ;
}
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 ;
}
2013-04-13 07:13:08 +02:00
std : : map < CTxDestination , int64_t > CWallet : : GetAddressBalances ( )
2012-08-01 18:48:42 +02:00
{
2013-04-13 07:13:08 +02:00
map < CTxDestination , int64_t > balances ;
2012-08-01 18:48:42 +02:00
{
LOCK ( cs_wallet ) ;
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
2014-02-13 01:23:06 +01:00
if ( ! IsFinalTx ( * pcoin ) | | ! pcoin - > IsTrusted ( ) )
2012-08-01 18:48:42 +02:00
continue ;
if ( pcoin - > IsCoinBase ( ) & & pcoin - > GetBlocksToMaturity ( ) > 0 )
continue ;
int nDepth = pcoin - > GetDepthInMainChain ( ) ;
if ( nDepth < ( pcoin - > IsFromMe ( ) ? 0 : 1 ) )
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-02-15 22:38:28 +01:00
int64_t 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 ;
}
2013-07-16 01:01:09 +02:00
set < CTxDestination > CWallet : : GetAccountAddresses ( string strAccount ) const
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
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 {
if ( pwallet - > vchDefaultKey . IsValid ( ) ) {
2013-09-18 12:38:08 +02:00
LogPrintf ( " CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool! " ) ;
2013-04-25 19:30:28 +02:00
vchPubKey = pwallet - > vchDefaultKey ;
} else
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 ) )
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 ) )
2011-07-11 21:49:45 +02: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
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 ) ;
}
}
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 ;
std : : map < uint256 , CBlockIndex * > : : 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
: : ExtractAffectedKeys ( * this , txout . scriptPubKey , vAffected ) ;
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 + + )
mapKeyBirth [ it - > first ] = it - > second - > nTime - 7200 ; // block times can be 2h off
}
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 ;
}