Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add chain supply, transparent and burned coins value pools #65

Merged
merged 6 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 0)
define(_CLIENT_VERSION_MINOR, 8)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_BUILD, 2)
define(_CLIENT_VERSION_BUILD, 4)
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
define(_CLIENT_VERSION_IS_RELEASE, true)
Expand Down
60 changes: 60 additions & 0 deletions src/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ extern CCriticalSection cs_main;

static const int SPROUT_VALUE_VERSION = 80102;
static const int SAPLING_VALUE_VERSION = 80102;
static const int TRANSPARENT_VALUE_VERSION = 80103;
static const int BURNED_VALUE_VERSION = 80104;

// These 5 are declared here to avoid circular dependencies
// code used this moved into .cpp
Expand Down Expand Up @@ -191,6 +193,44 @@ class CBlockIndex
//! (memory only) The anchor for the tree state up to the end of this block
uint256 hashFinalSproutRoot;

//! The change to the chain supply caused by this block. This is defined as
//! the value of the coinbase outputs in this block, minus fees not claimed
//! by the miner.
//!
//! Will be boost::none under the following conditions:
//! - if the block has never been connected to a chain tip
//! - for older blocks until a reindex has taken place
boost::optional<CAmount> nChainSupplyDelta;

//! (memory only) Total chain supply up to and including this block.
//!
//! Will be boost::none until a reindex has taken place, if nChainTx is
//! zero, or if the block has never been connected to a chain tip.
boost::optional<CAmount> nChainTotalSupply;

//! Change in value in the transparent pool produced by the action of the
//! transparent inputs to and outputs from transactions in this block.
//!
//! Will be boost::none for older blocks until a reindex has taken place.
boost::optional<CAmount> nTransparentValue;

//! (memory only) Total value of the transparent value pool up to and
//! including this block.
//!
//! Will be boost::none until a reindex has taken place.
//! Will be boost::none if nChainTx is zero.
boost::optional<CAmount> nChainTransparentValue;

// This refers to the number of coins burned in this block,
// essentially making them unspendable (due to the OP_RETURN scripts value).
//!
//! For older blocks, this will be boost::none until a reindexing has occurred.
boost::optional<CAmount> nBurnedAmountDelta;

//! (memory only) Total value of the burned coins up to and
//! including this block.
boost::optional<CAmount> nChainTotalBurned;

//! Change in value held by the Sprout circuit over this block.
//! Will be boost::none for older blocks on old nodes until a reindex has taken place.
boost::optional<CAmount> nSproutValue;
Expand Down Expand Up @@ -246,6 +286,13 @@ class CBlockIndex
hashSproutAnchor = uint256();
hashFinalSproutRoot = uint256();
nSequenceId = 0;

nChainSupplyDelta = boost::none;
nChainTotalSupply = boost::none;
nTransparentValue = boost::none;
nChainTransparentValue = boost::none;
nBurnedAmountDelta = boost::none;
nChainTotalBurned = boost::none;
nSproutValue = boost::none;
nChainSproutValue = boost::none;
nSaplingValue = 0;
Expand Down Expand Up @@ -440,6 +487,19 @@ class CDiskBlockIndex : public CBlockIndex
READWRITE(nNonce);
READWRITE(nSolution);

// Only read/write nTransparentValue if the client version used to create
// this index was storing them.
if ((s.GetType() & SER_DISK) && (nVersion >= TRANSPARENT_VALUE_VERSION)) {
READWRITE(nChainSupplyDelta);
READWRITE(nTransparentValue);
}

// Only read/write nBurnedAmountDelta if the client version used to create
// this index was storing them.
if ((s.GetType() & SER_DISK) && (nVersion >= BURNED_VALUE_VERSION)) {
READWRITE(nBurnedAmountDelta);
}

// Only read/write nSproutValue if the client version used to create
// this index was storing them.
if ((s.GetType() & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) {
Expand Down
2 changes: 1 addition & 1 deletion src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class CMainParams : public CChainParams {

vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));

fMiningRequiresPeers = true;
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
Expand Down
7 changes: 6 additions & 1 deletion src/coins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,12 @@ const CScript &CCoinsViewCache::GetSpendFor(const CTxIn& input) const
* @returns Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new
*/
CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const
{
return GetTransparentValueIn(nHeight, interestp, tx) + tx.GetShieldedValueIn();
}

// TODO: remove this if it ends up unused
CAmount CCoinsViewCache::GetTransparentValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const
{
CAmount value,nResult = 0;
interestp = 0;
Expand Down Expand Up @@ -617,7 +623,6 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t &interestp,const CTr
}
#endif
}
nResult += tx.GetShieldedValueIn();

