raw
experimental-genesis    1 //  /****************************\
experimental-genesis 2 // * EXPERIMENTAL BRANCH. *
experimental-genesis 3 // * FOR LABORATORY USE ONLY. *
experimental-genesis 4 // ********************************
experimental-genesis 5 // ************
experimental-genesis 6 // **************
experimental-genesis 7 // ****************
experimental-genesis 8 // **** **** ****
experimental-genesis 9 // *** *** ***
experimental-genesis 10 // *** *** ***
experimental-genesis 11 // *** * * **
experimental-genesis 12 // ******** ********
experimental-genesis 13 // ******* ******
experimental-genesis 14 // *** **
experimental-genesis 15 // * ******* **
experimental-genesis 16 // ** * * * * *
experimental-genesis 17 // ** * * ***
experimental-genesis 18 // **** * * * * ****
experimental-genesis 19 // **** *** * * ** ***
experimental-genesis 20 // **** ********* ******
experimental-genesis 21 // ******* ***** *******
experimental-genesis 22 // ********* ****** **
experimental-genesis 23 // ** ****** ******
experimental-genesis 24 // ** ******* **
experimental-genesis 25 // ** ******* ***
experimental-genesis 26 // **** ******** ************
experimental-genesis 27 // ************ ************
experimental-genesis 28 // ******** *******
experimental-genesis 29 // ****** ****
experimental-genesis 30 // *** ***
experimental-genesis 31 // ********************************
experimental-genesis 32 // Copyright (c) 2009-2010 Satoshi Nakamoto
experimental-genesis 33 // Copyright (c) 2011 The Bitcoin developers
experimental-genesis 34 // Distributed under the MIT/X11 software license, see the accompanying
experimental-genesis 35 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
experimental-genesis 36
experimental-genesis 37 #include "headers.h"
experimental-genesis 38 #include "db.h"
experimental-genesis 39 #include "crypter.h"
experimental-genesis 40
experimental-genesis 41 using namespace std;
experimental-genesis 42
experimental-genesis 43
experimental-genesis 44 //////////////////////////////////////////////////////////////////////////////
experimental-genesis 45 //
experimental-genesis 46 // mapWallet
experimental-genesis 47 //
experimental-genesis 48
experimental-genesis 49 bool CWallet::AddKey(const CKey& key)
experimental-genesis 50 {
experimental-genesis 51 if (!CCryptoKeyStore::AddKey(key))
experimental-genesis 52 return false;
experimental-genesis 53 if (!fFileBacked)
experimental-genesis 54 return true;
experimental-genesis 55 if (!IsCrypted())
experimental-genesis 56 return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
experimental-genesis 57 return true;
experimental-genesis 58 }
experimental-genesis 59
experimental-genesis 60 bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
experimental-genesis 61 {
experimental-genesis 62 if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
experimental-genesis 63 return false;
experimental-genesis 64 if (!fFileBacked)
experimental-genesis 65 return true;
experimental-genesis 66 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 67 {
experimental-genesis 68 if (pwalletdbEncryption)
experimental-genesis 69 return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
experimental-genesis 70 else
experimental-genesis 71 return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
experimental-genesis 72 }
experimental-genesis 73 return false;
experimental-genesis 74 }
experimental-genesis 75
experimental-genesis 76 bool CWallet::Unlock(const SecureString& strWalletPassphrase)
experimental-genesis 77 {
experimental-genesis 78 if (!IsLocked())
experimental-genesis 79 return false;
experimental-genesis 80
experimental-genesis 81 CCrypter crypter;
experimental-genesis 82 CKeyingMaterial vMasterKey;
experimental-genesis 83
experimental-genesis 84 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 85 BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
experimental-genesis 86 {
experimental-genesis 87 if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
experimental-genesis 88 return false;
experimental-genesis 89 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
experimental-genesis 90 return false;
experimental-genesis 91 if (CCryptoKeyStore::Unlock(vMasterKey))
experimental-genesis 92 return true;
experimental-genesis 93 }
experimental-genesis 94 return false;
experimental-genesis 95 }
experimental-genesis 96
experimental-genesis 97 bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase)
experimental-genesis 98 {
experimental-genesis 99 bool fWasLocked = IsLocked();
experimental-genesis 100
experimental-genesis 101 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 102 {
experimental-genesis 103 Lock();
experimental-genesis 104
experimental-genesis 105 CCrypter crypter;
experimental-genesis 106 CKeyingMaterial vMasterKey;
experimental-genesis 107 BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
experimental-genesis 108 {
experimental-genesis 109 if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
experimental-genesis 110 return false;
experimental-genesis 111 if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
experimental-genesis 112 return false;
experimental-genesis 113 if (CCryptoKeyStore::Unlock(vMasterKey))
experimental-genesis 114 {
experimental-genesis 115 int64 nStartTime = GetTimeMillis();
experimental-genesis 116 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
experimental-genesis 117 pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
experimental-genesis 118
experimental-genesis 119 nStartTime = GetTimeMillis();
experimental-genesis 120 crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
experimental-genesis 121 pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
experimental-genesis 122
experimental-genesis 123 if (pMasterKey.second.nDeriveIterations < 25000)
experimental-genesis 124 pMasterKey.second.nDeriveIterations = 25000;
experimental-genesis 125
experimental-genesis 126 printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
experimental-genesis 127
experimental-genesis 128 if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
experimental-genesis 129 return false;
experimental-genesis 130 if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
experimental-genesis 131 return false;
experimental-genesis 132 CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
experimental-genesis 133 if (fWasLocked)
experimental-genesis 134 Lock();
experimental-genesis 135 return true;
experimental-genesis 136 }
experimental-genesis 137 }
experimental-genesis 138 }
experimental-genesis 139
experimental-genesis 140 return false;
experimental-genesis 141 }
experimental-genesis 142
experimental-genesis 143
experimental-genesis 144 // This class implements an addrIncoming entry that causes pre-0.4
experimental-genesis 145 // clients to crash on startup if reading a private-key-encrypted wallet.
experimental-genesis 146 class CCorruptAddress
experimental-genesis 147 {
experimental-genesis 148 public:
experimental-genesis 149 IMPLEMENT_SERIALIZE
experimental-genesis 150 (
experimental-genesis 151 if (nType & SER_DISK)
experimental-genesis 152 READWRITE(nVersion);
experimental-genesis 153 )
experimental-genesis 154 };
experimental-genesis 155
experimental-genesis 156 bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
experimental-genesis 157 {
experimental-genesis 158 if (IsCrypted())
experimental-genesis 159 return false;
experimental-genesis 160
experimental-genesis 161 CKeyingMaterial vMasterKey;
experimental-genesis 162 RandAddSeedPerfmon();
experimental-genesis 163
experimental-genesis 164 vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
experimental-genesis 165 RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
experimental-genesis 166
experimental-genesis 167 CMasterKey kMasterKey;
experimental-genesis 168
experimental-genesis 169 RandAddSeedPerfmon();
experimental-genesis 170 kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
experimental-genesis 171 RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
experimental-genesis 172
experimental-genesis 173 CCrypter crypter;
experimental-genesis 174 int64 nStartTime = GetTimeMillis();
experimental-genesis 175 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
experimental-genesis 176 kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
experimental-genesis 177
experimental-genesis 178 nStartTime = GetTimeMillis();
experimental-genesis 179 crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
experimental-genesis 180 kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
experimental-genesis 181
experimental-genesis 182 if (kMasterKey.nDeriveIterations < 25000)
experimental-genesis 183 kMasterKey.nDeriveIterations = 25000;
experimental-genesis 184
experimental-genesis 185 printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
experimental-genesis 186
experimental-genesis 187 if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
experimental-genesis 188 return false;
experimental-genesis 189 if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
experimental-genesis 190 return false;
experimental-genesis 191
experimental-genesis 192 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 193 {
experimental-genesis 194 mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
experimental-genesis 195 if (fFileBacked)
experimental-genesis 196 {
experimental-genesis 197 pwalletdbEncryption = new CWalletDB(strWalletFile);
experimental-genesis 198 pwalletdbEncryption->TxnBegin();
experimental-genesis 199 pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
experimental-genesis 200 }
experimental-genesis 201
experimental-genesis 202 if (!EncryptKeys(vMasterKey))
experimental-genesis 203 {
experimental-genesis 204 if (fFileBacked)
experimental-genesis 205 pwalletdbEncryption->TxnAbort();
experimental-genesis 206 exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
experimental-genesis 207 }
experimental-genesis 208
experimental-genesis 209 if (fFileBacked)
experimental-genesis 210 {
experimental-genesis 211 CCorruptAddress corruptAddress;
experimental-genesis 212 pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
experimental-genesis 213 if (!pwalletdbEncryption->TxnCommit())
experimental-genesis 214 exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
experimental-genesis 215
experimental-genesis 216 delete pwalletdbEncryption;
experimental-genesis 217 pwalletdbEncryption = NULL;
experimental-genesis 218 }
experimental-genesis 219
experimental-genesis 220 Lock();
experimental-genesis 221 Unlock(strWalletPassphrase);
experimental-genesis 222 NewKeyPool();
experimental-genesis 223 Lock();
experimental-genesis 224
experimental-genesis 225 // Need to completely rewrite the wallet file; if we don't, bdb might keep
experimental-genesis 226 // bits of the unencrypted private key in slack space in the database file.
experimental-genesis 227 CDB::Rewrite(strWalletFile);
experimental-genesis 228 }
experimental-genesis 229
experimental-genesis 230 return true;
experimental-genesis 231 }
experimental-genesis 232
experimental-genesis 233 void CWallet::WalletUpdateSpent(const CTransaction &tx)
experimental-genesis 234 {
experimental-genesis 235 // Anytime a signature is successfully verified, it's proof the outpoint is spent.
experimental-genesis 236 // Update the wallet spent flag if it doesn't know due to wallet.dat being
experimental-genesis 237 // restored from backup or the user making copies of wallet.dat.
experimental-genesis 238 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 239 {
experimental-genesis 240 BOOST_FOREACH(const CTxIn& txin, tx.vin)
experimental-genesis 241 {
experimental-genesis 242 map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
experimental-genesis 243 if (mi != mapWallet.end())
experimental-genesis 244 {
experimental-genesis 245 CWalletTx& wtx = (*mi).second;
experimental-genesis 246 if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
experimental-genesis 247 {
experimental-genesis 248 printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
experimental-genesis 249 wtx.MarkSpent(txin.prevout.n);
experimental-genesis 250 wtx.WriteToDisk();
experimental-genesis 251 vWalletUpdated.push_back(txin.prevout.hash);
experimental-genesis 252 }
experimental-genesis 253 }
experimental-genesis 254 }
experimental-genesis 255 }
experimental-genesis 256 }
experimental-genesis 257
experimental-genesis 258 bool CWallet::AddToWallet(const CWalletTx& wtxIn)
experimental-genesis 259 {
experimental-genesis 260 uint256 hash = wtxIn.GetHash();
experimental-genesis 261 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 262 {
experimental-genesis 263 // Inserts only if not already there, returns tx inserted or tx found
experimental-genesis 264 pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
experimental-genesis 265 CWalletTx& wtx = (*ret.first).second;
experimental-genesis 266 wtx.pwallet = this;
experimental-genesis 267 bool fInsertedNew = ret.second;
experimental-genesis 268 if (fInsertedNew)
experimental-genesis 269 wtx.nTimeReceived = GetAdjustedTime();
experimental-genesis 270
experimental-genesis 271 bool fUpdated = false;
experimental-genesis 272 if (!fInsertedNew)
experimental-genesis 273 {
experimental-genesis 274 // Merge
experimental-genesis 275 if (wtxIn.hashBlock != 0 && wtxIn.hashBlock != wtx.hashBlock)
experimental-genesis 276 {
experimental-genesis 277 wtx.hashBlock = wtxIn.hashBlock;
experimental-genesis 278 fUpdated = true;
experimental-genesis 279 }
experimental-genesis 280 if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex))
experimental-genesis 281 {
experimental-genesis 282 wtx.vMerkleBranch = wtxIn.vMerkleBranch;
experimental-genesis 283 wtx.nIndex = wtxIn.nIndex;
experimental-genesis 284 fUpdated = true;
experimental-genesis 285 }
experimental-genesis 286 if (wtxIn.fFromMe && wtxIn.fFromMe != wtx.fFromMe)
experimental-genesis 287 {
experimental-genesis 288 wtx.fFromMe = wtxIn.fFromMe;
experimental-genesis 289 fUpdated = true;
experimental-genesis 290 }
experimental-genesis 291 fUpdated |= wtx.UpdateSpent(wtxIn.vfSpent);
experimental-genesis 292 }
experimental-genesis 293
experimental-genesis 294 //// debug print
experimental-genesis 295 printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().substr(0,10).c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : ""));
experimental-genesis 296
experimental-genesis 297 // Write to disk
experimental-genesis 298 if (fInsertedNew || fUpdated)
experimental-genesis 299 if (!wtx.WriteToDisk())
experimental-genesis 300 return false;
experimental-genesis 301 #ifndef QT_GUI
experimental-genesis 302 // If default receiving address gets used, replace it with a new one
experimental-genesis 303 CScript scriptDefaultKey;
experimental-genesis 304 scriptDefaultKey.SetBitcoinAddress(vchDefaultKey);
experimental-genesis 305 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
experimental-genesis 306 {
experimental-genesis 307 if (txout.scriptPubKey == scriptDefaultKey)
experimental-genesis 308 {
experimental-genesis 309 std::vector<unsigned char> newDefaultKey;
experimental-genesis 310 if (GetKeyFromPool(newDefaultKey, false))
experimental-genesis 311 {
experimental-genesis 312 SetDefaultKey(newDefaultKey);
experimental-genesis 313 SetAddressBookName(CBitcoinAddress(vchDefaultKey), "");
experimental-genesis 314 }
experimental-genesis 315 }
experimental-genesis 316 }
experimental-genesis 317 #endif
experimental-genesis 318 // Notify UI
experimental-genesis 319 vWalletUpdated.push_back(hash);
experimental-genesis 320
experimental-genesis 321 // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
experimental-genesis 322 WalletUpdateSpent(wtx);
experimental-genesis 323 }
experimental-genesis 324
experimental-genesis 325 // Refresh UI
experimental-genesis 326 MainFrameRepaint();
experimental-genesis 327 return true;
experimental-genesis 328 }
experimental-genesis 329
experimental-genesis 330 // Add a transaction to the wallet, or update it.
experimental-genesis 331 // pblock is optional, but should be provided if the transaction is known to be in a block.
experimental-genesis 332 // If fUpdate is true, existing transactions will be updated.
experimental-genesis 333 bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
experimental-genesis 334 {
experimental-genesis 335 uint256 hash = tx.GetHash();
experimental-genesis 336 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 337 {
experimental-genesis 338 bool fExisted = mapWallet.count(hash);
experimental-genesis 339 if (fExisted && !fUpdate) return false;
experimental-genesis 340 if (fExisted || IsMine(tx) || IsFromMe(tx))
experimental-genesis 341 {
experimental-genesis 342 CWalletTx wtx(this,tx);
experimental-genesis 343 // Get merkle branch if transaction was found in a block
experimental-genesis 344 if (pblock)
experimental-genesis 345 wtx.SetMerkleBranch(pblock);
experimental-genesis 346 return AddToWallet(wtx);
experimental-genesis 347 }
experimental-genesis 348 else
experimental-genesis 349 WalletUpdateSpent(tx);
experimental-genesis 350 }
experimental-genesis 351 return false;
experimental-genesis 352 }
experimental-genesis 353
experimental-genesis 354 bool CWallet::EraseFromWallet(uint256 hash)
experimental-genesis 355 {
experimental-genesis 356 if (!fFileBacked)
experimental-genesis 357 return false;
experimental-genesis 358 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 359 {
experimental-genesis 360 if (mapWallet.erase(hash))
experimental-genesis 361 CWalletDB(strWalletFile).EraseTx(hash);
experimental-genesis 362 }
experimental-genesis 363 return true;
experimental-genesis 364 }
experimental-genesis 365
experimental-genesis 366
experimental-genesis 367 bool CWallet::IsMine(const CTxIn &txin) const
experimental-genesis 368 {
experimental-genesis 369 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 370 {
experimental-genesis 371 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
experimental-genesis 372 if (mi != mapWallet.end())
experimental-genesis 373 {
experimental-genesis 374 const CWalletTx& prev = (*mi).second;
experimental-genesis 375 if (txin.prevout.n < prev.vout.size())
experimental-genesis 376 if (IsMine(prev.vout[txin.prevout.n]))
experimental-genesis 377 return true;
experimental-genesis 378 }
experimental-genesis 379 }
experimental-genesis 380 return false;
experimental-genesis 381 }
experimental-genesis 382
experimental-genesis 383 int64 CWallet::GetDebit(const CTxIn &txin) const
experimental-genesis 384 {
experimental-genesis 385 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 386 {
experimental-genesis 387 map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
experimental-genesis 388 if (mi != mapWallet.end())
experimental-genesis 389 {
experimental-genesis 390 const CWalletTx& prev = (*mi).second;
experimental-genesis 391 if (txin.prevout.n < prev.vout.size())
experimental-genesis 392 if (IsMine(prev.vout[txin.prevout.n]))
experimental-genesis 393 return prev.vout[txin.prevout.n].nValue;
experimental-genesis 394 }
experimental-genesis 395 }
experimental-genesis 396 return 0;
experimental-genesis 397 }
experimental-genesis 398
experimental-genesis 399 int64 CWalletTx::GetTxTime() const
experimental-genesis 400 {
experimental-genesis 401 return nTimeReceived;
experimental-genesis 402 }
experimental-genesis 403
experimental-genesis 404 int CWalletTx::GetRequestCount() const
experimental-genesis 405 {
experimental-genesis 406 // Returns -1 if it wasn't being tracked
experimental-genesis 407 int nRequests = -1;
experimental-genesis 408 CRITICAL_BLOCK(pwallet->cs_wallet)
experimental-genesis 409 {
experimental-genesis 410 if (IsCoinBase())
experimental-genesis 411 {
experimental-genesis 412 // Generated block
experimental-genesis 413 if (hashBlock != 0)
experimental-genesis 414 {
experimental-genesis 415 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
experimental-genesis 416 if (mi != pwallet->mapRequestCount.end())
experimental-genesis 417 nRequests = (*mi).second;
experimental-genesis 418 }
experimental-genesis 419 }
experimental-genesis 420 else
experimental-genesis 421 {
experimental-genesis 422 // Did anyone request this transaction?
experimental-genesis 423 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
experimental-genesis 424 if (mi != pwallet->mapRequestCount.end())
experimental-genesis 425 {
experimental-genesis 426 nRequests = (*mi).second;
experimental-genesis 427
experimental-genesis 428 // How about the block it's in?
experimental-genesis 429 if (nRequests == 0 && hashBlock != 0)
experimental-genesis 430 {
experimental-genesis 431 map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
experimental-genesis 432 if (mi != pwallet->mapRequestCount.end())
experimental-genesis 433 nRequests = (*mi).second;
experimental-genesis 434 else
experimental-genesis 435 nRequests = 1; // If it's in someone else's block it must have got out
experimental-genesis 436 }
experimental-genesis 437 }
experimental-genesis 438 }
experimental-genesis 439 }
experimental-genesis 440 return nRequests;
experimental-genesis 441 }
experimental-genesis 442
experimental-genesis 443 void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
experimental-genesis 444 list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
experimental-genesis 445 {
experimental-genesis 446 nGeneratedImmature = nGeneratedMature = nFee = 0;
experimental-genesis 447 listReceived.clear();
experimental-genesis 448 listSent.clear();
experimental-genesis 449 strSentAccount = strFromAccount;
experimental-genesis 450
experimental-genesis 451 if (IsCoinBase())
experimental-genesis 452 {
experimental-genesis 453 if (GetBlocksToMaturity() > 0)
experimental-genesis 454 nGeneratedImmature = pwallet->GetCredit(*this);
experimental-genesis 455 else
experimental-genesis 456 nGeneratedMature = GetCredit();
experimental-genesis 457 return;
experimental-genesis 458 }
experimental-genesis 459
experimental-genesis 460 // Compute fee:
experimental-genesis 461 int64 nDebit = GetDebit();
experimental-genesis 462 if (nDebit > 0) // debit>0 means we signed/sent this transaction
experimental-genesis 463 {
experimental-genesis 464 int64 nValueOut = GetValueOut();
experimental-genesis 465 nFee = nDebit - nValueOut;
experimental-genesis 466 }
experimental-genesis 467
experimental-genesis 468 // Sent/received. Standard client will never generate a send-to-multiple-recipients,
experimental-genesis 469 // but non-standard clients might (so return a list of address/amount pairs)
experimental-genesis 470 BOOST_FOREACH(const CTxOut& txout, vout)
experimental-genesis 471 {
experimental-genesis 472 CBitcoinAddress address;
experimental-genesis 473 vector<unsigned char> vchPubKey;
experimental-genesis 474 if (!ExtractAddress(txout.scriptPubKey, NULL, address))
experimental-genesis 475 {
experimental-genesis 476 printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
experimental-genesis 477 this->GetHash().ToString().c_str());
experimental-genesis 478 address = " unknown ";
experimental-genesis 479 }
experimental-genesis 480
experimental-genesis 481 // Don't report 'change' txouts
experimental-genesis 482 if (nDebit > 0 && pwallet->IsChange(txout))
experimental-genesis 483 continue;
experimental-genesis 484
experimental-genesis 485 if (nDebit > 0)
experimental-genesis 486 listSent.push_back(make_pair(address, txout.nValue));
experimental-genesis 487
experimental-genesis 488 if (pwallet->IsMine(txout))
experimental-genesis 489 listReceived.push_back(make_pair(address, txout.nValue));
experimental-genesis 490 }
experimental-genesis 491
experimental-genesis 492 }
experimental-genesis 493
experimental-genesis 494 void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
experimental-genesis 495 int64& nSent, int64& nFee) const
experimental-genesis 496 {
experimental-genesis 497 nGenerated = nReceived = nSent = nFee = 0;
experimental-genesis 498
experimental-genesis 499 int64 allGeneratedImmature, allGeneratedMature, allFee;
experimental-genesis 500 allGeneratedImmature = allGeneratedMature = allFee = 0;
experimental-genesis 501 string strSentAccount;
experimental-genesis 502 list<pair<CBitcoinAddress, int64> > listReceived;
experimental-genesis 503 list<pair<CBitcoinAddress, int64> > listSent;
experimental-genesis 504 GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
experimental-genesis 505
experimental-genesis 506 if (strAccount == "")
experimental-genesis 507 nGenerated = allGeneratedMature;
experimental-genesis 508 if (strAccount == strSentAccount)
experimental-genesis 509 {
experimental-genesis 510 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
experimental-genesis 511 nSent += s.second;
experimental-genesis 512 nFee = allFee;
experimental-genesis 513 }
experimental-genesis 514 CRITICAL_BLOCK(pwallet->cs_wallet)
experimental-genesis 515 {
experimental-genesis 516 BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
experimental-genesis 517 {
experimental-genesis 518 if (pwallet->mapAddressBook.count(r.first))
experimental-genesis 519 {
experimental-genesis 520 map<CBitcoinAddress, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
experimental-genesis 521 if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
experimental-genesis 522 nReceived += r.second;
experimental-genesis 523 }
experimental-genesis 524 else if (strAccount.empty())
experimental-genesis 525 {
experimental-genesis 526 nReceived += r.second;
experimental-genesis 527 }
experimental-genesis 528 }
experimental-genesis 529 }
experimental-genesis 530 }
experimental-genesis 531
experimental-genesis 532 void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
experimental-genesis 533 {
experimental-genesis 534 vtxPrev.clear();
experimental-genesis 535
experimental-genesis 536 const int COPY_DEPTH = 3;
experimental-genesis 537 if (SetMerkleBranch() < COPY_DEPTH)
experimental-genesis 538 {
experimental-genesis 539 vector<uint256> vWorkQueue;
experimental-genesis 540 BOOST_FOREACH(const CTxIn& txin, vin)
experimental-genesis 541 vWorkQueue.push_back(txin.prevout.hash);
experimental-genesis 542
experimental-genesis 543 // This critsect is OK because txdb is already open
experimental-genesis 544 CRITICAL_BLOCK(pwallet->cs_wallet)
experimental-genesis 545 {
experimental-genesis 546 map<uint256, const CMerkleTx*> mapWalletPrev;
experimental-genesis 547 set<uint256> setAlreadyDone;
experimental-genesis 548 for (int i = 0; i < vWorkQueue.size(); i++)
experimental-genesis 549 {
experimental-genesis 550 uint256 hash = vWorkQueue[i];
experimental-genesis 551 if (setAlreadyDone.count(hash))
experimental-genesis 552 continue;
experimental-genesis 553 setAlreadyDone.insert(hash);
experimental-genesis 554
experimental-genesis 555 CMerkleTx tx;
experimental-genesis 556 map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
experimental-genesis 557 if (mi != pwallet->mapWallet.end())
experimental-genesis 558 {
experimental-genesis 559 tx = (*mi).second;
experimental-genesis 560 BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
experimental-genesis 561 mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
experimental-genesis 562 }
experimental-genesis 563 else if (mapWalletPrev.count(hash))
experimental-genesis 564 {
experimental-genesis 565 tx = *mapWalletPrev[hash];
experimental-genesis 566 }
experimental-genesis 567 else if (!fClient && txdb.ReadDiskTx(hash, tx))
experimental-genesis 568 {
experimental-genesis 569 ;
experimental-genesis 570 }
experimental-genesis 571 else
experimental-genesis 572 {
experimental-genesis 573 printf("ERROR: AddSupportingTransactions() : unsupported transaction\n");
experimental-genesis 574 continue;
experimental-genesis 575 }
experimental-genesis 576
experimental-genesis 577 int nDepth = tx.SetMerkleBranch();
experimental-genesis 578 vtxPrev.push_back(tx);
experimental-genesis 579
experimental-genesis 580 if (nDepth < COPY_DEPTH)
experimental-genesis 581 BOOST_FOREACH(const CTxIn& txin, tx.vin)
experimental-genesis 582 vWorkQueue.push_back(txin.prevout.hash);
experimental-genesis 583 }
experimental-genesis 584 }
experimental-genesis 585 }
experimental-genesis 586
experimental-genesis 587 reverse(vtxPrev.begin(), vtxPrev.end());
experimental-genesis 588 }
experimental-genesis 589
experimental-genesis 590 bool CWalletTx::WriteToDisk()
experimental-genesis 591 {
experimental-genesis 592 return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
experimental-genesis 593 }
experimental-genesis 594
experimental-genesis 595 // Scan the block chain (starting in pindexStart) for transactions
experimental-genesis 596 // from or to us. If fUpdate is true, found transactions that already
experimental-genesis 597 // exist in the wallet will be updated.
experimental-genesis 598 int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
experimental-genesis 599 {
experimental-genesis 600 int ret = 0;
experimental-genesis 601
experimental-genesis 602 CBlockIndex* pindex = pindexStart;
experimental-genesis 603 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 604 {
experimental-genesis 605 while (pindex)
experimental-genesis 606 {
experimental-genesis 607 CBlock block;
experimental-genesis 608 block.ReadFromDisk(pindex, true);
experimental-genesis 609 BOOST_FOREACH(CTransaction& tx, block.vtx)
experimental-genesis 610 {
experimental-genesis 611 if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
experimental-genesis 612 ret++;
experimental-genesis 613 }
experimental-genesis 614 pindex = pindex->pnext;
experimental-genesis 615 }
experimental-genesis 616 }
experimental-genesis 617 return ret;
experimental-genesis 618 }
experimental-genesis 619
experimental-genesis 620 void CWallet::ReacceptWalletTransactions()
experimental-genesis 621 {
experimental-genesis 622 CTxDB txdb("r");
experimental-genesis 623 bool fRepeat = true;
experimental-genesis 624 while (fRepeat) CRITICAL_BLOCK(cs_wallet)
experimental-genesis 625 {
experimental-genesis 626 fRepeat = false;
experimental-genesis 627 vector<CDiskTxPos> vMissingTx;
experimental-genesis 628 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
experimental-genesis 629 {
experimental-genesis 630 CWalletTx& wtx = item.second;
experimental-genesis 631 if (wtx.IsCoinBase() && wtx.IsSpent(0))
experimental-genesis 632 continue;
experimental-genesis 633
experimental-genesis 634 CTxIndex txindex;
experimental-genesis 635 bool fUpdated = false;
experimental-genesis 636 if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
experimental-genesis 637 {
experimental-genesis 638 // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
experimental-genesis 639 if (txindex.vSpent.size() != wtx.vout.size())
experimental-genesis 640 {
experimental-genesis 641 printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size());
experimental-genesis 642 continue;
experimental-genesis 643 }
experimental-genesis 644 for (int i = 0; i < txindex.vSpent.size(); i++)
experimental-genesis 645 {
experimental-genesis 646 if (wtx.IsSpent(i))
experimental-genesis 647 continue;
experimental-genesis 648 if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
experimental-genesis 649 {
experimental-genesis 650 wtx.MarkSpent(i);
experimental-genesis 651 fUpdated = true;
experimental-genesis 652 vMissingTx.push_back(txindex.vSpent[i]);
experimental-genesis 653 }
experimental-genesis 654 }
experimental-genesis 655 if (fUpdated)
experimental-genesis 656 {
experimental-genesis 657 printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
experimental-genesis 658 wtx.MarkDirty();
experimental-genesis 659 wtx.WriteToDisk();
experimental-genesis 660 }
experimental-genesis 661 }
experimental-genesis 662 else
experimental-genesis 663 {
experimental-genesis 664 // Reaccept any txes of ours that aren't already in a block
experimental-genesis 665 if (!wtx.IsCoinBase())
experimental-genesis 666 wtx.AcceptWalletTransaction(txdb, false);
experimental-genesis 667 }
experimental-genesis 668 }
experimental-genesis 669 if (!vMissingTx.empty())
experimental-genesis 670 {
experimental-genesis 671 // TODO: optimize this to scan just part of the block chain?
experimental-genesis 672 if (ScanForWalletTransactions(pindexGenesisBlock))
experimental-genesis 673 fRepeat = true; // Found missing transactions: re-do Reaccept.
experimental-genesis 674 }
experimental-genesis 675 }
experimental-genesis 676 }
experimental-genesis 677
experimental-genesis 678 void CWalletTx::RelayWalletTransaction(CTxDB& txdb)
experimental-genesis 679 {
experimental-genesis 680 BOOST_FOREACH(const CMerkleTx& tx, vtxPrev)
experimental-genesis 681 {
experimental-genesis 682 if (!tx.IsCoinBase())
experimental-genesis 683 {
experimental-genesis 684 uint256 hash = tx.GetHash();
experimental-genesis 685 if (!txdb.ContainsTx(hash))
experimental-genesis 686 RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx);
experimental-genesis 687 }
experimental-genesis 688 }
experimental-genesis 689 if (!IsCoinBase())
experimental-genesis 690 {
experimental-genesis 691 uint256 hash = GetHash();
experimental-genesis 692 if (!txdb.ContainsTx(hash))
experimental-genesis 693 {
experimental-genesis 694 printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str());
experimental-genesis 695 RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this);
experimental-genesis 696 }
experimental-genesis 697 }
experimental-genesis 698 }
experimental-genesis 699
experimental-genesis 700 void CWalletTx::RelayWalletTransaction()
experimental-genesis 701 {
experimental-genesis 702 CTxDB txdb("r");
experimental-genesis 703 RelayWalletTransaction(txdb);
experimental-genesis 704 }
experimental-genesis 705
experimental-genesis 706 void CWallet::ResendWalletTransactions()
experimental-genesis 707 {
experimental-genesis 708 // Do this infrequently and randomly to avoid giving away
experimental-genesis 709 // that these are our transactions.
experimental-genesis 710 static int64 nNextTime;
experimental-genesis 711 if (GetTime() < nNextTime)
experimental-genesis 712 return;
experimental-genesis 713 bool fFirst = (nNextTime == 0);
experimental-genesis 714 nNextTime = GetTime() + GetRand(30 * 60);
experimental-genesis 715 if (fFirst)
experimental-genesis 716 return;
experimental-genesis 717
experimental-genesis 718 // Only do it if there's been a new block since last time
experimental-genesis 719 static int64 nLastTime;
experimental-genesis 720 if (nTimeBestReceived < nLastTime)
experimental-genesis 721 return;
experimental-genesis 722 nLastTime = GetTime();
experimental-genesis 723
experimental-genesis 724 // Rebroadcast any of our txes that aren't in a block yet
experimental-genesis 725 printf("ResendWalletTransactions()\n");
experimental-genesis 726 CTxDB txdb("r");
experimental-genesis 727 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 728 {
experimental-genesis 729 // Sort them in chronological order
experimental-genesis 730 multimap<unsigned int, CWalletTx*> mapSorted;
experimental-genesis 731 BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
experimental-genesis 732 {
experimental-genesis 733 CWalletTx& wtx = item.second;
experimental-genesis 734 // Don't rebroadcast until it's had plenty of time that
experimental-genesis 735 // it should have gotten in already by now.
experimental-genesis 736 if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
experimental-genesis 737 mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
experimental-genesis 738 }
experimental-genesis 739 BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
experimental-genesis 740 {
experimental-genesis 741 CWalletTx& wtx = *item.second;
experimental-genesis 742 wtx.RelayWalletTransaction(txdb);
experimental-genesis 743 }
experimental-genesis 744 }
experimental-genesis 745 }
experimental-genesis 746
experimental-genesis 747
experimental-genesis 748
experimental-genesis 749
experimental-genesis 750
experimental-genesis 751
experimental-genesis 752 //////////////////////////////////////////////////////////////////////////////
experimental-genesis 753 //
experimental-genesis 754 // Actions
experimental-genesis 755 //
experimental-genesis 756
experimental-genesis 757
experimental-genesis 758 int64 CWallet::GetBalance() const
experimental-genesis 759 {
experimental-genesis 760 int64 nTotal = 0;
experimental-genesis 761 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 762 {
experimental-genesis 763 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
experimental-genesis 764 {
experimental-genesis 765 const CWalletTx* pcoin = &(*it).second;
experimental-genesis 766 if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
experimental-genesis 767 continue;
experimental-genesis 768 nTotal += pcoin->GetAvailableCredit();
experimental-genesis 769 }
experimental-genesis 770 }
experimental-genesis 771
experimental-genesis 772 return nTotal;
experimental-genesis 773 }
experimental-genesis 774
experimental-genesis 775 int64 CWallet::GetUnconfirmedBalance() const
experimental-genesis 776 {
experimental-genesis 777 int64 nTotal = 0;
experimental-genesis 778 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 779 {
experimental-genesis 780 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
experimental-genesis 781 {
experimental-genesis 782 const CWalletTx* pcoin = &(*it).second;
experimental-genesis 783 if (pcoin->IsFinal() && pcoin->IsConfirmed())
experimental-genesis 784 continue;
experimental-genesis 785 nTotal += pcoin->GetAvailableCredit();
experimental-genesis 786 }
experimental-genesis 787 }
experimental-genesis 788 return nTotal;
experimental-genesis 789 }
experimental-genesis 790
experimental-genesis 791 bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
experimental-genesis 792 {
experimental-genesis 793 setCoinsRet.clear();
experimental-genesis 794 nValueRet = 0;
experimental-genesis 795
experimental-genesis 796 // List of values less than target
experimental-genesis 797 pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
experimental-genesis 798 coinLowestLarger.first = INT64_MAX;
experimental-genesis 799 coinLowestLarger.second.first = NULL;
experimental-genesis 800 vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
experimental-genesis 801 int64 nTotalLower = 0;
experimental-genesis 802
experimental-genesis 803 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 804 {
experimental-genesis 805 vector<const CWalletTx*> vCoins;
experimental-genesis 806 vCoins.reserve(mapWallet.size());
experimental-genesis 807 for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
experimental-genesis 808 vCoins.push_back(&(*it).second);
experimental-genesis 809 random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
experimental-genesis 810
experimental-genesis 811 BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
experimental-genesis 812 {
experimental-genesis 813 if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
experimental-genesis 814 continue;
experimental-genesis 815
experimental-genesis 816 if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
experimental-genesis 817 continue;
experimental-genesis 818
experimental-genesis 819 int nDepth = pcoin->GetDepthInMainChain();
experimental-genesis 820 if (nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs))
experimental-genesis 821 continue;
experimental-genesis 822
experimental-genesis 823 for (int i = 0; i < pcoin->vout.size(); i++)
experimental-genesis 824 {
experimental-genesis 825 if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
experimental-genesis 826 continue;
experimental-genesis 827
experimental-genesis 828 int64 n = pcoin->vout[i].nValue;
experimental-genesis 829
experimental-genesis 830 if (n <= 0)
experimental-genesis 831 continue;
experimental-genesis 832
experimental-genesis 833 pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
experimental-genesis 834
experimental-genesis 835 if (n == nTargetValue)
experimental-genesis 836 {
experimental-genesis 837 setCoinsRet.insert(coin.second);
experimental-genesis 838 nValueRet += coin.first;
experimental-genesis 839 return true;
experimental-genesis 840 }
experimental-genesis 841 else if (n < nTargetValue + CENT)
experimental-genesis 842 {
experimental-genesis 843 vValue.push_back(coin);
experimental-genesis 844 nTotalLower += n;
experimental-genesis 845 }
experimental-genesis 846 else if (n < coinLowestLarger.first)
experimental-genesis 847 {
experimental-genesis 848 coinLowestLarger = coin;
experimental-genesis 849 }
experimental-genesis 850 }
experimental-genesis 851 }
experimental-genesis 852 }
experimental-genesis 853
experimental-genesis 854 if (nTotalLower == nTargetValue || nTotalLower == nTargetValue + CENT)
experimental-genesis 855 {
experimental-genesis 856 for (int i = 0; i < vValue.size(); ++i)
experimental-genesis 857 {
experimental-genesis 858 setCoinsRet.insert(vValue[i].second);
experimental-genesis 859 nValueRet += vValue[i].first;
experimental-genesis 860 }
experimental-genesis 861 return true;
experimental-genesis 862 }
experimental-genesis 863
experimental-genesis 864 if (nTotalLower < nTargetValue + (coinLowestLarger.second.first ? CENT : 0))
experimental-genesis 865 {
experimental-genesis 866 if (coinLowestLarger.second.first == NULL)
experimental-genesis 867 return false;
experimental-genesis 868 setCoinsRet.insert(coinLowestLarger.second);
experimental-genesis 869 nValueRet += coinLowestLarger.first;
experimental-genesis 870 return true;
experimental-genesis 871 }
experimental-genesis 872
experimental-genesis 873 if (nTotalLower >= nTargetValue + CENT)
experimental-genesis 874 nTargetValue += CENT;
experimental-genesis 875
experimental-genesis 876 // Solve subset sum by stochastic approximation
experimental-genesis 877 sort(vValue.rbegin(), vValue.rend());
experimental-genesis 878 vector<char> vfIncluded;
experimental-genesis 879 vector<char> vfBest(vValue.size(), true);
experimental-genesis 880 int64 nBest = nTotalLower;
experimental-genesis 881
experimental-genesis 882 for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
experimental-genesis 883 {
experimental-genesis 884 vfIncluded.assign(vValue.size(), false);
experimental-genesis 885 int64 nTotal = 0;
experimental-genesis 886 bool fReachedTarget = false;
experimental-genesis 887 for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
experimental-genesis 888 {
experimental-genesis 889 for (int i = 0; i < vValue.size(); i++)
experimental-genesis 890 {
experimental-genesis 891 if (nPass == 0 ? rand() % 2 : !vfIncluded[i])
experimental-genesis 892 {
experimental-genesis 893 nTotal += vValue[i].first;
experimental-genesis 894 vfIncluded[i] = true;
experimental-genesis 895 if (nTotal >= nTargetValue)
experimental-genesis 896 {
experimental-genesis 897 fReachedTarget = true;
experimental-genesis 898 if (nTotal < nBest)
experimental-genesis 899 {
experimental-genesis 900 nBest = nTotal;
experimental-genesis 901 vfBest = vfIncluded;
experimental-genesis 902 }
experimental-genesis 903 nTotal -= vValue[i].first;
experimental-genesis 904 vfIncluded[i] = false;
experimental-genesis 905 }
experimental-genesis 906 }
experimental-genesis 907 }
experimental-genesis 908 }
experimental-genesis 909 }
experimental-genesis 910
experimental-genesis 911 // If the next larger is still closer, return it
experimental-genesis 912 if (coinLowestLarger.second.first && coinLowestLarger.first - nTargetValue <= nBest - nTargetValue)
experimental-genesis 913 {
experimental-genesis 914 setCoinsRet.insert(coinLowestLarger.second);
experimental-genesis 915 nValueRet += coinLowestLarger.first;
experimental-genesis 916 }
experimental-genesis 917 else {
experimental-genesis 918 for (int i = 0; i < vValue.size(); i++)
experimental-genesis 919 if (vfBest[i])
experimental-genesis 920 {
experimental-genesis 921 setCoinsRet.insert(vValue[i].second);
experimental-genesis 922 nValueRet += vValue[i].first;
experimental-genesis 923 }
experimental-genesis 924
experimental-genesis 925 //// debug print
experimental-genesis 926 printf("SelectCoins() best subset: ");
experimental-genesis 927 for (int i = 0; i < vValue.size(); i++)
experimental-genesis 928 if (vfBest[i])
experimental-genesis 929 printf("%s ", FormatMoney(vValue[i].first).c_str());
experimental-genesis 930 printf("total %s\n", FormatMoney(nBest).c_str());
experimental-genesis 931 }
experimental-genesis 932
experimental-genesis 933 return true;
experimental-genesis 934 }
experimental-genesis 935
experimental-genesis 936 bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
experimental-genesis 937 {
experimental-genesis 938 return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
experimental-genesis 939 SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
experimental-genesis 940 SelectCoinsMinConf(nTargetValue, 0, 1, setCoinsRet, nValueRet));
experimental-genesis 941 }
experimental-genesis 942
experimental-genesis 943
experimental-genesis 944
experimental-genesis 945
experimental-genesis 946 bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
experimental-genesis 947 {
experimental-genesis 948 int64 nValue = 0;
experimental-genesis 949 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
experimental-genesis 950 {
experimental-genesis 951 if (nValue < 0)
experimental-genesis 952 return false;
experimental-genesis 953 nValue += s.second;
experimental-genesis 954 }
experimental-genesis 955 if (vecSend.empty() || nValue < 0)
experimental-genesis 956 return false;
experimental-genesis 957
experimental-genesis 958 wtxNew.pwallet = this;
experimental-genesis 959
experimental-genesis 960 CRITICAL_BLOCK(cs_main)
experimental-genesis 961 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 962 {
experimental-genesis 963 // txdb must be opened before the mapWallet lock
experimental-genesis 964 CTxDB txdb("r");
experimental-genesis 965 {
experimental-genesis 966 nFeeRet = nTransactionFee;
experimental-genesis 967 loop
experimental-genesis 968 {
experimental-genesis 969 wtxNew.vin.clear();
experimental-genesis 970 wtxNew.vout.clear();
experimental-genesis 971 wtxNew.fFromMe = true;
experimental-genesis 972
experimental-genesis 973 int64 nTotalValue = nValue + nFeeRet;
experimental-genesis 974 double dPriority = 0;
experimental-genesis 975 // vouts to the payees
experimental-genesis 976 BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
experimental-genesis 977 wtxNew.vout.push_back(CTxOut(s.second, s.first));
experimental-genesis 978
experimental-genesis 979 // Choose coins to use
experimental-genesis 980 set<pair<const CWalletTx*,unsigned int> > setCoins;
experimental-genesis 981 int64 nValueIn = 0;
experimental-genesis 982 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
experimental-genesis 983 return false;
experimental-genesis 984 BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
experimental-genesis 985 {
experimental-genesis 986 int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
experimental-genesis 987 dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
experimental-genesis 988 }
experimental-genesis 989
experimental-genesis 990 int64 nChange = nValueIn - nValue - nFeeRet;
experimental-genesis 991 // if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
experimental-genesis 992 // or until nChange becomes zero
experimental-genesis 993 if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
experimental-genesis 994 {
experimental-genesis 995 int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
experimental-genesis 996 nChange -= nMoveToFee;
experimental-genesis 997 nFeeRet += nMoveToFee;
experimental-genesis 998 }
experimental-genesis 999
experimental-genesis 1000 if (nChange > 0)
experimental-genesis 1001 {
experimental-genesis 1002 // Note: We use a new key here to keep it from being obvious which side is the change.
experimental-genesis 1003 // The drawback is that by not reusing a previous key, the change may be lost if a
experimental-genesis 1004 // backup is restored, if the backup doesn't have the new private key for the change.
experimental-genesis 1005 // If we reused the old key, it would be possible to add code to look for and
experimental-genesis 1006 // rediscover unknown transactions that were written with keys of ours to recover
experimental-genesis 1007 // post-backup change.
experimental-genesis 1008
experimental-genesis 1009 // Reserve a new key pair from key pool
experimental-genesis 1010 vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
experimental-genesis 1011 // assert(mapKeys.count(vchPubKey));
experimental-genesis 1012
experimental-genesis 1013 // Fill a vout to ourself, using same address type as the payment
experimental-genesis 1014 CScript scriptChange;
experimental-genesis 1015 if (vecSend[0].first.GetBitcoinAddress().IsValid())
experimental-genesis 1016 scriptChange.SetBitcoinAddress(vchPubKey);
experimental-genesis 1017 else
experimental-genesis 1018 scriptChange << vchPubKey << OP_CHECKSIG;
experimental-genesis 1019
experimental-genesis 1020 // Insert change txn at random position:
experimental-genesis 1021 vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size());
experimental-genesis 1022 wtxNew.vout.insert(position, CTxOut(nChange, scriptChange));
experimental-genesis 1023 }
experimental-genesis 1024 else
experimental-genesis 1025 reservekey.ReturnKey();
experimental-genesis 1026
experimental-genesis 1027 // Fill vin
experimental-genesis 1028 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
experimental-genesis 1029 wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
experimental-genesis 1030
experimental-genesis 1031 // Sign
experimental-genesis 1032 int nIn = 0;
experimental-genesis 1033 BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
experimental-genesis 1034 if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
experimental-genesis 1035 return false;
experimental-genesis 1036
experimental-genesis 1037 // Limit size
experimental-genesis 1038 unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK);
experimental-genesis 1039 if (nBytes >= MAX_BLOCK_SIZE_GEN/5)
experimental-genesis 1040 return false;
experimental-genesis 1041 dPriority /= nBytes;
experimental-genesis 1042
experimental-genesis 1043 // Check that enough fee is included
experimental-genesis 1044 int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
experimental-genesis 1045 bool fAllowFree = CTransaction::AllowFree(dPriority);
experimental-genesis 1046 int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree);
experimental-genesis 1047 if (nFeeRet < max(nPayFee, nMinFee))
experimental-genesis 1048 {
experimental-genesis 1049 nFeeRet = max(nPayFee, nMinFee);
experimental-genesis 1050 continue;
experimental-genesis 1051 }
experimental-genesis 1052
experimental-genesis 1053 // Fill vtxPrev by copying from previous transactions vtxPrev
experimental-genesis 1054 wtxNew.AddSupportingTransactions(txdb);
experimental-genesis 1055 wtxNew.fTimeReceivedIsTxTime = true;
experimental-genesis 1056
experimental-genesis 1057 break;
experimental-genesis 1058 }
experimental-genesis 1059 }
experimental-genesis 1060 }
experimental-genesis 1061 return true;
experimental-genesis 1062 }
experimental-genesis 1063
experimental-genesis 1064 bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
experimental-genesis 1065 {
experimental-genesis 1066 vector< pair<CScript, int64> > vecSend;
experimental-genesis 1067 vecSend.push_back(make_pair(scriptPubKey, nValue));
experimental-genesis 1068 return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
experimental-genesis 1069 }
experimental-genesis 1070
experimental-genesis 1071 // Call after CreateTransaction unless you want to abort
experimental-genesis 1072 bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
experimental-genesis 1073 {
experimental-genesis 1074 CRITICAL_BLOCK(cs_main)
experimental-genesis 1075 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1076 {
experimental-genesis 1077 printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
experimental-genesis 1078 {
experimental-genesis 1079 // This is only to keep the database open to defeat the auto-flush for the
experimental-genesis 1080 // duration of this scope. This is the only place where this optimization
experimental-genesis 1081 // maybe makes sense; please don't do it anywhere else.
experimental-genesis 1082 CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
experimental-genesis 1083
experimental-genesis 1084 // Take key pair from key pool so it won't be used again
experimental-genesis 1085 reservekey.KeepKey();
experimental-genesis 1086
experimental-genesis 1087 // Add tx to wallet, because if it has change it's also ours,
experimental-genesis 1088 // otherwise just for transaction history.
experimental-genesis 1089 AddToWallet(wtxNew);
experimental-genesis 1090
experimental-genesis 1091 // Mark old coins as spent
experimental-genesis 1092 set<CWalletTx*> setCoins;
experimental-genesis 1093 BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
experimental-genesis 1094 {
experimental-genesis 1095 CWalletTx &coin = mapWallet[txin.prevout.hash];
experimental-genesis 1096 coin.pwallet = this;
experimental-genesis 1097 coin.MarkSpent(txin.prevout.n);
experimental-genesis 1098 coin.WriteToDisk();
experimental-genesis 1099 vWalletUpdated.push_back(coin.GetHash());
experimental-genesis 1100 }
experimental-genesis 1101
experimental-genesis 1102 if (fFileBacked)
experimental-genesis 1103 delete pwalletdb;
experimental-genesis 1104 }
experimental-genesis 1105
experimental-genesis 1106 // Track how many getdata requests our transaction gets
experimental-genesis 1107 mapRequestCount[wtxNew.GetHash()] = 0;
experimental-genesis 1108
experimental-genesis 1109 // Broadcast
experimental-genesis 1110 if (!wtxNew.AcceptToMemoryPool())
experimental-genesis 1111 {
experimental-genesis 1112 // This must not fail. The transaction has already been signed and recorded.
experimental-genesis 1113 printf("CommitTransaction() : Error: Transaction not valid");
experimental-genesis 1114 return false;
experimental-genesis 1115 }
experimental-genesis 1116 wtxNew.RelayWalletTransaction();
experimental-genesis 1117 }
experimental-genesis 1118 MainFrameRepaint();
experimental-genesis 1119 return true;
experimental-genesis 1120 }
experimental-genesis 1121
experimental-genesis 1122
experimental-genesis 1123
experimental-genesis 1124
experimental-genesis 1125 string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
experimental-genesis 1126 {
experimental-genesis 1127 CReserveKey reservekey(this);
experimental-genesis 1128 int64 nFeeRequired;
experimental-genesis 1129
experimental-genesis 1130 if (IsLocked())
experimental-genesis 1131 {
experimental-genesis 1132 string strError = _("Error: Wallet locked, unable to create transaction ");
experimental-genesis 1133 printf("SendMoney() : %s", strError.c_str());
experimental-genesis 1134 return strError;
experimental-genesis 1135 }
experimental-genesis 1136 if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
experimental-genesis 1137 {
experimental-genesis 1138 string strError;
experimental-genesis 1139 if (nValue + nFeeRequired > GetBalance())
experimental-genesis 1140 strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
experimental-genesis 1141 else
experimental-genesis 1142 strError = _("Error: Transaction creation failed ");
experimental-genesis 1143 printf("SendMoney() : %s", strError.c_str());
experimental-genesis 1144 return strError;
experimental-genesis 1145 }
experimental-genesis 1146
experimental-genesis 1147 if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
experimental-genesis 1148 return "ABORTED";
experimental-genesis 1149
experimental-genesis 1150 if (!CommitTransaction(wtxNew, reservekey))
experimental-genesis 1151 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.");
experimental-genesis 1152
experimental-genesis 1153 MainFrameRepaint();
experimental-genesis 1154 return "";
experimental-genesis 1155 }
experimental-genesis 1156
experimental-genesis 1157
experimental-genesis 1158
experimental-genesis 1159 string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
experimental-genesis 1160 {
experimental-genesis 1161 // Check amount
experimental-genesis 1162 if (nValue <= 0)
experimental-genesis 1163 return _("Invalid amount");
experimental-genesis 1164 if (nValue + nTransactionFee > GetBalance())
experimental-genesis 1165 return _("Insufficient funds");
experimental-genesis 1166
experimental-genesis 1167 // Parse bitcoin address
experimental-genesis 1168 CScript scriptPubKey;
experimental-genesis 1169 scriptPubKey.SetBitcoinAddress(address);
experimental-genesis 1170
experimental-genesis 1171 return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee);
experimental-genesis 1172 }
experimental-genesis 1173
experimental-genesis 1174
experimental-genesis 1175
experimental-genesis 1176
experimental-genesis 1177 int CWallet::LoadWallet(bool& fFirstRunRet)
experimental-genesis 1178 {
experimental-genesis 1179 if (!fFileBacked)
experimental-genesis 1180 return false;
experimental-genesis 1181 fFirstRunRet = false;
experimental-genesis 1182 int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
experimental-genesis 1183 if (nLoadWalletRet == DB_NEED_REWRITE)
experimental-genesis 1184 {
experimental-genesis 1185 if (CDB::Rewrite(strWalletFile, "\x04pool"))
experimental-genesis 1186 {
experimental-genesis 1187 setKeyPool.clear();
experimental-genesis 1188 // Note: can't top-up keypool here, because wallet is locked.
experimental-genesis 1189 // User will be prompted to unlock wallet the next operation
experimental-genesis 1190 // the requires a new key.
experimental-genesis 1191 }
experimental-genesis 1192 nLoadWalletRet = DB_NEED_REWRITE;
experimental-genesis 1193 }
experimental-genesis 1194
experimental-genesis 1195 if (nLoadWalletRet != DB_LOAD_OK)
experimental-genesis 1196 return nLoadWalletRet;
experimental-genesis 1197 fFirstRunRet = vchDefaultKey.empty();
experimental-genesis 1198
experimental-genesis 1199 if (!HaveKey(Hash160(vchDefaultKey)))
experimental-genesis 1200 {
experimental-genesis 1201 // Create new keyUser and set as default key
experimental-genesis 1202 RandAddSeedPerfmon();
experimental-genesis 1203
experimental-genesis 1204 std::vector<unsigned char> newDefaultKey;
experimental-genesis 1205 if (!GetKeyFromPool(newDefaultKey, false))
experimental-genesis 1206 return DB_LOAD_FAIL;
experimental-genesis 1207 SetDefaultKey(newDefaultKey);
experimental-genesis 1208 if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
experimental-genesis 1209 return DB_LOAD_FAIL;
experimental-genesis 1210 }
experimental-genesis 1211
experimental-genesis 1212 CreateThread(ThreadFlushWalletDB, &strWalletFile);
experimental-genesis 1213 return DB_LOAD_OK;
experimental-genesis 1214 }
experimental-genesis 1215
experimental-genesis 1216
experimental-genesis 1217 bool CWallet::SetAddressBookName(const CBitcoinAddress& address, const string& strName)
experimental-genesis 1218 {
experimental-genesis 1219 mapAddressBook[address] = strName;
experimental-genesis 1220 if (!fFileBacked)
experimental-genesis 1221 return false;
experimental-genesis 1222 return CWalletDB(strWalletFile).WriteName(address.ToString(), strName);
experimental-genesis 1223 }
experimental-genesis 1224
experimental-genesis 1225 bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
experimental-genesis 1226 {
experimental-genesis 1227 mapAddressBook.erase(address);
experimental-genesis 1228 if (!fFileBacked)
experimental-genesis 1229 return false;
experimental-genesis 1230 return CWalletDB(strWalletFile).EraseName(address.ToString());
experimental-genesis 1231 }
experimental-genesis 1232
experimental-genesis 1233
experimental-genesis 1234 void CWallet::PrintWallet(const CBlock& block)
experimental-genesis 1235 {
experimental-genesis 1236 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1237 {
experimental-genesis 1238 if (mapWallet.count(block.vtx[0].GetHash()))
experimental-genesis 1239 {
experimental-genesis 1240 CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
experimental-genesis 1241 printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
experimental-genesis 1242 }
experimental-genesis 1243 }
experimental-genesis 1244 printf("\n");
experimental-genesis 1245 }
experimental-genesis 1246
experimental-genesis 1247 bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
experimental-genesis 1248 {
experimental-genesis 1249 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1250 {
experimental-genesis 1251 map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
experimental-genesis 1252 if (mi != mapWallet.end())
experimental-genesis 1253 {
experimental-genesis 1254 wtx = (*mi).second;
experimental-genesis 1255 return true;
experimental-genesis 1256 }
experimental-genesis 1257 }
experimental-genesis 1258 return false;
experimental-genesis 1259 }
experimental-genesis 1260
experimental-genesis 1261 bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
experimental-genesis 1262 {
experimental-genesis 1263 if (fFileBacked)
experimental-genesis 1264 {
experimental-genesis 1265 if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
experimental-genesis 1266 return false;
experimental-genesis 1267 }
experimental-genesis 1268 vchDefaultKey = vchPubKey;
experimental-genesis 1269 return true;
experimental-genesis 1270 }
experimental-genesis 1271
experimental-genesis 1272 bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
experimental-genesis 1273 {
experimental-genesis 1274 if (!pwallet->fFileBacked)
experimental-genesis 1275 return false;
experimental-genesis 1276 strWalletFileOut = pwallet->strWalletFile;
experimental-genesis 1277 return true;
experimental-genesis 1278 }
experimental-genesis 1279
experimental-genesis 1280 //
experimental-genesis 1281 // Mark old keypool keys as used,
experimental-genesis 1282 // and generate all new keys
experimental-genesis 1283 //
experimental-genesis 1284 bool CWallet::NewKeyPool()
experimental-genesis 1285 {
experimental-genesis 1286 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1287 {
experimental-genesis 1288 CWalletDB walletdb(strWalletFile);
experimental-genesis 1289 BOOST_FOREACH(int64 nIndex, setKeyPool)
experimental-genesis 1290 walletdb.ErasePool(nIndex);
experimental-genesis 1291 setKeyPool.clear();
experimental-genesis 1292
experimental-genesis 1293 if (IsLocked())
experimental-genesis 1294 return false;
experimental-genesis 1295
experimental-genesis 1296 int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
experimental-genesis 1297 for (int i = 0; i < nKeys; i++)
experimental-genesis 1298 {
experimental-genesis 1299 int64 nIndex = i+1;
experimental-genesis 1300 walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
experimental-genesis 1301 setKeyPool.insert(nIndex);
experimental-genesis 1302 }
experimental-genesis 1303 printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys);
experimental-genesis 1304 }
experimental-genesis 1305 return true;
experimental-genesis 1306 }
experimental-genesis 1307
experimental-genesis 1308 bool CWallet::TopUpKeyPool()
experimental-genesis 1309 {
experimental-genesis 1310 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1311 {
experimental-genesis 1312 if (IsLocked())
experimental-genesis 1313 return false;
experimental-genesis 1314
experimental-genesis 1315 CWalletDB walletdb(strWalletFile);
experimental-genesis 1316
experimental-genesis 1317 // Top up key pool
experimental-genesis 1318 int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
experimental-genesis 1319 while (setKeyPool.size() < nTargetSize+1)
experimental-genesis 1320 {
experimental-genesis 1321 int64 nEnd = 1;
experimental-genesis 1322 if (!setKeyPool.empty())
experimental-genesis 1323 nEnd = *(--setKeyPool.end()) + 1;
experimental-genesis 1324 if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
experimental-genesis 1325 throw runtime_error("TopUpKeyPool() : writing generated key failed");
experimental-genesis 1326 setKeyPool.insert(nEnd);
experimental-genesis 1327 printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
experimental-genesis 1328 }
experimental-genesis 1329 }
experimental-genesis 1330 return true;
experimental-genesis 1331 }
experimental-genesis 1332
experimental-genesis 1333 void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
experimental-genesis 1334 {
experimental-genesis 1335 nIndex = -1;
experimental-genesis 1336 keypool.vchPubKey.clear();
experimental-genesis 1337 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1338 {
experimental-genesis 1339 if (!IsLocked())
experimental-genesis 1340 TopUpKeyPool();
experimental-genesis 1341
experimental-genesis 1342 // Get the oldest key
experimental-genesis 1343 if(setKeyPool.empty())
experimental-genesis 1344 return;
experimental-genesis 1345
experimental-genesis 1346 CWalletDB walletdb(strWalletFile);
experimental-genesis 1347
experimental-genesis 1348 nIndex = *(setKeyPool.begin());
experimental-genesis 1349 setKeyPool.erase(setKeyPool.begin());
experimental-genesis 1350 if (!walletdb.ReadPool(nIndex, keypool))
experimental-genesis 1351 throw runtime_error("ReserveKeyFromKeyPool() : read failed");
experimental-genesis 1352 if (!HaveKey(Hash160(keypool.vchPubKey)))
experimental-genesis 1353 throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
experimental-genesis 1354 assert(!keypool.vchPubKey.empty());
experimental-genesis 1355 printf("keypool reserve %"PRI64d"\n", nIndex);
experimental-genesis 1356 }
experimental-genesis 1357 }
experimental-genesis 1358
experimental-genesis 1359 void CWallet::KeepKey(int64 nIndex)
experimental-genesis 1360 {
experimental-genesis 1361 // Remove from key pool
experimental-genesis 1362 if (fFileBacked)
experimental-genesis 1363 {
experimental-genesis 1364 CWalletDB walletdb(strWalletFile);
experimental-genesis 1365 walletdb.ErasePool(nIndex);
experimental-genesis 1366 }
experimental-genesis 1367 printf("keypool keep %"PRI64d"\n", nIndex);
experimental-genesis 1368 }
experimental-genesis 1369
experimental-genesis 1370 void CWallet::ReturnKey(int64 nIndex)
experimental-genesis 1371 {
experimental-genesis 1372 // Return to key pool
experimental-genesis 1373 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1374 setKeyPool.insert(nIndex);
experimental-genesis 1375 printf("keypool return %"PRI64d"\n", nIndex);
experimental-genesis 1376 }
experimental-genesis 1377
experimental-genesis 1378 bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
experimental-genesis 1379 {
experimental-genesis 1380 int64 nIndex = 0;
experimental-genesis 1381 CKeyPool keypool;
experimental-genesis 1382 CRITICAL_BLOCK(cs_wallet)
experimental-genesis 1383 {
experimental-genesis 1384 ReserveKeyFromKeyPool(nIndex, keypool);
experimental-genesis 1385 if (nIndex == -1)
experimental-genesis 1386 {
experimental-genesis 1387 if (fAllowReuse && !vchDefaultKey.empty())
experimental-genesis 1388 {
experimental-genesis 1389 result = vchDefaultKey;
experimental-genesis 1390 return true;
experimental-genesis 1391 }
experimental-genesis 1392 if (IsLocked()) return false;
experimental-genesis 1393 result = GenerateNewKey();
experimental-genesis 1394 return true;
experimental-genesis 1395 }
experimental-genesis 1396 KeepKey(nIndex);
experimental-genesis 1397 result = keypool.vchPubKey;
experimental-genesis 1398 }
experimental-genesis 1399 return true;
experimental-genesis 1400 }
experimental-genesis 1401
experimental-genesis 1402 int64 CWallet::GetOldestKeyPoolTime()
experimental-genesis 1403 {
experimental-genesis 1404 int64 nIndex = 0;
experimental-genesis 1405 CKeyPool keypool;
experimental-genesis 1406 ReserveKeyFromKeyPool(nIndex, keypool);
experimental-genesis 1407 if (nIndex == -1)
experimental-genesis 1408 return GetTime();
experimental-genesis 1409 ReturnKey(nIndex);
experimental-genesis 1410 return keypool.nTime;
experimental-genesis 1411 }
experimental-genesis 1412
experimental-genesis 1413 vector<unsigned char> CReserveKey::GetReservedKey()
experimental-genesis 1414 {
experimental-genesis 1415 if (nIndex == -1)
experimental-genesis 1416 {
experimental-genesis 1417 CKeyPool keypool;
experimental-genesis 1418 pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
experimental-genesis 1419 if (nIndex != -1)
experimental-genesis 1420 vchPubKey = keypool.vchPubKey;
experimental-genesis 1421 else
experimental-genesis 1422 {
experimental-genesis 1423 printf("CReserveKey::GetReservedKey(): Warning: using default key instead of a new key, top up your keypool.");
experimental-genesis 1424 vchPubKey = pwallet->vchDefaultKey;
experimental-genesis 1425 }
experimental-genesis 1426 }
experimental-genesis 1427 assert(!vchPubKey.empty());
experimental-genesis 1428 return vchPubKey;
experimental-genesis 1429 }
experimental-genesis 1430
experimental-genesis 1431 void CReserveKey::KeepKey()
experimental-genesis 1432 {
experimental-genesis 1433 if (nIndex != -1)
experimental-genesis 1434 pwallet->KeepKey(nIndex);
experimental-genesis 1435 nIndex = -1;
experimental-genesis 1436 vchPubKey.clear();
experimental-genesis 1437 }
experimental-genesis 1438
experimental-genesis 1439 void CReserveKey::ReturnKey()
experimental-genesis 1440 {
experimental-genesis 1441 if (nIndex != -1)
experimental-genesis 1442 pwallet->ReturnKey(nIndex);
experimental-genesis 1443 nIndex = -1;
experimental-genesis 1444 vchPubKey.clear();
experimental-genesis 1445 }
experimental-genesis 1446