From 461764cbbea5965ebbd248f221876743d7a9ccd4 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Mon, 8 Nov 2010 22:06:07 +0000 Subject: [PATCH] -paytxfee is now per KB, BitcoinMiner prioritise transactions by how old their dependencies are git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@176 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- build-msw.txt | 5 +-- init.cpp | 3 +- main.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++-------- main.h | 8 ++-- serialize.h | 2 +- ui.cpp | 9 +++- 6 files changed, 119 insertions(+), 27 deletions(-) diff --git a/build-msw.txt b/build-msw.txt index 7a58aaa6..3082f694 100644 --- a/build-msw.txt +++ b/build-msw.txt @@ -63,8 +63,7 @@ nmake -f makefile.vc OpenSSL ------- -Bitcoin does not use any encryption. If you want to do a no-everything -build of OpenSSL to exclude encryption routines, a few patches are required. +If you want to exclude unused optional algorithms, a few patches are required. (instructions for OpenSSL v0.9.8k) Edit engines\e_gmp.c and engines\e_capi.c and add this #ifndef around @@ -88,7 +87,7 @@ Build cd \openssl ms\mingw32.bat -If you want to use it with MSVC, generate the .lib file +If you're using MSVC, generate the .lib file lib /machine:i386 /def:ms\libeay32.def /out:out\libeay32.lib diff --git a/init.cpp b/init.cpp index b10e22a3..78e842b5 100644 --- a/init.cpp +++ b/init.cpp @@ -173,6 +173,7 @@ bool AppInit2(int argc, char* argv[]) " -proxy= \t " + _("Connect through socks4 proxy\n") + " -addnode= \t " + _("Add a node to connect to\n") + " -connect= \t\t " + _("Connect only to the specified node\n") + + " -paytxfee= \t " + _("Fee per KB to add to transactions you send\n") + " -server \t\t " + _("Accept command line and JSON-RPC commands\n") + " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") + " -testnet \t\t " + _("Use the test network\n") + @@ -413,7 +414,7 @@ bool AppInit2(int argc, char* argv[]) wxMessageBox(_("Invalid amount for -paytxfee="), "Bitcoin"); return false; } - if (nTransactionFee > 1 * COIN) + if (nTransactionFee > 0.25 * COIN) wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION); } diff --git a/main.cpp b/main.cpp index 2cb418aa..904c2b8f 100644 --- a/main.cpp +++ b/main.cpp @@ -277,6 +277,34 @@ void EraseOrphanTx(uint256 hash) // CTransaction // +bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet) +{ + SetNull(); + if (!txdb.ReadTxIndex(prevout.hash, txindexRet)) + return false; + if (!ReadFromDisk(txindexRet.pos)) + return false; + if (prevout.n >= vout.size()) + { + SetNull(); + return false; + } + return true; +} + +bool CTransaction::ReadFromDisk(CTxDB& txdb, COutPoint prevout) +{ + CTxIndex txindex; + return ReadFromDisk(txdb, prevout, txindex); +} + +bool CTransaction::ReadFromDisk(COutPoint prevout) +{ + CTxDB txdb("r"); + CTxIndex txindex; + return ReadFromDisk(txdb, prevout, txindex); +} + bool CTxIn::IsMine() const { CRITICAL_BLOCK(cs_mapWallet) @@ -2882,7 +2910,7 @@ void CallCPUID(int in, int& aret, int& cret) "mov %2, %%eax; " // in into eax "cpuid;" "mov %%eax, %0;" // eax into a - "mov %%ecx, %1;" // eax into c + "mov %%ecx, %1;" // ecx into c :"=r"(a),"=r"(c) /* output */ :"r"(in) /* input */ :"%eax","%ecx" /* clobbered register */ @@ -3068,42 +3096,97 @@ void BitcoinMiner() CRITICAL_BLOCK(cs_mapTransactions) { CTxDB txdb("r"); + + // Priority order to process transactions + multimap mapPriority; + for (map::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi) + { + CTransaction& tx = (*mi).second; + if (tx.IsCoinBase() || !tx.IsFinal()) + continue; + + double dPriority = 0; + foreach(const CTxIn& txin, tx.vin) + { + // Read prev transaction + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + continue; + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + + // Read block header + int nConf = 0; + CBlock block; + if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + { + map::iterator it = mapBlockIndex.find(block.GetHash()); + if (it != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*it).second; + if (pindex->IsInMainChain()) + nConf = 1 + nBestHeight - pindex->nHeight; + } + } + + dPriority += (double)nValueIn * nConf; + + if (fDebug && mapArgs.count("-printpriority")) + printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); + } + + // Priority is sum(valuein * age) / txsize + dPriority /= ::GetSerializeSize(tx, SER_NETWORK); + + mapPriority.insert(make_pair(-dPriority, &(*mi).second)); + + if (fDebug && mapArgs.count("-printpriority")) + printf("priority %-20.1f %s\n%s\n", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str()); + } + + // Collect transactions into block map mapTestPool; - vector vfAlreadyAdded(mapTransactions.size()); uint64 nBlockSize = 1000; int nBlockSigOps = 100; bool fFoundSomething = true; while (fFoundSomething) { fFoundSomething = false; - unsigned int n = 0; - for (map::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n) + for (multimap::iterator mi = mapPriority.begin(); mi != mapPriority.end();) { - if (vfAlreadyAdded[n]) - continue; - CTransaction& tx = (*mi).second; - if (tx.IsCoinBase() || !tx.IsFinal()) - continue; + CTransaction& tx = *(*mi).second; unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK); if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) + { + mapPriority.erase(mi++); continue; + } int nTxSigOps = tx.GetSigOpCount(); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + { + mapPriority.erase(mi++); continue; + } // Transaction fee based on block size int64 nMinFee = tx.GetMinFee(nBlockSize); + // Connecting can fail due to dependency on other memory pool transactions + // that aren't in the block yet, so keep trying in later passes map mapTestPoolTmp(mapTestPool); if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee)) + { + mi++; continue; + } swap(mapTestPool, mapTestPoolTmp); + // Added pblock->vtx.push_back(tx); nBlockSize += nTxSize; nBlockSigOps += nTxSigOps; - vfAlreadyAdded[n] = true; fFoundSomething = true; + mapPriority.erase(mi++); } } } @@ -3426,16 +3509,15 @@ bool SelectCoins(int64 nTargetValue, set& setCoinsRet) -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRequiredRet) +bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet) { - nFeeRequiredRet = 0; CRITICAL_BLOCK(cs_main) { // txdb must be opened before the mapWallet lock CTxDB txdb("r"); CRITICAL_BLOCK(cs_mapWallet) { - int64 nFee = nTransactionFee; + nFeeRet = nTransactionFee; loop { wtxNew.vin.clear(); @@ -3444,7 +3526,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR if (nValue < 0) return false; int64 nValueOut = nValue; - int64 nTotalValue = nValue + nFee; + int64 nTotalValue = nValue + nFeeRet; // Choose coins to use set setCoins; @@ -3504,13 +3586,16 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR return false; // Limit size - if (::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK) >= MAX_BLOCK_SIZE_GEN/5) + unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK); + if (nBytes >= MAX_BLOCK_SIZE_GEN/5) return false; // Check that enough fee is included - if (nFee < wtxNew.GetMinFee()) + int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); + int64 nMinFee = wtxNew.GetMinFee(); + if (nFeeRet < max(nPayFee, nMinFee)) { - nFee = nFeeRequiredRet = wtxNew.GetMinFee(); + nFeeRet = max(nPayFee, nMinFee); continue; } diff --git a/main.h b/main.h index af552a5b..5176d90c 100644 --- a/main.h +++ b/main.h @@ -76,7 +76,7 @@ bool ProcessMessages(CNode* pfrom); bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv); bool SendMessages(CNode* pto, bool fSendTrickle); int64 GetBalance(); -bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRequiredRet); +bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); bool BroadcastTransaction(CWalletTx& wtxNew); string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); @@ -580,7 +580,6 @@ public: return true; } - friend bool operator==(const CTransaction& a, const CTransaction& b) { return (a.nVersion == b.nVersion && @@ -617,6 +616,9 @@ public: } + bool ReadFromDisk(CTxDB& txdb, COutPoint prevout, CTxIndex& txindexRet); + bool ReadFromDisk(CTxDB& txdb, COutPoint prevout); + bool ReadFromDisk(COutPoint prevout); bool DisconnectInputs(CTxDB& txdb); bool ConnectInputs(CTxDB& txdb, map& mapTestPool, CDiskTxPos posThisTx, CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0); @@ -1654,7 +1656,7 @@ public: bool Cancels(const CAlert& alert) const { if (!IsInEffect()) - false; + return false; // this was a no-op before 31403 return (alert.nID <= nCancel || setCancel.count(alert.nID)); } diff --git a/serialize.h b/serialize.h index af45d898..7b7ab840 100644 --- a/serialize.h +++ b/serialize.h @@ -22,7 +22,7 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int VERSION = 31402; +static const int VERSION = 31403; static const char* pszSubVer = ""; diff --git a/ui.cpp b/ui.cpp index a6f55005..b4eec0a5 100644 --- a/ui.cpp +++ b/ui.cpp @@ -196,7 +196,7 @@ int ThreadSafeMessageBox(const string& message, const string& caption, int style bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent) { - if (nFeeRequired < CENT || fDaemon) + if (nFeeRequired < CENT || nFeeRequired <= nTransactionFee || fDaemon) return true; string strMessage = strprintf( _("This transaction is over the size limit. You can still send it for a fee of %s, " @@ -1966,8 +1966,13 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) string strError = SendMoney(scriptPubKey, nValue, wtx, true); if (strError == "") wxMessageBox(_("Payment sent "), _("Sending...")); - else if (strError != "ABORTED") + else if (strError == "ABORTED") + return; // leave send dialog open + else + { wxMessageBox(strError + " ", _("Sending...")); + EndModal(false); + } } else {