return nResult;
}
Expand Down
15 changes: 13 additions & 2 deletions src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,11 +562,22 @@ class CCoinsViewCache : public CCoinsViewBacked
* so may not be able to calculate this.
* @param[in] nHeight the chain height
* @param[out] interestp the interest found
* @param[in] tx transaction for which we are checking input total
* @returns Sum of value of all inputs (scriptSigs), (positive valueBalance or zero) and JoinSplit vpub_new
* @param[in] tx transaction for which we are checking input total
* @return Sum of value of all inputs (scriptSigs), JoinSplit vpub_new, and
* positive values of valueBalanceSapling, and valueBalanceOrchard.
*/
CAmount GetValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const;

/**
* Amount of coins coming in to a transaction in the transparent inputs.
*
* @param[in] nHeight the chain height
* @param[out] interestp the interest found
* @param[in] tx transaction for which we are checking input total
* @return Sum of value of all inputs (scriptSigs)
*/
CAmount GetTransparentValueIn(int32_t nHeight,int64_t &interestp,const CTransaction& tx) const;

//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;

Expand Down
137 changes: 135 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3545,6 +3545,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Grab the consensus branch ID for the block's height
auto consensusBranchId = CurrentEpochBranchId(pindex->nHeight, Params().GetConsensus());

CAmount chainSupplyDelta = 0;
CAmount transparentValueDelta = 0;
CAmount burnedAmountDelta = 0;
std::vector<PrecomputedTransactionData> txdata;
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
Expand All @@ -3565,6 +3568,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state.DoS(100, error("ConnectBlock(): inputs missing/spent"),
REJECT_INVALID, "bad-txns-inputs-missingorspent");
}

for (const auto& input : tx.vin) {
const auto prevout = view.GetOutputFor(input);
transparentValueDelta -= prevout.nValue;
}

// are the JoinSplit's requirements met?
if (!view.HaveJoinSplitRequirements(tx))
return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"),
Expand Down Expand Up @@ -3618,9 +3627,21 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
LogPrintf("valueout %.8f too big\n",(double)valueout/COIN);
return state.DoS(100, error("ConnectBlock(): GetValueOut too big"),REJECT_INVALID,"tx valueout is too big");
}
if (!tx.IsCoinBase())
if (tx.IsCoinBase())
{
nFees += (stakeTxValue= view.GetValueIn(chainActive.Tip()->nHeight,interest,tx) - valueout);
// Add the output value of the coinbase transaction to the chain supply
// delta. This includes fees, which are then canceled out by the fee
// subtractions in the other branch of this conditional.
chainSupplyDelta += tx.GetValueOut();
} else {
const auto txFee = (stakeTxValue= view.GetValueIn(chainActive.Tip()->nHeight,interest,tx) - valueout);
nFees += txFee;

// Fees from a transaction do not go into an output of the transaction,
// and therefore decrease the chain supply. If the miner claims them,
// they will be re-added in the other branch of this conditional.
chainSupplyDelta -= txFee;

sum += interest;

std::vector<CScriptCheck> vChecks;
Expand Down Expand Up @@ -3672,6 +3693,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
sapling_tree.append(outputDescription.cm);
}

for (const auto& out : tx.vout) {
if (!out.scriptPubKey.IsUnspendable()) {
transparentValueDelta += out.nValue;
} else {
// If the outputs are unspendable, we should not include them in the transparent pool,
// but include in the burned amount calculations
burnedAmountDelta += out.nValue;
}
}

vPos.push_back(std::make_pair(tx.GetHash(), pos));
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
}
Expand All @@ -3684,6 +3715,35 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
view.PushAnchor(sprout_tree);
view.PushAnchor(sapling_tree);
if (!fJustCheck) {
// Update pindex with the net change in transparent value and the chain's total
// transparent value.
pindex->nChainSupplyDelta = chainSupplyDelta;
pindex->nTransparentValue = transparentValueDelta;
pindex->nBurnedAmountDelta = burnedAmountDelta;
if (pindex->pprev) {
if (pindex->pprev->nChainTotalSupply) {
pindex->nChainTotalSupply = *pindex->pprev->nChainTotalSupply + chainSupplyDelta;
} else {
pindex->nChainTotalSupply = boost::none;
}

if (pindex->pprev->nChainTransparentValue) {
pindex->nChainTransparentValue = *pindex->pprev->nChainTransparentValue + transparentValueDelta;
} else {
pindex->nChainTransparentValue = boost::none;
}

if (pindex->pprev->nChainTotalBurned) {
pindex->nChainTotalBurned = *pindex->pprev->nChainTotalBurned + burnedAmountDelta;
} else {
pindex->nChainTotalBurned = boost::none;
}
} else {
pindex->nChainTotalSupply = chainSupplyDelta;
pindex->nChainTransparentValue = transparentValueDelta;
pindex->nChainTotalBurned = burnedAmountDelta;
}

pindex->hashFinalSproutRoot = sprout_tree.root();
}
blockundo.old_sprout_tree_root = old_sprout_tree_root;
Expand Down Expand Up @@ -4781,9 +4841,27 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;

// the following values are computed here only for the genesis block
CAmount chainSupplyDelta = 0;
CAmount transparentValueDelta = 0;
CAmount burnedAmountDelta = 0;

