Browse Source

-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
miguelfreitas
s_nakamoto 14 years ago
parent
commit
461764cbbe
  1. 5
      build-msw.txt
  2. 3
      init.cpp
  3. 119
      main.cpp
  4. 8
      main.h
  5. 2
      serialize.h
  6. 9
      ui.cpp

5
build-msw.txt

@ -63,8 +63,7 @@ nmake -f makefile.vc
OpenSSL OpenSSL
------- -------
Bitcoin does not use any encryption. If you want to do a no-everything If you want to exclude unused optional algorithms, a few patches are required.
build of OpenSSL to exclude encryption routines, a few patches are required.
(instructions for OpenSSL v0.9.8k) (instructions for OpenSSL v0.9.8k)
Edit engines\e_gmp.c and engines\e_capi.c and add this #ifndef around Edit engines\e_gmp.c and engines\e_capi.c and add this #ifndef around
@ -88,7 +87,7 @@ Build
cd \openssl cd \openssl
ms\mingw32.bat 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 lib /machine:i386 /def:ms\libeay32.def /out:out\libeay32.lib

3
init.cpp

@ -173,6 +173,7 @@ bool AppInit2(int argc, char* argv[])
" -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") + " -proxy=<ip:port> \t " + _("Connect through socks4 proxy\n") +
" -addnode=<ip> \t " + _("Add a node to connect to\n") + " -addnode=<ip> \t " + _("Add a node to connect to\n") +
" -connect=<ip> \t\t " + _("Connect only to the specified node\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") + " -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") + " -daemon \t\t " + _("Run in the background as a daemon and accept commands\n") +
" -testnet \t\t " + _("Use the test network\n") + " -testnet \t\t " + _("Use the test network\n") +
@ -413,7 +414,7 @@ bool AppInit2(int argc, char* argv[])
wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin"); wxMessageBox(_("Invalid amount for -paytxfee=<amount>"), "Bitcoin");
return false; 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); wxMessageBox(_("Warning: -paytxfee is set very high. This is the transaction fee you will pay if you send a transaction."), "Bitcoin", wxOK | wxICON_EXCLAMATION);
} }

119
main.cpp

