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<uint256, BlockTxInfo*> 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<uint256, BlockTxInfo*>::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="<<bti.fMaybeCPFP<<",feerate="<<bti.feerate.ToString()<<"\n";
+ if (!bti.fMaybeCPFP) {
+ if (bti.feerate < nLastFeerate || bti.feerate == CFeeRate()) {
+ break;
+ }
+ }
+ nFirstFeerateIncreaseTx = i;
+ nLastFeerate = bti.feerate;
+ }
+ }
+ unsigned int nLastPriorityIncreaseTx = 1;
+ {
+ double dLastPriority = vbti[1].dPriority;
+ for (unsigned int i = 1; i < block.vtx.size(); ++i) {
+ const BlockTxInfo& bti = vbti[i];
+// std::cerr << i << " " << bti.ptx->GetHash().ToString() << ": delayed="<<bti.fMaybeDelayed<<",priority="<<strprintf("%.10f", bti.dPriority)<<"\n";
+ if (!bti.fMaybeDelayed) {
+ if (bti.dPriority > 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);