diff options
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 397 |
1 files changed, 288 insertions, 109 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 50d20485de..28479c0ed1 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -7,14 +7,21 @@ #include "base58.h" #include "checkpoints.h" +#include "chain.h" #include "coincontrol.h" #include "consensus/consensus.h" #include "consensus/validation.h" +#include "key.h" +#include "keystore.h" #include "main.h" #include "net.h" +#include "policy/policy.h" +#include "primitives/block.h" +#include "primitives/transaction.h" #include "script/script.h" #include "script/sign.h" #include "timedata.h" +#include "txmempool.h" #include "util.h" #include "utilmoneystr.h" @@ -32,15 +39,14 @@ using namespace std; CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; -bool bSpendZeroConfChange = true; -bool fSendFreeTransactions = false; -bool fPayAtLeastCustomFee = true; +bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; +bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS; /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Override with -mintxfee */ -CFeeRate CWallet::minTxFee = CFeeRate(1000); +CFeeRate CWallet::minTxFee = CFeeRate(DEFAULT_TRANSACTION_MINFEE); /** @defgroup mapWallet * @@ -107,6 +113,9 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) script = GetScriptForDestination(pubkey.GetID()); if (HaveWatchOnly(script)) RemoveWatchOnly(script); + script = GetScriptForRawPubKey(pubkey); + if (HaveWatchOnly(script)) + RemoveWatchOnly(script); if (!fFileBacked) return true; @@ -419,6 +428,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range) const uint256& hash = it->second; CWalletTx* copyTo = &mapWallet[hash]; if (copyFrom == copyTo) continue; + if (!copyFrom->IsEquivalentTo(*copyTo)) continue; copyTo->mapValue = copyFrom->mapValue; copyTo->vOrderForm = copyFrom->vOrderForm; // fTimeReceivedIsTxTime not copied on purpose @@ -577,31 +587,6 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) return nRet; } -CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount) -{ - AssertLockHeld(cs_wallet); // mapWallet - CWalletDB walletdb(strWalletFile); - - // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. - TxItems txOrdered; - - // Note: maintaining indices in the database of (account,time) --> txid and (account, time) --> acentry - // would make this much faster for applications that do this a lot. - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) - { - CWalletTx* wtx = &((*it).second); - txOrdered.insert(make_pair(wtx->nOrderPos, TxPair(wtx, (CAccountingEntry*)0))); - } - acentries.clear(); - walletdb.ListAccountCreditDebit(strAccount, acentries); - BOOST_FOREACH(CAccountingEntry& entry, acentries) - { - txOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); - } - - return txOrdered; -} - void CWallet::MarkDirty() { { @@ -618,8 +603,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD if (fFromLoadWallet) { mapWallet[hash] = wtxIn; - mapWallet[hash].BindWallet(this); + CWalletTx& wtx = mapWallet[hash]; + wtx.BindWallet(this); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); AddToSpends(hash); + BOOST_FOREACH(const CTxIn& txin, wtx.vin) { + if (mapWallet.count(txin.prevout.hash)) { + CWalletTx& prevtx = mapWallet[txin.prevout.hash]; + if (prevtx.nIndex == -1 && !prevtx.hashBlock.IsNull()) { + MarkConflicted(prevtx.hashBlock, wtx.GetHash()); + } + } + } } else { @@ -633,6 +628,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { wtx.nTimeReceived = GetAdjustedTime(); wtx.nOrderPos = IncOrderPosNext(pwalletdb); + wtxOrdered.insert(make_pair(wtx.nOrderPos, TxPair(&wtx, (CAccountingEntry*)0))); wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashBlock.IsNull()) @@ -644,9 +640,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD { // Tolerate times up to the last timestamp in the wallet not more than 5 minutes into the future int64_t latestTolerated = latestNow + 300; - std::list<CAccountingEntry> acentries; - TxItems txOrdered = OrderedTxItems(acentries); - for (TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + const TxItems & txOrdered = wtxOrdered; + for (TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) { CWalletTx *const pwtx = (*it).second.first; if (pwtx == &wtx) @@ -691,9 +686,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD wtx.hashBlock = wtxIn.hashBlock; fUpdated = true; } - if (wtxIn.nIndex != -1 && (wtxIn.vMerkleBranch != wtx.vMerkleBranch || wtxIn.nIndex != wtx.nIndex)) + if (wtxIn.nIndex != -1 && (wtxIn.nIndex != wtx.nIndex)) { - wtx.vMerkleBranch = wtxIn.vMerkleBranch; wtx.nIndex = wtxIn.nIndex; fUpdated = true; } @@ -740,6 +734,20 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl { { AssertLockHeld(cs_wallet); + + if (pblock) { + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout); + while (range.first != range.second) { + if (range.first->second != tx.GetHash()) { + LogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pblock->GetHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n); + MarkConflicted(pblock->GetHash(), range.first->second); + } + range.first++; + } + } + } + bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; if (fExisted || IsMine(tx) || IsFromMe(tx)) @@ -760,9 +768,57 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl return false; } +void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) +{ + LOCK2(cs_main, cs_wallet); + + CBlockIndex* pindex; + assert(mapBlockIndex.count(hashBlock)); + pindex = mapBlockIndex[hashBlock]; + int conflictconfirms = 0; + if (chainActive.Contains(pindex)) { + conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1); + } + assert(conflictconfirms < 0); + + // Do not flush the wallet here for performance reasons + CWalletDB walletdb(strWalletFile, "r+", false); + + std::deque<uint256> todo; + std::set<uint256> done; + + todo.push_back(hashTx); + + while (!todo.empty()) { + uint256 now = todo.front(); + todo.pop_front(); + done.insert(now); + assert(mapWallet.count(now)); + CWalletTx& wtx = mapWallet[now]; + int currentconfirm = wtx.GetDepthInMainChain(); + if (conflictconfirms < currentconfirm) { + // Block is 'more conflicted' than current confirm; update. + // Mark transaction as conflicted with this block. + wtx.nIndex = -1; + wtx.hashBlock = hashBlock; + wtx.MarkDirty(); + wtx.WriteToDisk(&walletdb); + // Iterate over all its outputs, and mark transactions in the wallet that spend them conflicted too + TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0)); + while (iter != mapTxSpends.end() && iter->first.hash == now) { + if (!done.count(iter->second)) { + todo.push_back(iter->second); + } + iter++; + } + } + } +} + void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) { LOCK2(cs_main, cs_wallet); + if (!AddToWalletIfInvolvingMe(tx, pblock, true)) return; // Not one of ours @@ -1068,7 +1124,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ShowProgress(_("Rescanning..."), std::max(1, std::min(99, (int)((Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex, false) - dProgressStart) / (dProgressTip - dProgressStart) * 100)))); CBlock block; - ReadBlockFromDisk(block, pindex); + ReadBlockFromDisk(block, pindex, Params().GetConsensus()); BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) @@ -1102,7 +1158,7 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && nDepth < 0) { + if (!wtx.IsCoinBase() && nDepth == 0) { mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx)); } } @@ -1316,6 +1372,14 @@ bool CWalletTx::IsTrusted() const if (!bSpendZeroConfChange || !IsFromMe(ISMINE_ALL)) // using wtx's cached debit return false; + // Don't trust unconfirmed transactions from us unless they are in the mempool. + { + LOCK(mempool.cs); + if (!mempool.exists(GetHash())) { + return false; + } + } + // Trusted if all inputs are from us and are in the mempool: BOOST_FOREACH(const CTxIn& txin, vin) { @@ -1330,6 +1394,15 @@ bool CWalletTx::IsTrusted() const return true; } +bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const +{ + CMutableTransaction tx1 = *this; + CMutableTransaction tx2 = tx; + for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript(); + for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript(); + return CTransaction(tx1) == CTransaction(tx2); +} + std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime) { std::vector<uint256> result; @@ -1478,9 +1551,6 @@ CAmount CWallet::GetImmatureWatchOnlyBalance() const return nTotal; } -/** - * populate vCoins with vector of available COutputs. - */ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const CCoinControl *coinControl, bool fIncludeZeroValue) const { vCoins.clear(); @@ -1509,8 +1579,10 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const isminetype mine = IsMine(pcoin->vout[i]); if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO && !IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) && - (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) - vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO)); + (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i))) + vCoins.push_back(COutput(pcoin, i, nDepth, + ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || + (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO))); } } } @@ -1598,7 +1670,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nValueRet += coin.first; return true; } - else if (n < nTargetValue + CENT) + else if (n < nTargetValue + MIN_CHANGE) { vValue.push_back(coin); nTotalLower += n; @@ -1633,14 +1705,14 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int vector<char> vfBest; CAmount nBest; - ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000); - if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT) - ApproximateBestSubset(vValue, nTotalLower, nTargetValue + CENT, vfBest, nBest, 1000); + ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest); + if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) + ApproximateBestSubset(vValue, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest); // If we have a bigger coin and (either the stochastic approximation didn't find a good solution, // or the next bigger coin is closer), return the bigger coin if (coinLowestLarger.second.first && - ((nBest != nTargetValue && nBest < nTargetValue + CENT) || coinLowestLarger.first <= nBest)) + ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || coinLowestLarger.first <= nBest)) { setCoinsRet.insert(coinLowestLarger.second); nValueRet += coinLowestLarger.first; @@ -1669,25 +1741,109 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx* AvailableCoins(vCoins, true, coinControl); // coin control -> return all selected outputs (we want all selected to go into the transaction for sure) - if (coinControl && coinControl->HasSelected()) + if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs) { BOOST_FOREACH(const COutput& out, vCoins) { - if(!out.fSpendable) - continue; + if (!out.fSpendable) + continue; nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); } return (nValueRet >= nTargetValue); } - return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || - SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || - (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); + // calculate value from preset inputs and store them + set<pair<const CWalletTx*, uint32_t> > setPresetCoins; + CAmount nValueFromPresetInputs = 0; + + std::vector<COutPoint> vPresetInputs; + if (coinControl) + coinControl->ListSelected(vPresetInputs); + BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs) + { + map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash); + if (it != mapWallet.end()) + { + const CWalletTx* pcoin = &it->second; + // Clearly invalid input, fail + if (pcoin->vout.size() <= outpoint.n) + return false; + nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue; + setPresetCoins.insert(make_pair(pcoin, outpoint.n)); + } else + return false; // TODO: Allow non-wallet inputs + } + + // remove preset inputs from vCoins + for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();) + { + if (setPresetCoins.count(make_pair(it->tx, it->i))) + it = vCoins.erase(it); + else + ++it; + } + + bool res = nTargetValue <= nValueFromPresetInputs || + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) || + SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) || + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet)); + + // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset + setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end()); + + // add preset inputs to the total value selected + nValueRet += nValueFromPresetInputs; + + return res; +} + +bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching) +{ + vector<CRecipient> vecSend; + + // Turn the txout set into a CRecipient vector + BOOST_FOREACH(const CTxOut& txOut, tx.vout) + { + CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false}; + vecSend.push_back(recipient); + } + + CCoinControl coinControl; + coinControl.fAllowOtherInputs = true; + coinControl.fAllowWatchOnly = includeWatching; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + coinControl.Select(txin.prevout); + + CReserveKey reservekey(this); + CWalletTx wtx; + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false)) + return false; + + if (nChangePosRet != -1) + tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]); + + // Add new txins (keeping original txin scriptSig/order) + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + { + bool found = false; + BOOST_FOREACH(const CTxIn& origTxIn, tx.vin) + { + if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n) + { + found = true; + break; + } + } + if (!found) + tx.vin.push_back(txin); + } + + return true; } -bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, - CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl) +bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, + int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign) { CAmount nValue = 0; unsigned int nSubtractFeeFromAmount = 0; @@ -1749,6 +1905,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, LOCK2(cs_main, cs_wallet); { nFeeRet = 0; + // Start with no fee and loop until there is enough fee while (true) { txNew.vin.clear(); @@ -1757,9 +1914,9 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, nChangePosRet = -1; bool fFirst = true; - CAmount nTotalValue = nValue; + CAmount nValueToSelect = nValue; if (nSubtractFeeFromAmount == 0) - nTotalValue += nFeeRet; + nValueToSelect += nFeeRet; double dPriority = 0; // vouts to the payees BOOST_FOREACH (const CRecipient& recipient, vecSend) @@ -1796,7 +1953,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, // Choose coins to use set<pair<const CWalletTx*,unsigned int> > setCoins; CAmount nValueIn = 0; - if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl)) + if (!SelectCoins(nValueToSelect, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient funds"); return false; @@ -1809,15 +1966,13 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, //a chance at a free transaction. //But mempool inputs might still be in the mempool, so their age stays 0 int age = pcoin.first->GetDepthInMainChain(); + assert(age >= 0); if (age != 0) age += 1; dPriority += (double)nCredit * age; } - CAmount nChange = nValueIn - nValue; - if (nSubtractFeeFromAmount == 0) - nChange -= nFeeRet; - + const CAmount nChange = nValueIn - nValueToSelect; if (nChange > 0) { // Fill a vout to ourself @@ -1900,40 +2055,59 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, // Sign int nIn = 0; + CTransaction txNewConst(txNew); BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) - if (!SignSignature(*this, *coin.first, txNew, nIn++)) + { + bool signSuccess; + const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey; + CScript& scriptSigRes = txNew.vin[nIn].scriptSig; + if (sign) + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes); + else + signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes); + + if (!signSuccess) { strFailReason = _("Signing transaction failed"); return false; } + nIn++; + } + + unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION); + + // Remove scriptSigs if we used dummy signatures for fee calculation + if (!sign) { + BOOST_FOREACH (CTxIn& vin, txNew.vin) + vin.scriptSig = CScript(); + } // Embed the constructed transaction data in wtxNew. *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew); // 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 = wtxNew.ComputePriority(dPriority, nBytes); // Can we complete this as a free transaction? if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE) { // Not enough fee: enough priority? - double dPriorityNeeded = mempool.estimatePriority(nTxConfirmTarget); - // Not enough mempool history to estimate: use hard-coded AllowFree. - if (dPriorityNeeded <= 0 && AllowFree(dPriority)) - break; - - // Small enough, and priority high enough, to send for free - if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded) + double dPriorityNeeded = mempool.estimateSmartPriority(nTxConfirmTarget); + // Require at least hard-coded AllowFree. + if (dPriority >= dPriorityNeeded && AllowFree(dPriority)) break; } CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { + nFeeNeeded = coinControl->nMinimumTotalFee; + } // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. @@ -1999,7 +2173,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) if (!wtxNew.AcceptToMemoryPool(false)) { // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CommitTransaction(): Error: Transaction not valid"); + LogPrintf("CommitTransaction(): Error: Transaction not valid\n"); return false; } wtxNew.RelayWalletTransaction(); @@ -2008,20 +2182,36 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) return true; } +bool CWallet::AddAccountingEntry(const CAccountingEntry& acentry, CWalletDB & pwalletdb) +{ + if (!pwalletdb.WriteAccountingEntry_Backend(acentry)) + return false; + + laccentries.push_back(acentry); + CAccountingEntry & entry = laccentries.back(); + wtxOrdered.insert(make_pair(entry.nOrderPos, TxPair((CWalletTx*)0, &entry))); + + return true; +} + +CAmount CWallet::GetRequiredFee(unsigned int nTxBytes) +{ + return std::max(minTxFee.GetFee(nTxBytes), ::minRelayTxFee.GetFee(nTxBytes)); +} + CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) { // payTxFee is user-set "I want to pay this much" CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes); - // user selected total at least (default=true) - if (fPayAtLeastCustomFee && nFeeNeeded > 0 && nFeeNeeded < payTxFee.GetFeePerK()) - nFeeNeeded = payTxFee.GetFeePerK(); // User didn't set: use -txconfirmtarget to estimate... - if (nFeeNeeded == 0) - nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes); - // ... unless we don't have enough mempool data, in which case fall - // back to a hard-coded fee - if (nFeeNeeded == 0) - nFeeNeeded = minTxFee.GetFee(nTxBytes); + if (nFeeNeeded == 0) { + int estimateFoundTarget = nConfirmTarget; + nFeeNeeded = pool.estimateSmartFee(nConfirmTarget, &estimateFoundTarget).GetFee(nTxBytes); + // ... unless we don't have enough mempool data for our desired target + // so we make sure we're paying at least minTxFee + if (nFeeNeeded == 0 || (unsigned int)estimateFoundTarget > nConfirmTarget) + nFeeNeeded = std::max(nFeeNeeded, GetRequiredFee(nTxBytes)); + } // prevent user from paying a non-sense fee (like 1 satoshi): 0 < fee < minRelayFee if (nFeeNeeded < ::minRelayTxFee.GetFee(nTxBytes)) nFeeNeeded = ::minRelayTxFee.GetFee(nTxBytes); @@ -2158,7 +2348,7 @@ bool CWallet::NewKeyPool() if (IsLocked()) return false; - int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0); + int64_t nKeys = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t)0); for (int i = 0; i < nKeys; i++) { int64_t nIndex = i+1; @@ -2185,7 +2375,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize) if (kpSize > 0) nTargetSize = kpSize; else - nTargetSize = max(GetArg("-keypool", 100), (int64_t) 0); + nTargetSize = max(GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), (int64_t) 0); while (setKeyPool.size() < (nTargetSize + 1)) { @@ -2490,6 +2680,17 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) } } +void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script) +{ + boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this)); + CPubKey pubkey; + if (!rKey->GetReservedKey(pubkey)) + return; + + script = rKey; + script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; +} + void CWallet::LockCoin(COutPoint& output) { AssertLockHeld(cs_wallet); // setLockedCoins @@ -2685,15 +2886,11 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block) break; if (nIndex == (int)block.vtx.size()) { - vMerkleBranch.clear(); nIndex = -1; LogPrintf("ERROR: SetMerkleBranch(): couldn't find tx in block\n"); return 0; } - // Fill in merkle branch - vMerkleBranch = block.GetMerkleBranch(nIndex); - // Is the tx in a block that's in the main chain BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi == mapBlockIndex.end()) @@ -2705,9 +2902,9 @@ int CMerkleTx::SetMerkleBranch(const CBlock& block) return chainActive.Height() - pindex->nHeight + 1; } -int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const +int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const { - if (hashBlock.IsNull() || nIndex == -1) + if (hashBlock.IsNull()) return 0; AssertLockHeld(cs_main); @@ -2719,26 +2916,8 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const if (!pindex || !chainActive.Contains(pindex)) return 0; - // Make sure the merkle branch connects to this block - if (!fMerkleVerified) - { - if (CBlock::CheckMerkleBranch(GetHash(), vMerkleBranch, nIndex) != pindex->hashMerkleRoot) - return 0; - fMerkleVerified = true; - } - pindexRet = pindex; - return chainActive.Height() - pindex->nHeight + 1; -} - -int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet) const -{ - AssertLockHeld(cs_main); - int nResult = GetDepthInMainChainINTERNAL(pindexRet); - if (nResult == 0 && !mempool.exists(GetHash())) - return -1; // Not in chain, not in mempool - - return nResult; + return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1); } int CMerkleTx::GetBlocksToMaturity() const @@ -2752,6 +2931,6 @@ int CMerkleTx::GetBlocksToMaturity() const bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) { CValidationState state; - return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, fRejectAbsurdFee); + return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, fRejectAbsurdFee); } |