changeset 295:20eee25f3a5b draft

-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
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Mon, 08 Nov 2010 22:06:07 +0000
parents 90af44713689
children 0b03a5606452 1184c5a9c997
files build-msw.txt init.cpp main.cpp main.h serialize.h ui.cpp
diffstat 6 files changed, 119 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/build-msw.txt
+++ b/build-msw.txt
@@ -63,8 +63,7 @@
 
 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 @@
   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
 
 
--- a/init.cpp
+++ b/init.cpp
@@ -173,6 +173,7 @@
             "  -proxy=<ip:port> \t  "   + _("Connect through socks4 proxy\n") +
             "  -addnode=<ip>    \t  "   + _("Add a node to connect to\n") +
             "  -connect=<ip>    \t\t  " + _("Connect only to the specified node\n") +
+            "  -paytxfee=<amt>  \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 @@
             wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "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);
     }
 
--- a/main.cpp
+++ b/main.cpp
@@ -277,6 +277,34 @@
 // 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 @@
         "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 @@
         CRITICAL_BLOCK(cs_mapTransactions)
         {
             CTxDB txdb("r");
+
+            // Priority order to process transactions
+            multimap<double, CTransaction*> mapPriority;
+            for (map<uint256, CTransaction>::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<uint256, CBlockIndex*>::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<uint256, CTxIndex> mapTestPool;
-            vector<char> vfAlreadyAdded(mapTransactions.size());
             uint64 nBlockSize = 1000;
             int nBlockSigOps = 100;
             bool fFoundSomething = true;
             while (fFoundSomething)
             {
                 fFoundSomething = false;
-                unsigned int n = 0;
-                for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)
+                for (multimap<double, CTransaction*>::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<uint256, CTxIndex> 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 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 @@
                 if (nValue < 0)
                     return false;
                 int64 nValueOut = nValue;
-                int64 nTotalValue = nValue + nFee;
+                int64 nTotalValue = nValue + nFeeRet;
 
                 // Choose coins to use
                 set<CWalletTx*> setCoins;
@@ -3504,13 +3586,16 @@
                                 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;
                 }
 
--- a/main.h
+++ b/main.h
@@ -76,7 +76,7 @@
 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 @@
         return true;
     }
 
-
     friend bool operator==(const CTransaction& a, const CTransaction& b)
     {
         return (a.nVersion  == b.nVersion &&
@@ -617,6 +616,9 @@
     }
 
 
+    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<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
                        CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
@@ -1654,7 +1656,7 @@
     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));
     }
 
--- a/serialize.h
+++ b/serialize.h
@@ -22,7 +22,7 @@
 class CAutoFile;
 static const unsigned int MAX_SIZE = 0x02000000;
 
-static const int VERSION = 31402;
+static const int VERSION = 31403;
 static const char* pszSubVer = "";
 
 
--- a/ui.cpp
+++ b/ui.cpp
@@ -196,7 +196,7 @@
 
 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 @@
             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
         {