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-03-18 00:06:58 +01:00
// Copyright (c) 2014-2015 The Dash developers
2014-10-26 08:03:12 +01:00
// Distributed under the MIT software license, see the accompanying
2012-05-18 16:02:28 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2011-06-26 19:23:24 +02:00
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"
2015-07-10 00:08:26 +02:00
# include "masternode-budget.h"
2014-12-26 12:53:29 +01:00
# include "keepass.h"
2015-02-03 23:40:00 +01:00
# include "instantx.h"
2014-08-27 17:22:33 +02:00
# include "script/script.h"
# include "script/sign.h"
2015-04-03 00:51:08 +02:00
# include "spork.h"
2014-06-19 15:08:37 +02:00
# include "timedata.h"
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
# include "util.h"
# include "utilmoneystr.h"
2013-04-13 07:13:08 +02:00
2014-10-01 08:50:24 +02:00
# include <assert.h>
2013-04-13 07:13:08 +02:00
2012-11-03 15:58:41 +01:00
# include <boost/algorithm/string/replace.hpp>
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
# include <boost/thread.hpp>
2011-06-26 19:23:24 +02:00
2014-12-06 20:41:53 +01:00
2011-06-26 19:23:24 +02:00
using namespace std ;
2014-10-26 08:03:12 +01:00
/**
* Settings
*/
2014-04-10 20:14:18 +02:00
CFeeRate payTxFee ( DEFAULT_TRANSACTION_FEE ) ;
2014-12-16 10:43:40 +01:00
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE ;
2014-05-27 21:44:57 +02:00
unsigned int nTxConfirmTarget = 1 ;
2014-02-11 12:49:33 +01:00
bool bSpendZeroConfChange = true ;
2014-11-02 00:14:47 +01:00
bool fSendFreeTransactions = false ;
2014-11-02 00:47:39 +01:00
bool fPayAtLeastCustomFee = true ;
2011-06-26 19:23:24 +02:00
2014-10-26 08:03:12 +01:00
/**
2015-06-23 17:02:46 +02:00
* Fees smaller than this ( in duffs ) are considered zero fee ( for transaction creation )
* We are ~ 100 times smaller then bitcoin now ( 2015 - 06 - 23 ) , set minTxFee 10 times higher
* so it ' s still 10 times lower comparing to bitcoin .
2014-10-26 08:03:12 +01:00
* Override with - mintxfee
*/
2015-06-23 17:02:46 +02:00
CFeeRate CWallet : : minTxFee = CFeeRate ( 10000 ) ;
2011-06-26 19:23:24 +02:00
2014-10-26 08:03:12 +01:00
/** @defgroup mapWallet
*
* @ {
*/
2011-06-26 19:23:24 +02:00
2012-04-07 21:45:39 +02:00
struct CompareValueOnly
{
2014-04-23 00:46:19 +02:00
bool operator ( ) ( const pair < CAmount , pair < const CWalletTx * , unsigned int > > & t1 ,
const pair < CAmount , pair < const CWalletTx * , unsigned int > > & t2 ) const
2012-04-07 21:45:39 +02:00
{
return t1 . first < t2 . first ;
}
} ;
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
std : : string COutput : : ToString ( ) const
{
2014-09-08 12:25:52 +02:00
return strprintf ( " COutput(%s, %d, %d) [ % s ] " , tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue)) ;
Split up util.cpp/h
Split up util.cpp/h into:
- string utilities (hex, base32, base64): no internal dependencies, no dependency on boost (apart from foreach)
- money utilities (parsesmoney, formatmoney)
- time utilities (gettime*, sleep, format date):
- and the rest (logging, argument parsing, config file parsing)
The latter is basically the environment and OS handling,
and is stripped of all utility functions, so we may want to
rename it to something else than util.cpp/h for clarity (Matt suggested
osinterface).
Breaks dependency of sha256.cpp on all the things pulled in by util.
2014-08-21 16:11:09 +02:00
}
2014-02-15 22:38:28 +01:00
const CWalletTx * CWallet : : GetWalletTx ( const uint256 & hash ) const
{
LOCK ( cs_wallet ) ;
std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . find ( hash ) ;
if ( it = = mapWallet . end ( ) )
return NULL ;
return & ( it - > second ) ;
}
2012-05-14 19:07:52 +02:00
CPubKey CWallet : : GenerateNewKey ( )
2012-02-18 15:02:36 +01:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2012-03-22 03:56:31 +01:00
bool fCompressed = CanSupportFeature ( FEATURE_COMPRPUBKEY ) ; // default to compressed public keys if we want 0.6.0 wallets
2012-02-18 15:06:32 +01:00
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 ( ) ;
2014-11-06 10:17:48 +01:00
assert ( secret . VerifyPubKey ( pubkey ) ) ;
2013-06-20 01:13:55 +02:00
// Create new metadata
2013-04-13 07:13:08 +02:00
int64_t nCreationTime = GetTime ( ) ;
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ pubkey . GetID ( ) ] = CKeyMetadata ( nCreationTime ) ;
if ( ! nTimeFirstKey | | nCreationTime < nTimeFirstKey )
nTimeFirstKey = nCreationTime ;
2013-05-01 06:52:05 +02:00
if ( ! AddKeyPubKey ( secret , pubkey ) )
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 ;
2014-07-26 21:05:11 +02:00
// check if we need to remove from watch-only
CScript script ;
script = GetScriptForDestination ( pubkey . GetID ( ) ) ;
if ( HaveWatchOnly ( script ) )
RemoveWatchOnly ( script ) ;
2011-06-26 19:23:24 +02:00
if ( ! fFileBacked )
return true ;
2013-05-01 06:52:05 +02:00
if ( ! IsCrypted ( ) ) {
2013-06-10 15:36:29 +02:00
return CWalletDB ( strWalletFile ) . WriteKey ( pubkey ,
secret . GetPrivKey ( ) ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ pubkey . GetID ( ) ] ) ;
2013-05-01 06:52:05 +02:00
}
2011-07-13 13:43:50 +02:00
return true ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2013-06-10 15:36:29 +02:00
bool CWallet : : AddCryptedKey ( const CPubKey & vchPubKey ,
2013-06-20 01:13:55 +02:00
const vector < unsigned char > & vchCryptedSecret )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
if ( ! CCryptoKeyStore : : AddCryptedKey ( vchPubKey , vchCryptedSecret ) )
return false ;
if ( ! fFileBacked )
return true ;
2011-07-08 15:08:27 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-07-08 15:08:27 +02:00
if ( pwalletdbEncryption )
2013-06-10 15:36:29 +02:00
return pwalletdbEncryption - > WriteCryptedKey ( vchPubKey ,
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
else
2013-06-10 15:36:29 +02:00
return CWalletDB ( strWalletFile ) . WriteCryptedKey ( vchPubKey ,
vchCryptedSecret ,
2013-06-20 01:13:55 +02:00
mapKeyMetadata [ vchPubKey . GetID ( ) ] ) ;
2011-07-08 15:08:27 +02:00
}
2011-10-10 21:51:07 +02:00
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
2013-06-20 01:13:55 +02:00
bool CWallet : : LoadKeyMetadata ( const CPubKey & pubkey , const CKeyMetadata & meta )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2013-06-20 01:13:55 +02:00
if ( meta . nCreateTime & & ( ! nTimeFirstKey | | meta . nCreateTime < nTimeFirstKey ) )
nTimeFirstKey = meta . nCreateTime ;
mapKeyMetadata [ pubkey . GetID ( ) ] = meta ;
return true ;
}
2013-05-02 18:43:07 +02:00
bool CWallet : : LoadCryptedKey ( const CPubKey & vchPubKey , const std : : vector < unsigned char > & vchCryptedSecret )
{
return CCryptoKeyStore : : AddCryptedKey ( vchPubKey , vchCryptedSecret ) ;
}
2012-01-05 03:40:52 +01:00
bool CWallet : : AddCScript ( const CScript & redeemScript )
2011-10-03 19:05:43 +02:00
{
2012-01-05 03:40:52 +01:00
if ( ! CCryptoKeyStore : : AddCScript ( redeemScript ) )
2011-10-03 19:05:43 +02:00
return false ;
if ( ! fFileBacked )
return true ;
2012-01-05 03:40:52 +01:00
return CWalletDB ( strWalletFile ) . WriteCScript ( Hash160 ( redeemScript ) , redeemScript ) ;
2011-10-03 19:05:43 +02:00
}
2014-06-10 09:42:42 +02:00
bool CWallet : : LoadCScript ( const CScript & redeemScript )
{
/* A sanity check was added in pull #3843 to avoid adding redeemScripts
* that never can be redeemed . However , old wallets may still contain
* these . Do not add them to the wallet and warn . */
if ( redeemScript . size ( ) > MAX_SCRIPT_ELEMENT_SIZE )
{
2014-09-25 04:24:46 +02:00
std : : string strAddr = CBitcoinAddress ( CScriptID ( redeemScript ) ) . ToString ( ) ;
2014-06-10 09:42:42 +02:00
LogPrintf ( " %s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s. \n " ,
__func__ , redeemScript . size ( ) , MAX_SCRIPT_ELEMENT_SIZE , strAddr ) ;
return true ;
}
return CCryptoKeyStore : : AddCScript ( redeemScript ) ;
}
2014-06-09 21:11:59 +02:00
bool CWallet : : AddWatchOnly ( const CScript & dest )
2013-07-26 01:06:01 +02:00
{
if ( ! CCryptoKeyStore : : AddWatchOnly ( dest ) )
return false ;
nTimeFirstKey = 1 ; // No birthday information for watch-only keys.
2014-07-26 21:05:11 +02:00
NotifyWatchonlyChanged ( true ) ;
2013-07-26 01:06:01 +02:00
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . WriteWatchOnly ( dest ) ;
}
2014-07-26 21:05:11 +02:00
bool CWallet : : RemoveWatchOnly ( const CScript & dest )
{
AssertLockHeld ( cs_wallet ) ;
if ( ! CCryptoKeyStore : : RemoveWatchOnly ( dest ) )
return false ;
if ( ! HaveWatchOnly ( ) )
NotifyWatchonlyChanged ( false ) ;
if ( fFileBacked )
if ( ! CWalletDB ( strWalletFile ) . EraseWatchOnly ( dest ) )
return false ;
return true ;
}
2014-06-09 21:11:59 +02:00
bool CWallet : : LoadWatchOnly ( const CScript & dest )
2013-07-26 01:06:01 +02:00
{
return CCryptoKeyStore : : AddWatchOnly ( dest ) ;
}
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-10-26 08:03:12 +01:00
/**
* Outpoint is spent if any non - conflicted transaction
* spends it :
*/
2014-02-15 22:38:28 +01:00
bool CWallet : : IsSpent ( const uint256 & hash , unsigned int n ) const
2014-02-14 02:12:51 +01:00
{
2014-02-15 22:38:28 +01:00
const COutPoint outpoint ( hash , n ) ;
pair < TxSpends : : const_iterator , TxSpends : : const_iterator > range ;
range = mapTxSpends . equal_range ( outpoint ) ;
2014-02-14 02:12:51 +01:00
2014-02-15 22:38:28 +01:00
for ( TxSpends : : const_iterator it = range . first ; it ! = range . second ; + + it )
2014-02-14 02:12:51 +01:00
{
2014-02-15 22:38:28 +01:00
const uint256 & wtxid = it - > second ;
std : : map < uint256 , CWalletTx > : : const_iterator mit = mapWallet . find ( wtxid ) ;
if ( mit ! = mapWallet . end ( ) & & mit - > second . GetDepthInMainChain ( ) > = 0 )
return true ; // Spent
2014-02-14 02:12:51 +01:00
}
2014-02-15 22:38:28 +01:00
return false ;
}
void CWallet : : AddToSpends ( const COutPoint & outpoint , const uint256 & wtxid )
{
mapTxSpends . insert ( make_pair ( outpoint , wtxid ) ) ;
pair < TxSpends : : iterator , TxSpends : : iterator > range ;
range = mapTxSpends . equal_range ( outpoint ) ;
SyncMetaData ( range ) ;
}
void CWallet : : AddToSpends ( const uint256 & wtxid )
{
assert ( mapWallet . count ( wtxid ) ) ;
CWalletTx & thisTx = mapWallet [ wtxid ] ;
if ( thisTx . IsCoinBase ( ) ) // Coinbases don't spend anything!
return ;
BOOST_FOREACH ( const CTxIn & txin , thisTx . vin )
AddToSpends ( txin . prevout , wtxid ) ;
2014-02-14 02:12:51 +01:00
}
2011-11-26 07:02:04 +01:00
bool CWallet : : EncryptWallet ( const SecureString & strWalletPassphrase )
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
{
2011-08-26 20:37:23 +02:00
if ( IsCrypted ( ) )
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
CKeyingMaterial vMasterKey ;
RandAddSeedPerfmon ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
vMasterKey . resize ( WALLET_CRYPTO_KEY_SIZE ) ;
2014-11-07 13:42:52 +01:00
GetRandBytes ( & vMasterKey [ 0 ] , WALLET_CRYPTO_KEY_SIZE ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
CMasterKey kMasterKey ;
RandAddSeedPerfmon ( ) ;
2014-06-24 14:27:32 +02:00
2011-08-26 20:37:23 +02:00
kMasterKey . vchSalt . resize ( WALLET_CRYPTO_SALT_SIZE ) ;
2014-11-07 13:42:52 +01:00
GetRandBytes ( & kMasterKey . vchSalt [ 0 ] , WALLET_CRYPTO_SALT_SIZE ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
CCrypter crypter ;
2013-04-13 07:13:08 +02:00
int64_t nStartTime = GetTimeMillis ( ) ;
2011-08-26 20:37:23 +02:00
crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , 25000 , kMasterKey . nDerivationMethod ) ;
kMasterKey . nDeriveIterations = 2500000 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
nStartTime = GetTimeMillis ( ) ;
crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , kMasterKey . nDeriveIterations , kMasterKey . nDerivationMethod ) ;
kMasterKey . nDeriveIterations = ( kMasterKey . nDeriveIterations + kMasterKey . nDeriveIterations * 100 / ( ( double ) ( GetTimeMillis ( ) - nStartTime ) ) ) / 2 ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
if ( kMasterKey . nDeriveIterations < 25000 )
kMasterKey . nDeriveIterations = 25000 ;
2011-06-28 15:31:09 +02:00
2013-09-18 12:38:08 +02:00
LogPrintf ( " Encrypting Wallet with an nDeriveIterations of %i \n " , kMasterKey . nDeriveIterations ) ;
2011-06-28 15:31:09 +02:00
2011-08-26 20:37:23 +02:00
if ( ! crypter . SetKeyFromPassphrase ( strWalletPassphrase , kMasterKey . vchSalt , kMasterKey . nDeriveIterations , kMasterKey . nDerivationMethod ) )
return false ;
if ( ! crypter . Encrypt ( vMasterKey , kMasterKey . vchCryptedKey ) )
return false ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-08-26 20:37:23 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
mapMasterKeys [ + + nMasterKeyMaxID ] = kMasterKey ;
if ( fFileBacked )
{
2014-09-28 16:11:17 +02:00
assert ( ! pwalletdbEncryption ) ;
2011-07-08 15:08:27 +02:00
pwalletdbEncryption = new CWalletDB ( strWalletFile ) ;
2014-09-28 16:11:17 +02:00
if ( ! pwalletdbEncryption - > TxnBegin ( ) ) {
delete pwalletdbEncryption ;
pwalletdbEncryption = NULL ;
2012-05-14 07:11:11 +02:00
return false ;
2014-09-28 16:11:17 +02:00
}
2011-07-08 15:08:27 +02:00
pwalletdbEncryption - > WriteMasterKey ( nMasterKeyMaxID , kMasterKey ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
if ( ! EncryptKeys ( vMasterKey ) )
2011-07-08 15:08:27 +02:00
{
2014-09-28 16:11:17 +02:00
if ( fFileBacked ) {
2011-07-08 15:08:27 +02:00
pwalletdbEncryption - > TxnAbort ( ) ;
2014-09-28 16:11:17 +02:00
delete pwalletdbEncryption ;
}
// We now probably have half of our keys encrypted in memory, and half not...
// die and let the user reload their unencrypted wallet.
2014-10-01 08:50:24 +02:00
assert ( false ) ;
2011-07-08 15:08:27 +02:00
}
2012-02-18 14:55:02 +01:00
// Encryption was introduced in version 0.4.0
2012-03-22 03:56:31 +01:00
SetMinVersion ( FEATURE_WALLETCRYPT , pwalletdbEncryption , true ) ;
2012-02-18 14:55:02 +01:00
2011-07-08 15:08:27 +02:00
if ( fFileBacked )
{
2014-09-28 16:11:17 +02:00
if ( ! pwalletdbEncryption - > TxnCommit ( ) ) {
delete pwalletdbEncryption ;
2014-10-26 08:03:12 +01:00
// We now have keys encrypted in memory, but not on disk...
2014-09-28 16:11:17 +02:00
// die to avoid confusion and let the user reload their unencrypted wallet.
2014-10-01 08:50:24 +02:00
assert ( false ) ;
2014-09-28 16:11:17 +02:00
}
2011-07-08 15:08:27 +02:00
2012-02-18 15:36:40 +01:00
delete pwalletdbEncryption ;
2011-07-08 15:08:27 +02:00
pwalletdbEncryption = NULL ;
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
2011-11-17 20:01:25 +01:00
Lock ( ) ;
Unlock ( strWalletPassphrase ) ;
NewKeyPool ( ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
Lock ( ) ;
2011-08-26 20:37:23 +02:00
2011-11-11 03:12:46 +01:00
// Need to completely rewrite the wallet file; if we don't, bdb might keep
// bits of the unencrypted private key in slack space in the database file.
2011-11-20 16:39:01 +01:00
CDB : : Rewrite ( strWalletFile ) ;
2012-05-05 16:07:14 +02:00
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 ) )
{
2014-06-28 23:36:06 +02:00
int64_t latestNow = wtx . nTimeReceived ;
int64_t latestEntry = 0 ;
2012-05-28 20:45:12 +02:00
{
// Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future
2013-04-13 07:13:08 +02:00
int64_t latestTolerated = latestNow + 300 ;
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 ;
}
}
}
2014-06-28 23:36:06 +02:00
int64_t blocktime = mapBlockIndex [ wtxIn . hashBlock ] - > GetBlockTime ( ) ;
2012-05-28 20:45:12 +02:00
wtx . nTimeSmart = std : : max ( latestEntry , std : : min ( blocktime , latestNow ) ) ;
}
else
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 ;
}
2014-10-26 08:03:12 +01:00
/**
* Add a transaction to the wallet , or update it .
* pblock is optional , but should be provided if the transaction is known to be in a block .
* If fUpdate is true , existing transactions will be updated .
*/
2014-06-09 10:02:00 +02:00
bool CWallet : : AddToWalletIfInvolvingMe ( const CTransaction & tx , const CBlock * pblock , bool fUpdate )
2011-06-26 19:23:24 +02:00
{
{
2014-03-09 12:41:22 +01:00
AssertLockHeld ( cs_wallet ) ;
2014-09-06 21:59:59 +02:00
bool fExisted = mapWallet . count ( tx . GetHash ( ) ) ! = 0 ;
2011-08-26 20:37:23 +02:00
if ( fExisted & & ! fUpdate ) return false ;
if ( fExisted | | IsMine ( tx ) | | IsFromMe ( tx ) )
{
CWalletTx wtx ( this , tx ) ;
// Get merkle branch if transaction was found in a block
if ( pblock )
2014-08-29 20:24:16 +02:00
wtx . SetMerkleBranch ( * pblock ) ;
2011-08-26 20:37:23 +02:00
return AddToWallet ( wtx ) ;
}
2011-06-26 19:23:24 +02:00
}
return false ;
}
2014-06-09 10:02:00 +02:00
void CWallet : : SyncTransaction ( const CTransaction & tx , const CBlock * pblock )
2014-02-15 22:38:28 +01:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-06-09 10:02:00 +02:00
if ( ! AddToWalletIfInvolvingMe ( tx , pblock , true ) )
2014-02-15 22:38:28 +01:00
return ; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
// available of the outputs it spends. So force those to be
// recomputed, also:
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
if ( mapWallet . count ( txin . prevout . hash ) )
mapWallet [ txin . prevout . hash ] . MarkDirty ( ) ;
}
2013-10-19 18:34:06 +02:00
}
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
}
2013-07-26 01:06:01 +02:00
isminetype CWallet : : IsMine ( const CTxIn & txin ) const
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-06-26 19:23:24 +02:00
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
if ( txin . prevout . n < prev . vout . size ( ) )
2013-07-26 01:06:01 +02:00
return IsMine ( prev . vout [ txin . prevout . n ] ) ;
2011-06-26 19:23:24 +02:00
}
}
2014-07-01 11:00:22 +02:00
return ISMINE_NO ;
2011-06-26 19:23:24 +02:00
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetDebit ( const CTxIn & txin , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-06-26 19:23:24 +02:00
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
if ( txin . prevout . n < prev . vout . size ( ) )
2014-04-08 15:23:50 +02:00
if ( IsMine ( prev . vout [ txin . prevout . n ] ) & filter )
2011-06-26 19:23:24 +02:00
return prev . vout [ txin . prevout . n ] . nValue ;
}
}
return 0 ;
}
2015-07-26 01:24:19 +02:00
// Recursively determine the rounds of a given input (How deep is the Darksend chain for a given input)
int CWallet : : GetRealInputDarksendRounds ( CTxIn in , int rounds ) const
{
static std : : map < uint256 , CMutableTransaction > mDenomWtxes ;
if ( rounds > = 16 ) return 15 ; // 16 rounds max
uint256 hash = in . prevout . hash ;
unsigned int nout = in . prevout . n ;
const CWalletTx * wtx = GetWalletTx ( hash ) ;
if ( wtx ! = NULL )
{
std : : map < uint256 , CMutableTransaction > : : const_iterator mdwi = mDenomWtxes . find ( hash ) ;
// not known yet, let's add it
if ( mdwi = = mDenomWtxes . end ( ) )
{
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds INSERTING %s \n " , hash . ToString ( ) ) ;
2015-07-26 01:24:19 +02:00
mDenomWtxes [ hash ] = CMutableTransaction ( * wtx ) ;
}
// found and it's not an initial value, just return it
else if ( mDenomWtxes [ hash ] . vout [ nout ] . nRounds ! = - 10 )
{
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
// bounds check
if ( nout > = wtx - > vout . size ( ) )
{
// should never actually hit this
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , - 4 ) ;
2015-07-26 01:24:19 +02:00
return - 4 ;
}
if ( pwalletMain - > IsCollateralAmount ( wtx - > vout [ nout ] . nValue ) )
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 3 ;
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
//make sure the final output is non-denominate
if ( /*rounds == 0 && */ ! IsDenominatedAmount ( wtx - > vout [ nout ] . nValue ) ) //NOT DENOM
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 2 ;
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
bool fAllDenoms = true ;
BOOST_FOREACH ( CTxOut out , wtx - > vout )
{
fAllDenoms = fAllDenoms & & IsDenominatedAmount ( out . nValue ) ;
}
// this one is denominated but there is another non-denominated output found in the same tx
if ( ! fAllDenoms )
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = 0 ;
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
int nShortest = - 10 ; // an initial value, should be no way to get this by calculations
bool fDenomFound = false ;
// only denoms here so let's look up
BOOST_FOREACH ( CTxIn in2 , wtx - > vin )
{
if ( IsMine ( in2 ) )
{
int n = GetRealInputDarksendRounds ( in2 , rounds + 1 ) ;
// denom found, find the shortest chain or initially assign nShortest with the first found value
if ( n > = 0 & & ( n < nShortest | | nShortest = = - 10 ) )
{
nShortest = n ;
fDenomFound = true ;
}
}
}
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = fDenomFound
? ( nShortest > = 15 ? 16 : nShortest + 1 ) // good, we a +1 to the shortest one but only 16 rounds max allowed
: 0 ; // too bad, we are the fist one in that chain
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-07-26 01:24:19 +02:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
return rounds - 1 ;
}
// respect current settings
int CWallet : : GetInputDarksendRounds ( CTxIn in ) const {
2015-07-29 17:06:45 +02:00
LOCK ( cs_wallet ) ;
2015-07-26 01:24:19 +02:00
int realDarksendRounds = GetRealInputDarksendRounds ( in , 0 ) ;
return realDarksendRounds > nDarksendRounds ? nDarksendRounds : realDarksendRounds ;
}
2015-01-29 11:36:18 +01:00
bool CWallet : : IsDenominated ( const CTxIn & txin ) const
2014-12-09 02:17:57 +01:00
{
{
LOCK ( cs_wallet ) ;
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( txin . prevout . hash ) ;
if ( mi ! = mapWallet . end ( ) )
{
const CWalletTx & prev = ( * mi ) . second ;
2015-01-29 11:36:18 +01:00
if ( txin . prevout . n < prev . vout . size ( ) ) return IsDenominatedAmount ( prev . vout [ txin . prevout . n ] . nValue ) ;
2014-12-09 02:17:57 +01:00
}
}
2015-01-29 11:36:18 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
2015-07-26 01:24:19 +02:00
bool CWallet : : IsDenominated ( const CTransaction & tx ) const
{
/*
Return false if ANY inputs are non - denom
*/
bool ret = true ;
BOOST_FOREACH ( const CTxIn & txin , tx . vin )
{
if ( ! IsDenominated ( txin ) ) {
ret = false ;
}
}
return ret ;
}
2015-01-28 08:35:17 +01:00
bool CWallet : : IsDenominatedAmount ( int64_t nInputAmount ) const
{
BOOST_FOREACH ( int64_t d , darkSendDenominations )
if ( nInputAmount = = d )
return true ;
return false ;
}
2011-10-03 19:05:43 +02:00
bool CWallet : : IsChange ( const CTxOut & txout ) const
{
2011-11-08 19:20:29 +01:00
// TODO: fix handling of 'change' outputs. The assumption is that any
2014-06-09 21:11:59 +02:00
// payment to a script that is ours, but is not in the address book
2011-11-08 19:20:29 +01:00
// is change. That assumption is likely to break when we implement multisignature
// wallets that return change back into a multi-signature-protected address;
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
2014-06-09 21:11:59 +02:00
if ( : : IsMine ( * this , txout . scriptPubKey ) )
2012-04-06 18:39:12 +02:00
{
2014-06-09 21:11:59 +02:00
CTxDestination address ;
if ( ! ExtractDestination ( txout . scriptPubKey , address ) )
return true ;
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
if ( ! mapAddressBook . count ( address ) )
return true ;
}
2011-10-03 19:05:43 +02:00
return false ;
}
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 ;
}
2014-05-30 00:54:00 +02:00
void CWalletTx : : GetAmounts ( list < COutputEntry > & listReceived ,
2014-04-23 00:46:19 +02:00
list < COutputEntry > & listSent , CAmount & nFee , string & strSentAccount , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
2012-06-02 04:33:28 +02:00
nFee = 0 ;
2011-06-26 19:23:24 +02:00
listReceived . clear ( ) ;
listSent . clear ( ) ;
strSentAccount = strFromAccount ;
// Compute fee:
2014-04-23 00:46:19 +02:00
CAmount nDebit = GetDebit ( filter ) ;
2011-06-26 19:23:24 +02:00
if ( nDebit > 0 ) // debit>0 means we signed/sent this transaction
{
2014-04-23 00:46:19 +02:00
CAmount nValueOut = GetValueOut ( ) ;
2011-06-26 19:23:24 +02:00
nFee = nDebit - nValueOut ;
}
2011-10-03 19:05:43 +02:00
// Sent/received.
2014-07-18 13:24:38 +02:00
for ( unsigned int i = 0 ; i < vout . size ( ) ; + + i )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
const CTxOut & txout = vout [ i ] ;
2014-04-29 19:39:01 +02:00
isminetype fIsMine = pwallet - > IsMine ( txout ) ;
2012-09-22 05:20:14 +02:00
// Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent)
// 2) the output is to us (received)
if ( nDebit > 0 )
{
// Don't report 'change' txouts
if ( pwallet - > IsChange ( txout ) )
continue ;
}
2014-04-29 19:39:01 +02:00
else if ( ! ( fIsMine & filter ) )
2012-09-22 05:20:14 +02:00
continue ;
// In either case, we need to get the destination address
2012-05-14 23:44:52 +02:00
CTxDestination address ;
if ( ! ExtractDestination ( txout . scriptPubKey , address ) )
2011-06-26 19:23:24 +02:00
{
2013-09-18 12:38:08 +02:00
LogPrintf ( " CWalletTx::GetAmounts: Unknown transaction type found, txid %s \n " ,
2014-01-16 16:15:27 +01:00
this - > GetHash ( ) . ToString ( ) ) ;
2012-09-22 05:20:14 +02:00
address = CNoDestination ( ) ;
2011-06-26 19:23:24 +02:00
}
2014-07-18 13:24:38 +02:00
COutputEntry output = { address , txout . nValue , ( int ) i } ;
2014-05-30 00:54:00 +02:00
2012-09-22 05:20:14 +02:00
// If we are debited by the transaction, add the output as a "sent" entry
2011-06-26 19:23:24 +02:00
if ( nDebit > 0 )
2014-05-30 00:54:00 +02:00
listSent . push_back ( output ) ;
2011-06-26 19:23:24 +02:00
2012-09-22 05:20:14 +02:00
// If we are receiving the output, add it as a "received" entry
2014-07-12 17:15:17 +02:00
if ( fIsMine & filter )
2014-05-30 00:54:00 +02:00
listReceived . push_back ( output ) ;
2011-06-26 19:23:24 +02:00
}
}
2014-04-23 00:46:19 +02:00
void CWalletTx : : GetAccountAmounts ( const string & strAccount , CAmount & nReceived ,
CAmount & nSent , CAmount & nFee , const isminefilter & filter ) const
2011-06-26 19:23:24 +02:00
{
2012-06-02 04:33:28 +02:00
nReceived = nSent = nFee = 0 ;
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
CAmount allFee ;
2011-06-26 19:23:24 +02:00
string strSentAccount ;
2014-05-30 00:54:00 +02:00
list < COutputEntry > listReceived ;
list < COutputEntry > listSent ;
2014-04-08 15:23:50 +02:00
GetAmounts ( listReceived , listSent , allFee , strSentAccount , filter ) ;
2011-06-26 19:23:24 +02:00
if ( strAccount = = strSentAccount )
{
2014-05-30 00:54:00 +02:00
BOOST_FOREACH ( const COutputEntry & s , listSent )
nSent + = s . amount ;
2011-06-26 19:23:24 +02:00
nFee = allFee ;
}
{
2012-04-06 18:39:12 +02:00
LOCK ( pwallet - > cs_wallet ) ;
2014-05-30 00:54:00 +02:00
BOOST_FOREACH ( const COutputEntry & r , listReceived )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
if ( pwallet - > mapAddressBook . count ( r . destination ) )
2011-06-26 19:23:24 +02:00
{
2014-05-30 00:54:00 +02:00
map < CTxDestination , CAddressBookData > : : const_iterator mi = pwallet - > mapAddressBook . find ( r . destination ) ;
2013-07-15 07:20:50 +02:00
if ( mi ! = pwallet - > mapAddressBook . end ( ) & & ( * mi ) . second . name = = strAccount )
2014-05-30 00:54:00 +02:00
nReceived + = r . amount ;
2011-06-26 19:23:24 +02:00
}
else if ( strAccount . empty ( ) )
{
2014-05-30 00:54:00 +02:00
nReceived + = r . amount ;
2011-06-26 19:23:24 +02:00
}
}
}
}
2013-10-19 18:42:14 +02:00
2011-06-26 19:23:24 +02:00
bool CWalletTx : : WriteToDisk ( )
{
return CWalletDB ( pwallet - > strWalletFile ) . WriteTx ( GetHash ( ) , * this ) ;
}
2014-10-26 08:03:12 +01:00
/**
* Scan the block chain ( starting in pindexStart ) for transactions
* from or to us . If fUpdate is true , found transactions that already
* exist in the wallet will be updated .
*/
2011-06-26 19:23:24 +02:00
int CWallet : : ScanForWalletTransactions ( CBlockIndex * pindexStart , bool fUpdate )
{
int ret = 0 ;
2014-02-18 01:35:37 +01:00
int64_t nNow = GetTime ( ) ;
2011-06-26 19:23:24 +02:00
CBlockIndex * pindex = pindexStart ;
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-19 00:26:14 +01:00
// no need to read and scan block, if block was created before
// our wallet birthday (as adjusted for block time variability)
2014-06-28 23:36:06 +02:00
while ( pindex & & nTimeFirstKey & & ( pindex - > GetBlockTime ( ) < ( nTimeFirstKey - 7200 ) ) )
2014-03-19 00:26:14 +01:00
pindex = chainActive . Next ( pindex ) ;
ShowProgress ( _ ( " Rescanning... " ) , 0 ) ; // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
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 )
{
2014-06-09 10:02:00 +02:00
if ( AddToWalletIfInvolvingMe ( tx , & block , fUpdate ) )
2011-06-26 19:23:24 +02:00
ret + + ;
}
2013-10-10 23:07:44 +02:00
pindex = chainActive . Next ( pindex ) ;
2014-02-18 01:35:37 +01:00
if ( GetTime ( ) > = nNow + 60 ) {
nNow = GetTime ( ) ;
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
2015-07-10 00:08:26 +02:00
if ( strCommand = = " ix " ) {
2015-04-03 00:51:08 +02:00
mapTxLockReq . insert ( make_pair ( hash , ( CTransaction ) * this ) ) ;
2015-02-04 22:59:19 +01:00
CreateNewLock ( ( ( CTransaction ) * this ) ) ;
2015-04-03 00:51:08 +02:00
RelayTransactionLockReq ( ( CTransaction ) * this , true ) ;
2014-12-09 02:17:57 +01:00
} else {
2015-04-03 00:51:08 +02:00
RelayTransaction ( ( CTransaction ) * this ) ;
2014-12-09 02:17:57 +01:00
}
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
}
}
}
2014-10-26 08:03:12 +01:00
/** @} */ // end of mapWallet
2011-06-26 19:23:24 +02:00
2014-10-26 08:03:12 +01:00
/** @defgroup Actions
*
* @ {
*/
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetBalance ( ) const
2011-06-26 19:23:24 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2011-06-26 19:23:24 +02:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2014-02-13 01:23:06 +01:00
if ( pcoin - > IsTrusted ( ) )
2012-02-14 12:08:00 +01:00
nTotal + = pcoin - > GetAvailableCredit ( ) ;
2011-06-26 19:23:24 +02:00
}
}
return nTotal ;
}
2015-07-26 01:24:19 +02:00
CAmount CWallet : : GetAnonymizableBalance ( ) const
2015-04-30 00:06:24 +02:00
{
if ( fLiteMode ) return 0 ;
CAmount nTotal = 0 ;
{
LOCK2 ( cs_main , cs_wallet ) ;
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) )
2015-07-26 01:24:19 +02:00
nTotal + = pcoin - > GetAnonymizableCredit ( ) ;
2015-04-30 00:06:24 +02:00
}
}
return nTotal ;
}
2015-04-03 00:51:08 +02:00
CAmount CWallet : : GetAnonymizedBalance ( ) const
2014-12-09 02:17:57 +01:00
{
2015-03-15 19:19:25 +01:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2014-12-09 02:17:57 +01:00
{
2015-02-12 14:26:32 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-09 02:17:57 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-02-06 02:53:28 +01:00
if ( pcoin - > IsTrusted ( ) )
2015-07-26 01:24:19 +02:00
nTotal + = pcoin - > GetAnonymizedCredit ( ) ;
2014-12-09 02:17:57 +01:00
}
}
return nTotal ;
}
2015-07-07 09:21:13 +02:00
// Note: calculated including unconfirmed,
// that's ok as long as we use it for informational purposes only
2014-12-09 02:17:57 +01:00
double CWallet : : GetAverageAnonymizedRounds ( ) const
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2014-12-09 02:17:57 +01:00
double fTotal = 0 ;
double fCount = 0 ;
{
2015-02-12 14:26:32 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-09 02:17:57 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-01-02 23:20:30 +01:00
2015-07-07 09:21:13 +02:00
uint256 hash = ( * it ) . first ;
2014-12-09 02:17:57 +01:00
2015-07-07 09:21:13 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
2014-12-09 02:17:57 +01:00
2015-07-07 09:21:13 +02:00
CTxIn vin = CTxIn ( hash , i ) ;
2015-02-06 02:53:28 +01:00
2015-07-26 01:24:19 +02:00
if ( IsSpent ( hash , i ) | | IsMine ( pcoin - > vout [ i ] ) ! = ISMINE_SPENDABLE | | ! IsDenominated ( vin ) ) continue ;
2014-12-09 02:17:57 +01:00
2015-07-07 09:21:13 +02:00
int rounds = GetInputDarksendRounds ( vin ) ;
fTotal + = ( float ) rounds ;
fCount + = 1 ;
2014-12-09 02:17:57 +01:00
}
}
}
if ( fCount = = 0 ) return 0 ;
return fTotal / fCount ;
}
2015-07-07 09:21:13 +02:00
// Note: calculated including unconfirmed,
// that's ok as long as we use it for informational purposes only
2015-04-03 00:51:08 +02:00
CAmount CWallet : : GetNormalizedAnonymizedBalance ( ) const
2015-01-28 08:35:17 +01:00
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2015-01-28 08:35:17 +01:00
{
2015-02-12 14:26:32 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2015-01-28 08:35:17 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-07-07 09:21:13 +02:00
uint256 hash = ( * it ) . first ;
2015-02-06 02:53:28 +01:00
2015-07-07 09:21:13 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
2015-01-28 08:35:17 +01:00
2015-07-07 09:21:13 +02:00
CTxIn vin = CTxIn ( hash , i ) ;
2015-02-06 02:53:28 +01:00
2015-07-26 01:24:19 +02:00
if ( IsSpent ( hash , i ) | | IsMine ( pcoin - > vout [ i ] ) ! = ISMINE_SPENDABLE | | ! IsDenominated ( vin ) ) continue ;
if ( pcoin - > GetDepthInMainChain ( ) < 0 ) continue ;
2015-01-28 08:35:17 +01:00
2015-07-07 09:21:13 +02:00
int rounds = GetInputDarksendRounds ( vin ) ;
nTotal + = pcoin - > vout [ i ] . nValue * rounds / nDarksendRounds ;
2015-01-28 08:35:17 +01:00
}
}
}
return nTotal ;
}
2015-07-26 01:24:19 +02:00
CAmount CWallet : : GetDenominatedBalance ( bool unconfirmed ) const
2014-12-09 02:17:57 +01:00
{
2015-07-26 01:24:19 +02:00
if ( fLiteMode ) return 0 ;
2015-04-03 00:51:08 +02:00
CAmount nTotal = 0 ;
2014-12-09 02:17:57 +01:00
{
2015-02-12 14:26:32 +01:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-12-09 02:17:57 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
2015-07-26 01:24:19 +02:00
nTotal + = pcoin - > GetDenominatedCredit ( unconfirmed ) ;
2014-12-09 02:17:57 +01:00
}
}
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetUnconfirmedBalance ( ) const
2011-07-11 20:42:10 +02:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2011-07-11 20:42:10 +02:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-07-11 20:42:10 +02:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
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 ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetImmatureBalance ( ) const
2012-02-14 12:08:00 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2012-02-14 12:08:00 +01:00
{
2014-04-15 17:38:25 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2012-02-14 12:08:00 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
2012-06-18 08:32:33 +02:00
const CWalletTx * pcoin = & ( * it ) . second ;
nTotal + = pcoin - > GetImmatureCredit ( ) ;
2011-07-11 20:42:10 +02:00
}
}
return nTotal ;
}
2011-06-26 19:23:24 +02:00
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetWatchOnlyBalance ( ) const
2014-03-29 05:15:28 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2014-03-29 05:15:28 +01:00
{
2014-07-13 09:33:45 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( pcoin - > IsTrusted ( ) )
nTotal + = pcoin - > GetAvailableWatchOnlyCredit ( ) ;
}
}
2014-09-28 16:11:17 +02:00
2014-03-29 05:15:28 +01:00
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetUnconfirmedWatchOnlyBalance ( ) const
2014-03-29 05:15:28 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2014-03-29 05:15:28 +01:00
{
2014-07-13 09:33:45 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
if ( ! IsFinalTx ( * pcoin ) | | ( ! pcoin - > IsTrusted ( ) & & pcoin - > GetDepthInMainChain ( ) = = 0 ) )
nTotal + = pcoin - > GetAvailableWatchOnlyCredit ( ) ;
}
}
return nTotal ;
}
2014-04-23 00:46:19 +02:00
CAmount CWallet : : GetImmatureWatchOnlyBalance ( ) const
2014-03-29 05:15:28 +01:00
{
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2014-03-29 05:15:28 +01:00
{
2014-07-13 09:33:45 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2014-03-29 05:15:28 +01:00
for ( map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; + + it )
{
const CWalletTx * pcoin = & ( * it ) . second ;
nTotal + = pcoin - > GetImmatureWatchOnlyCredit ( ) ;
}
}
return nTotal ;
}
2014-10-26 08:03:12 +01:00
/**
* populate vCoins with vector of available COutputs .
*/
2015-02-03 21:25:00 +01:00
void CWallet : : AvailableCoins ( vector < COutput > & vCoins , bool fOnlyConfirmed , const CCoinControl * coinControl , AvailableCoinsType coin_type , bool useIX ) 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 ;
2015-02-01 18:11:49 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( false ) ;
2015-02-04 09:51:38 +01:00
// do not use IX for inputs that have less then 6 blockchain confirmations
if ( useIX & & nDepth < 6 )
2014-02-12 19:43:07 +01:00
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 ) {
2015-01-29 11:36:18 +01:00
found = IsDenominatedAmount ( pcoin - > vout [ i ] . nValue ) ;
2015-08-16 02:26:20 +02:00
} else if ( coin_type = = ONLY_NOT1000IFMN ) {
found = ! ( fMasterNode & & pcoin - > vout [ i ] . nValue = = 1000 * COIN ) ;
} else if ( coin_type = = ONLY_NONDENOMINATED_NOT1000IFMN ) {
2015-01-27 05:13:34 +01:00
if ( IsCollateralAmount ( pcoin - > vout [ i ] . nValue ) ) continue ; // do not use collateral amounts
2015-01-29 11:36:18 +01:00
found = ! IsDenominatedAmount ( pcoin - > vout [ i ] . nValue ) ;
2015-08-16 02:26:20 +02:00
if ( found & & fMasterNode ) found = pcoin - > vout [ i ] . nValue ! = 1000 * COIN ; // do not use Hot MN funds
2014-12-09 02:17:57 +01:00
} else {
found = true ;
}
if ( ! found ) continue ;
2013-07-26 01:06:01 +02:00
isminetype mine = IsMine ( pcoin - > vout [ i ] ) ;
2014-07-01 11:00:22 +02:00
if ( ! ( IsSpent ( wtxid , i ) ) & & mine ! = ISMINE_NO & &
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-09-06 21:59:59 +02:00
vCoins . push_back ( COutput ( pcoin , i , nDepth , ( mine & ISMINE_SPENDABLE ) ! = ISMINE_NO ) ) ;
2012-09-27 19:52:09 +02:00
}
2012-02-27 13:19:32 +01:00
}
}
}
2014-04-23 00:46:19 +02:00
static void ApproximateBestSubset ( vector < pair < CAmount , pair < const CWalletTx * , unsigned int > > > vValue , const CAmount & nTotalLower , const CAmount & nTargetValue ,
vector < char > & vfBest , CAmount & nBest , int iterations = 1000 )
2012-04-13 01:22:15 +02:00
{
vector < char > vfIncluded ;
vfBest . assign ( vValue . size ( ) , true ) ;
nBest = nTotalLower ;
2013-02-16 00:27:57 +01:00
seed_insecure_rand ( ) ;
2012-04-13 01:22:15 +02:00
for ( int nRep = 0 ; nRep < iterations & & nBest ! = nTargetValue ; nRep + + )
{
vfIncluded . assign ( vValue . size ( ) , false ) ;
2014-04-23 00:46:19 +02:00
CAmount nTotal = 0 ;
2012-04-13 01:22:15 +02:00
bool fReachedTarget = false ;
for ( int nPass = 0 ; nPass < 2 & & ! fReachedTarget ; nPass + + )
{
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
{
2013-02-16 00:27:57 +01:00
//The solver here uses a randomized algorithm,
//the randomness serves no real security purpose but is just
//needed to prevent degenerate behavior and it is important
2014-10-26 08:03:12 +01:00
//that the rng is fast. We do not use a constant random sequence,
2013-02-16 00:27:57 +01:00
//because there may be some privacy improvement by making
//the selection random.
if ( nPass = = 0 ? insecure_rand ( ) & 1 : ! vfIncluded [ i ] )
2012-04-13 01:22:15 +02:00
{
nTotal + = vValue [ i ] . first ;
vfIncluded [ i ] = true ;
if ( nTotal > = nTargetValue )
{
fReachedTarget = true ;
if ( nTotal < nBest )
{
nBest = nTotal ;
vfBest = vfIncluded ;
}
nTotal - = vValue [ i ] . first ;
vfIncluded [ i ] = false ;
}
}
}
}
}
}
2014-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 ) ;
}
2014-04-23 00:46:19 +02:00
bool CWallet : : SelectCoinsMinConf ( const CAmount & nTargetValue , int nConfMine , int nConfTheirs , vector < COutput > vCoins ,
set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet ) const
2011-06-26 19:23:24 +02:00
{
setCoinsRet . clear ( ) ;
nValueRet = 0 ;
// List of values less than target
2014-04-23 00:46:19 +02:00
pair < CAmount , pair < const CWalletTx * , unsigned int > > coinLowestLarger ;
coinLowestLarger . first = std : : numeric_limits < CAmount > : : max ( ) ;
2011-06-26 19:23:24 +02:00
coinLowestLarger . second . first = NULL ;
2014-04-23 00:46:19 +02:00
vector < pair < CAmount , pair < const CWalletTx * , unsigned int > > > vValue ;
CAmount nTotalLower = 0 ;
2011-06-26 19:23:24 +02:00
2012-04-07 19:52:40 +02:00
random_shuffle ( vCoins . begin ( ) , vCoins . end ( ) , GetRandInt ) ;
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 ) ;
2015-02-03 22:00:54 +01:00
vValue . clear ( ) ;
2014-12-23 04:06:47 +01:00
nTotalLower = 0 ;
2015-04-03 00:51:08 +02:00
BOOST_FOREACH ( const COutput & output , vCoins )
2014-12-23 04:06:47 +01:00
{
2015-04-03 00:51:08 +02:00
if ( ! output . fSpendable )
continue ;
2013-07-26 01:06:01 +02:00
2014-12-23 04:06:47 +01:00
const CWalletTx * pcoin = output . tx ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
// if (fDebug) LogPrint("selectcoins", "value %s confirms %d\n", FormatMoney(pcoin->vout[output.i].nValue), output.nDepth);
2015-04-03 00:51:08 +02:00
if ( output . nDepth < ( pcoin - > IsFromMe ( ISMINE_ALL ) ? nConfMine : nConfTheirs ) )
2014-12-23 04:06:47 +01:00
continue ;
2011-06-26 19:23:24 +02:00
2014-12-23 04:06:47 +01:00
int i = output . i ;
2015-04-03 00:51:08 +02:00
CAmount n = pcoin - > vout [ i ] . nValue ;
2015-01-29 11:36:18 +01:00
if ( tryDenom = = 0 & & IsDenominatedAmount ( n ) ) continue ; // we don't want denom values on first run
2014-12-23 04:06:47 +01:00
2015-04-03 00:51:08 +02:00
pair < CAmount , pair < const CWalletTx * , unsigned int > > coin = make_pair ( n , make_pair ( pcoin , i ) ) ;
2014-12-23 04:06:47 +01:00
if ( n = = nTargetValue )
{
setCoinsRet . insert ( coin . second ) ;
nValueRet + = coin . first ;
return true ;
}
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 ;
2014-04-23 00:46:19 +02:00
CAmount 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 {
2015-02-07 06:19:02 +01:00
string s = " CWallet::SelectCoinsMinConf best subset: " ;
2012-04-15 22:52:09 +02:00
for ( unsigned int i = 0 ; i < vValue . size ( ) ; i + + )
2015-02-06 06:38:29 +01:00
{
2011-06-26 19:23:24 +02:00
if ( vfBest [ i ] )
{
setCoinsRet . insert ( vValue [ i ] . second ) ;
nValueRet + = vValue [ i ] . first ;
2015-06-23 22:44:20 +02:00
s + = FormatMoney ( vValue [ i ] . first ) + " " ;
2011-06-26 19:23:24 +02:00
}
2015-02-06 06:38:29 +01:00
}
LogPrintf ( " %s - total %s \n " , s , FormatMoney ( nBest ) ) ;
2011-06-26 19:23:24 +02:00
}
return true ;
}
2015-04-03 00:51:08 +02:00
bool CWallet : : SelectCoins ( const CAmount & nTargetValue , set < pair < const CWalletTx * , unsigned int > > & setCoinsRet , CAmount & nValueRet , const CCoinControl * coinControl , AvailableCoinsType coin_type , bool useIX ) const
2011-06-26 19:23:24 +02:00
{
2015-03-24 16:11:00 +01:00
// Note: this function should never be used for "always free" tx types like dstx
2012-02-27 13:19:32 +01:00
vector < COutput > vCoins ;
2015-04-02 18:06:06 +02:00
AvailableCoins ( vCoins , true , coinControl , coin_type , useIX ) ;
2013-08-12 17:03:03 +02:00
2015-06-23 17:47:05 +02:00
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
if ( coinControl & & coinControl - > HasSelected ( ) )
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
if ( ! out . fSpendable )
continue ;
if ( coin_type = = ONLY_DENOMINATED ) {
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
int rounds = GetInputDarksendRounds ( vin ) ;
// make sure it's actually anonymized
if ( rounds < nDarksendRounds ) continue ;
}
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
}
return ( nValueRet > = nTargetValue ) ;
}
2014-12-09 02:17:57 +01:00
//if we're doing only denominated, we need to round up to the nearest .1DRK
2015-06-23 17:47:05 +02:00
if ( coin_type = = ONLY_DENOMINATED ) {
2014-12-09 02:17:57 +01:00
// Make outputs by looping through denominations, from large to small
BOOST_FOREACH ( int64_t v , darkSendDenominations )
{
BOOST_FOREACH ( const COutput & out , vCoins )
{
2015-01-21 14:02:59 +01:00
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 ) + 100 //round the amount up to .1DRK over
2015-03-24 16:11:00 +01:00
) {
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
int rounds = GetInputDarksendRounds ( vin ) ;
// make sure it's actually anonymized
if ( rounds < nDarksendRounds ) continue ;
nValueRet + = out . tx - > vout [ out . i ] . nValue ;
setCoinsRet . insert ( make_pair ( out . tx , out . i ) ) ;
2014-12-09 02:17:57 +01:00
}
}
}
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-04-07 03:45:30 +02:00
bool CWallet : : SelectCoinsByDenominations ( int nDenom , int64_t nValueMin , int64_t nValueMax , std : : vector < CTxIn > & vCoinsRet , std : : vector < COutput > & vCoinsRet2 , int64_t & nValueRet , int nDarksendRoundsMin , int nDarksendRoundsMax )
2014-12-30 01:09:34 +01:00
{
2015-04-07 03:45:30 +02:00
vCoinsRet . clear ( ) ;
2014-12-30 01:09:34 +01:00
nValueRet = 0 ;
2015-04-07 03:45:30 +02:00
vCoinsRet2 . clear ( ) ;
2014-12-30 01:09:34 +01:00
vector < COutput > vCoins ;
2015-04-07 03:45:30 +02:00
AvailableCoins ( vCoins , true , NULL , ONLY_DENOMINATED ) ;
2014-12-30 01:09:34 +01:00
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 )
{
2015-04-07 03:45:30 +02:00
// masternode-like input should not be selected by AvailableCoins now anyway
//if(out.tx->vout[out.i].nValue == 1000*COIN) continue;
2014-12-30 01:09:34 +01:00
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 ( ) ) ;
2015-04-07 03:45:30 +02:00
if ( ( int ) vCoinsRet . 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
2015-01-21 14:02:59 +01:00
if ( ( nDenom & ( 1 < < 0 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 100 * COIN ) + 100000 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 1 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 10 * COIN ) + 10000 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 2 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 1 * COIN ) + 1000 ) ) { fAccepted = true ; }
else if ( ( nDenom & ( 1 < < 3 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( .1 * COIN ) + 100 ) ) { fAccepted = true ; }
2014-12-30 01:09:34 +01:00
} else {
//Criterion has not been satisfied, we will only take 1 of each until it is.
2015-01-21 14:02:59 +01:00
if ( ( nDenom & ( 1 < < 0 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 100 * COIN ) + 100000 ) ) { fAccepted = true ; fFound100 = true ; }
else if ( ( nDenom & ( 1 < < 1 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 10 * COIN ) + 10000 ) ) { fAccepted = true ; fFound10 = true ; }
else if ( ( nDenom & ( 1 < < 2 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( 1 * COIN ) + 1000 ) ) { fAccepted = true ; fFound1 = true ; }
else if ( ( nDenom & ( 1 < < 3 ) ) & & out . tx - > vout [ out . i ] . nValue = = ( ( .1 * COIN ) + 100 ) ) { 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 ;
2015-04-07 03:45:30 +02:00
vCoinsRet . push_back ( vin ) ;
vCoinsRet2 . 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
}
2015-04-30 00:06:24 +02:00
bool CWallet : : SelectCoinsDark ( CAmount nValueMin , CAmount nValueMax , std : : vector < CTxIn > & setCoinsRet , CAmount & 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-08-16 02:26:20 +02:00
AvailableCoins ( vCoins , true , coinControl , nDarksendRoundsMin < 0 ? ONLY_NONDENOMINATED_NOT1000IFMN : ONLY_DENOMINATED ) ;
2014-12-09 02:17:57 +01:00
set < pair < const CWalletTx * , unsigned int > > setCoinsRet2 ;
2015-02-18 13:31:40 +01:00
//order the array so largest nondenom are first, then denominations, then very small inputs.
2014-12-09 02:17:57 +01:00
sort ( vCoins . rbegin ( ) , vCoins . rend ( ) , CompareByPriority ( ) ) ;
BOOST_FOREACH ( const COutput & out , vCoins )
{
2015-04-30 00:06:24 +02:00
//do not allow inputs less than 1 CENT
if ( out . tx - > vout [ out . i ] . nValue < CENT ) continue ;
//do not allow collaterals to be selected
if ( IsCollateralAmount ( out . tx - > vout [ out . i ] . nValue ) ) 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
{
vector < COutput > vCoins ;
//printf(" selecting coins for collateral\n");
2015-01-29 23:15:04 +01:00
AvailableCoins ( vCoins ) ;
2014-12-09 02:17:57 +01:00
//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
2015-01-27 05:13:34 +01:00
if ( IsCollateralAmount ( out . tx - > vout [ out . i ] . nValue ) )
{
2014-12-09 02:17:57 +01:00
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 ( ) ) {
2015-02-06 02:53:28 +01:00
int nDepth = pcoin - > GetDepthInMainChain ( false ) ;
2014-12-09 02:17:57 +01:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + ) {
2015-04-03 00:51:08 +02:00
COutput out = COutput ( pcoin , i , nDepth , true ) ;
2014-12-09 02:17:57 +01:00
CTxIn vin = CTxIn ( out . tx - > GetHash ( ) , out . i ) ;
if ( out . tx - > vout [ out . i ] . nValue ! = nInputAmount ) continue ;
2015-02-06 02:53:28 +01:00
if ( ! IsDenominatedAmount ( pcoin - > vout [ i ] . nValue ) ) continue ;
2015-07-26 01:24:19 +02:00
if ( IsSpent ( out . tx - > GetHash ( ) , i ) | | IsMine ( pcoin - > vout [ i ] ) ! = ISMINE_SPENDABLE | | ! IsDenominated ( vin ) ) continue ;
2014-12-09 02:17:57 +01:00
2015-02-06 02:53:28 +01:00
nTotal + + ;
2014-12-09 02:17:57 +01:00
}
}
}
}
return nTotal ;
}
2015-08-16 02:29:16 +02:00
bool CWallet : : HasCollateralInputs ( bool fOnlyConfirmed ) const
2014-12-09 02:17:57 +01:00
{
vector < COutput > vCoins ;
2015-08-16 02:29:16 +02:00
AvailableCoins ( vCoins , fOnlyConfirmed ) ;
2014-12-09 02:17:57 +01:00
2015-01-25 00:57:55 +01:00
int nFound = 0 ;
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( const COutput & out , vCoins )
2015-01-27 05:13:34 +01:00
if ( IsCollateralAmount ( out . tx - > vout [ out . i ] . nValue ) ) nFound + + ;
2014-12-09 02:17:57 +01:00
2015-02-23 18:42:13 +01:00
return nFound > 0 ;
2014-12-09 02:17:57 +01:00
}
2015-01-27 05:13:34 +01:00
bool CWallet : : IsCollateralAmount ( int64_t nInputAmount ) const
{
2015-02-18 20:17:33 +01:00
return nInputAmount ! = 0 & & nInputAmount % DARKSEND_COLLATERAL = = 0 & & nInputAmount < DARKSEND_COLLATERAL * 5 & & nInputAmount > DARKSEND_COLLATERAL ;
2014-12-09 02:17:57 +01:00
}
2015-07-10 00:08:26 +02:00
bool CWallet : : CreateCollateralTransaction ( CMutableTransaction & txCollateral , std : : string & strReason )
2014-12-09 02:17:57 +01:00
{
/*
To doublespend a collateral transaction , it will require a fee higher than this . So there ' s
still a significant cost .
*/
2015-04-03 00:51:08 +02:00
CAmount nFeeRet = 0.001 * COIN ;
2014-12-09 02:17:57 +01:00
txCollateral . vin . clear ( ) ;
txCollateral . vout . clear ( ) ;
CReserveKey reservekey ( this ) ;
2015-04-03 00:51:08 +02:00
CAmount nValueIn2 = 0 ;
2014-12-09 02:17:57 +01:00
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
2015-04-03 00:51:08 +02:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
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
2015-03-02 00:09:33 +01:00
strReason = " CDarksendPool::Sign - Unable to sign collateral transaction! \n " ;
2014-12-09 02:17:57 +01:00
return false ;
}
vinNumber + + ;
}
return true ;
}
2015-07-12 19:34:21 +02:00
bool CWallet : : GetBudgetSystemCollateralTX ( CTransaction & tx , uint256 hash , bool useIX )
{
CWalletTx wtx ;
if ( GetBudgetSystemCollateralTX ( wtx , hash , useIX ) ) {
tx = ( CTransaction ) wtx ;
return true ;
}
return false ;
}
2015-07-10 00:08:26 +02:00
bool CWallet : : GetBudgetSystemCollateralTX ( CWalletTx & tx , uint256 hash , bool useIX )
{
// make our change address
CReserveKey reservekey ( pwalletMain ) ;
CScript scriptChange ;
scriptChange < < OP_RETURN < < ToByteVector ( hash ) ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
2015-07-12 19:38:32 +02:00
vecSend . push_back ( make_pair ( scriptChange , BUDGET_FEE_TX ) ) ;
2015-07-10 00:08:26 +02:00
CCoinControl * coinControl = NULL ;
2015-07-12 19:38:32 +02:00
bool success = CreateTransaction ( vecSend , tx , reservekey , nFeeRet , strFail , coinControl , ALL_COINS , useIX , ( CAmount ) 0 ) ;
2015-07-10 00:08:26 +02:00
if ( ! success ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " GetBudgetSystemCollateralTX: Error - %s \n " , strFail ) ;
2015-07-10 00:08:26 +02:00
return false ;
}
return true ;
}
2014-12-09 02:17:57 +01:00
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
2014-04-23 00:46:19 +02:00
bool CWallet : : CreateTransaction ( const vector < pair < CScript , CAmount > > & vecSend ,
2015-07-17 17:32:50 +02:00
CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet , std : : string & strFailReason , const CCoinControl * coinControl , AvailableCoinsType coin_type , bool useIX , CAmount nFeePay )
2011-06-26 19:23:24 +02:00
{
2015-07-17 17:32:50 +02:00
if ( useIX & & nFeePay < CENT ) nFeePay = CENT ;
2015-07-10 00:08:26 +02:00
2014-04-23 00:46:19 +02:00
CAmount nValue = 0 ;
2015-07-17 17:32:50 +02:00
2014-04-23 00:46:19 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CScript , CAmount ) & 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
2014-05-27 21:44:57 +02:00
wtxNew . fTimeReceivedIsTxTime = true ;
2011-06-28 23:45:22 +02:00
wtxNew . BindWallet ( this ) ;
2014-06-07 13:53:27 +02:00
CMutableTransaction txNew ;
2011-06-26 19:23:24 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2011-06-26 19:23:24 +02:00
{
2014-11-02 00:14:47 +01:00
nFeeRet = 0 ;
2015-07-17 17:32:50 +02:00
if ( nFeePay > 0 ) nFeeRet = nFeePay ;
2013-07-31 06:06:44 +02:00
while ( true )
2011-06-26 19:23:24 +02:00
{
2014-06-07 13:53:27 +02:00
txNew . vin . clear ( ) ;
txNew . vout . clear ( ) ;
2011-06-26 19:23:24 +02:00
wtxNew . fFromMe = true ;
2015-07-18 02:26:43 +02:00
CAmount nTotalValue = nValue + nFeeRet ;
2011-06-26 19:23:24 +02:00
double dPriority = 0 ;
// vouts to the payees
2014-04-23 00:46:19 +02:00
BOOST_FOREACH ( const PAIRTYPE ( CScript , CAmount ) & s , vecSend )
2013-04-25 00:27:00 +02:00
{
CTxOut txout ( s . second , s . first ) ;
2014-07-03 20:25:32 +02:00
if ( txout . IsDust ( : : minRelayTxFee ) )
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
}
2014-06-07 13:53:27 +02:00
txNew . vout . push_back ( txout ) ;
2013-04-25 00:27:00 +02:00
}
2011-06-26 19:23:24 +02:00
// Choose coins to use
set < pair < const CWalletTx * , unsigned int > > setCoins ;
2014-04-23 00:46:19 +02:00
CAmount nValueIn = 0 ;
2015-02-03 21:25:00 +01:00
if ( ! SelectCoins ( nTotalValue , setCoins , nValueIn , coinControl , coin_type , useIX ) )
2013-04-25 23:31:22 +02:00
{
2015-02-04 16:30:00 +01:00
if ( coin_type = = ALL_COINS ) {
strFailReason = _ ( " Insufficient funds. " ) ;
2015-08-16 02:26:20 +02:00
} else if ( coin_type = = ONLY_NOT1000IFMN ) {
strFailReason = _ ( " Unable to locate enough funds for this transaction that are not equal 1000 DASH. " ) ;
} else if ( coin_type = = ONLY_NONDENOMINATED_NOT1000IFMN ) {
2015-03-18 00:06:58 +01:00
strFailReason = _ ( " Unable to locate enough Darksend non-denominated funds for this transaction that are not equal 1000 DASH. " ) ;
2015-02-04 16:30:00 +01:00
} else {
strFailReason = _ ( " Unable to locate enough Darksend denominated funds for this transaction. " ) ;
2015-08-02 04:05:49 +02:00
strFailReason + = " " + _ ( " Darksend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins. " ) ;
2015-02-04 16:30:00 +01:00
}
if ( useIX ) {
2015-08-02 04:05:49 +02:00
strFailReason + = " " + _ ( " InstantX requires inputs with at least 6 confirmations, you might need to wait a few minutes and try again. " ) ;
2015-02-04 16:30:00 +01:00
}
2014-12-09 02:17:57 +01:00
2011-06-26 19:23:24 +02:00
return false ;
2013-04-25 23:31:22 +02:00
}
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 )
{
2014-04-23 00:46:19 +02:00
CAmount nCredit = pcoin . first - > vout [ pcoin . second ] . nValue ;
2015-01-16 18:17:57 +01:00
//The coin age after the next block (depth+1) is used instead of the current,
2012-12-26 18:45:42 +01:00
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
2015-01-16 18:17:57 +01:00
//But mempool inputs might still be in the mempool, so their age stays 0
int age = pcoin . first - > GetDepthInMainChain ( ) ;
if ( age ! = 0 )
age + = 1 ;
dPriority + = ( double ) nCredit * age ;
2011-06-26 19:23:24 +02:00
}
2014-04-23 00:46:19 +02:00
CAmount nChange = nValueIn - nValue - nFeeRet ;
2011-07-24 16:37:09 +02:00
2015-01-27 15:29:25 +01:00
//over pay for denominated transactions
if ( coin_type = = ONLY_DENOMINATED ) {
2015-03-02 05:26:38 +01:00
nFeeRet + = nChange ;
2015-01-27 15:29:25 +01:00
nChange = 0 ;
2015-02-08 15:03:39 +01:00
wtxNew . mapValue [ " DS " ] = " 1 " ;
2015-12-02 23:12:16 +01:00
// recheck skipped denominations during next mixing
darkSendPool . ClearSkippedDenominations ( ) ;
2015-01-27 15:29:25 +01:00
}
2011-07-24 16:37:09 +02:00
if ( nChange > 0 )
2011-06-26 19:23:24 +02:00
{
2011-09-28 18:30:06 +02:00
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
2015-03-19 15:15:08 +01:00
// change transaction isn't always pay-to-dash-address
2011-06-26 19:23:24 +02:00
CScript scriptChange ;
2013-08-12 17:03:03 +02:00
// coin control: send change to custom address
if ( coinControl & & ! boost : : get < CNoDestination > ( & coinControl - > destChange ) )
2014-09-11 19:15:29 +02:00
scriptChange = GetScriptForDestination ( coinControl - > destChange ) ;
2013-08-12 17:03:03 +02:00
// no coin control: send change to newly generated address
else
{
// Note: We use a new key here to keep it from being obvious which side is the change.
// The drawback is that by not reusing a previous key, the change may be lost if a
// backup is restored, if the backup doesn't have the new private key for the change.
// If we reused the old key, it would be possible to add code to look for and
// rediscover unknown transactions that were written with keys of ours to recover
// post-backup change.
// Reserve a new key pair from key pool
CPubKey vchPubKey ;
2013-12-02 20:33:44 +01:00
bool ret ;
ret = reservekey . GetReservedKey ( vchPubKey ) ;
assert ( ret ) ; // should never fail, as we just unlocked
2013-08-12 17:03:03 +02:00
2014-09-11 19:15:29 +02:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2013-08-12 17:03:03 +02:00
}
2011-06-26 19:23:24 +02:00
2013-04-25 00:27:00 +02:00
CTxOut newTxOut ( nChange , scriptChange ) ;
// Never create dust outputs; if we would, just
2015-07-18 02:26:43 +02:00
// add the dust to the fee.
if ( newTxOut . IsDust ( : : minRelayTxFee ) )
2013-04-25 00:27:00 +02:00
{
nFeeRet + = nChange ;
2015-06-22 21:21:44 +02:00
nChange = 0 ;
2013-04-25 00:27:00 +02:00
reservekey . ReturnKey ( ) ;
}
else
{
// Insert change txn at random position:
2014-06-07 13:53:27 +02:00
vector < CTxOut > : : iterator position = txNew . vout . begin ( ) + GetRandInt ( txNew . vout . size ( ) + 1 ) ;
txNew . vout . insert ( position , newTxOut ) ;
2013-04-25 00:27:00 +02:00
}
2011-06-26 19:23:24 +02:00
}
else
reservekey . ReturnKey ( ) ;
// Fill vin
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
2014-06-07 13:53:27 +02:00
txNew . vin . push_back ( CTxIn ( coin . first - > GetHash ( ) , coin . second ) ) ;
2011-06-26 19:23:24 +02:00
2015-08-21 03:28:17 +02:00
// BIP69 https://github.com/kristovatlas/bips/blob/master/bip-0069.mediawiki
sort ( txNew . vin . begin ( ) , txNew . vin . end ( ) ) ;
sort ( txNew . vout . begin ( ) , txNew . vout . end ( ) ) ;
2011-06-26 19:23:24 +02:00
// Sign
int nIn = 0 ;
2015-08-21 03:28:17 +02:00
BOOST_FOREACH ( const CTxIn & vin , txNew . vin )
if ( ! SignSignature ( * this , mapWallet [ vin . prevout . hash ] , txNew , 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
2014-06-07 13:53:27 +02:00
// Embed the constructed transaction data in wtxNew.
* static_cast < CTransaction * > ( & wtxNew ) = CTransaction ( txNew ) ;
2011-06-26 19:23:24 +02:00
// Limit size
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
2014-12-16 10:43:40 +01:00
// Can we complete this as a free transaction?
if ( fSendFreeTransactions & & nBytes < = MAX_FREE_TRANSACTION_CREATE_SIZE )
2011-06-26 19:23:24 +02:00
{
2014-12-16 10:43:40 +01:00
// Not enough fee: enough priority?
double dPriorityNeeded = mempool . estimatePriority ( nTxConfirmTarget ) ;
// Not enough mempool history to estimate: use hard-coded AllowFree.
if ( dPriorityNeeded < = 0 & & AllowFree ( dPriority ) )
break ;
// Small enough, and priority high enough, to send for free
if ( dPriorityNeeded > 0 & & dPriority > = dPriorityNeeded )
break ;
}
2014-05-27 21:44:57 +02:00
2015-07-17 17:32:50 +02:00
CAmount nFeeNeeded = max ( nFeePay , GetMinimumFee ( nBytes , nTxConfirmTarget , mempool ) ) ;
2014-05-27 21:44:57 +02:00
2014-12-16 10:43:40 +01:00
// If we made it here and we aren't even able to meet the relay fee on the next pass, give up
// because we must be at the maximum allowed fee.
if ( nFeeNeeded < : : minRelayTxFee . GetFee ( nBytes ) )
2011-06-26 19:23:24 +02:00
{
2014-12-16 10:43:40 +01:00
strFailReason = _ ( " Transaction too large for fee policy " ) ;
return false ;
2011-06-26 19:23:24 +02:00
}
2015-07-18 02:26:43 +02:00
if ( nFeeRet > = nFeeNeeded ) // Done, enough fee included
2015-07-17 17:32:50 +02:00
break ;
2011-06-26 19:23:24 +02:00
2014-05-27 21:44:57 +02:00
// Include more fee and try again.
nFeeRet = nFeeNeeded ;
continue ;
2011-06-26 19:23:24 +02:00
}
}
}
return true ;
}
2014-04-23 00:46:19 +02:00
bool CWallet : : CreateTransaction ( CScript scriptPubKey , const CAmount & nValue ,
2015-07-17 17:32:50 +02:00
CWalletTx & wtxNew , CReserveKey & reservekey , CAmount & nFeeRet , std : : string & strFailReason , const CCoinControl * coinControl , AvailableCoinsType coin_type , bool useIX , CAmount nFeePay )
2011-06-26 19:23:24 +02:00
{
2014-04-23 00:46:19 +02:00
vector < pair < CScript , CAmount > > vecSend ;
2011-06-26 19:23:24 +02:00
vecSend . push_back ( make_pair ( scriptPubKey , nValue ) ) ;
2015-07-17 17:32:50 +02:00
return CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRet , strFailReason , coinControl , coin_type , useIX , nFeePay ) ;
2011-06-26 19:23:24 +02:00
}
2014-10-26 08:03:12 +01: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
2015-02-06 05:25:46 +01:00
set < uint256 > updated_hahes ;
2011-06-26 19:23:24 +02:00
BOOST_FOREACH ( const CTxIn & txin , wtxNew . vin )
{
2015-02-06 05:25:46 +01:00
// notify only once
if ( updated_hahes . find ( txin . prevout . hash ) ! = updated_hahes . end ( ) ) continue ;
2011-06-26 19:23:24 +02:00
CWalletTx & coin = mapWallet [ txin . prevout . hash ] ;
2011-06-28 23:45:22 +02:00
coin . BindWallet ( this ) ;
2015-02-06 05:25:46 +01:00
NotifyTransactionChanged ( this , txin . prevout . hash , CT_UPDATED ) ;
updated_hahes . insert ( txin . prevout . hash ) ;
2011-06-26 19:23:24 +02:00
}
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.
2015-01-25 00:57:55 +01:00
LogPrintf ( " CommitTransaction() : Error: Transaction not valid \n " ) ;
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-04-23 00:46:19 +02:00
CAmount CWallet : : GetMinimumFee ( unsigned int nTxBytes , unsigned int nConfirmTarget , const CTxMemPool & pool )
2014-05-27 21:44:57 +02:00
{
// payTxFee is user-set "I want to pay this much"
2014-04-23 00:46:19 +02:00
CAmount nFeeNeeded = payTxFee . GetFee ( nTxBytes ) ;
2014-11-02 00:14:47 +01:00
// user selected total at least (default=true)
if ( fPayAtLeastCustomFee & & nFeeNeeded > 0 & & nFeeNeeded < payTxFee . GetFeePerK ( ) )
nFeeNeeded = payTxFee . GetFeePerK ( ) ;
2014-05-27 21:44:57 +02:00
// User didn't set: use -txconfirmtarget to estimate...
if ( nFeeNeeded = = 0 )
nFeeNeeded = pool . estimateFee ( nConfirmTarget ) . GetFee ( nTxBytes ) ;
// ... unless we don't have enough mempool data, in which case fall
// back to a hard-coded fee
if ( nFeeNeeded = = 0 )
2014-07-03 20:25:32 +02:00
nFeeNeeded = minTxFee . GetFee ( nTxBytes ) ;
2014-12-16 10:43:40 +01:00
// prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee
if ( nFeeNeeded < : : minRelayTxFee . GetFee ( nTxBytes ) )
nFeeNeeded = : : minRelayTxFee . GetFee ( nTxBytes ) ;
// But always obey the maximum
if ( nFeeNeeded > maxTxFee )
nFeeNeeded = maxTxFee ;
2014-05-27 21:44:57 +02:00
return nFeeNeeded ;
}
2014-12-09 02:17:57 +01:00
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 )
2015-07-26 00:43:40 +02:00
if ( darkSendPool . GetEntriesCount ( ) > 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-07-07 00:09:28 +02:00
std : : vector < CTxIn > vCoinsResult ;
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 ) )
2015-08-02 04:05:49 +02:00
return _ ( " Error: Can't select current denominated inputs " ) ;
2014-12-30 20:42:34 +01:00
}
2014-12-09 02:17:57 +01:00
2015-07-07 00:09:28 +02:00
LogPrintf ( " PrepareDarksendDenominate - preparing darksend denominate . Got: %d \n " , nValueIn ) ;
2014-12-09 02:17:57 +01:00
2015-08-08 19:01:18 +02:00
{
LOCK ( cs_wallet ) ;
BOOST_FOREACH ( CTxIn v , vCoins )
LockCoin ( v . prevout ) ;
}
2014-12-09 02:17:57 +01:00
2015-07-07 00:09:28 +02:00
int64_t nValueLeft = nValueIn ;
2014-12-09 02:17:57 +01:00
std : : vector < CTxOut > vOut ;
2011-06-26 19:23:24 +02:00
2015-01-21 14:02:59 +01:00
/*
TODO : Front load with needed denominations ( e . g . .1 , 1 )
*/
2014-12-30 20:42:34 +01:00
2015-07-07 00:09:28 +02:00
// Make outputs by looping through denominations: try to add every needed denomination, repeat up to 5-10 times.
// This way we can be pretty sure that it should have at least one of each needed denomination.
// NOTE: No need to randomize order of inputs because they were
// initially shuffled in CWallet::SelectCoinsByDenominations already.
int nStep = 0 ;
int nStepsMax = 5 + GetRandInt ( 5 ) ;
while ( nStep < nStepsMax ) {
2015-01-21 14:02:59 +01:00
2015-07-07 00:09:28 +02:00
BOOST_FOREACH ( int64_t v , darkSendDenominations ) {
// only use the ones that are approved
bool fAccepted = false ;
if ( ( darkSendPool . sessionDenom & ( 1 < < 0 ) ) & & v = = ( ( 100 * COIN ) + 100000 ) ) { fAccepted = true ; }
else if ( ( darkSendPool . sessionDenom & ( 1 < < 1 ) ) & & v = = ( ( 10 * COIN ) + 10000 ) ) { fAccepted = true ; }
else if ( ( darkSendPool . sessionDenom & ( 1 < < 2 ) ) & & v = = ( ( 1 * COIN ) + 1000 ) ) { fAccepted = true ; }
else if ( ( darkSendPool . sessionDenom & ( 1 < < 3 ) ) & & v = = ( ( .1 * COIN ) + 100 ) ) { fAccepted = true ; }
if ( ! fAccepted ) continue ;
2015-01-20 16:59:37 +01:00
2015-07-07 00:09:28 +02:00
// try to add it
if ( nValueLeft - v > = 0 ) {
// Note: this relies on a fact that both vectors MUST have same size
std : : vector < CTxIn > : : iterator it = vCoins . begin ( ) ;
std : : vector < COutput > : : iterator it2 = vCoins2 . begin ( ) ;
while ( it2 ! = vCoins2 . end ( ) ) {
// we have matching inputs
if ( ( * it2 ) . tx - > vout [ ( * it2 ) . i ] . nValue = = v ) {
// add new input in resulting vector
vCoinsResult . push_back ( * it ) ;
// remove corresponting items from initial vectors
vCoins . erase ( it ) ;
vCoins2 . erase ( it2 ) ;
CScript scriptChange ;
CPubKey vchPubKey ;
// use a unique change address
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
reservekey . KeepKey ( ) ;
2015-01-21 14:02:59 +01:00
2015-07-07 00:09:28 +02:00
// add new output
CTxOut o ( v , scriptChange ) ;
vOut . push_back ( o ) ;
2015-01-21 14:02:59 +01:00
2015-07-07 00:09:28 +02:00
// subtract denomination amount
nValueLeft - = v ;
2015-01-21 14:02:59 +01:00
2015-07-07 00:09:28 +02:00
break ;
}
+ + it ;
+ + it2 ;
}
}
2015-01-21 14:02:59 +01:00
}
2015-01-20 16:59:37 +01:00
2015-07-07 00:09:28 +02:00
nStep + + ;
2015-01-20 16:59:37 +01:00
if ( nValueLeft = = 0 ) break ;
2014-12-09 02:17:57 +01:00
}
2015-08-08 19:01:18 +02:00
{
// unlock unused coins
LOCK ( cs_wallet ) ;
BOOST_FOREACH ( CTxIn v , vCoins )
UnlockCoin ( v . prevout ) ;
}
2015-01-21 14:02:59 +01:00
2015-06-28 16:07:44 +02:00
if ( darkSendPool . GetDenominations ( vOut ) ! = darkSendPool . sessionDenom ) {
2015-07-07 00:09:28 +02:00
// unlock used coins on failure
2015-08-08 19:01:18 +02:00
LOCK ( cs_wallet ) ;
2015-07-07 00:09:28 +02:00
BOOST_FOREACH ( CTxIn v , vCoinsResult )
2015-06-28 16:07:44 +02:00
UnlockCoin ( v . prevout ) ;
2015-01-21 14:02:59 +01:00
return " Error: can't make current denominated outputs " ;
2015-06-28 16:07:44 +02:00
}
2015-01-21 14:02:59 +01:00
2015-07-07 00:09:28 +02:00
// We also do not care about full amount as long as we have right denominations, just pass what we found
darkSendPool . SendDarksendDenominate ( vCoinsResult , vOut , nValueIn - nValueLeft ) ;
2014-12-09 02:17:57 +01:00
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 18:27:15 +01:00
DBErrors CWallet : : ZapWalletTx ( std : : vector < CWalletTx > & vWtx )
2014-02-14 17:33:07 +01:00
{
if ( ! fFileBacked )
return DB_LOAD_OK ;
2014-02-14 18:27:15 +01:00
DBErrors nZapWalletTxRet = CWalletDB ( strWalletFile , " cr+ " ) . ZapWalletTx ( this , vWtx ) ;
2014-02-14 17:33:07 +01:00
if ( nZapWalletTxRet = = DB_NEED_REWRITE )
{
if ( CDB : : Rewrite ( strWalletFile , " \x04 pool " ) )
{
LOCK ( cs_wallet ) ;
setKeyPool . clear ( ) ;
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
2014-10-26 08:03:12 +01:00
// that requires a new key.
2014-02-14 17:33:07 +01:00
}
}
if ( nZapWalletTxRet ! = DB_LOAD_OK )
return nZapWalletTxRet ;
return DB_LOAD_OK ;
}
2013-07-22 08:50:39 +02:00
bool CWallet : : SetAddressBook ( const CTxDestination & address , const string & strName , const string & strPurpose )
2011-07-07 15:22:54 +02:00
{
2014-02-18 18:11:46 +01:00
bool fUpdated = false ;
{
LOCK ( cs_wallet ) ; // mapAddressBook
std : : map < CTxDestination , CAddressBookData > : : iterator mi = mapAddressBook . find ( address ) ;
fUpdated = mi ! = mapAddressBook . end ( ) ;
mapAddressBook [ address ] . name = strName ;
if ( ! strPurpose . empty ( ) ) /* update purpose only if requested */
mapAddressBook [ address ] . purpose = strPurpose ;
}
2014-09-06 21:59:59 +02:00
NotifyAddressBookChanged ( this , address , strName , : : IsMine ( * this , address ) ! = ISMINE_NO ,
2014-02-18 18:11:46 +01:00
strPurpose , ( fUpdated ? CT_UPDATED : CT_NEW ) ) ;
2011-07-07 15:22:54 +02:00
if ( ! fFileBacked )
return false ;
2013-07-22 08:50:39 +02:00
if ( ! strPurpose . empty ( ) & & ! CWalletDB ( strWalletFile ) . WritePurpose ( CBitcoinAddress ( address ) . ToString ( ) , strPurpose ) )
return false ;
2012-05-14 23:44:52 +02:00
return CWalletDB ( strWalletFile ) . WriteName ( CBitcoinAddress ( address ) . ToString ( ) , strName ) ;
2011-07-07 15:22:54 +02:00
}
2013-07-22 08:50:39 +02:00
bool CWallet : : DelAddressBook ( const CTxDestination & address )
2011-07-07 15:22:54 +02:00
{
2013-11-18 16:55:54 +01:00
{
2014-02-18 18:11:46 +01:00
LOCK ( cs_wallet ) ; // mapAddressBook
if ( fFileBacked )
2013-11-18 16:55:54 +01:00
{
2014-02-18 18:11:46 +01:00
// Delete destdata tuples associated with address
std : : string strAddress = CBitcoinAddress ( address ) . ToString ( ) ;
BOOST_FOREACH ( const PAIRTYPE ( string , string ) & item , mapAddressBook [ address ] . destdata )
{
CWalletDB ( strWalletFile ) . EraseDestData ( strAddress , item . first ) ;
}
2013-11-18 16:55:54 +01:00
}
2014-02-18 18:11:46 +01:00
mapAddressBook . erase ( address ) ;
2013-11-18 16:55:54 +01:00
}
2014-09-06 21:59:59 +02:00
NotifyAddressBookChanged ( this , address , " " , : : IsMine ( * this , address ) ! = ISMINE_NO , " " , CT_DELETED ) ;
2014-02-18 18:11:46 +01:00
2011-07-07 15:22:54 +02:00
if ( ! fFileBacked )
return false ;
2013-07-22 08:50:39 +02:00
CWalletDB ( strWalletFile ) . ErasePurpose ( CBitcoinAddress ( address ) . ToString ( ) ) ;
2012-05-14 23:44:52 +02:00
return CWalletDB ( strWalletFile ) . EraseName ( CBitcoinAddress ( address ) . ToString ( ) ) ;
2011-07-07 15:22:54 +02:00
}
2012-05-14 19:07:52 +02:00
bool CWallet : : SetDefaultKey ( const CPubKey & vchPubKey )
2011-07-07 15:22:54 +02:00
{
if ( fFileBacked )
{
if ( ! CWalletDB ( strWalletFile ) . WriteDefaultKey ( vchPubKey ) )
return false ;
}
vchDefaultKey = vchPubKey ;
return true ;
}
2014-10-26 08:03:12 +01:00
/**
* Mark old keypool keys as used ,
* and generate all new keys
*/
2011-11-17 20:01:25 +01:00
bool CWallet : : NewKeyPool ( )
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-11-17 20:01:25 +01:00
CWalletDB walletdb ( strWalletFile ) ;
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( int64_t nIndex , setKeyPool )
2011-11-17 20:01:25 +01:00
walletdb . ErasePool ( nIndex ) ;
setKeyPool . clear ( ) ;
if ( IsLocked ( ) )
return false ;
2015-10-04 13:55:33 +02:00
int64_t nKeys = max ( GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2011-11-17 20:01:25 +01:00
for ( int i = 0 ; i < nKeys ; i + + )
{
2013-04-13 07:13:08 +02:00
int64_t nIndex = i + 1 ;
2011-11-17 20:01:25 +01:00
walletdb . WritePool ( nIndex , CKeyPool ( GenerateNewKey ( ) ) ) ;
setKeyPool . insert ( nIndex ) ;
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " CWallet::NewKeyPool wrote %d new keys \n " , nKeys ) ;
2011-11-17 20:01:25 +01:00
}
return true ;
}
2013-06-25 22:07:29 +02:00
bool CWallet : : TopUpKeyPool ( unsigned int kpSize )
2011-06-26 19:23:24 +02:00
{
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( IsLocked ( ) )
return false ;
2011-06-26 19:23:24 +02:00
CWalletDB walletdb ( strWalletFile ) ;
// Top up key pool
2013-06-25 22:07:29 +02:00
unsigned int nTargetSize ;
if ( kpSize > 0 )
nTargetSize = kpSize ;
else
2015-10-04 13:55:33 +02:00
nTargetSize = max ( GetArg ( " -keypool " , DEFAULT_KEYPOOL_SIZE ) , ( int64_t ) 0 ) ;
2013-06-25 22:07:29 +02:00
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 ( ) ) ;
2015-02-15 00:20:58 +01:00
double dProgress = 100.f * nEnd / ( nTargetSize + 1 ) ;
2014-12-02 12:43:06 +01:00
std : : string strMsg = strprintf ( _ ( " Loading wallet... (%3.2f %%) " ) , dProgress ) ;
2014-12-02 09:48:47 +01:00
uiInterface . InitMessage ( strMsg ) ;
2011-06-26 19:23:24 +02:00
}
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
}
return true ;
}
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
void CWallet : : KeepKey ( int64_t nIndex )
2011-06-26 19:23:24 +02:00
{
// Remove from key pool
if ( fFileBacked )
{
CWalletDB walletdb ( strWalletFile ) ;
2011-08-26 20:37:23 +02:00
walletdb . ErasePool ( nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " keypool keep %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2013-04-13 07:13:08 +02:00
void CWallet : : ReturnKey ( int64_t nIndex )
2011-06-26 19:23:24 +02:00
{
// Return to key pool
2012-04-06 18:39:12 +02:00
{
LOCK ( cs_wallet ) ;
2011-06-26 19:23:24 +02:00
setKeyPool . insert ( nIndex ) ;
2012-04-06 18:39:12 +02:00
}
2014-02-24 09:08:56 +01:00
LogPrintf ( " keypool return %d \n " , nIndex ) ;
2011-06-26 19:23:24 +02:00
}
2013-08-23 21:54:50 +02:00
bool CWallet : : GetKeyFromPool ( CPubKey & result )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nIndex = 0 ;
2011-06-26 19:23:24 +02:00
CKeyPool keypool ;
2011-08-12 22:32:07 +02:00
{
2012-04-06 18:39:12 +02:00
LOCK ( cs_wallet ) ;
2011-09-01 16:58:08 +02:00
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
if ( nIndex = = - 1 )
2011-08-12 22:32:07 +02:00
{
2011-09-01 16:58:08 +02:00
if ( IsLocked ( ) ) return false ;
result = GenerateNewKey ( ) ;
2011-08-12 22:32:07 +02:00
return true ;
}
2011-09-01 16:58:08 +02:00
KeepKey ( nIndex ) ;
result = keypool . vchPubKey ;
2011-08-12 22:32:07 +02:00
}
return true ;
2011-06-26 19:23:24 +02:00
}
2013-04-13 07:13:08 +02:00
int64_t CWallet : : GetOldestKeyPoolTime ( )
2011-06-26 19:23:24 +02:00
{
2013-04-13 07:13:08 +02:00
int64_t nIndex = 0 ;
2011-06-26 19:23:24 +02:00
CKeyPool keypool ;
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
Add wallet privkey encryption.
This commit adds support for ckeys, or enCrypted private keys, to the wallet.
All keys are stored in memory in their encrypted form and thus the passphrase
is required from the user to spend coins, or to create new addresses.
Keys are encrypted with AES-256-CBC using OpenSSL's EVP library. The key is
calculated via EVP_BytesToKey using SHA512 with (by default) 25000 rounds and
a random salt.
By default, the user's wallet remains unencrypted until they call the RPC
command encryptwallet <passphrase> or, from the GUI menu, Options->
Encrypt Wallet.
When the user is attempting to call RPC functions which require the password
to unlock the wallet, an error will be returned unless they call
walletpassphrase <passphrase> <time to keep key in memory> first.
A keypoolrefill command has been added which tops up the users keypool
(requiring the passphrase via walletpassphrase first).
keypoolsize has been added to the output of getinfo to show the user the
number of keys left before they need to specify their passphrase (and call
keypoolrefill).
Note that walletpassphrase will automatically fill keypool in a separate
thread which it spawns when the passphrase is set. This could cause some
delays in other threads waiting for locks on the wallet passphrase, including
one which could cause the passphrase to be stored longer than expected,
however it will not allow the passphrase to be used longer than expected as
ThreadCleanWalletPassphrase will attempt to get a lock on the key as soon
as the specified lock time has arrived.
When the keypool runs out (and wallet is locked) GetOrReuseKeyFromPool
returns vchDefaultKey, meaning miners may start to generate many blocks to
vchDefaultKey instead of a new key each time.
A walletpassphrasechange <oldpassphrase> <newpassphrase> has been added to
allow the user to change their password via RPC.
Whenever keying material (unencrypted private keys, the user's passphrase,
the wallet's AES key) is stored unencrypted in memory, any reasonable attempt
is made to mlock/VirtualLock that memory before storing the keying material.
This is not true in several (commented) cases where mlock/VirtualLocking the
memory is not possible.
Although encryption of private keys in memory can be very useful on desktop
systems (as some small amount of protection against stupid viruses), on an
RPC server, the password is entered fairly insecurely. Thus, the only main
advantage encryption has for RPC servers is for RPC servers that do not spend
coins, except in rare cases, eg. a webserver of a merchant which only receives
payment except for cases of manual intervention.
Thanks to jgarzik for the original patch and sipa, gmaxwell and many others
for all their input.
Conflicts:
src/wallet.cpp
2011-07-08 15:47:35 +02:00
if ( nIndex = = - 1 )
return GetTime ( ) ;
2011-06-26 19:23:24 +02:00
ReturnKey ( nIndex ) ;
return keypool . nTime ;
}
2014-04-23 00:46:19 +02:00
std : : map < CTxDestination , CAmount > CWallet : : GetAddressBalances ( )
2012-08-01 18:48:42 +02:00
{
2014-04-23 00:46:19 +02:00
map < CTxDestination , CAmount > balances ;
2012-08-01 18:48:42 +02:00
{
LOCK ( cs_wallet ) ;
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
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 ( ) ;
2014-07-01 11:00:22 +02:00
if ( nDepth < ( pcoin - > IsFromMe ( ISMINE_ALL ) ? 0 : 1 ) )
2012-08-01 18:48:42 +02:00
continue ;
2012-08-20 19:43:33 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
2012-08-01 18:48:42 +02:00
{
2012-08-20 19:43:33 +02:00
CTxDestination addr ;
2012-08-01 18:48:42 +02:00
if ( ! IsMine ( pcoin - > vout [ i ] ) )
continue ;
2012-08-20 19:43:33 +02:00
if ( ! ExtractDestination ( pcoin - > vout [ i ] . scriptPubKey , addr ) )
continue ;
2012-08-01 18:48:42 +02:00
2014-04-23 00:46:19 +02:00
CAmount n = IsSpent ( walletEntry . first , i ) ? 0 : pcoin - > vout [ i ] . nValue ;
2012-08-01 18:48:42 +02:00
if ( ! balances . count ( addr ) )
balances [ addr ] = 0 ;
balances [ addr ] + = n ;
}
}
}
return balances ;
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > CWallet : : GetAddressGroupings ( )
2012-08-01 18:48:42 +02:00
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapWallet
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > groupings ;
set < CTxDestination > grouping ;
2012-08-01 18:48:42 +02:00
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
2012-09-27 19:29:35 +02:00
if ( pcoin - > vin . size ( ) > 0 )
2012-08-01 18:48:42 +02:00
{
2012-09-27 19:29:35 +02:00
bool any_mine = false ;
2012-08-01 18:48:42 +02:00
// group all input addresses with each other
BOOST_FOREACH ( CTxIn txin , pcoin - > vin )
2012-08-20 19:43:33 +02:00
{
CTxDestination address ;
2012-09-27 19:29:35 +02:00
if ( ! IsMine ( txin ) ) /* If this input isn't mine, ignore it */
continue ;
2012-08-20 19:43:33 +02:00
if ( ! ExtractDestination ( mapWallet [ txin . prevout . hash ] . vout [ txin . prevout . n ] . scriptPubKey , address ) )
continue ;
grouping . insert ( address ) ;
2012-09-27 19:29:35 +02:00
any_mine = true ;
2012-08-20 19:43:33 +02:00
}
2012-08-01 18:48:42 +02:00
// group change with input addresses
2012-09-27 19:29:35 +02:00
if ( any_mine )
{
BOOST_FOREACH ( CTxOut txout , pcoin - > vout )
if ( IsChange ( txout ) )
{
CTxDestination txoutAddr ;
if ( ! ExtractDestination ( txout . scriptPubKey , txoutAddr ) )
continue ;
grouping . insert ( txoutAddr ) ;
}
}
if ( grouping . size ( ) > 0 )
{
groupings . insert ( grouping ) ;
grouping . clear ( ) ;
}
2012-08-01 18:48:42 +02:00
}
// group lone addrs by themselves
2012-08-20 19:43:33 +02:00
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
2012-08-01 18:48:42 +02:00
if ( IsMine ( pcoin - > vout [ i ] ) )
{
2012-08-20 19:43:33 +02:00
CTxDestination address ;
if ( ! ExtractDestination ( pcoin - > vout [ i ] . scriptPubKey , address ) )
continue ;
grouping . insert ( address ) ;
2012-08-01 18:48:42 +02:00
groupings . insert ( grouping ) ;
grouping . clear ( ) ;
}
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > * > uniqueGroupings ; // a set of pointers to groups of addresses
map < CTxDestination , set < CTxDestination > * > setmap ; // map addresses to the unique group containing it
BOOST_FOREACH ( set < CTxDestination > grouping , groupings )
2012-08-01 18:48:42 +02:00
{
// make a set of all the groups hit by this new group
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > * > hits ;
map < CTxDestination , set < CTxDestination > * > : : iterator it ;
BOOST_FOREACH ( CTxDestination address , grouping )
2012-08-01 18:48:42 +02:00
if ( ( it = setmap . find ( address ) ) ! = setmap . end ( ) )
hits . insert ( ( * it ) . second ) ;
// merge all hit groups into a new single group and delete old groups
2012-08-20 19:43:33 +02:00
set < CTxDestination > * merged = new set < CTxDestination > ( grouping ) ;
BOOST_FOREACH ( set < CTxDestination > * hit , hits )
2012-08-01 18:48:42 +02:00
{
merged - > insert ( hit - > begin ( ) , hit - > end ( ) ) ;
uniqueGroupings . erase ( hit ) ;
delete hit ;
}
uniqueGroupings . insert ( merged ) ;
// update setmap
2012-08-20 19:43:33 +02:00
BOOST_FOREACH ( CTxDestination element , * merged )
2012-08-01 18:48:42 +02:00
setmap [ element ] = merged ;
}
2012-08-20 19:43:33 +02:00
set < set < CTxDestination > > ret ;
BOOST_FOREACH ( set < CTxDestination > * uniqueGrouping , uniqueGroupings )
2012-08-01 18:48:42 +02:00
{
ret . insert ( * uniqueGrouping ) ;
delete uniqueGrouping ;
}
return ret ;
}
2013-07-16 01:01:09 +02:00
set < CTxDestination > CWallet : : GetAccountAddresses ( string strAccount ) const
{
2014-11-28 19:11:49 +01:00
LOCK ( cs_wallet ) ;
2013-07-16 01:01:09 +02:00
set < CTxDestination > result ;
BOOST_FOREACH ( const PAIRTYPE ( CTxDestination , CAddressBookData ) & item , mapAddressBook )
{
const CTxDestination & address = item . first ;
const string & strName = item . second . name ;
if ( strName = = strAccount )
result . insert ( address ) ;
}
return result ;
}
2013-04-25 19:30:28 +02:00
bool CReserveKey : : GetReservedKey ( CPubKey & pubkey )
2011-06-26 19:23:24 +02:00
{
if ( nIndex = = - 1 )
{
CKeyPool keypool ;
pwallet - > ReserveKeyFromKeyPool ( nIndex , keypool ) ;
2011-07-14 03:11:40 +02:00
if ( nIndex ! = - 1 )
vchPubKey = keypool . vchPubKey ;
2013-04-25 19:30:28 +02:00
else {
2014-06-16 14:45:32 +02:00
return false ;
2011-07-14 03:28:31 +02:00
}
2011-06-26 19:23:24 +02:00
}
2012-05-14 19:07:52 +02:00
assert ( vchPubKey . IsValid ( ) ) ;
2013-04-25 19:30:28 +02:00
pubkey = vchPubKey ;
return true ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : KeepKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > KeepKey ( nIndex ) ;
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
vchPubKey = CPubKey ( ) ;
2011-06-26 19:23:24 +02:00
}
void CReserveKey : : ReturnKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > ReturnKey ( nIndex ) ;
nIndex = - 1 ;
2012-05-14 19:07:52 +02:00
vchPubKey = CPubKey ( ) ;
2011-06-26 19:23:24 +02:00
}
2011-07-07 15:22:54 +02:00
2013-04-29 19:50:40 +02:00
void CWallet : : GetAllReserveKeys ( set < CKeyID > & setAddress ) const
2011-07-11 21:49:45 +02:00
{
setAddress . clear ( ) ;
CWalletDB walletdb ( strWalletFile ) ;
2012-04-06 18:39:12 +02:00
LOCK2 ( cs_main , cs_wallet ) ;
2013-04-13 07:13:08 +02:00
BOOST_FOREACH ( const int64_t & id , setKeyPool )
2011-07-11 21:49:45 +02:00
{
CKeyPool keypool ;
if ( ! walletdb . ReadPool ( id , keypool ) )
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
2015-02-02 13:06:43 +01:00
bool CWallet : : UpdatedTransaction ( const uint256 & hashTx )
2012-05-05 16:07:14 +02:00
{
{
LOCK ( cs_wallet ) ;
// Only notify UI if this transaction is in this wallet
map < uint256 , CWalletTx > : : const_iterator mi = mapWallet . find ( hashTx ) ;
2015-02-02 13:06:43 +01:00
if ( mi ! = mapWallet . end ( ) ) {
2012-05-05 16:07:14 +02:00
NotifyTransactionChanged ( this , hashTx , CT_UPDATED ) ;
2015-02-02 13:06:43 +01:00
return true ;
}
2012-05-05 16:07:14 +02:00
}
2015-02-02 13:06:43 +01:00
return false ;
2012-05-05 16:07:14 +02:00
}
2012-09-27 19:52:09 +02:00
void CWallet : : LockCoin ( COutPoint & output )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . insert ( output ) ;
}
void CWallet : : UnlockCoin ( COutPoint & output )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . erase ( output ) ;
}
void CWallet : : UnlockAllCoins ( )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
setLockedCoins . clear ( ) ;
}
bool CWallet : : IsLockedCoin ( uint256 hash , unsigned int n ) const
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
COutPoint outpt ( hash , n ) ;
return ( setLockedCoins . count ( outpt ) > 0 ) ;
}
void CWallet : : ListLockedCoins ( std : : vector < COutPoint > & vOutpts )
{
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // setLockedCoins
2012-09-27 19:52:09 +02:00
for ( std : : set < COutPoint > : : iterator it = setLockedCoins . begin ( ) ;
it ! = setLockedCoins . end ( ) ; it + + ) {
COutPoint outpt = ( * it ) ;
vOutpts . push_back ( outpt ) ;
}
}
2014-10-26 08:03:12 +01:00
/** @} */ // end of Actions
2014-08-27 17:46:30 +02:00
class CAffectedKeysVisitor : public boost : : static_visitor < void > {
private :
const CKeyStore & keystore ;
std : : vector < CKeyID > & vKeys ;
public :
CAffectedKeysVisitor ( const CKeyStore & keystoreIn , std : : vector < CKeyID > & vKeysIn ) : keystore ( keystoreIn ) , vKeys ( vKeysIn ) { }
void Process ( const CScript & script ) {
txnouttype type ;
std : : vector < CTxDestination > vDest ;
int nRequired ;
if ( ExtractDestinations ( script , type , vDest , nRequired ) ) {
BOOST_FOREACH ( const CTxDestination & dest , vDest )
boost : : apply_visitor ( * this , dest ) ;
}
}
void operator ( ) ( const CKeyID & keyId ) {
if ( keystore . HaveKey ( keyId ) )
vKeys . push_back ( keyId ) ;
}
void operator ( ) ( const CScriptID & scriptId ) {
CScript script ;
if ( keystore . GetCScript ( scriptId , script ) )
Process ( script ) ;
}
void operator ( ) ( const CNoDestination & none ) { }
} ;
2013-04-13 07:13:08 +02:00
void CWallet : : GetKeyBirthTimes ( std : : map < CKeyID , int64_t > & mapKeyBirth ) const {
2013-12-12 08:07:59 +01:00
AssertLockHeld ( cs_wallet ) ; // mapKeyMetadata
2013-04-29 19:50:40 +02:00
mapKeyBirth . clear ( ) ;
// get birth times for keys with metadata
for ( std : : map < CKeyID , CKeyMetadata > : : const_iterator it = mapKeyMetadata . begin ( ) ; it ! = mapKeyMetadata . end ( ) ; it + + )
if ( it - > second . nCreateTime )
mapKeyBirth [ it - > first ] = it - > second . nCreateTime ;
// map in which we'll infer heights of other keys
2013-10-10 23:07:44 +02:00
CBlockIndex * pindexMax = chainActive [ std : : max ( 0 , chainActive . Height ( ) - 144 ) ] ; // the tip can be reorganised; use a 144-block safety margin
2013-04-29 19:50:40 +02:00
std : : map < CKeyID , CBlockIndex * > mapKeyFirstBlock ;
std : : set < CKeyID > setKeys ;
GetKeys ( setKeys ) ;
BOOST_FOREACH ( const CKeyID & keyid , setKeys ) {
if ( mapKeyBirth . count ( keyid ) = = 0 )
mapKeyFirstBlock [ keyid ] = pindexMax ;
}
setKeys . clear ( ) ;
// if there are no such keys, we're done
if ( mapKeyFirstBlock . empty ( ) )
return ;
// find first block that affects those keys, if there are any left
std : : vector < CKeyID > vAffected ;
for ( std : : map < uint256 , CWalletTx > : : const_iterator it = mapWallet . begin ( ) ; it ! = mapWallet . end ( ) ; it + + ) {
// iterate over all wallet transactions...
const CWalletTx & wtx = ( * it ) . second ;
2014-09-04 02:02:44 +02:00
BlockMap : : const_iterator blit = mapBlockIndex . find ( wtx . hashBlock ) ;
2013-10-10 23:07:44 +02:00
if ( blit ! = mapBlockIndex . end ( ) & & chainActive . Contains ( blit - > second ) ) {
2013-04-29 19:50:40 +02:00
// ... which are already in a block
int nHeight = blit - > second - > nHeight ;
BOOST_FOREACH ( const CTxOut & txout , wtx . vout ) {
// iterate over all their outputs
2014-08-27 17:46:30 +02:00
CAffectedKeysVisitor ( * this , vAffected ) . Process ( txout . scriptPubKey ) ;
2013-04-29 19:50:40 +02:00
BOOST_FOREACH ( const CKeyID & keyid , vAffected ) {
// ... and all their affected keys
std : : map < CKeyID , CBlockIndex * > : : iterator rit = mapKeyFirstBlock . find ( keyid ) ;
if ( rit ! = mapKeyFirstBlock . end ( ) & & nHeight < rit - > second - > nHeight )
rit - > second = blit - > second ;
}
vAffected . clear ( ) ;
}
}
}
// Extract block timestamps for those keys
for ( std : : map < CKeyID , CBlockIndex * > : : const_iterator it = mapKeyFirstBlock . begin ( ) ; it ! = mapKeyFirstBlock . end ( ) ; it + + )
2014-06-28 23:36:06 +02:00
mapKeyBirth [ it - > first ] = it - > second - > GetBlockTime ( ) - 7200 ; // block times can be 2h off
2013-04-29 19:50:40 +02:00
}
2013-11-18 16:55:54 +01:00
bool CWallet : : AddDestData ( const CTxDestination & dest , const std : : string & key , const std : : string & value )
{
2014-01-14 05:05:43 +01:00
if ( boost : : get < CNoDestination > ( & dest ) )
return false ;
2013-11-18 16:55:54 +01:00
mapAddressBook [ dest ] . destdata . insert ( std : : make_pair ( key , value ) ) ;
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . WriteDestData ( CBitcoinAddress ( dest ) . ToString ( ) , key , value ) ;
}
bool CWallet : : EraseDestData ( const CTxDestination & dest , const std : : string & key )
{
if ( ! mapAddressBook [ dest ] . destdata . erase ( key ) )
return false ;
if ( ! fFileBacked )
return true ;
return CWalletDB ( strWalletFile ) . EraseDestData ( CBitcoinAddress ( dest ) . ToString ( ) , key ) ;
}
bool CWallet : : LoadDestData ( const CTxDestination & dest , const std : : string & key , const std : : string & value )
{
mapAddressBook [ dest ] . destdata . insert ( std : : make_pair ( key , value ) ) ;
return true ;
}
bool CWallet : : GetDestData ( const CTxDestination & dest , const std : : string & key , std : : string * value ) const
{
std : : map < CTxDestination , CAddressBookData > : : const_iterator i = mapAddressBook . find ( dest ) ;
if ( i ! = mapAddressBook . end ( ) )
{
CAddressBookData : : StringMap : : const_iterator j = i - > second . destdata . find ( key ) ;
if ( j ! = i - > second . destdata . end ( ) )
{
if ( value )
* value = j - > second ;
return true ;
}
}
return false ;
}
2014-08-21 05:04:43 +02:00
CKeyPool : : CKeyPool ( )
{
nTime = GetTime ( ) ;
}
CKeyPool : : CKeyPool ( const CPubKey & vchPubKeyIn )
{
nTime = GetTime ( ) ;
vchPubKey = vchPubKeyIn ;
}
CWalletKey : : CWalletKey ( int64_t nExpires )
{
nTimeCreated = ( nExpires ? GetTime ( ) : 0 ) ;
nTimeExpires = nExpires ;
}
2014-08-28 17:15:21 +02:00
2014-08-29 20:24:16 +02:00
int CMerkleTx : : SetMerkleBranch ( const CBlock & block )
2014-08-28 17:15:21 +02:00
{
AssertLockHeld ( cs_main ) ;
CBlock blockTmp ;
2014-08-29 20:24:16 +02:00
// Update the tx's hashBlock
hashBlock = block . GetHash ( ) ;
2014-08-28 17:15:21 +02:00
2014-08-29 20:24:16 +02:00
// Locate the transaction
for ( nIndex = 0 ; nIndex < ( int ) block . vtx . size ( ) ; nIndex + + )
if ( block . vtx [ nIndex ] = = * ( CTransaction * ) this )
break ;
if ( nIndex = = ( int ) block . vtx . size ( ) )
{
vMerkleBranch . clear ( ) ;
nIndex = - 1 ;
LogPrintf ( " ERROR: SetMerkleBranch() : couldn't find tx in block \n " ) ;
return 0 ;
2014-08-28 17:15:21 +02:00
}
2014-08-29 20:24:16 +02:00
// Fill in merkle branch
vMerkleBranch = block . GetMerkleBranch ( nIndex ) ;
2014-08-28 17:15:21 +02:00
// Is the tx in a block that's in the main chain
2014-09-04 02:02:44 +02:00
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
2014-08-28 17:15:21 +02:00
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
2014-08-29 20:24:16 +02:00
const CBlockIndex * pindex = ( * mi ) . second ;
2014-08-28 17:15:21 +02:00
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
return 0 ;
return chainActive . Height ( ) - pindex - > nHeight + 1 ;
}
2014-10-24 16:13:41 +02:00
int CMerkleTx : : GetDepthInMainChainINTERNAL ( const CBlockIndex * & pindexRet ) const
2014-08-28 17:15:21 +02:00
{
if ( hashBlock = = 0 | | nIndex = = - 1 )
return 0 ;
AssertLockHeld ( cs_main ) ;
// Find the block it claims to be in
2014-09-04 02:02:44 +02:00
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
2014-08-28 17:15:21 +02:00
if ( mi = = mapBlockIndex . end ( ) )
return 0 ;
CBlockIndex * pindex = ( * mi ) . second ;
if ( ! pindex | | ! chainActive . Contains ( pindex ) )
return 0 ;
// Make sure the merkle branch connects to this block
if ( ! fMerkleVerified )
{
if ( CBlock : : CheckMerkleBranch ( GetHash ( ) , vMerkleBranch , nIndex ) ! = pindex - > hashMerkleRoot )
return 0 ;
fMerkleVerified = true ;
}
pindexRet = pindex ;
return chainActive . Height ( ) - pindex - > nHeight + 1 ;
}
2015-04-03 00:51:08 +02:00
int CMerkleTx : : GetDepthInMainChain ( const CBlockIndex * & pindexRet , bool enableIX ) const
2014-08-28 17:15:21 +02:00
{
AssertLockHeld ( cs_main ) ;
int nResult = GetDepthInMainChainINTERNAL ( pindexRet ) ;
if ( nResult = = 0 & & ! mempool . exists ( GetHash ( ) ) )
return - 1 ; // Not in chain, not in mempool
2015-04-03 00:51:08 +02:00
if ( enableIX ) {
if ( nResult < 6 ) {
int signatures = GetTransactionLockSignatures ( ) ;
if ( signatures > = INSTANTX_SIGNATURES_REQUIRED ) {
return nInstantXDepth + nResult ;
}
}
}
2014-08-28 17:15:21 +02:00
return nResult ;
}
int CMerkleTx : : GetBlocksToMaturity ( ) const
{
if ( ! IsCoinBase ( ) )
return 0 ;
return max ( 0 , ( COINBASE_MATURITY + 1 ) - GetDepthInMainChain ( ) ) ;
}
2015-06-23 06:12:24 +02:00
bool CMerkleTx : : AcceptToMemoryPool ( bool fLimitFree , bool fRejectInsaneFee , bool ignoreFees )
2014-08-28 17:15:21 +02:00
{
CValidationState state ;
2015-06-23 06:12:24 +02:00
return : : AcceptToMemoryPool ( mempool , state , * this , fLimitFree , NULL , fRejectInsaneFee , ignoreFees ) ;
2014-08-28 17:15:21 +02:00
}
2015-04-03 00:51:08 +02:00
int CMerkleTx : : GetTransactionLockSignatures ( ) const
{
if ( fLargeWorkForkFound | | fLargeWorkInvalidChainFound ) return - 2 ;
if ( ! IsSporkActive ( SPORK_2_INSTANTX ) ) return - 3 ;
2015-09-11 20:19:14 +02:00
if ( ! fEnableInstantX ) return - 1 ;
2015-04-03 00:51:08 +02:00
//compile consessus vote
std : : map < uint256 , CTransactionLock > : : iterator i = mapTxLocks . find ( GetHash ( ) ) ;
if ( i ! = mapTxLocks . end ( ) ) {
return ( * i ) . second . CountSignatures ( ) ;
}
return - 1 ;
}
bool CMerkleTx : : IsTransactionLockTimedOut ( ) const
{
2015-09-11 20:19:14 +02:00
if ( ! fEnableInstantX ) return 0 ;
2015-04-03 00:51:08 +02:00
//compile consessus vote
std : : map < uint256 , CTransactionLock > : : iterator i = mapTxLocks . find ( GetHash ( ) ) ;
if ( i ! = mapTxLocks . end ( ) ) {
return GetTime ( ) > ( * i ) . second . nTimeout ;
}
return false ;
}