diff options
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r-- | src/wallet.cpp | 199 |
1 files changed, 106 insertions, 93 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp index f9da100e21..3892e4b801 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -292,10 +292,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) return true; } -int64 CWallet::IncOrderPosNext() +int64 CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { - int64 nRet = nOrderPosNext; - CWalletDB(strWalletFile).WriteOrderPosNext(++nOrderPosNext); + int64 nRet = nOrderPosNext++; + if (pwalletdb) { + pwalletdb->WriteOrderPosNext(nOrderPosNext); + } else { + CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); + } return nRet; } @@ -336,7 +340,9 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) if (mi != mapWallet.end()) { CWalletTx& wtx = (*mi).second; - if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) + if (txin.prevout.n >= wtx.vout.size()) + printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); + else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) { printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkSpent(txin.prevout.n); @@ -488,9 +494,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) // 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. -bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) +bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock) { - uint256 hash = tx.GetHash(); { LOCK(cs_wallet); bool fExisted = mapWallet.count(hash); @@ -694,7 +699,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived, } } -void CWalletTx::AddSupportingTransactions(CTxDB& txdb) +void CWalletTx::AddSupportingTransactions() { vtxPrev.clear(); @@ -705,7 +710,6 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) BOOST_FOREACH(const CTxIn& txin, vin) vWorkQueue.push_back(txin.prevout.hash); - // This critsect is OK because txdb is already open { LOCK(pwallet->cs_wallet); map<uint256, const CMerkleTx*> mapWalletPrev; @@ -729,15 +733,6 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb) { tx = *mapWalletPrev[hash]; } - else if (!fClient && txdb.ReadDiskTx(hash, tx)) - { - ; - } - else - { - printf("ERROR: AddSupportingTransactions() : unsupported transaction\n"); - continue; - } int nDepth = tx.SetMerkleBranch(); vtxPrev.push_back(tx); @@ -772,10 +767,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) while (pindex) { CBlock block; - block.ReadFromDisk(pindex, true); + block.ReadFromDisk(pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { - if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) + if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) ret++; } pindex = pindex->pnext; @@ -784,49 +779,35 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) return ret; } -int CWallet::ScanForWalletTransaction(const uint256& hashTx) -{ - CTransaction tx; - tx.ReadFromDisk(COutPoint(hashTx, 0)); - if (AddToWalletIfInvolvingMe(tx, NULL, true, true)) - return 1; - return 0; -} - void CWallet::ReacceptWalletTransactions() { - CTxDB txdb("r"); bool fRepeat = true; while (fRepeat) { LOCK(cs_wallet); fRepeat = false; - vector<CDiskTxPos> vMissingTx; + bool fMissing = false; BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) { CWalletTx& wtx = item.second; if (wtx.IsCoinBase() && wtx.IsSpent(0)) continue; - CTxIndex txindex; + CCoins coins; bool fUpdated = false; - if (txdb.ReadTxIndex(wtx.GetHash(), txindex)) + bool fFound = pcoinsTip->GetCoins(wtx.GetHash(), coins); + if (fFound || wtx.GetDepthInMainChain() > 0) { // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat - if (txindex.vSpent.size() != wtx.vout.size()) - { - printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %d != wtx.vout.size() %d\n", txindex.vSpent.size(), wtx.vout.size()); - continue; - } - for (unsigned int i = 0; i < txindex.vSpent.size(); i++) + for (unsigned int i = 0; i < wtx.vout.size(); i++) { if (wtx.IsSpent(i)) continue; - if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i])) + if ((i >= coins.vout.size() || coins.vout[i].IsNull()) && IsMine(wtx.vout[i])) { wtx.MarkSpent(i); fUpdated = true; - vMissingTx.push_back(txindex.vSpent[i]); + fMissing = true; } } if (fUpdated) @@ -840,10 +821,10 @@ void CWallet::ReacceptWalletTransactions() { // Re-accept any txes of ours that aren't already in a block if (!wtx.IsCoinBase()) - wtx.AcceptWalletTransaction(txdb, false); + wtx.AcceptWalletTransaction(false); } } - if (!vMissingTx.empty()) + if (fMissing) { // TODO: optimize this to scan just part of the block chain? if (ScanForWalletTransactions(pindexGenesisBlock)) @@ -852,34 +833,24 @@ void CWallet::ReacceptWalletTransactions() } } -void CWalletTx::RelayWalletTransaction(CTxDB& txdb) +void CWalletTx::RelayWalletTransaction() { BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) { if (!tx.IsCoinBase()) - { - uint256 hash = tx.GetHash(); - if (!txdb.ContainsTx(hash)) - RelayMessage(CInv(MSG_TX, hash), (CTransaction)tx); - } + if (tx.GetDepthInMainChain() == 0) + RelayTransaction((CTransaction)tx, tx.GetHash()); } if (!IsCoinBase()) { - uint256 hash = GetHash(); - if (!txdb.ContainsTx(hash)) - { + if (GetDepthInMainChain() == 0) { + uint256 hash = GetHash(); printf("Relaying wtx %s\n", hash.ToString().substr(0,10).c_str()); - RelayMessage(CInv(MSG_TX, hash), (CTransaction)*this); + RelayTransaction((CTransaction)*this, hash); } } } -void CWalletTx::RelayWalletTransaction() -{ - CTxDB txdb("r"); - RelayWalletTransaction(txdb); -} - void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away @@ -900,7 +871,6 @@ void CWallet::ResendWalletTransactions() // Rebroadcast any of our txes that aren't in a block yet printf("ResendWalletTransactions()\n"); - CTxDB txdb("r"); { LOCK(cs_wallet); // Sort them in chronological order @@ -916,7 +886,7 @@ void CWallet::ResendWalletTransactions() BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) { CWalletTx& wtx = *item.second; - wtx.RelayWalletTransaction(txdb); + wtx.RelayWalletTransaction(); } } } @@ -970,9 +940,8 @@ int64 CWallet::GetImmatureBalance() const LOCK(cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { - const CWalletTx& pcoin = (*it).second; - if (pcoin.IsCoinBase() && pcoin.GetBlocksToMaturity() > 0 && pcoin.GetDepthInMainChain() >= 2) - nTotal += GetCredit(pcoin); + const CWalletTx* pcoin = &(*it).second; + nTotal += pcoin->GetImmatureCredit(); } } return nTotal; @@ -998,9 +967,11 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; - for (unsigned int i = 0; i < pcoin->vout.size(); i++) - if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && pcoin->vout[i].nValue > 0) + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { + if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && + !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0) vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + } } } } @@ -1171,8 +1142,6 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW { LOCK2(cs_main, cs_wallet); - // txdb must be opened before the mapWallet lock - CTxDB txdb("r"); { nFeeRet = nTransactionFee; loop @@ -1195,7 +1164,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; - dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain(); + //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; @@ -1229,7 +1201,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW scriptChange.SetDestination(vchPubKey.GetID()); // Insert change txn at random position: - vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()); + vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); wtxNew.vout.insert(position, CTxOut(nChange, scriptChange)); } else @@ -1247,7 +1219,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= MAX_BLOCK_SIZE_GEN/5) + if (nBytes >= MAX_STANDARD_TX_SIZE) return false; dPriority /= nBytes; @@ -1262,7 +1234,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW } // Fill vtxPrev by copying from previous transactions vtxPrev - wtxNew.AddSupportingTransactions(txdb); + wtxNew.AddSupportingTransactions(); wtxNew.fTimeReceivedIsTxTime = true; break; @@ -1317,7 +1289,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) mapRequestCount[wtxNew.GetHash()] = 0; // Broadcast - if (!wtxNew.AcceptToMemoryPool()) + if (!wtxNew.AcceptToMemoryPool(true, false)) { // This must not fail. The transaction has already been signed and recorded. printf("CommitTransaction() : Error: Transaction not valid"); @@ -1338,7 +1310,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, if (IsLocked()) { - string strError = _("Error: Wallet locked, unable to create transaction "); + string strError = _("Error: Wallet locked, unable to create transaction!"); printf("SendMoney() : %s", strError.c_str()); return strError; } @@ -1346,18 +1318,18 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, { string strError; if (nValue + nFeeRequired > GetBalance()) - 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()); + 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()); else - strError = _("Error: Transaction creation failed "); + strError = _("Error: Transaction creation failed!"); printf("SendMoney() : %s", strError.c_str()); return strError; } - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired, _("Sending..."))) + 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 _("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 ""; } @@ -1382,12 +1354,12 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64 nVal -int CWallet::LoadWallet(bool& fFirstRunRet) +DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (!fFileBacked) return DB_LOAD_OK; fFirstRunRet = false; - int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); + DBErrors nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this); if (nLoadWalletRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) @@ -1435,7 +1407,7 @@ void CWallet::PrintWallet(const CBlock& block) if (mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } } printf("\n"); @@ -1522,7 +1494,7 @@ bool CWallet::TopUpKeyPool() if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size()); + printf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size()); } } return true; @@ -1675,29 +1647,38 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() { CWalletTx *pcoin = &walletEntry.second; - if (pcoin->vin.size() > 0 && IsMine(pcoin->vin[0])) + 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)) /* If this input isn't mine, ignore it */ + 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 - BOOST_FOREACH(CTxOut txout, pcoin->vout) - if (IsChange(txout)) - { - CWalletTx tx = mapWallet[pcoin->vin[0].prevout.hash]; - CTxDestination txoutAddr; - if(!ExtractDestination(txout.scriptPubKey, txoutAddr)) - continue; - grouping.insert(txoutAddr); - } - groupings.insert(grouping); - grouping.clear(); + 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 @@ -1813,3 +1794,35 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) NotifyTransactionChanged(this, hashTx, CT_UPDATED); } } + +void CWallet::LockCoin(COutPoint& output) +{ + setLockedCoins.insert(output); +} + +void CWallet::UnlockCoin(COutPoint& output) +{ + setLockedCoins.erase(output); +} + +void CWallet::UnlockAllCoins() +{ + setLockedCoins.clear(); +} + +bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const +{ + COutPoint outpt(hash, n); + + return (setLockedCoins.count(outpt) > 0); +} + +void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) +{ + for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); + it != setLockedCoins.end(); it++) { + COutPoint outpt = (*it); + vOutpts.push_back(outpt); + } +} + |