aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp157
1 files changed, 61 insertions, 96 deletions
diff --git a/src/main.cpp b/src/main.cpp
index aace382d8b..a98b83b6af 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,6 +31,7 @@ CTxMemPool mempool;
unsigned int nTransactionsUpdated = 0;
map<uint256, CBlockIndex*> mapBlockIndex;
+std::vector<CBlockIndex*> vBlockIndexByHeight;
uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
CBlockIndex* pindexGenesisBlock = NULL;
@@ -48,6 +49,11 @@ bool fBenchmark = false;
bool fTxIndex = false;
unsigned int nCoinCacheSize = 5000;
+/** Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) */
+int64 CTransaction::nMinTxFee = 10000; // Override with -mintxfee
+/** Fees smaller than this (in satoshi) are considered zero fee (for relaying) */
+int64 CTransaction::nMinRelayTxFee = 10000;
+
CMedianFilter<int> cPeerBlockCounts(8, 0); // Amount of blocks that other nodes claim to have
map<uint256, CBlock*> mapOrphanBlocks;
@@ -352,9 +358,22 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
//////////////////////////////////////////////////////////////////////////////
//
-// CTransaction
+// CTransaction / CTxOut
//
+bool CTxOut::IsDust() const
+{
+ // "Dust" is defined in terms of CTransaction::nMinRelayTxFee,
+ // which has units satoshis-per-kilobyte.
+ // If you'd pay more than 1/3 in fees
+ // to spend something, then we consider it dust.
+ // A typical txout is 33 bytes big, and will
+ // need a CTxIn of at least 148 bytes to spend,
+ // so dust is a txout less than 54 uBTC
+ // (5430 satoshis) with default nMinRelayTxFee
+ return ((nValue*1000)/(3*((int)GetSerializeSize(SER_DISK,0)+148)) < CTransaction::nMinRelayTxFee);
+}
+
bool CTransaction::IsStandard() const
{
if (nVersion > CTransaction::CURRENT_VERSION)
@@ -384,7 +403,7 @@ bool CTransaction::IsStandard() const
BOOST_FOREACH(const CTxOut& txout, vout) {
if (!::IsStandard(txout.scriptPubKey))
return false;
- if (txout.nValue == 0)
+ if (txout.IsDust())
return false;
}
return true;
@@ -574,8 +593,8 @@ bool CTransaction::CheckTransaction(CValidationState &state) const
int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
enum GetMinFee_mode mode) const
{
- // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE
- int64 nBaseFee = (mode == GMF_RELAY) ? MIN_RELAY_TX_FEE : MIN_TX_FEE;
+ // Base fee is either nMinTxFee or nMinRelayTxFee
+ int64 nBaseFee = (mode == GMF_RELAY) ? nMinRelayTxFee : nMinTxFee;
unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
unsigned int nNewBlockSize = nBlockSize + nBytes;
@@ -598,7 +617,7 @@ int64 CTransaction::GetMinFee(unsigned int nBlockSize, bool fAllowFree,
}
}
- // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
+ // To limit dust spam, require base fee if any output is less than 0.01
if (nMinFee < nBaseFee)
{
BOOST_FOREACH(const CTxOut& txout, vout)
@@ -746,7 +765,7 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fCheckIn
// Continuously rate-limit free transactions
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
// be annoying or make others' transactions take longer to confirm.
- if (fLimitFree && nFees < MIN_RELAY_TX_FEE)
+ if (fLimitFree && nFees < CTransaction::nMinRelayTxFee)
{
static double dFreeCount;
static int64 nLastTime;
@@ -1018,19 +1037,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
static CBlockIndex* pblockindexFBBHLast;
CBlockIndex* FindBlockByHeight(int nHeight)
{
- CBlockIndex *pblockindex;
- if (nHeight < nBestHeight / 2)
- pblockindex = pindexGenesisBlock;
- else
- pblockindex = pindexBest;
- if (pblockindexFBBHLast && abs(nHeight - pblockindex->nHeight) > abs(nHeight - pblockindexFBBHLast->nHeight))
- pblockindex = pblockindexFBBHLast;
- while (pblockindex->nHeight > nHeight)
- pblockindex = pblockindex->pprev;
- while (pblockindex->nHeight < nHeight)
- pblockindex = pblockindex->pnext;
- pblockindexFBBHLast = pblockindex;
- return pblockindex;
+ if (nHeight >= (int)vBlockIndexByHeight.size())
+ return NULL;
+ return vBlockIndexByHeight[nHeight];
}
bool CBlock::ReadFromDisk(const CBlockIndex* pindex)
@@ -1213,7 +1222,7 @@ void static InvalidBlockFound(CBlockIndex *pindex) {
pblocktree->WriteBlockIndex(CDiskBlockIndex(pindex));
setBlockIndexValid.erase(pindex);
InvalidChainFound(pindex);
- if (pindex->pnext) {
+ if (pindex->GetNextInMainChain()) {
CValidationState stateDummy;
ConnectBestBlock(stateDummy); // reorganise away from the failed block
}
@@ -1253,7 +1262,7 @@ bool ConnectBestBlock(CValidationState &state) {
if (pindexBest == NULL || pindexTest->nChainWork > pindexBest->nChainWork)
vAttach.push_back(pindexTest);
- if (pindexTest->pprev == NULL || pindexTest->pnext != NULL) {
+ if (pindexTest->pprev == NULL || pindexTest->GetNextInMainChain()) {
reverse(vAttach.begin(), vAttach.end());
BOOST_FOREACH(CBlockIndex *pindexSwitch, vAttach) {
boost::this_thread::interruption_point();
@@ -1324,7 +1333,7 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsViewCache& inputs) const
return nSigOps;
}
-bool CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
+void CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
{
// mark inputs spent
if (!IsCoinBase()) {
@@ -1338,8 +1347,6 @@ bool CTransaction::UpdateCoins(CValidationState &state, CCoinsViewCache &inputs,
// add outputs
assert(inputs.SetCoins(txhash, CCoins(*this, nHeight)));
-
- return true;
}
bool CTransaction::HaveInputs(CCoinsViewCache &inputs) const
@@ -1665,8 +1672,7 @@ bool CBlock::ConnectBlock(CValidationState &state, CBlockIndex* pindex, CCoinsVi
}
CTxUndo txundo;
- if (!tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i)))
- return error("ConnectBlock() : UpdateInputs failed");
+ tx.UpdateCoins(state, view, txundo, pindex->nHeight, GetTxHash(i));
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
@@ -1831,15 +1837,10 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
// At this point, all changes have been done to the database.
// Proceed by updating the memory structures.
- // Disconnect shorter branch
- BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
- if (pindex->pprev)
- pindex->pprev->pnext = NULL;
-
- // Connect longer branch
+ // Register new best chain
+ vBlockIndexByHeight.resize(pindexNew->nHeight + 1);
BOOST_FOREACH(CBlockIndex* pindex, vConnect)
- if (pindex->pprev)
- pindex->pprev->pnext = pindex;
+ vBlockIndexByHeight[pindex->nHeight] = pindex;
// Resurrect memory transactions that were in the disconnected branch
BOOST_FOREACH(CTransaction& tx, vResurrect) {
@@ -1855,7 +1856,7 @@ bool SetBestChain(CValidationState &state, CBlockIndex* pindexNew)
}
// Update best block in wallet (so we can detect restored wallets)
- if (!fIsInitialDownload)
+ if ((pindexNew->nHeight % 20160) == 0 || (!fIsInitialDownload && (pindexNew->nHeight % 144) == 0))
{
const CBlockLocator locator(pindexNew);
::SetBestChain(locator);
@@ -2058,25 +2059,6 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return state.DoS(100, error("CheckBlock() : size limits failed"));
- // Special short-term limits to avoid 10,000 BDB lock limit:
- if (GetBlockTime() >= 1363867200 && // start enforcing 21 March 2013, noon GMT
- GetBlockTime() < 1368576000) // stop enforcing 15 May 2013 00:00:00
- {
- // Rule is: #unique txids referenced <= 4,500
- // ... to prevent 10,000 BDB lock exhaustion on old clients
- set<uint256> setTxIn;
- for (size_t i = 0; i < vtx.size(); i++)
- {
- setTxIn.insert(vtx[i].GetHash());
- if (i == 0) continue; // skip coinbase txin
- BOOST_FOREACH(const CTxIn& txin, vtx[i].vin)
- setTxIn.insert(txin.prevout.hash);
- }
- size_t nTxids = setTxIn.size();
- if (nTxids > 4500)
- return error("CheckBlock() : 15 May maxlocks violation");
- }
-
// Check proof of work matches claimed amount
if (fCheckPOW && !CheckProofOfWork(GetHash(), nBits))
return state.DoS(50, error("CheckBlock() : proof of work failed"));
@@ -2591,12 +2573,12 @@ bool static LoadBlockIndexDB()
nBestHeight = pindexBest->nHeight;
nBestChainWork = pindexBest->nChainWork;
- // set 'next' pointers in best chain
+ // register best chain
CBlockIndex *pindex = pindexBest;
- while(pindex != NULL && pindex->pprev != NULL) {
- CBlockIndex *pindexPrev = pindex->pprev;
- pindexPrev->pnext = pindex;
- pindex = pindexPrev;
+ vBlockIndexByHeight.resize(pindexBest->nHeight + 1);
+ while(pindex != NULL) {
+ vBlockIndexByHeight[pindex->nHeight] = pindex;
+ pindex = pindex->pprev;
}
printf("LoadBlockIndexDB(): hashBestChain=%s height=%d date=%s\n",
hashBestChain.ToString().c_str(), nBestHeight,
@@ -2665,7 +2647,7 @@ bool VerifyDB() {
CBlockIndex *pindex = pindexState;
while (pindex != pindexBest) {
boost::this_thread::interruption_point();
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("VerifyDB() : *** block.ReadFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
@@ -2841,7 +2823,7 @@ void PrintBlockTree()
vector<CBlockIndex*>& vNext = mapNext[pindex];
for (unsigned int i = 0; i < vNext.size(); i++)
{
- if (vNext[i]->pnext)
+ if (vNext[i]->GetNextInMainChain())
{
swap(vNext[0], vNext[i]);
break;
@@ -2949,7 +2931,7 @@ string GetWarnings(string strFor)
string strStatusBar;
string strRPC;
- if (GetBoolArg("-testsafemode"))
+ if (GetBoolArg("-testsafemode", false))
strRPC = "test";
if (!CLIENT_VERSION_IS_RELEASE)
@@ -3422,10 +3404,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Send the rest of the chain
if (pindex)
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
int nLimit = 500;
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str(), nLimit);
- for (; pindex; pindex = pindex->pnext)
+ for (; pindex; pindex = pindex->GetNextInMainChain())
{
if (pindex->GetBlockHash() == hashStop)
{
@@ -3465,14 +3447,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Find the last block the caller has in the main chain
pindex = locator.GetBlockIndex();
if (pindex)
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
}
// we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end
vector<CBlock> vHeaders;
int nLimit = 2000;
printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().c_str());
- for (; pindex; pindex = pindex->pnext)
+ for (; pindex; pindex = pindex->GetNextInMainChain())
{
vHeaders.push_back(pindex->GetBlockHeader());
if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
@@ -4158,7 +4140,10 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
- txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+ CPubKey pubkey;
+ if (!reservekey.GetReservedKey(pubkey))
+ return NULL;
+ txNew.vout[0].scriptPubKey << pubkey << OP_CHECKSIG;
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
@@ -4170,10 +4155,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
- // Special compatibility rule before 15 May: limit size to 500,000 bytes:
- if (GetAdjustedTime() < 1368576000)
- nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN));
-
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000);
@@ -4184,15 +4165,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
unsigned int nBlockMinSize = GetArg("-blockminsize", 0);
nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);
- // Fee-per-kilobyte amount considered the same as "free"
- // Be careful setting this: if you set it to zero then
- // a transaction spammer can cheaply fill blocks using
- // 1-satoshi-fee transactions. It should be set above the real
- // cost to you of processing a transaction.
- int64 nMinTxFee = MIN_TX_FEE;
- if (mapArgs.count("-mintxfee"))
- ParseMoney(mapArgs["-mintxfee"], nMinTxFee);
-
// Collect memory pool transactions into the block
int64 nFees = 0;
{
@@ -4203,7 +4175,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
// Priority order to process transactions
list<COrphan> vOrphan; // list memory doesn't move
map<uint256, vector<COrphan*> > mapDependers;
- bool fPrintPriority = GetBoolArg("-printpriority");
+ bool fPrintPriority = GetBoolArg("-printpriority", false);
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
@@ -4221,8 +4193,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
// Read prev transaction
- CCoins coins;
- if (!view.GetCoins(txin.prevout.hash, coins))
+ if (!view.HaveCoins(txin.prevout.hash))
{
// This should never happen; all transactions in the memory
// pool should connect to either transactions in the chain
@@ -4249,6 +4220,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue;
continue;
}
+ const CCoins &coins = view.GetCoins(txin.prevout.hash);
int64 nValueIn = coins.vout[txin.prevout.n].nValue;
nTotalIn += nValueIn;
@@ -4296,9 +4268,6 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer);
vecPriority.pop_back();
- // second layer cached modifications just for this transaction
- CCoinsViewCache viewTemp(view, true);
-
// Size limits
unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
if (nBlockSize + nTxSize >= nBlockMaxSize)
@@ -4310,7 +4279,7 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
continue;
// Skip free transactions if we're past the minimum block size:
- if (fSortedByFee && (dFeePerKb < nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
+ if (fSortedByFee && (dFeePerKb < CTransaction::nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize))
continue;
// Prioritize by fee once past the priority size or we run out of high-priority
@@ -4323,26 +4292,22 @@ CBlockTemplate* CreateNewBlock(CReserveKey& reservekey)
std::make_heap(vecPriority.begin(), vecPriority.end(), comparer);
}
- if (!tx.HaveInputs(viewTemp))
+ if (!tx.HaveInputs(view))
continue;
- int64 nTxFees = tx.GetValueIn(viewTemp)-tx.GetValueOut();
+ int64 nTxFees = tx.GetValueIn(view)-tx.GetValueOut();
- nTxSigOps += tx.GetP2SHSigOpCount(viewTemp);
+ nTxSigOps += tx.GetP2SHSigOpCount(view);
if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS)
continue;
CValidationState state;
- if (!tx.CheckInputs(state, viewTemp, true, SCRIPT_VERIFY_P2SH))
+ if (!tx.CheckInputs(state, view, true, SCRIPT_VERIFY_P2SH))
continue;
CTxUndo txundo;
uint256 hash = tx.GetHash();
- if (!tx.UpdateCoins(state, viewTemp, txundo, pindexPrev->nHeight+1, hash))
- continue;
-
- // push changes from the second layer cache to the first one
- viewTemp.Flush();
+ tx.UpdateCoins(state, view, txundo, pindexPrev->nHeight+1, hash);
// Added
pblock->vtx.push_back(tx);