CAmount sproutValue = 0;
CAmount saplingValue = 0;
for (auto tx : block.vtx) {
// For the genesis block only, compute the chain supply delta and the transparent
// output total.
if (pindexNew->pprev == nullptr) {
chainSupplyDelta = tx.GetValueOut();
for (const auto& out : tx.vout) {
if (!out.scriptPubKey.IsUnspendable()) {
transparentValueDelta += out.nValue;
} else {
burnedAmountDelta += out.nValue;
}
}
}
// Negative valueBalance "takes" money from the transparent value pool
// and adds it to the Sapling value pool. Positive valueBalance "gives"
// money to the transparent value pool, removing from the Sapling value
Expand All @@ -4795,6 +4873,23 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
sproutValue -= js.vpub_new;
}
}

// These values can only be computed here for the genesis block.
// For all other blocks, we update them in ConnectBlock instead.
if (pindexNew->pprev == nullptr) {
pindexNew->nChainSupplyDelta = chainSupplyDelta;
pindexNew->nTransparentValue = transparentValueDelta;
pindexNew->nBurnedAmountDelta = burnedAmountDelta;
} else {
pindexNew->nChainSupplyDelta = boost::none;
pindexNew->nTransparentValue = boost::none;
pindexNew->nBurnedAmountDelta = boost::none;
}

pindexNew->nChainTotalSupply = boost::none;
pindexNew->nChainTransparentValue = boost::none;
pindexNew->nChainTotalBurned = boost::none;

pindexNew->nSproutValue = sproutValue;
pindexNew->nChainSproutValue = boost::none;
pindexNew->nSaplingValue = saplingValue;
Expand All @@ -4816,18 +4911,30 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
CBlockIndex *pindex = queue.front();
queue.pop_front();
pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx;

if (pindex->pprev) {
// Transparent value and chain total supply are added to the
// block index only in `ConnectBlock`, because that's the only
// place that we have a valid coins view with which to compute
// the transparent input value and fees.

// Calculate the block's effect on the Sprout chain value pool balance.
if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) {
pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue;
} else {
pindex->nChainSproutValue = boost::none;
}

// calculate the block's effect on the chain's net Sapling value
if (pindex->pprev->nChainSaplingValue) {
pindex->nChainSaplingValue = *pindex->pprev->nChainSaplingValue + pindex->nSaplingValue;
} else {
pindex->nChainSaplingValue = boost::none;
}
} else {
pindex->nChainTotalSupply = pindex->nChainSupplyDelta;
pindex->nChainTransparentValue = pindex->nTransparentValue;
pindex->nChainTotalBurned = pindex->nBurnedAmountDelta;
pindex->nChainSproutValue = pindex->nSproutValue;
pindex->nChainSaplingValue = pindex->nSaplingValue;
}
Expand Down Expand Up @@ -6146,24 +6253,50 @@ bool static LoadBlockIndexDB()
if (pindex->pprev) {
if (pindex->pprev->nChainTx) {
pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx;

if (pindex->pprev->nChainTotalSupply && pindex->nChainSupplyDelta) {
pindex->nChainTotalSupply = *pindex->pprev->nChainTotalSupply + *pindex->nChainSupplyDelta;
} else {
pindex->nChainTotalSupply = boost::none;
}

if (pindex->pprev->nChainTransparentValue && pindex->nTransparentValue) {
pindex->nChainTransparentValue = *pindex->pprev->nChainTransparentValue + *pindex->nTransparentValue;
} else {
pindex->nChainTransparentValue = boost::none;
}

if (pindex->pprev->nChainTotalBurned && pindex->nBurnedAmountDelta) {
pindex->nChainTotalBurned = *pindex->pprev->nChainTotalBurned + *pindex->nBurnedAmountDelta;
} else {
pindex->nChainTotalBurned = boost::none;
}

if (pindex->pprev->nChainSproutValue && pindex->nSproutValue) {
pindex->nChainSproutValue = *pindex->pprev->nChainSproutValue + *pindex->nSproutValue;
} else {
pindex->nChainSproutValue = boost::none;
}

if (pindex->pprev->nChainSaplingValue) {
pindex->nChainSaplingValue = *pindex->pprev->nChainSaplingValue + pindex->nSaplingValue;
} else {
pindex->nChainSaplingValue = boost::none;
}
} else {
pindex->nChainTx = 0;
pindex->nChainTotalSupply = boost::none;
pindex->nChainTransparentValue = boost::none;
pindex->nChainTotalBurned = boost::none;
pindex->nChainSproutValue = boost::none;
pindex->nChainSaplingValue = boost::none;
mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex));
}
} else {
pindex->nChainTx = pindex->nTx;
pindex->nChainTotalSupply = pindex->nChainSupplyDelta;
pindex->nChainTransparentValue = pindex->nTransparentValue;
pindex->nChainTotalBurned = pindex->nBurnedAmountDelta;
pindex->nChainSproutValue = pindex->nSproutValue;
pindex->nChainSaplingValue = pindex->nSaplingValue;
}
Expand Down
Loading