diff --git a/src/chain.h b/src/chain.h index b893e3a06..f6c2bf980 100644 --- a/src/chain.h +++ b/src/chain.h @@ -29,6 +29,7 @@ class CChainPower; #include "tinyformat.h" #include "uint256.h" extern int8_t is_STAKED(const char *chain_name); +extern bool fZindex; #include @@ -254,15 +255,108 @@ public: //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block CChainPower chainPower; + // block stats //! Number of transactions in this block. //! Note: in a potential headers-first mode, this number cannot be relied upon unsigned int nTx; + //! Number of notarization transactions in this block. + unsigned int nNotarizations; + + //! (memory only) Number of payments (shielded or transparent) in the block + //! up to and including this block. One transaction can contain one or more + //! payments. This stat allows us to calculate ratios of shielded/transparent + //! when combined with shielded payment stats + unsigned int nPayments; + + //! (memory only) Number of shielded transactions (of any kind) in the block up to and including this block. + //! A shielded transaction is defined as a transaction that contains at least 1 JoinSplit, which includes + //! shielding/de-shielding and other complex transaction possibilties including multiple taddrs/zaddrs as + //! inputs and outputs. + unsigned int nShieldedTx; + + //! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined + //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent + // inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc... + unsigned int nFullyShieldedTx; + + //! (memory only) Number of shielding payments. A shielding payment is defined + //! as having a shielded output but transparent input: t->z + unsigned int nShieldingPayments; + + //! (memory only) Number of shielded payments. A shielded payment is defined + //! as having a shielded input or output: t->z or z->t + unsigned int nShieldedPayments; + + //! (memory only) Number of fully shielded payments. A fully shielded payment is defined + //! as having a shielded input and shielded output: z->z + unsigned int nFullyShieldedPayments; + + //! (memory only) Number of deshielding transactions. A deshielding transaction is defined + //! as a transaction containing JoinSplits and at least one transparent output. + unsigned int nDeshieldingTx; + + //! (memory only) Number of deshielding payments. A deshielding payment is defined + //! as one transparent input and one shielded output: z->t + unsigned int nDeshieldingPayments; + + //! (memory only) Number of shielding transactions. A shielding transaction is defined + //! as a transaction containing JoinSplits and at least one transparent input + // i.e. t->z or t->(z,t) or z->(z,z,t) + unsigned int nShieldingTx; + + // chain stats //! (memory only) Number of transactions in the chain up to and including this block. //! This value will be non-zero only if and only if transactions for this block and all its parents are available. //! Change to 64-bit type when necessary; won't happen before 2030 unsigned int nChainTx; + //! Number of notarization transactions in this chain + int64_t nChainNotarizations; + + //! (memory only) Number of payments (shielded or transparent) in the chain + //! up to and including this block. One transaction can contain one or more + //! payments. This stat allows us to calculate ratios of shielded/transparent + //! when combined with shielded payment stats + int64_t nChainPayments; + + //! (memory only) Number of shielded transactions (of any kind) in the chain up to and including this block. + //! A shielded transaction is defined as a transaction that contains at least 1 JoinSplit, which includes + //! shielding/de-shielding and other complex transaction possibilties including multiple taddrs/zaddrs as + //! inputs and outputs. + int64_t nChainShieldedTx; + + //! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined + //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent + // inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc... + int64_t nChainFullyShieldedTx; + + //! (memory only) Number of shielding payments. A shielding payment is defined + //! as having a shielded output but transparent input: t->z + int64_t nChainShieldingPayments; + + //! (memory only) Number of shielded payments. A shielded payment is defined + //! as having a shielded input or output: t->z or z->t + int64_t nChainShieldedPayments; + + //! (memory only) Number of fully shielded payments. A fully shielded payment is defined + //! as having a shielded input and shielded output: z->z + int64_t nChainFullyShieldedPayments; + + //! (memory only) Number of deshielding transactions. A deshielding transaction is defined + //! as a transaction containing JoinSplits and at least one transparent output. + int64_t nChainDeshieldingTx; + + //! (memory only) Number of deshielding payments. A deshielding payment is defined + //! as one transparent input and one shielded output: z->t + int64_t nChainDeshieldingPayments; + + //! (memory only) Number of shielding transactions. A shielding transaction is defined + //! as a transaction containing JoinSplits and at least one transparent input + // i.e. t->z or t->(z,t) or z->(z,z,t) + int64_t nChainShieldingTx; + + //! Verification status of this block. See enum BlockStatus unsigned int nStatus; @@ -321,6 +415,24 @@ public: chainPower = CChainPower(); nTx = 0; nChainTx = 0; + + nChainShieldedTx = 0; + nChainShieldingTx = 0; + nChainDeshieldingTx = 0; + nChainFullyShieldedTx = 0; + nChainShieldedPayments = 0; + nChainShieldingPayments = 0; + nChainDeshieldingPayments = 0; + nChainFullyShieldedPayments = 0; + nShieldedTx = 0; + nShieldingTx = 0; + nDeshieldingTx = 0; + nFullyShieldedTx = 0; + nShieldedPayments = 0; + nShieldingPayments = 0; + nDeshieldingPayments = 0; + nFullyShieldedPayments = 0; + nStatus = 0; nCachedBranchId = boost::none; hashSproutAnchor = uint256(); @@ -506,6 +618,22 @@ public: READWRITE(VARINT(chainPower.nHeight)); READWRITE(VARINT(nStatus)); READWRITE(VARINT(nTx)); + + // These values only serialized when -zindex enabled + if(fZindex) { + READWRITE(VARINT(nShieldedTx)); + READWRITE(VARINT(nShieldingTx)); + READWRITE(VARINT(nDeshieldingTx)); + READWRITE(VARINT(nFullyShieldedTx)); + + READWRITE(VARINT(nShieldedPayments)); + READWRITE(VARINT(nShieldingPayments)); + READWRITE(VARINT(nDeshieldingPayments)); + READWRITE(VARINT(nFullyShieldedPayments)); + + READWRITE(VARINT(nNotarizations)); + } + if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) READWRITE(VARINT(nFile)); if (nStatus & BLOCK_HAVE_DATA) diff --git a/src/init.cpp b/src/init.cpp index 96ad85361..079a3ae8d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -400,6 +400,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-addressindex", strprintf(_("Maintain a full address index, used to query for the balance, txids and unspent outputs for addresses (default: %u)"), DEFAULT_ADDRESSINDEX)); strUsage += HelpMessageOpt("-timestampindex", strprintf(_("Maintain a timestamp index for block hashes, used to query blocks hashes by a range of timestamps (default: %u)"), DEFAULT_TIMESTAMPINDEX)); strUsage += HelpMessageOpt("-spentindex", strprintf(_("Maintain a full spent index, used to query the spending txid and input index for an outpoint (default: %u)"), DEFAULT_SPENTINDEX)); + strUsage += HelpMessageOpt("-zindex", strprintf(_("Maintain extra statistics about shielded transactions and payments (default: %u)"), 0)); strUsage += HelpMessageGroup(_("Connection options:")); strUsage += HelpMessageOpt("-addnode=", _("Add a node to connect to and attempt to keep the connection open")); strUsage += HelpMessageOpt("-banscore=", strprintf(_("Threshold for disconnecting misbehaving peers (default: %u)"), 100)); @@ -1282,14 +1283,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Komodo is probably already running.") + " %s.", strDataDir, e.what())); } - fprintf(stderr,"About to create pidfile\n"); #ifndef _WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - fprintf(stderr,"created pidfile\n"); if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); - fprintf(stderr,"past shrinkdebugfile\n"); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); LogPrintf("Komodo version %s (%s)\n", FormatFullVersion(), CLIENT_DATE); @@ -1668,6 +1666,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) break; } + fprintf(stderr, "zindex=%s in block index\n", fZindex ? "enabled" : "disabled"); + if (fZindex != GetBoolArg("-zindex", false)) { + strLoadError = _("You need to rebuild the database using -reindex to change -zindex"); + break; + } + // Check for changed -prune state. What we are concerned about is a user who has pruned blocks // in the past, but is now trying to run unpruned. if (fHavePruned && !fPruneMode) { diff --git a/src/main.cpp b/src/main.cpp index 700eb6c75..880cffa85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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) diff --git a/src/main.h b/src/main.h index 931954da0..800f05745 100644 --- a/src/main.h +++ b/src/main.h @@ -125,6 +125,7 @@ static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; #define DEFAULT_ADDRESSINDEX (GetArg("-ac_cc",0) != 0 || GetArg("-ac_ccactivate",0) != 0) #define DEFAULT_SPENTINDEX (GetArg("-ac_cc",0) != 0 || GetArg("-ac_ccactivate",0) != 0) static const bool DEFAULT_TIMESTAMPINDEX = false; +static const bool DEFAULT_SHIELDEDINDEX = false; static const unsigned int DEFAULT_DB_MAX_OPEN_FILES = 1000; static const bool DEFAULT_DB_COMPRESSION = true; @@ -157,6 +158,7 @@ extern bool fImporting; extern bool fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; +extern bool fZindex; extern bool fIsBareMultisigStd; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index c63def984..f965fdeef 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -49,6 +49,7 @@ using namespace std; extern int32_t KOMODO_INSYNC; +extern bool fZindex; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); int32_t komodo_notarized_height(int32_t *prevMoMheightp,uint256 *hashp,uint256 *txidp); @@ -1949,7 +1950,7 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp) "{\n" " \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n" " \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n" - " \"window_final_block_hash\": \"...\", (string) The hash of the final block in the window.\n" + " \"window_final_block_hash\": \"...\", (string) The hash of the final block in the window.\n" " \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n" " \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n" " \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n" @@ -1990,20 +1991,91 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp) } } - const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->GetHeight() - blockcount); - int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast(); - int nTxDiff = pindex->nChainTx - pindexPast->nChainTx; + const CBlockIndex* pindexPast = pindex->GetAncestor(pindex->GetHeight() - blockcount); + int nTimeDiff = pindex->GetMedianTimePast() - pindexPast->GetMedianTimePast(); + int nTxDiff = pindex->nChainTx - pindexPast->nChainTx; UniValue ret(UniValue::VOBJ); ret.pushKV("time", (int64_t)pindex->nTime); ret.pushKV("txcount", (int64_t)pindex->nChainTx); + + if (fZindex) { + ret.pushKV("notarizations", (int64_t)pindex->nChainNotarizations); + ret.pushKV("shielded_txcount", (int64_t)pindex->nChainShieldedTx); + ret.pushKV("fully_shielded_txcount", (int64_t)pindex->nChainFullyShieldedTx); + ret.pushKV("deshielding_txcount", (int64_t)pindex->nChainDeshieldingTx); + ret.pushKV("shielding_txcount", (int64_t)pindex->nChainShieldingTx); + ret.pushKV("shielded_payments", (int64_t)pindex->nChainShieldedPayments); + ret.pushKV("fully_shielded_payments", (int64_t)pindex->nChainFullyShieldedPayments); + ret.pushKV("deshielding_payments", (int64_t)pindex->nChainDeshieldingPayments); + ret.pushKV("shielding_payments", (int64_t)pindex->nChainShieldingPayments); + } + ret.pushKV("window_final_block_hash", pindex->GetBlockHash().GetHex()); + ret.pushKV("window_final_block_height", pindex->GetHeight()); ret.pushKV("window_block_count", blockcount); + if (blockcount > 0) { - ret.pushKV("window_tx_count", nTxDiff); + int64_t nPaymentsDiff = pindex->nChainPayments - pindexPast->nChainPayments; + int64_t nShieldedTxDiff = pindex->nChainShieldedTx - pindexPast->nChainShieldedTx; + int64_t nShieldingTxDiff = pindex->nChainShieldingTx - pindexPast->nChainShieldingTx; + int64_t nDeshieldingTxDiff = pindex->nChainDeshieldingTx - pindexPast->nChainDeshieldingTx; + int64_t nFullyShieldedTxDiff = pindex->nChainFullyShieldedTx - pindexPast->nChainFullyShieldedTx; + int64_t nShieldedPaymentsDiff = pindex->nChainShieldedPayments - pindexPast->nChainShieldedPayments; + int64_t nShieldingPaymentsDiff = pindex->nChainShieldingPayments - pindexPast->nChainShieldingPayments; + int64_t nDeshieldingPaymentsDiff = pindex->nChainDeshieldingPayments - pindexPast->nChainDeshieldingPayments; + int64_t nFullyShieldedPaymentsDiff = pindex->nChainFullyShieldedPayments - pindexPast->nChainFullyShieldedPayments; + unsigned int nNotarizationsDiff = pindex->nChainNotarizations - pindexPast->nChainNotarizations; + ret.pushKV("window_interval", nTimeDiff); + ret.pushKV("window_txcount", nTxDiff); + ret.pushKV("window_payments", nPaymentsDiff); + ret.pushKV("window_notarizations", (int) nNotarizationsDiff); + if (nTimeDiff > 0) { - ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff); + ret.pushKV("txrate", ((double)nTxDiff) / nTimeDiff); + if (fZindex) { + ret.pushKV("notarization_txrate", ((double)nNotarizationsDiff) / nTimeDiff); + ret.pushKV("shielded_txrate", ((double)nShieldedTxDiff) / nTimeDiff); + ret.pushKV("fully_shielded_txrate", ((double)nFullyShieldedTxDiff) / nTimeDiff); + ret.pushKV("paymentrate", ((double)nPaymentsDiff) / nTimeDiff); + ret.pushKV("shielded_paymentrate", ((double)nShieldedPaymentsDiff) / nTimeDiff); + ret.pushKV("fully_shielded_paymentrate", ((double)nFullyShieldedPaymentsDiff) / nTimeDiff); + } + } + + if (fZindex) { + ret.pushKV("window_fully_shielded_payments", nFullyShieldedPaymentsDiff); + ret.pushKV("window_shielded_payments", nShieldedPaymentsDiff); + ret.pushKV("window_shielding_payments", nShieldingPaymentsDiff); + ret.pushKV("window_deshielding_payments", nDeshieldingPaymentsDiff); + if (nTxDiff > 0) { + ret.pushKV("shielded_tx_percent", ((double)nShieldedTxDiff) / nTxDiff); + ret.pushKV("fully_shielded_tx_percent", ((double)nFullyShieldedTxDiff) / nTxDiff); + ret.pushKV("shielding_tx_percent", ((double)nShieldingTxDiff) / nTxDiff); + ret.pushKV("deshielding_tx_percent", ((double)nDeshieldingTxDiff) / nTxDiff); + } + if (nPaymentsDiff > 0) { + ret.pushKV("shielded_payments_percent", ((double)nShieldedPaymentsDiff) / nPaymentsDiff); + ret.pushKV("fully_shielded_payments_percent", ((double)nFullyShieldedPaymentsDiff) / nPaymentsDiff); + ret.pushKV("shielding_payments_percent", ((double)nShieldingPaymentsDiff) / nPaymentsDiff); + ret.pushKV("deshielding_payments_percent", ((double)nDeshieldingPaymentsDiff) / nPaymentsDiff); + } + + // Shielded-only statistics + UniValue shielded(UniValue::VOBJ); + if (nShieldedTxDiff > 0) { + shielded.pushKV("fully_shielded_tx_percent", ((double)nFullyShieldedTxDiff) / nShieldedTxDiff ); + shielded.pushKV("shielding_tx_percent", ((double)nShieldingTxDiff) / nShieldedTxDiff ); + shielded.pushKV("deshielding_tx_percent", ((double)nDeshieldingTxDiff) / nShieldedTxDiff ); + } + if (nShieldedPaymentsDiff > 0) { + shielded.pushKV("fully_shielded_payments_percent", ((double)nFullyShieldedPaymentsDiff) / nShieldedPaymentsDiff ); + shielded.pushKV("shielding_payments_percent", ((double)nShieldingPaymentsDiff) / nShieldedPaymentsDiff ); + shielded.pushKV("deshielding_payments_percent", ((double)nDeshieldingPaymentsDiff) / nShieldedPaymentsDiff ); + } + if(nShieldedTxDiff+nShieldedPaymentsDiff > 0) + ret.pushKV("shielded_only", shielded); } } diff --git a/src/txdb.cpp b/src/txdb.cpp index 82885044e..a462061a1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -702,24 +702,33 @@ bool CBlockTreeDB::LoadBlockIndexGuts() CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->SetHeight(diskindex.GetHeight()); - pindexNew->nFile = diskindex.nFile; - pindexNew->nDataPos = diskindex.nDataPos; - pindexNew->nUndoPos = diskindex.nUndoPos; - pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor; - pindexNew->nVersion = diskindex.nVersion; - pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->nFile = diskindex.nFile; + pindexNew->nDataPos = diskindex.nDataPos; + pindexNew->nUndoPos = diskindex.nUndoPos; + pindexNew->hashSproutAnchor = diskindex.hashSproutAnchor; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot; - pindexNew->nTime = diskindex.nTime; - pindexNew->nBits = diskindex.nBits; - pindexNew->nNonce = diskindex.nNonce; - pindexNew->nSolution = diskindex.nSolution; - pindexNew->nStatus = diskindex.nStatus; - pindexNew->nCachedBranchId = diskindex.nCachedBranchId; - pindexNew->nTx = diskindex.nTx; - pindexNew->nSproutValue = diskindex.nSproutValue; - pindexNew->nSaplingValue = diskindex.nSaplingValue; - pindexNew->segid = diskindex.segid; - pindexNew->nNotaryPay = diskindex.nNotaryPay; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + pindexNew->nSolution = diskindex.nSolution; + pindexNew->nStatus = diskindex.nStatus; + pindexNew->nCachedBranchId = diskindex.nCachedBranchId; + pindexNew->nTx = diskindex.nTx; + pindexNew->nShieldedTx = diskindex.nShieldedTx; + pindexNew->nShieldedPayments = diskindex.nShieldedPayments; + pindexNew->nShieldingTx = diskindex.nShieldingTx; + pindexNew->nShieldingPayments = diskindex.nShieldingPayments; + pindexNew->nDeshieldingTx = diskindex.nDeshieldingTx; + pindexNew->nDeshieldingPayments = diskindex.nDeshieldingPayments; + pindexNew->nFullyShieldedTx = diskindex.nFullyShieldedTx; + pindexNew->nFullyShieldedPayments = diskindex.nFullyShieldedPayments; + pindexNew->nSproutValue = diskindex.nSproutValue; + pindexNew->nSaplingValue = diskindex.nSaplingValue; + pindexNew->segid = diskindex.segid; + pindexNew->nNotaryPay = diskindex.nNotaryPay; + //fprintf(stderr,"loadguts ht.%d\n",pindexNew->GetHeight()); // Consistency checks auto header = pindexNew->GetBlockHeader();