bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) { assert(!fClient); txindex.SetNull(); if(TXReadWritePool) { boost::unordered_map<uint256, CTxIndex, BlockHasher>::iterator iter = TXReadWritePool->find(hash); if(iter == TXReadWritePool->end()) return Read(make_pair(string("tx"), hash), txindex); txindex = iter->second; return true; } return Read(make_pair(string("tx"), hash), txindex); }
bool CTxDB::ReadTxIndex(uint256 hash, CTxIndex& txindex) { assert(!fClient); txindex.SetNull(); return Read(make_pair(string("tx"), hash), txindex); }
// CreateRestOfTheBlock: collect transactions into block and fill in header bool CreateRestOfTheBlock(CBlock &block, CBlockIndex* pindexPrev) { int nHeight = pindexPrev->nHeight + 1; // Create coinbase tx CTransaction &CoinBase= block.vtx[0]; CoinBase.nTime=block.nTime; CoinBase.vin.resize(1); CoinBase.vin[0].prevout.SetNull(); CoinBase.vout.resize(1); // Height first in coinbase required for block.version=2 CoinBase.vin[0].scriptSig = (CScript() << nHeight) + COINBASE_FLAGS; assert(CoinBase.vin[0].scriptSig.size() <= 100); CoinBase.vout[0].SetEmpty(); // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2); // 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)); // 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); nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); // Minimum block size you want to create; block will be filled with free transactions // until there are no more or the block reaches this size: 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_t nMinTxFee = MIN_TX_FEE; if (mapArgs.count("-mintxfee")) ParseMoney(mapArgs["-mintxfee"], nMinTxFee); // Collect memory pool transactions into the block int64_t nFees = 0; { LOCK2(cs_main, mempool.cs); CTxDB txdb("r"); // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; // This vector will be sorted into a priority queue: vector<TxPriority> vecPriority; vecPriority.reserve(mempool.mapTx.size()); for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi) { CTransaction& tx = (*mi).second; if (tx.IsCoinBase() || tx.IsCoinStake() || !IsFinalTx(tx, nHeight)) continue; COrphan* porphan = NULL; double dPriority = 0; int64_t nTotalIn = 0; bool fMissingInputs = false; for (auto const& txin : tx.vin) { // Read prev transaction CTransaction txPrev; CTxIndex txindex; if (fDebug10) LogPrintf("Enumerating tx %s ",tx.GetHash().GetHex()); if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) { // This should never happen; all transactions in the memory // pool should connect to either transactions in the chain // or other transactions in the memory pool. if (!mempool.mapTx.count(txin.prevout.hash)) { LogPrintf("ERROR: mempool transaction missing input\n"); if (fDebug) assert("mempool transaction missing input" == 0); fMissingInputs = true; if (porphan) vOrphan.pop_back(); break; } // Has to wait for dependencies if (!porphan) { // Use list for automatic deletion vOrphan.push_back(COrphan(&tx)); porphan = &vOrphan.back(); if (fDebug10) LogPrintf("Orphan tx %s ",tx.GetHash().GetHex()); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":ORPHAN;"; } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); nTotalIn += mempool.mapTx[txin.prevout.hash].vout[txin.prevout.n].nValue; continue; } int64_t nValueIn = txPrev.vout[txin.prevout.n].nValue; nTotalIn += nValueIn; int nConf = txindex.GetDepthInMainChain(); dPriority += (double)nValueIn * nConf; } if (fMissingInputs) continue; // Priority is sum(valuein * age) / txsize unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); dPriority /= nTxSize; // This is a more accurate fee-per-kilobyte than is used by the client code, because the // client code rounds up the size to the nearest 1K. That's good, because it gives an // incentive to create smaller transactions. double dFeePerKb = double(nTotalIn-tx.GetValueOut()) / (double(nTxSize)/1000.0); if (porphan) { porphan->dPriority = dPriority; porphan->dFeePerKb = dFeePerKb; } else vecPriority.push_back(TxPriority(dPriority, dFeePerKb, &(*mi).second)); } // Collect transactions into block map<uint256, CTxIndex> mapTestPool; uint64_t nBlockSize = 1000; uint64_t nBlockTx = 0; int nBlockSigOps = 100; bool fSortedByFee = (nBlockPrioritySize <= 0); TxPriorityCompare comparer(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); double dFeePerKb = vecPriority.front().get<1>(); CTransaction& tx = *(vecPriority.front().get<2>()); std::pop_heap(vecPriority.begin(), vecPriority.end(), comparer); vecPriority.pop_back(); // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (fDebug10) LogPrintf("Tx Size for %s %f",tx.GetHash().GetHex(), (double)nTxSize); if (nBlockSize + nTxSize >= nBlockMaxSize) { if (fDebug10) LogPrintf("Tx size too large for tx %s blksize %f , tx siz %f",tx.GetHash().GetHex().c_str(),(double)nBlockSize,(double)nTxSize); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":SizeTooLarge(" + ToString(nBlockSize) + "," + ToString(nTxSize) + ")(" + ToString(nBlockSize) + ");"; continue; } // Legacy limits on sigOps: unsigned int nTxSigOps = tx.GetLegacySigOpCount(); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) { msMiningErrorsExcluded += tx.GetHash().GetHex() + ":LegacySigOpLimit(" + ToString(nBlockSigOps) + "," + ToString(nTxSigOps) + ")(" + ToString(MAX_BLOCK_SIGOPS) + ");"; continue; } // Timestamp limit if (tx.nTime > block.nTime) { msMiningErrorsExcluded += tx.GetHash().GetHex() + ":TimestampLimit(" + ToString(tx.nTime) + "," + ToString(block.vtx[0].nTime) + ");"; continue; } // Transaction fee int64_t nMinFee = tx.GetMinFee(nBlockSize, GMF_BLOCK); // Skip free transactions if we're past the minimum block size: if (fSortedByFee && (dFeePerKb < nMinTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && ((nBlockSize + nTxSize >= nBlockPrioritySize) || (dPriority < COIN * 144 / 250))) { fSortedByFee = true; comparer = TxPriorityCompare(fSortedByFee); std::make_heap(vecPriority.begin(), vecPriority.end(), comparer); } // Connecting shouldn't fail due to dependency on other memory pool transactions // because we're already processing them in order of dependency map<uint256, CTxIndex> mapTestPoolTmp(mapTestPool); MapPrevTx mapInputs; bool fInvalid; if (!tx.FetchInputs(txdb, mapTestPoolTmp, false, true, mapInputs, fInvalid)) { if (fDebug10) LogPrintf("Unable to fetch inputs for tx %s ", tx.GetHash().GetHex()); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":UnableToFetchInputs;"; continue; } int64_t nTxFees = tx.GetValueIn(mapInputs)-tx.GetValueOut(); if (nTxFees < nMinFee) { if (fDebug10) LogPrintf("Not including tx %s due to TxFees of %f ; bare min fee is %f", tx.GetHash().GetHex(), (double)nTxFees, (double)nMinFee); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":FeeTooSmall(" + RoundToString(CoinToDouble(nFees),8) + "," +RoundToString(CoinToDouble(nMinFee),8) + ");"; continue; } nTxSigOps += tx.GetP2SHSigOpCount(mapInputs); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) { if (fDebug10) LogPrintf("Not including tx %s due to exceeding max sigops of %f ; sigops is %f", tx.GetHash().GetHex(), (double)(nBlockSigOps+nTxSigOps), (double)MAX_BLOCK_SIGOPS); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":ExceededSigOps(" + ToString(nBlockSigOps) + "," + ToString(nTxSigOps) + ")(" + ToString(MAX_BLOCK_SIGOPS) + ");"; continue; } if (!tx.ConnectInputs(txdb, mapInputs, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, false, true)) { if (fDebug10) LogPrintf("Unable to connect inputs for tx %s ",tx.GetHash().GetHex()); msMiningErrorsExcluded += tx.GetHash().GetHex() + ":UnableToConnectInputs();"; continue; } mapTestPoolTmp[tx.GetHash()] = CTxIndex(CDiskTxPos(1,1,1), tx.vout.size()); swap(mapTestPool, mapTestPoolTmp); // Added msMiningErrorsIncluded += tx.GetHash().GetHex() + ";"; block.vtx.push_back(tx); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; nFees += nTxFees; if (fDebug10 || GetBoolArg("-printpriority")) { LogPrintf("priority %.1f feeperkb %.1f txid %s\n", dPriority, dFeePerKb, tx.GetHash().ToString()); } // Add transactions that depend on this one to the priority queue uint256 hash = tx.GetHash(); if (mapDependers.count(hash)) { for (auto const& porphan : mapDependers[hash]) { if (!porphan->setDependsOn.empty()) { porphan->setDependsOn.erase(hash); if (porphan->setDependsOn.empty()) { vecPriority.push_back(TxPriority(porphan->dPriority, porphan->dFeePerKb, porphan->ptx)); std::push_heap(vecPriority.begin(), vecPriority.end(), comparer); } } } } } if (fDebug10 || GetBoolArg("-printpriority")) LogPrintf("CreateNewBlock(): total size %" PRIu64 "\n", nBlockSize); } //Add fees to coinbase block.vtx[0].vout[0].nValue= nFees; // Fill in header block.hashPrevBlock = pindexPrev->GetBlockHash(); block.vtx[0].nTime=block.nTime; return true; }