Merge pull request #27 from MyHush/ztxstats

Add shielded stats to getchaintxstats via zindex
This commit is contained in:
Duke Leto
2019-08-22 08:19:06 -04:00
committed by GitHub
6 changed files with 405 additions and 41 deletions

View File

@@ -98,6 +98,7 @@ bool fExperimentalMode = true;
bool fImporting = false;
bool fReindex = false;
bool fTxIndex = false;
bool fZindex = false;
bool fAddressIndex = false;
bool fTimestampIndex = false;
bool fSpentIndex = false;
@@ -4767,10 +4768,17 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
CAmount sproutValue = 0;
CAmount saplingValue = 0;
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
pindexNew->nChainPayments = 0;
CAmount sproutValue = 0;
CAmount saplingValue = 0;
bool isShieldedTx = false;
int64_t nShieldedSpends=0,nShieldedOutputs=0,nPayments=0;
int64_t nShieldedTx=0,nFullyShieldedTx=0,nDeshieldingTx=0,nShieldingTx=0;
int64_t nShieldedPayments=0,nFullyShieldedPayments=0,nShieldingPayments=0,nDeshieldingPayments=0;
int64_t nNotarizations=0;
for (auto tx : block.vtx) {
// Negative valueBalance "takes" money from the transparent value pool
// and adds it to the Sapling value pool. Positive valueBalance "gives"
@@ -4782,7 +4790,71 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
sproutValue += js.vpub_old;
sproutValue -= js.vpub_new;
}
// Ignore following stats unless -zindex
if (!fZindex)
continue;
nShieldedSpends = tx.vShieldedSpend.size();
nShieldedOutputs = tx.vShieldedOutput.size();
isShieldedTx = (nShieldedSpends + nShieldedOutputs) > 0 ? true : false;
// We want to avoid full verification with a low false-positive rate
if(tx.vin.size()==13 && tx.vout.size()==2 && tx.vout[1].scriptPubKey.IsOpReturn() && tx.vout[1].nValue==0) {
nNotarizations++;
}
if(isShieldedTx) {
nShieldedTx++;
if(tx.vin.size()==0 && tx.vout.size()==0) {
nFullyShieldedTx++;
} else if(tx.vin.size()>0) {
nShieldingTx++;
} else if(tx.vout.size()>0) {
nDeshieldingTx++;
}
//NOTE: These are at best heuristics. Improve them as much as possible.
// You cannot compare stats generated from different sets of heuristics, so
// if you change this code, you must delete and resync from scratch, or you
// will be mixing together data from two set of heuristics.
if (nShieldedOutputs >= 1) {
// If there are shielded outputs, count each as a payment
// By default, if there is more than 1 output, we assume 1 change output which is not a payment.
// In the case of multiple outputs which spend inputs exactly, there is no change output and this
// heuristic will undercount payments. Since this edge case is rare, this seems acceptable.
// t->(t,t,z) = 1 shielded payment
// z->(z,z) = 1 shielded payment + shielded change
// t->(z,z) = 1 shielded payment + shielded change
// t->(t,z) = 1 shielded payment + transparent change
// (z,z)->z = 1 shielded payment (has this xtn ever occurred?)
// z->(z,z,z) = 2 shielded payments + shielded change
// Assume that there is always 1 change output when there are more than one
nShieldedPayments += nShieldedOutputs > 1 ? (nShieldedOutputs-1) : 1;
// Fully shielded do not count toward shielding/deshielding
if(tx.vin.size()==0 && tx.vout.size()==0) {
nFullyShieldedPayments += nShieldedOutputs > 1 ? (nShieldedOutputs-1) : 1;
} else {
nShieldingPayments += nShieldedOutputs > 1 ? (nShieldedOutputs-1) : 1;
}
} else if (nShieldedSpends >=1) {
// Shielded inputs with no shielded outputs. We know none are change output because
// change would flow back to the zaddr
// z->t = 1 shielded payment
// z->(t,t) = 2 shielded payments
// z->(t,t,t) = 3 shielded payments
nShieldedPayments += tx.vout.size();
nDeshieldingPayments += tx.vout.size() > 1 ? tx.vout.size()-1 : tx.vout.size();
}
//TODO: correctly add shielded payments to total chain payments
nPayments += nShieldedPayments;
} else {
// No shielded payments, add transparent payments minus a change address
nPayments += tx.vout.size() > 1 ? tx.vout.size()-1 : tx.vout.size();
}
}
pindexNew->nSproutValue = sproutValue;
pindexNew->nChainSproutValue = boost::none;
pindexNew->nSaplingValue = saplingValue;
@@ -4792,6 +4864,20 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA;
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
if (fZindex) {
pindexNew->nPayments = nPayments;
pindexNew->nShieldedTx = nShieldedTx;
pindexNew->nFullyShieldedTx = nFullyShieldedTx;
pindexNew->nDeshieldingTx = nDeshieldingTx;
pindexNew->nShieldingTx = nShieldingTx;
pindexNew->nShieldedPayments = nShieldedPayments;
pindexNew->nFullyShieldedPayments = nFullyShieldedPayments;
pindexNew->nDeshieldingPayments = nDeshieldingPayments;
pindexNew->nShieldingPayments = nShieldingPayments;
pindexNew->nNotarizations = nNotarizations;
}
setDirtyBlockIndex.insert(pindexNew);
if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) {
@@ -4803,7 +4889,22 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
while (!queue.empty()) {
CBlockIndex *pindex = queue.front();
queue.pop_front();
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
if (fZindex) {
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
pindex->nChainNotarizations = (pindex->pprev ? pindex->pprev->nChainNotarizations : 0) + pindex->nNotarizations;
pindex->nChainShieldedTx = (pindex->pprev ? pindex->pprev->nChainShieldedTx : 0) + pindex->nShieldedTx;
pindex->nChainFullyShieldedTx = (pindex->pprev ? pindex->pprev->nChainFullyShieldedTx : 0) + pindex->nFullyShieldedTx;
pindex->nChainShieldingTx = (pindex->pprev ? pindex->pprev->nChainShieldingTx : 0) + pindex->nShieldingTx;
pindex->nChainDeshieldingTx = (pindex->pprev ? pindex->pprev->nChainDeshieldingTx : 0) + pindex->nDeshieldingTx;
pindex->nChainPayments = (pindex->pprev ? pindex->pprev->nChainPayments : 0) + pindex->nPayments;
pindex->nChainShieldedPayments = (pindex->pprev ? pindex->pprev->nChainShieldedPayments : 0) + pindex->nShieldedPayments;
pindex->nChainFullyShieldedPayments = (pindex->pprev ? pindex->pprev->nChainFullyShieldedPayments : 0) + pindex->nFullyShieldedPayments;
pindex->nChainShieldingPayments = (pindex->pprev ? pindex->pprev->nChainShieldingPayments : 0) + pindex->nShieldingPayments;
pindex->nChainDeshieldingPayments = (pindex->pprev ? pindex->pprev->nChainDeshieldingPayments : 0) + pindex->nDeshieldingPayments;
}
if (pindex->pprev) {
if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) {
pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue;
@@ -4840,6 +4941,10 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
}
}
if (fZindex)
fprintf(stderr, "ht.%d, ShieldedPayments=%d, ShieldedTx=%d, FullyShieldedTx=%d, ntz=%d\n",
pindexNew->GetHeight(), nShieldedPayments, nShieldedTx, nFullyShieldedTx, nNotarizations );
return true;
}
@@ -6070,7 +6175,20 @@ bool static LoadBlockIndexDB()
if (pindex->nTx > 0) {
if (pindex->pprev) {
if (pindex->pprev->nChainTx) {
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
if (fZindex) {
pindex->nChainNotarizations = pindex->pprev->nChainNotarizations + pindex->nNotarizations;
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;
pindex->nChainShieldedTx = pindex->pprev->nChainShieldedTx + pindex->nShieldedTx;
pindex->nChainShieldedPayments = pindex->pprev->nChainShieldedPayments + pindex->nShieldedPayments;
pindex->nChainShieldingTx = pindex->pprev->nChainShieldingTx + pindex->nShieldingTx;
pindex->nChainShieldingPayments = pindex->pprev->nChainShieldingPayments + pindex->nShieldingPayments;
pindex->nChainDeshieldingTx = pindex->pprev->nChainShieldedTx + pindex->nShieldedTx;
pindex->nChainDeshieldingPayments = pindex->pprev->nChainShieldedPayments + pindex->nShieldedPayments;
pindex->nChainFullyShieldedTx = pindex->pprev->nChainFullyShieldedTx + pindex->nFullyShieldedTx;
pindex->nChainFullyShieldedPayments = pindex->pprev->nChainFullyShieldedPayments + pindex->nFullyShieldedPayments;
}
if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) {
pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue;
} else {
@@ -6082,15 +6200,36 @@ bool static LoadBlockIndexDB()
pindex->nChainSaplingValue = boost::none;
}
} else {
pindex->nChainTx = 0;
pindex->nChainSproutValue = boost::none;
pindex->nChainSaplingValue = boost::none;
pindex->nChainTx = 0;
if (fZindex) {
pindex->nChainNotarizations = 0;
pindex->nChainShieldedTx = 0;
pindex->nChainFullyShieldedTx = 0;
pindex->nChainShieldedPayments = 0;
pindex->nChainShieldingPayments = 0;
pindex->nChainDeshieldingTx = 0;
pindex->nChainDeshieldingPayments = 0;
pindex->nChainFullyShieldedTx = 0;
pindex->nChainFullyShieldedPayments = 0;
}
pindex->nChainSproutValue = boost::none;
pindex->nChainSaplingValue = boost::none;
mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex));
}
} else {
pindex->nChainTx = pindex->nTx;
pindex->nChainSproutValue = pindex->nSproutValue;
pindex->nChainSaplingValue = pindex->nSaplingValue;
pindex->nChainTx = pindex->nTx;
pindex->nChainSproutValue = pindex->nSproutValue;
pindex->nChainSaplingValue = pindex->nSaplingValue;
if (fZindex) {
pindex->nChainNotarizations = pindex->nNotarizations;
pindex->nChainShieldedTx = pindex->nShieldedTx;
pindex->nChainShieldedPayments = pindex->nShieldedPayments;
pindex->nChainShieldingTx = pindex->nShieldingTx;
pindex->nChainShieldingPayments = pindex->nShieldingPayments;
pindex->nChainDeshieldingTx = pindex->nDeshieldingTx;
pindex->nChainDeshieldingPayments = pindex->nDeshieldingPayments;
pindex->nChainFullyShieldedPayments = pindex->nFullyShieldedPayments;
}
}
}
// Construct in-memory chain of branch IDs.
@@ -6168,10 +6307,15 @@ bool static LoadBlockIndexDB()
// Check whether we have a transaction index
pblocktree->ReadFlag("txindex", fTxIndex);
LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled");
// Check whether we have an address index
pblocktree->ReadFlag("addressindex", fAddressIndex);
LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled");
// Check whether we have a shielded index
pblocktree->ReadFlag("zindex", fZindex);
LogPrintf("%s: shielded index %s\n", __func__, fZindex ? "enabled" : "disabled");
// Check whether we have a timestamp index
pblocktree->ReadFlag("timestampindex", fTimestampIndex);
LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled");
@@ -6535,17 +6679,22 @@ bool InitBlockIndex() {
// Use the provided setting for -txindex in the new database
fTxIndex = GetBoolArg("-txindex", true);
pblocktree->WriteFlag("txindex", fTxIndex);
// Use the provided setting for -addressindex in the new database
fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX);
pblocktree->WriteFlag("addressindex", fAddressIndex);
// Use the provided setting for -zindex in the new database
fZindex = GetBoolArg("-zindex", DEFAULT_SHIELDEDINDEX);
pblocktree->WriteFlag("zindex", fZindex);
// Use the provided setting for -timestampindex in the new database
fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX);
pblocktree->WriteFlag("timestampindex", fTimestampIndex);
fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX);
pblocktree->WriteFlag("spentindex", fSpentIndex);
fprintf(stderr,"fAddressIndex.%d/%d fSpentIndex.%d/%d\n",fAddressIndex,DEFAULT_ADDRESSINDEX,fSpentIndex,DEFAULT_SPENTINDEX);
fprintf(stderr,"fAddressIndex.%d/%d fSpentIndex.%d/%d fZindex.%d/%d\n",fAddressIndex,DEFAULT_ADDRESSINDEX,fSpentIndex,DEFAULT_SPENTINDEX,fZindex, DEFAULT_SHIELDEDINDEX );
LogPrintf("Initializing databases...\n");
}
// Only add the genesis block if not reindexing (in which case we reuse the one already on disk)