Various improvements to shielded transaction and payment stats gathering

This commit is contained in:
Jonathan "Duke" Leto
2019-08-10 22:00:14 -07:00
parent 8db846da67
commit 6ddcdc2497

View File

@@ -4767,19 +4767,20 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block)
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ /** 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) bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos)
{ {
pindexNew->nTx = block.vtx.size(); pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0; pindexNew->nChainTx = 0;
pindexNew->nChainPayments = 0; pindexNew->nChainPayments = 0;
pindexNew->nShieldedTx = 0; pindexNew->nShieldedTx = 0;
pindexNew->nShieldingTx = 0; pindexNew->nShieldingTx = 0;
pindexNew->nDeshieldingTx = 0; pindexNew->nDeshieldingTx = 0;
CAmount sproutValue = 0; CAmount sproutValue = 0;
CAmount saplingValue = 0; CAmount saplingValue = 0;
int64_t nShieldedSpends=0,nShieldedOutputs=0; bool isShieldedTx = false;
int64_t nShieldedPayments=0;
int64_t nFullyShielded=0,nShielding=0,nDeshielding=0,nMultipleShieldedInputs=0; int64_t nShieldedSpends=0,nShieldedOutputs=0,nChainPayments=0;
int64_t nShieldedTx=0,nFullyShieldedTx=0,nDeshieldingTx=0,nShieldingTx=0;
int64_t nShieldedPayments=0,nFullyShieldedPayments=0,nShieldingPayments=0,nDeshieldingPayments=0;
bool hasShieldedTx = false;
for (auto tx : block.vtx) { for (auto tx : block.vtx) {
// Negative valueBalance "takes" money from the transparent value pool // Negative valueBalance "takes" money from the transparent value pool
// and adds it to the Sapling value pool. Positive valueBalance "gives" // and adds it to the Sapling value pool. Positive valueBalance "gives"
@@ -4791,43 +4792,49 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
sproutValue += js.vpub_old; sproutValue += js.vpub_old;
sproutValue -= js.vpub_new; sproutValue -= js.vpub_new;
} }
nShieldedSpends = tx.vShieldedSpend.size(); nShieldedSpends = tx.vShieldedSpend.size();
nShieldedOutputs = tx.vShieldedOutput.size(); nShieldedOutputs = tx.vShieldedOutput.size();
isShieldedTx = (nShieldedSpends + nShieldedOutputs) > 0 ? true : false;
hasShieldedTx = (nShieldedSpends + nShieldedOutputs) > 0 ? true : false; if(isShieldedTx) {
nShieldedTx++;
if(hasShieldedTx) {
if(tx.vin.size()==0 && tx.vout.size()==0) { if(tx.vin.size()==0 && tx.vout.size()==0) {
nFullyShielded++; nFullyShieldedTx++;
} }
if(tx.vin.size()>0) { if(tx.vin.size()>0) {
nShielding++; nShieldingTx++;
} }
if(tx.vout.size()>0) { if(tx.vout.size()>0) {
nDeshielding++; nDeshieldingTx++;
} }
if(nShieldedSpends>1) { //NOTE: These are at best heuristics. Improve them as much as possible
nMultipleShieldedInputs++; // You cannot compare stats generated from different sets of heuristics
}
//TODO: These are at best heuristics. Improve them as much as possible
//TODO: Take into account change addresses
//NOTE: You cannot compare stats generated from different sets of heuristics
if (nShieldedOutputs >= 1) { if (nShieldedOutputs >= 1) {
// If there are shielded outputs, count each as a payment // 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 // t->(t,t,z) = 1 shielded payment
// z->(z,z) = 1 shielded payment + shielded change // z->(z,z) = 1 shielded payment + shielded change
// t->(z,z) = 1 shielded payment + shielded change // t->(z,z) = 1 shielded payment + shielded change
// t->(t,z) = 1 shielded payment + transparent 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 // 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; nShieldedPayments += nShieldedOutputs > 1 ? (nShieldedOutputs-1) : 1;
} else if (nShieldedSpends >=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 = 1 shielded payment
// (z,z)->z = 1 shielded payment // z->(t,t) = 2 shielded payments
// z->(t,t) = 1 shielded payment // z->(t,t,t) = 3 shielded payments
nShieldedPayments++; nShieldedPayments += tx.vout.size();
} }
nChainPayments += nShieldedPayments;
} else {
// No shielded payments, add transparent payments minus a change address
nChainPayments += tx.vout.size() > 1 ? tx.vout.size()-1 : tx.vout.size();
} }
} }
pindexNew->nSproutValue = sproutValue; pindexNew->nSproutValue = sproutValue;
@@ -4839,6 +4846,18 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
pindexNew->nUndoPos = 0; pindexNew->nUndoPos = 0;
pindexNew->nStatus |= BLOCK_HAVE_DATA; pindexNew->nStatus |= BLOCK_HAVE_DATA;
pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
// Store data for later use by gettxchainstats and other RPCs
pindexNew->nChainPayments = nChainPayments;
pindexNew->nShieldedTx = nShieldedTx;
pindexNew->nFullyShieldedTx = nFullyShieldedTx;
pindexNew->nDeshieldingTx = nDeshieldingTx;
pindexNew->nShieldingTx = nShieldingTx;
pindexNew->nShieldedPayments = nShieldedPayments;
pindexNew->nFullyShieldedPayments = nFullyShieldedPayments;
pindexNew->nDeshieldingPayments = nDeshieldingPayments;
pindexNew->nShieldingPayments = nShieldingPayments;
setDirtyBlockIndex.insert(pindexNew); setDirtyBlockIndex.insert(pindexNew);
if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) {
@@ -4851,10 +4870,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
CBlockIndex *pindex = queue.front(); CBlockIndex *pindex = queue.front();
queue.pop_front(); queue.pop_front();
// Keep track of shielded transaction stats
if(hasShieldedTx) {
pindex->nShieldedTx = pindex->nShieldedTx ? 0 : pindex->nShieldedTx + 1;
}
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;
if (pindex->pprev) { if (pindex->pprev) {
if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) { if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) {
@@ -4892,6 +4907,8 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
} }
} }
fprintf(stderr, "ht.%d, ShieldedPayments=%d, ShieldedTx=%d, FullyShieldedTx=%d\n",
pindexNew->GetHeight(), nShieldedPayments, nShieldedTx, nFullyShieldedTx );
return true; return true;
} }