diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 606108a..ab1ae22 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -806,3 +806,168 @@ Value measureblockchain(const Array& params, bool fHelp) return 0; } + +#define BPS_SANITY_CHECK + +class BlockTxInfo { +public: + unsigned int nIndex; + const CTransaction *ptx; + bool fMaybeCPFP; + bool fMaybeDelayed; + size_t nSize; + double dPriority; + CAmount nTxFee; + CFeeRate feerate; + size_t nBlockSizePrior; + + BlockTxInfo() : fMaybeCPFP(false), fMaybeDelayed(false), dPriority(0.0), nTxFee(0), feerate() {}; +}; + +Value bcprioritystats(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 0) + throw runtime_error( + "bcprioritystats\n" + ); + + unsigned long nTotalTxs = 0, nTotalTxsPriority = 0; + for (int nHeight = 300031; true; ++nHeight) + { + CBlock block; + { + LOCK(cs_main); + if (nHeight > chainActive.Height()) + break; + + CBlockIndex* pblockindex = chainActive[nHeight]; + + if(!ReadBlockFromDisk(block, pblockindex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + } + + if (block.vtx.size() <= 1) { + continue; + } + + // Gather info + unsigned int nBlockSizeSoFar = ::GetSerializeSize(block.vtx[0], SER_NETWORK, PROTOCOL_VERSION); + BlockTxInfo vbti[block.vtx.size()]; + std::map mbti; + for (unsigned int i = 1; i < block.vtx.size(); ++i) { + BlockTxInfo& bti = vbti[i]; + const CTransaction& tx = block.vtx[i]; + mbti[tx.GetHash()] = &bti; + bti.nIndex = i; + bti.ptx = &tx; + + bti.nBlockSizePrior = nBlockSizeSoFar; + bti.nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + + CAmount nValueIn = 0; + double& dPriority = bti.dPriority; + for (int txin_n = tx.vin.size(); --txin_n >= 0; ) { + const CTxIn& txin = tx.vin[txin_n]; + + std::map::iterator it = mbti.find(txin.prevout.hash); + if (it != mbti.end()) { + nValueIn += it->second->ptx->vout[txin.prevout.n].nValue; + it->second->fMaybeCPFP = true; + if (it->second->nIndex == i - 1) { + bti.fMaybeDelayed = true; + } + } else { + CTransaction txInput; + uint256 hashInputBlock = 0; + if (!GetTransaction(txin.prevout.hash, txInput, hashInputBlock, true)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("No information available about transaction (height=%d; i=%d)", nHeight, i)); + + CBlockIndex* const pblockindexInput = mapBlockIndex[hashInputBlock]; +#ifdef BPS_SANITY_CHECK +#warning "BPS sanity check enabled" + { + LOCK(cs_main); + if (!chainActive.Contains(pblockindexInput)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Input block is not in current chain"); + } +#endif + + const CAmount& nThisValueIn = txInput.vout[txin.prevout.n].nValue; + nValueIn += nThisValueIn; + dPriority += (double)nThisValueIn * (nHeight - pblockindexInput->nHeight); + } + } + CAmount& nTxFee = bti.nTxFee; + nTxFee = nValueIn; + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + nTxFee -= txout.nValue; + } + bti.feerate = CFeeRate(nTxFee, bti.nSize); + dPriority /= bti.nSize; + + nBlockSizeSoFar += bti.nSize; +// std::cerr << i << ": " << dPriority << "," << bti.feerate.ToString() << "\n"; + } + + unsigned int nFirstFeerateIncreaseTx = 1; + { + CFeeRate nLastFeerate = vbti[block.vtx.size() - 1].feerate; + for (unsigned int i = block.vtx.size(); --i >= 1; ) { + const BlockTxInfo& bti = vbti[i]; +// std::cerr << i << " " << bti.ptx->GetHash().ToString() << ": cpfp="<GetHash().ToString() << ": delayed="< dLastPriority) { + break; + } + } + nLastPriorityIncreaseTx = i; + dLastPriority = bti.dPriority; + } + } + + std::cerr << nHeight << "\ttxcount=" << strprintf("%5d", block.vtx.size()) << "\tlastprio=" << strprintf("%5d", nLastPriorityIncreaseTx) << "\tfirstfeerate=" << strprintf("%5d(%5d)", nFirstFeerateIncreaseTx, block.vtx.size() - nFirstFeerateIncreaseTx); +// std::cerr << nHeight << ",priosize="; +// if (nFirstFeebasedTx >= block.vtx.size() - 1) +// std::cerr << "*"; +// else +// std::cerr << nBlockPrioritySize; +// std::cerr << ",totaltx=" << nTotalTxs << ",totalpriority=" << nTotalTxsPriority << ",totalprioexceptions=" << nTotalTxsPriorityExceptions; + unsigned int n = (nFirstFeerateIncreaseTx ? nFirstFeerateIncreaseTx : block.vtx.size()) - 1; + unsigned int delta; + if (nLastPriorityIncreaseTx != n) { + if (nLastPriorityIncreaseTx > n) { + delta = (nLastPriorityIncreaseTx - n); + std::cerr << "\tOVERLAP=" << strprintf("%5d", delta); + nLastPriorityIncreaseTx -= delta; + } else if (nLastPriorityIncreaseTx < n) { + delta = (n - nLastPriorityIncreaseTx); + std::cerr << "\t space=" << strprintf("%5d", delta); + } + } else { + delta = 0; + } + if (delta < 8) { + nTotalTxs += block.vtx.size(); + nTotalTxsPriority += nLastPriorityIncreaseTx; + std::cerr << "\ttotaltx=" << strprintf("%9d", nTotalTxs) << "\ttotalpriority=" << strprintf("%9d", nTotalTxsPriority) << "(" << strprintf("%5.2f", nTotalTxsPriority * 100.0 / nTotalTxs) << "%)"; + } + std::cerr << "\n"; + } + + return 0; +} diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c3c5827..235f126 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -266,6 +266,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblock", &getblock, true, false, false }, { "blockchain", "getblockhash", &getblockhash, true, false, false }, { "blockchain", "measureblockchain", &measureblockchain, true, true, false }, + { "blockchain", "bcprioritystats", &bcprioritystats, true, true, false }, { "blockchain", "getchaintips", &getchaintips, true, false, false }, { "blockchain", "getdifficulty", &getdifficulty, true, false, false }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 8712cf7..af8cec7 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -220,6 +220,7 @@ extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool f extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value measureblockchain(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value bcprioritystats(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);