@ -277,6 +277,34 @@ void EraseOrphanTx(uint256 hash)
// CTransaction // 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 bool CTxIn::IsMine() const
{ {
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
@ -2882,7 +2910,7 @@ void CallCPUID(int in, int& aret, int& cret)
"mov %2, %%eax; " // in into eax "mov %2, %%eax; " // in into eax
"cpuid;" "cpuid;"
"mov %%eax, %0;" // eax into a "mov %%eax, %0;" // eax into a
"mov %%ecx, %1;" // eax into c "mov %%ecx, %1;" // ecx into c
:"=r"(a),"=r"(c) /* output */ :"=r"(a),"=r"(c) /* output */
:"r"(in) /* input */ :"r"(in) /* input */
:"%eax","%ecx" /* clobbered register */ :"%eax","%ecx" /* clobbered register */
@ -3068,42 +3096,97 @@ void BitcoinMiner()
CRITICAL_BLOCK(cs_mapTransactions) CRITICAL_BLOCK(cs_mapTransactions)
{ {
CTxDB txdb("r"); 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; map<uint256, CTxIndex> mapTestPool;
vector<char> vfAlreadyAdded(mapTransactions.size());
uint64 nBlockSize = 1000; uint64 nBlockSize = 1000;
int nBlockSigOps = 100; int nBlockSigOps = 100;
bool fFoundSomething = true; bool fFoundSomething = true;
while (fFoundSomething) while (fFoundSomething)
{ {
fFoundSomething = false; fFoundSomething = false;
unsigned int n = 0; for (multimap<double, CTransaction*>::iterator mi = mapPriority.begin(); mi != mapPriority.end();)
for (map<uint256, CTransaction>::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi, ++n)
{ {
if (vfAlreadyAdded[n]) CTransaction& tx = *(*mi).second;
continue;
CTransaction& tx = (*mi).second;
if (tx.IsCoinBase() || !tx.IsFinal())
continue;
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK); unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK);
if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN)
{
mapPriority.erase(mi++);
continue; continue;
}
int nTxSigOps = tx.GetSigOpCount(); int nTxSigOps = tx.GetSigOpCount();
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
{
mapPriority.erase(mi++);
continue; continue;
}
// Transaction fee based on block size // Transaction fee based on block size
int64 nMinFee = tx.GetMinFee(nBlockSize); 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); map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool);
if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee)) if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee))
{
mi++;
continue; continue;
}
swap(mapTestPool, mapTestPoolTmp); swap(mapTestPool, mapTestPoolTmp);
// Added
pblock->vtx.push_back(tx); pblock->vtx.push_back(tx);
nBlockSize += nTxSize; nBlockSize += nTxSize;
nBlockSigOps += nTxSigOps; nBlockSigOps += nTxSigOps;
vfAlreadyAdded[n] = true;
fFoundSomething = true; fFoundSomething = true;
mapPriority.erase(mi++);
} }
} }
} }
@ -3426,16 +3509,15 @@ bool SelectCoins(int64 nTargetValue, set<CWalletTx*>& 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) CRITICAL_BLOCK(cs_main)
{ {
// txdb must be opened before the mapWallet lock // txdb must be opened before the mapWallet lock
CTxDB txdb("r"); CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_mapWallet)
{ {
int64 nFee = nTransactionFee; nFeeRet = nTransactionFee;
loop loop
{ {
wtxNew.vin.clear(); wtxNew.vin.clear();
@ -3444,7 +3526,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR
if (nValue < 0) if (nValue < 0)
return false; return false;
int64 nValueOut = nValue; int64 nValueOut = nValue;
int64 nTotalValue = nValue + nFee; int64 nTotalValue = nValue + nFeeRet;
// Choose coins to use // Choose coins to use
set<CWalletTx*> setCoins; set<CWalletTx*> setCoins;
@ -3504,13 +3586,16 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR
return false; return false;
// Limit size // 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; return false;
// Check that enough fee is included // 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; continue;
} }

8
main.h

@ -76,7 +76,7 @@ bool ProcessMessages(CNode* pfrom);
bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv); bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv);
bool SendMessages(CNode* pto, bool fSendTrickle); bool SendMessages(CNode* pto, bool fSendTrickle);
int64 GetBalance(); 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 CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
bool BroadcastTransaction(CWalletTx& wtxNew); bool BroadcastTransaction(CWalletTx& wtxNew);
string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
@ -580,7 +580,6 @@ public:
return true; return true;
} }
friend bool operator==(const CTransaction& a, const CTransaction& b) friend bool operator==(const CTransaction& a, const CTransaction& b)
{ {
return (a.nVersion == b.nVersion && 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 DisconnectInputs(CTxDB& txdb);
bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx, bool ConnectInputs(CTxDB& txdb, map<uint256, CTxIndex>& mapTestPool, CDiskTxPos posThisTx,
CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0); CBlockIndex* pindexBlock, int64& nFees, bool fBlock, bool fMiner, int64 nMinFee=0);
@ -1654,7 +1656,7 @@ public:
bool Cancels(const CAlert& alert) const bool Cancels(const CAlert& alert) const
{ {
if (!IsInEffect()) if (!IsInEffect())
false; return false; // this was a no-op before 31403
return (alert.nID <= nCancel || setCancel.count(alert.nID)); return (alert.nID <= nCancel || setCancel.count(alert.nID));
} }

2
serialize.h

@ -22,7 +22,7 @@ class CDataStream;
class CAutoFile; class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000; static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 31402; static const int VERSION = 31403;
static const char* pszSubVer = ""; static const char* pszSubVer = "";

9
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) bool ThreadSafeAskFee(int64 nFeeRequired, const string& strCaption, wxWindow* parent)
{ {
if (nFeeRequired < CENT || fDaemon) if (nFeeRequired < CENT || nFeeRequired <= nTransactionFee || fDaemon)
return true; return true;
string strMessage = strprintf( string strMessage = strprintf(
_("This transaction is over the size limit. You can still send it for a fee of %s, " _("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); string strError = SendMoney(scriptPubKey, nValue, wtx, true);
if (strError == "") if (strError == "")
wxMessageBox(_("Payment sent "), _("Sending...")); wxMessageBox(_("Payment sent "), _("Sending..."));
else if (strError != "ABORTED") else if (strError == "ABORTED")
return; // leave send dialog open
else
{
wxMessageBox(strError + " ", _("Sending...")); wxMessageBox(strError + " ", _("Sending..."));
EndModal(false);
}
} }
else else
{ {

Loading…
Cancel
Save