@ -49,6 +49,9 @@ CPubKey CWallet::GenerateNewKey(std::string username)
if ( ! AddKeyPubKey ( secret , pubkey ) )
if ( ! AddKeyPubKey ( secret , pubkey ) )
throw std : : runtime_error ( " CWallet::GenerateNewKey() : AddKey failed " ) ;
throw std : : runtime_error ( " CWallet::GenerateNewKey() : AddKey failed " ) ;
if ( ! vchDefaultKey . IsValid ( ) )
vchDefaultKey = pubkey ;
return pubkey ;
return pubkey ;
}
}
@ -683,253 +686,6 @@ void CWallet::ResendWalletTransactions()
// Actions
// Actions
//
//
bool CWallet : : CreateTransaction ( const vector < pair < CScript , int64 > > & vecSend ,
CWalletTx & wtxNew , CReserveKey & reservekey , int64 & nFeeRet , std : : string & strFailReason )
{
int64 nValue = 0 ;
BOOST_FOREACH ( const PAIRTYPE ( CScript , int64 ) & s , vecSend )
{
if ( nValue < 0 )
{
strFailReason = _ ( " Transaction amounts must be positive " ) ;
return false ;
}
nValue + = s . second ;
}
if ( vecSend . empty ( ) | | nValue < 0 )
{
strFailReason = _ ( " Transaction amounts must be positive " ) ;
return false ;
}
wtxNew . BindWallet ( this ) ;
{
LOCK2 ( cs_main , cs_wallet ) ;
{
nFeeRet = nTransactionFee ;
/*
loop
{
wtxNew . vin . clear ( ) ;
wtxNew . vout . clear ( ) ;
wtxNew . fFromMe = true ;
int64 nTotalValue = nValue + nFeeRet ;
double dPriority = 0 ;
// vouts to the payees
BOOST_FOREACH ( const PAIRTYPE ( CScript , int64 ) & s , vecSend )
{
CTxOut txout ( s . second , s . first ) ;
if ( txout . IsDust ( CTransaction : : nMinRelayTxFee ) )
{
strFailReason = _ ( " Transaction amount too small " ) ;
return false ;
}
wtxNew . vout . push_back ( txout ) ;
}
// Choose coins to use
set < pair < const CWalletTx * , unsigned int > > setCoins ;
int64 nValueIn = 0 ;
if ( ! SelectCoins ( nTotalValue , setCoins , nValueIn ) )
{
strFailReason = _ ( " Insufficient funds " ) ;
return false ;
}
BOOST_FOREACH ( PAIRTYPE ( const CWalletTx * , unsigned int ) pcoin , setCoins )
{
int64 nCredit = pcoin . first - > vout [ pcoin . second ] . nValue ;
//The priority after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
dPriority + = ( double ) nCredit * ( pcoin . first - > GetDepthInMainChain ( ) + 1 ) ;
}
int64 nChange = nValueIn - nValue - nFeeRet ;
// if sub-cent change is required, the fee must be raised to at least nMinTxFee
// or until nChange becomes zero
// NOTE: this depends on the exact behaviour of GetMinFee
if ( nFeeRet < CTransaction : : nMinTxFee & & nChange > 0 & & nChange < CENT )
{
int64 nMoveToFee = min ( nChange , CTransaction : : nMinTxFee - nFeeRet ) ;
nChange - = nMoveToFee ;
nFeeRet + = nMoveToFee ;
}
if ( nChange > 0 )
{
// 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 ;
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
// Fill a vout to ourself
// TODO: pass in scriptChange instead of reservekey so
// change transaction isn't always pay-to-bitcoin-address
CScript scriptChange ;
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
CTxOut newTxOut ( nChange , scriptChange ) ;
// Never create dust outputs; if we would, just
// add the dust to the fee.
if ( newTxOut . IsDust ( CTransaction : : nMinRelayTxFee ) )
{
nFeeRet + = nChange ;
reservekey . ReturnKey ( ) ;
}
else
{
// Insert change txn at random position:
vector < CTxOut > : : iterator position = wtxNew . vout . begin ( ) + GetRandInt ( wtxNew . vout . size ( ) + 1 ) ;
wtxNew . vout . insert ( position , newTxOut ) ;
}
}
else
reservekey . ReturnKey ( ) ;
// Fill vin
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
wtxNew . vin . push_back ( CTxIn ( coin . first - > GetHash ( ) , coin . second ) ) ;
// Sign
int nIn = 0 ;
BOOST_FOREACH ( const PAIRTYPE ( const CWalletTx * , unsigned int ) & coin , setCoins )
if ( ! SignSignature ( * this , * coin . first , wtxNew , nIn + + ) )
{
strFailReason = _ ( " Signing transaction failed " ) ;
return false ;
}
// Limit size
unsigned int nBytes = : : GetSerializeSize ( * ( CTransaction * ) & wtxNew , SER_NETWORK , PROTOCOL_VERSION ) ;
if ( nBytes > = MAX_STANDARD_TX_SIZE )
{
strFailReason = _ ( " Transaction too large " ) ;
return false ;
}
dPriority / = nBytes ;
// Check that enough fee is included
int64 nPayFee = nTransactionFee * ( 1 + ( int64 ) nBytes / 1000 ) ;
bool fAllowFree = AllowFree ( dPriority ) ;
int64 nMinFee = GetMinFee ( wtxNew , fAllowFree , GMF_SEND ) ;
if ( nFeeRet < max ( nPayFee , nMinFee ) )
{
nFeeRet = max ( nPayFee , nMinFee ) ;
continue ;
}
// Fill vtxPrev by copying from previous transactions vtxPrev
wtxNew . AddSupportingTransactions ( ) ;
wtxNew . fTimeReceivedIsTxTime = true ;
break ;
}
*/
}
}
return true ;
}
bool CWallet : : CreateTransaction ( CScript scriptPubKey , int64 nValue ,
CWalletTx & wtxNew , CReserveKey & reservekey , int64 & nFeeRet , std : : string & strFailReason )
{
vector < pair < CScript , int64 > > vecSend ;
vecSend . push_back ( make_pair ( scriptPubKey , nValue ) ) ;
return CreateTransaction ( vecSend , wtxNew , reservekey , nFeeRet , strFailReason ) ;
}
// Call after CreateTransaction unless you want to abort
bool CWallet : : CommitTransaction ( CWalletTx & wtxNew , CReserveKey & reservekey )
{
{
LOCK2 ( cs_main , cs_wallet ) ;
printf ( " CommitTransaction: \n %s " , wtxNew . ToString ( ) . c_str ( ) ) ;
{
// 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 ) ;
// Mark old coins as spent
set < CWalletTx * > setCoins ;
/*
BOOST_FOREACH ( const CTxIn & txin , wtxNew . vin )
{
CWalletTx & coin = mapWallet [ txin . prevout . hash ] ;
coin . BindWallet ( this ) ;
coin . MarkSpent ( txin . prevout . n ) ;
coin . WriteToDisk ( ) ;
NotifyTransactionChanged ( this , coin . GetHash ( ) , CT_UPDATED ) ;
}
*/
if ( fFileBacked )
delete pwalletdb ;
}
// Track how many getdata requests our transaction gets
mapRequestCount [ wtxNew . GetHash ( ) ] = 0 ;
// Broadcast
if ( ! wtxNew . AcceptToMemoryPool ( false ) )
{
// This must not fail. The transaction has already been signed and recorded.
printf ( " CommitTransaction() : Error: Transaction not valid " ) ;
return false ;
}
wtxNew . RelayWalletTransaction ( ) ;
}
return true ;
}
string CWallet : : SendMoney ( CScript scriptPubKey , int64 nValue , CWalletTx & wtxNew , bool fAskFee )
{
CReserveKey reservekey ( this ) ;
int64 nFeeRequired ;
if ( IsLocked ( ) )
{
string strError = _ ( " Error: Wallet locked, unable to create transaction! " ) ;
printf ( " SendMoney() : %s " , strError . c_str ( ) ) ;
return strError ;
}
string strError ;
if ( ! CreateTransaction ( scriptPubKey , nValue , wtxNew , reservekey , nFeeRequired , strError ) )
{
printf ( " SendMoney() : %s \n " , strError . c_str ( ) ) ;
return strError ;
}
if ( fAskFee & & ! uiInterface . ThreadSafeAskFee ( nFeeRequired ) )
return " ABORTED " ;
if ( ! CommitTransaction ( wtxNew , reservekey ) )
return _ ( " Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here. " ) ;
return " " ;
}
DBErrors CWallet : : LoadWallet ( bool & fFirstRunRet )
DBErrors CWallet : : LoadWallet ( bool & fFirstRunRet )
{
{
if ( ! fFileBacked )
if ( ! fFileBacked )
@ -955,24 +711,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
}
bool CWallet : : SetAddressBookName ( const CTxDestination & address , const string & strName )
{
std : : map < CTxDestination , std : : string > : : iterator mi = mapAddressBook . find ( address ) ;
mapAddressBook [ address ] = strName ;
NotifyAddressBookChanged ( this , address , strName , : : IsMine ( * this , address ) , ( mi = = mapAddressBook . end ( ) ) ? CT_NEW : CT_UPDATED ) ;
if ( ! fFileBacked )
return false ;
return CWalletDB ( strWalletFile ) . WriteName ( CBitcoinAddress ( address ) . ToString ( ) , strName ) ;
}
bool CWallet : : DelAddressBookName ( const CTxDestination & address )
{
mapAddressBook . erase ( address ) ;
NotifyAddressBookChanged ( this , address , " " , : : IsMine ( * this , address ) , CT_DELETED ) ;
if ( ! fFileBacked )
return false ;
return CWalletDB ( strWalletFile ) . EraseName ( CBitcoinAddress ( address ) . ToString ( ) ) ;
}
bool CWallet : : SetDefaultKey ( const CPubKey & vchPubKey )
bool CWallet : : SetDefaultKey ( const CPubKey & vchPubKey )
@ -995,253 +733,6 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
}
}
void CWallet : : ReserveKeyFromKeyPool ( int64 & nIndex , CKeyPool & keypool )
{
nIndex = - 1 ;
keypool . vchPubKey = CPubKey ( ) ;
{
LOCK ( cs_wallet ) ;
// Get the oldest key
if ( setKeyPool . empty ( ) )
return ;
CWalletDB walletdb ( strWalletFile ) ;
nIndex = * ( setKeyPool . begin ( ) ) ;
setKeyPool . erase ( setKeyPool . begin ( ) ) ;
if ( ! walletdb . ReadPool ( nIndex , keypool ) )
throw runtime_error ( " ReserveKeyFromKeyPool() : read failed " ) ;
if ( ! HaveKey ( keypool . vchPubKey . GetID ( ) ) )
throw runtime_error ( " ReserveKeyFromKeyPool() : unknown key in key pool " ) ;
assert ( keypool . vchPubKey . IsValid ( ) ) ;
printf ( " keypool reserve % " PRI64d " \n " , nIndex ) ;
}
}
int64 CWallet : : AddReserveKey ( const CKeyPool & keypool )
{
{
LOCK2 ( cs_main , cs_wallet ) ;
CWalletDB walletdb ( strWalletFile ) ;
int64 nIndex = 1 + * ( - - setKeyPool . end ( ) ) ;
if ( ! walletdb . WritePool ( nIndex , keypool ) )
throw runtime_error ( " AddReserveKey() : writing added key failed " ) ;
setKeyPool . insert ( nIndex ) ;
return nIndex ;
}
return - 1 ;
}
void CWallet : : KeepKey ( int64 nIndex )
{
// Remove from key pool
if ( fFileBacked )
{
CWalletDB walletdb ( strWalletFile ) ;
walletdb . ErasePool ( nIndex ) ;
}
printf ( " keypool keep % " PRI64d " \n " , nIndex ) ;
}
void CWallet : : ReturnKey ( int64 nIndex )
{
// Return to key pool
{
LOCK ( cs_wallet ) ;
setKeyPool . insert ( nIndex ) ;
}
printf ( " keypool return % " PRI64d " \n " , nIndex ) ;
}
bool CWallet : : GetKeyFromPool ( CPubKey & result , bool fAllowReuse )
{
/* [MF] pool is going to die.
int64 nIndex = 0 ;
CKeyPool keypool ;
{
LOCK ( cs_wallet ) ;
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
if ( nIndex = = - 1 )
{
if ( fAllowReuse & & vchDefaultKey . IsValid ( ) )
{
result = vchDefaultKey ;
return true ;
}
if ( IsLocked ( ) ) return false ;
result = GenerateNewKey ( ) ;
return true ;
}
KeepKey ( nIndex ) ;
result = keypool . vchPubKey ;
}
return true ;
*/
return false ;
}
int64 CWallet : : GetOldestKeyPoolTime ( )
{
int64 nIndex = 0 ;
CKeyPool keypool ;
ReserveKeyFromKeyPool ( nIndex , keypool ) ;
if ( nIndex = = - 1 )
return GetTime ( ) ;
ReturnKey ( nIndex ) ;
return keypool . nTime ;
}
set < set < CTxDestination > > CWallet : : GetAddressGroupings ( )
{
set < set < CTxDestination > > groupings ;
set < CTxDestination > grouping ;
BOOST_FOREACH ( PAIRTYPE ( uint256 , CWalletTx ) walletEntry , mapWallet )
{
CWalletTx * pcoin = & walletEntry . second ;
/*
if ( pcoin - > vin . size ( ) > 0 )
{
bool any_mine = false ;
// group all input addresses with each other
BOOST_FOREACH ( CTxIn txin , pcoin - > vin )
{
CTxDestination address ;
if ( ! IsMine ( txin ) )
continue ;
if ( ! ExtractDestination ( mapWallet [ txin . prevout . hash ] . vout [ txin . prevout . n ] . scriptPubKey , address ) )
continue ;
grouping . insert ( address ) ;
any_mine = true ;
}
// group change with input addresses
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 ( ) ;
}
}
// group lone addrs by themselves
for ( unsigned int i = 0 ; i < pcoin - > vout . size ( ) ; i + + )
if ( IsMine ( pcoin - > vout [ i ] ) )
{
CTxDestination address ;
if ( ! ExtractDestination ( pcoin - > vout [ i ] . scriptPubKey , address ) )
continue ;
grouping . insert ( address ) ;
groupings . insert ( grouping ) ;
grouping . clear ( ) ;
}
*/
}
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 )
{
// make a set of all the groups hit by this new group
set < set < CTxDestination > * > hits ;
map < CTxDestination , set < CTxDestination > * > : : iterator it ;
BOOST_FOREACH ( CTxDestination address , grouping )
if ( ( it = setmap . find ( address ) ) ! = setmap . end ( ) )
hits . insert ( ( * it ) . second ) ;
// merge all hit groups into a new single group and delete old groups
set < CTxDestination > * merged = new set < CTxDestination > ( grouping ) ;
BOOST_FOREACH ( set < CTxDestination > * hit , hits )
{
merged - > insert ( hit - > begin ( ) , hit - > end ( ) ) ;
uniqueGroupings . erase ( hit ) ;
delete hit ;
}
uniqueGroupings . insert ( merged ) ;
// update setmap
BOOST_FOREACH ( CTxDestination element , * merged )
setmap [ element ] = merged ;
}
set < set < CTxDestination > > ret ;
BOOST_FOREACH ( set < CTxDestination > * uniqueGrouping , uniqueGroupings )
{
ret . insert ( * uniqueGrouping ) ;
delete uniqueGrouping ;
}
return ret ;
}
bool CReserveKey : : GetReservedKey ( CPubKey & pubkey )
{
if ( nIndex = = - 1 )
{
CKeyPool keypool ;
pwallet - > ReserveKeyFromKeyPool ( nIndex , keypool ) ;
if ( nIndex ! = - 1 )
vchPubKey = keypool . vchPubKey ;
else {
if ( pwallet - > vchDefaultKey . IsValid ( ) ) {
printf ( " CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool! " ) ;
vchPubKey = pwallet - > vchDefaultKey ;
} else
return false ;
}
}
assert ( vchPubKey . IsValid ( ) ) ;
pubkey = vchPubKey ;
return true ;
}
void CReserveKey : : KeepKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > KeepKey ( nIndex ) ;
nIndex = - 1 ;
vchPubKey = CPubKey ( ) ;
}
void CReserveKey : : ReturnKey ( )
{
if ( nIndex ! = - 1 )
pwallet - > ReturnKey ( nIndex ) ;
nIndex = - 1 ;
vchPubKey = CPubKey ( ) ;
}
void CWallet : : GetAllReserveKeys ( set < CKeyID > & setAddress ) const
{
setAddress . clear ( ) ;
CWalletDB walletdb ( strWalletFile ) ;
LOCK2 ( cs_main , cs_wallet ) ;
BOOST_FOREACH ( const int64 & id , setKeyPool )
{
CKeyPool keypool ;
if ( ! walletdb . ReadPool ( id , keypool ) )
throw runtime_error ( " GetAllReserveKeyHashes() : read failed " ) ;
assert ( keypool . vchPubKey . IsValid ( ) ) ;
CKeyID keyID = keypool . vchPubKey . GetID ( ) ;
if ( ! HaveKey ( keyID ) )
throw runtime_error ( " GetAllReserveKeyHashes() : unknown key in key pool " ) ;
setAddress . insert ( keyID ) ;
}
}
void CWallet : : UpdatedTransaction ( const uint256 & hashTx )
void CWallet : : UpdatedTransaction ( const uint256 & hashTx )
{
{