From 87d70f415245cba8f1e373bfa2c054606c70e14e Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sat, 5 Aug 2023 19:03:21 +0800 Subject: [PATCH 01/17] Finalize OP_RETURN default rules --- src/script/standard.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/script/standard.h b/src/script/standard.h index 9f22e5bb51..1dcdd3fba6 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -29,9 +29,9 @@ class CScriptID : public uint160 // While the relay options are free for interpretation to // each node, the accept values are enforced on validation -static const uint32_t MAX_OP_RETURN_CORE_ACCEPT = 2000; -static const uint32_t MAX_OP_RETURN_DVM_ACCEPT = 4000; -static const uint32_t MAX_OP_RETURN_EVM_ACCEPT = 20000; +static const uint64_t MAX_OP_RETURN_CORE_ACCEPT = 1024; +static const uint64_t MAX_OP_RETURN_DVM_ACCEPT = 4096; +static const uint64_t MAX_OP_RETURN_EVM_ACCEPT = 65536; /** * This is the check used for IsStandardChecks to allow all of the 3 above @@ -39,7 +39,7 @@ static const uint32_t MAX_OP_RETURN_EVM_ACCEPT = 20000; * Also used as default for nMaxDatacarrierBytes. * Actual data size = N - 3 // 1 for OP_RETURN, 2 for pushdata opcodes. */ -static constexpr uint32_t MAX_OP_RETURN_RELAY = std::max({MAX_OP_RETURN_CORE_ACCEPT, MAX_OP_RETURN_DVM_ACCEPT, MAX_OP_RETURN_EVM_ACCEPT}); +static constexpr uint64_t MAX_OP_RETURN_RELAY = std::max({MAX_OP_RETURN_CORE_ACCEPT, MAX_OP_RETURN_DVM_ACCEPT, MAX_OP_RETURN_EVM_ACCEPT}); /** * A data carrying output is an unspendable output containing data. The script From 8b3539ebafdbfd425057403434bb9109894f34e5 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sun, 6 Aug 2023 15:09:46 +0800 Subject: [PATCH 02/17] Cleanup coinbase rewards, getblock --- src/rpc/blockchain.cpp | 186 ++++++++++++++++------- src/rpc/blockchain.h | 2 +- src/validation.cpp | 331 ++++++++++++++++++++--------------------- 3 files changed, 290 insertions(+), 229 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 767b75de4e..811b38b2e3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -117,7 +117,121 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex return result; } -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails) +struct MinterInfo { + std::string Id{}; + std::string OwnerAddress{}; + std::string OperatorAddress{}; + std::string RewardAddress{}; + uint64_t MintedBlocks{}; + uint256 StakeModifier{}; + + static std::optional TryFrom(const CBlock& block, const CBlockIndex* blockindex, const CCustomCSView& view) { + MinterInfo result; + CKeyID minter; + block.ExtractMinterKey(minter); + auto id = view.GetMasternodeIdByOperator(minter); + if (!id) return {}; + result.Id = id->ToString(); + auto mn = view.GetMasternode(*id); + if (mn) { + auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); + result.OperatorAddress = EncodeDestination(dest); + } + result.MintedBlocks = blockindex->mintedBlocks; + result.StakeModifier = blockindex->stakeModifier; + return result; + } + + void PushToUniValueLegacy(UniValue& result) { + // Note: This follows legacy way of empty checks and prints to preserve + // compatibility. Don't change it. Use the new method ToUniValue method + // for new version. + if (Id.empty()) return; + result.pushKV("masternode", Id); + if (!OperatorAddress.empty()) result.pushKV("minter", OperatorAddress); + result.pushKV("mintedBlocks", MintedBlocks); + result.pushKV("stakeModifier", StakeModifier.ToString()); + } +}; + +struct RewardInfo { + struct TokenRewardItems { + CAmount Burnt{}; + CAmount IncentiveFunding{}; + CAmount AnchorReward{}; + CAmount CommunityDevFunds{}; + CAmount Loan{}; + CAmount Options{}; + }; + + CAmount BlockReward{}; + TokenRewardItems TokenRewards{}; + + static std::optional TryFrom(const CBlock& block, const CBlockIndex* blockindex, const Consensus::Params& consensus) { + if (blockindex->nHeight < consensus.AMKHeight) + return {}; + + RewardInfo result{}; + auto& tokenRewards = result.TokenRewards; + CAmount blockReward = GetBlockSubsidy(blockindex->nHeight, consensus); + result.BlockReward = blockReward; + + if (blockindex->nHeight < consensus.EunosHeight) { + for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) + { + CAmount subsidy = blockReward * accountVal / COIN; + switch (accountType) { + // CommunityDevFunds, Loan, Options don't exist in nonUtxoBlockSubsidies here + case CommunityAccountType::AnchorReward:{ tokenRewards.AnchorReward = subsidy; break; } + case CommunityAccountType::IncentiveFunding: { tokenRewards.IncentiveFunding = subsidy; break; } + default: { tokenRewards.Burnt += subsidy; } + } + } + return result; + } + + for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) + { + if (blockindex->nHeight < consensus.GrandCentralHeight + && accountType == CommunityAccountType::CommunityDevFunds) { + continue; + } + + CAmount subsidy = CalculateCoinbaseReward(blockReward, accountVal); + switch (accountType) { + // Everything else is burnt. Should update post fort canning. Retaining + // compatibility for old logic for now. + case CommunityAccountType::AnchorReward:{ tokenRewards.AnchorReward = subsidy; break; } + case CommunityAccountType::CommunityDevFunds: { tokenRewards.CommunityDevFunds = subsidy; break; } + default: { tokenRewards.Burnt += subsidy; } + } + } + return result; + } + + void PushToUniValueLegacy(UniValue& result) { + // Note: This follows legacy way of empty checks and prints to preserve + // compatibility. Don't change it. Use the new method ToUniValue method + // for new version. + UniValue rewards(UniValue::VARR); + UniValue obj(UniValue::VOBJ); + + auto& r = TokenRewards; + auto items = std::vector>{ + { CommunityAccountType::AnchorReward, r.AnchorReward }, + { CommunityAccountType::CommunityDevFunds, r.CommunityDevFunds }, + { CommunityAccountType::Unallocated, r.Burnt }}; + + for (const auto& [accountName, val]: items) { + obj.pushKV(GetCommunityAccountName(accountName), ValueFromAmount(val)); + } + + rewards.push_back(obj); + result.pushKV("nonutxo", rewards); + } +}; + +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, bool xVmDetails) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons @@ -132,66 +246,22 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("weight", (int)::GetBlockWeight(block)); result.pushKV("height", blockindex->nHeight); - CKeyID minter; - block.ExtractMinterKey(minter); - auto id = pcustomcsview->GetMasternodeIdByOperator(minter); - if (id) { - result.pushKV("masternode", id->ToString()); - auto mn = pcustomcsview->GetMasternode(*id); - if (mn) { - auto dest = mn->operatorType == 1 ? CTxDestination(PKHash(minter)) : CTxDestination(WitnessV0KeyHash(minter)); - result.pushKV("minter", EncodeDestination(dest)); - } + // For xVMDetails, we fix the past mistakes and don't just modify existing root schema. + // We'll add all these later. + if (!xVmDetails) { + auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); + if (minterInfo) { minterInfo->PushToUniValueLegacy(result); } } - result.pushKV("mintedBlocks", blockindex->mintedBlocks); - result.pushKV("stakeModifier", blockindex->stakeModifier.ToString()); - + result.pushKV("version", block.nVersion); result.pushKV("versionHex", strprintf("%08x", block.nVersion)); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); - UniValue rewards(UniValue::VARR); - if (blockindex->nHeight >= Params().GetConsensus().AMKHeight) - { - CAmount blockReward = GetBlockSubsidy(blockindex->nHeight, Params().GetConsensus()); - UniValue nonutxo(UniValue::VOBJ); - - if (blockindex->nHeight >= Params().GetConsensus().EunosHeight) - { - CAmount burnt{0}; - for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) - { - if (blockindex->nHeight < Params().GetConsensus().GrandCentralHeight - && kv.first == CommunityAccountType::CommunityDevFunds) { - continue; - } - - CAmount subsidy = CalculateCoinbaseReward(blockReward, kv.second); - - switch(kv.first) { - case CommunityAccountType::AnchorReward: - case CommunityAccountType::CommunityDevFunds: - nonutxo.pushKV(GetCommunityAccountName(kv.first), ValueFromAmount(subsidy)); - break; - default: - burnt += subsidy; // Everything else goes into burnt - } - } - - // Add burnt total - nonutxo.pushKV(GetCommunityAccountName(CommunityAccountType::Unallocated), ValueFromAmount(burnt)); - } - else - { - for (const auto& kv : Params().GetConsensus().nonUtxoBlockSubsidies) - { - // Anchor and LP incentive - nonutxo.pushKV(GetCommunityAccountName(kv.first), ValueFromAmount(blockReward * kv.second / COIN)); - } - } - rewards.push_back(nonutxo); + if (!xVmDetails) { + auto rewardInfo = RewardInfo::TryFrom(block, blockindex, Params().GetConsensus()); + if (rewardInfo) { rewardInfo->PushToUniValueLegacy(result); } } - result.pushKV("nonutxo", rewards); + UniValue txs(UniValue::VARR); for(const auto& tx : block.vtx) { @@ -216,6 +286,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()); if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); + + if (xVmDetails) { + // TODO: Add xVM details here + } return result; } @@ -969,7 +1043,7 @@ static UniValue getblock(const JSONRPCRequest& request) return strHex; } - return blockToJSON(block, tip, pblockindex, verbosity >= 2); + return blockToJSON(block, tip, pblockindex, verbosity >= 2, verbosity >= 3); } static UniValue pruneblockchain(const JSONRPCRequest& request) diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 5c205a8ef9..0d84caedac 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -32,7 +32,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false) LOCKS_EXCLUDED(cs_main); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, bool xVmDetails = false) LOCKS_EXCLUDED(cs_main); /** Mempool information to JSON */ UniValue MempoolInfoToJSON(const CTxMemPool& pool); diff --git a/src/validation.cpp b/src/validation.cpp index dff65fcef6..196d3cb08c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2051,216 +2051,203 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int if (cbValues.size() != 1 || cbValues.begin()->first != DCT_ID{0}) return Res::ErrDbg("bad-cb-wrong-tokens", "coinbase should pay only Defi coins"); + auto finalCheckAndReturn = [&]() { + if (cbValues.at(DCT_ID{0}) > blockReward + nFees) + return Res::ErrDbg("bad-cb-amount", "coinbase pays too much (actual=%d vs limit=%d)", cbValues.at(DCT_ID{0}), blockReward + nFees); + return Res::Ok(); + }; - if (height >= consensus.AMKHeight) - { - CAmount foundationReward{0}; - if (height >= consensus.GrandCentralHeight) - { - // no foundation utxo reward check anymore - } - else if (height >= consensus.EunosHeight) - { - foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); - } - else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) - { - foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; - } - - if (foundationReward) - { - bool foundationsRewardfound = false; - for (auto& txout : tx.vout) - { - if (txout.scriptPubKey == consensus.foundationShareScript) - { - if (txout.nValue < foundationReward) - { - return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); - } + auto logAccountChange = [](const CTransaction& tx, const CAmount subsidy, const std::string account) { + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", + tx.GetHash().ToString(), + account, + (CBalances{{{{0}, subsidy}}}.ToString())); + }; - foundationsRewardfound = true; - break; - } - } + auto isUnusedEmissionFundEnabled = [](const ATTRIBUTES& attrs) { + CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; + return attrs.GetValue(k, false); + }; - if (!foundationsRewardfound) - { - return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay foundation reward!"); - } - } + auto isGovernanceEnabled = [](const ATTRIBUTES& attrs) { + CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; + return attrs.GetValue(k, false); + }; - // count and subtract for non-UTXO community rewards - CAmount nonUtxoTotal = 0; - if (height >= consensus.EunosHeight) - { - CAmount subsidy; - for (const auto& kv : consensus.newNonUTXOSubsidies) - { - if (kv.first == CommunityAccountType::CommunityDevFunds) { - if (height < consensus.GrandCentralHeight) { - continue; - } - } + if (height < consensus.AMKHeight) { + return finalCheckAndReturn(); + } - subsidy = CalculateCoinbaseReward(blockReward, kv.second); + // TODO(legacy-cleanup): Clean up the rest of the method with proper structures + // and a more comprehensible flow - Res res = Res::Ok(); + CAmount foundationReward{0}; + if (height >= consensus.GrandCentralHeight) { + // no foundation utxo reward check anymore + } + else if (height >= consensus.EunosHeight) { + foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); + } + else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { + foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; + } - // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. - if ((height < consensus.FortCanningHeight && kv.first == CommunityAccountType::Loan) || - (height < consensus.GrandCentralHeight && kv.first == CommunityAccountType::Options)) - { - res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(CommunityAccountType::Unallocated), (CBalances{{{{0}, subsidy}}}.ToString())); + if (foundationReward) { + bool foundationsRewardfound = false; + for (auto& txout : tx.vout) { + if (txout.scriptPubKey == consensus.foundationShareScript) { + if (txout.nValue < foundationReward) { + return Res::ErrDbg("bad-cb-foundation-reward", + "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); } - else - { - if (height >= consensus.GrandCentralHeight) - { - const auto attributes = mnview.GetAttributes(); - assert(attributes); + foundationsRewardfound = true; + break; + } + } - if (kv.first == CommunityAccountType::CommunityDevFunds) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; + if (!foundationsRewardfound) { + return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay foundation reward!"); + } + } - if (!attributes->GetValue(enabledKey, false)) - { - res = mnview.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", - tx.GetHash().ToString(), ScriptToString(consensus.foundationShareScript), - (CBalances{{{{0}, subsidy}}}.ToString())); - nonUtxoTotal += subsidy; + // count and subtract for non-UTXO community rewards + CAmount nonUtxoTotal = 0; - continue; - } - } else if (kv.first == CommunityAccountType::Unallocated || kv.first == CommunityAccountType::Options) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - - if (attributes->GetValue(enabledKey, false)) { - res = mnview.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); - if (res) { - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", - tx.GetHash().ToString(), ScriptToString(consensus.unusedEmission), - (CBalances{{{{0}, subsidy}}}.ToString())); - } - } else { - // Previous behaviour was for Options and Unallocated to go to Unallocated - res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(CommunityAccountType::Unallocated), (CBalances{{{{0}, subsidy}}}.ToString())); - } - - nonUtxoTotal += subsidy; + if (height < consensus.EunosHeight) { + for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) { + CAmount subsidy = blockReward * accountVal / COIN; + Res res = mnview.AddCommunityBalance(accountType, subsidy); + if (!res.ok) { + return Res::ErrDbg("bad-cb-community-rewards", "can't take non-UTXO community share from coinbase"); + } else { + logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); + } + nonUtxoTotal += subsidy; + } + blockReward -= nonUtxoTotal; + return finalCheckAndReturn(); + } - continue; - } - } + CAmount subsidy; + for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) { + if (accountType == CommunityAccountType::CommunityDevFunds) { + if (height < consensus.GrandCentralHeight) { + continue; + } + } - res = mnview.AddCommunityBalance(kv.first, subsidy); - if (res) - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(kv.first), (CBalances{{{{0}, subsidy}}}.ToString())); - } + subsidy = CalculateCoinbaseReward(blockReward, accountVal); + Res res = Res::Ok(); - if (!res.ok) - { - return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); + // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. + if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || + (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { + res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) { + logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); + } + } else { + if (height >= consensus.GrandCentralHeight) { + const auto attributes = mnview.GetAttributes(); + assert(attributes); + if (accountType == CommunityAccountType::CommunityDevFunds) { + if (!isGovernanceEnabled(*attributes)) { + continue; + } else { + res = mnview.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); + // TODO: Result check missed; check full sync and add checks + logAccountChange(tx, subsidy, ScriptToString(consensus.foundationShareScript)); + nonUtxoTotal += subsidy; + continue; + } + } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { + if (isUnusedEmissionFundEnabled(*attributes)) { + res = mnview.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); + if (res) { logAccountChange(tx, subsidy, ScriptToString(consensus.unusedEmission)); } + } else { + // Previous behaviour was for Options and Unallocated to go to Unallocated + res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) { logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); } + } + nonUtxoTotal += subsidy; + continue; } + } - nonUtxoTotal += subsidy; + res = mnview.AddCommunityBalance(accountType, subsidy); + if (res) { + logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); } } - else - { - for (const auto& kv : consensus.nonUtxoBlockSubsidies) { - CAmount subsidy = blockReward * kv.second / COIN; - Res res = mnview.AddCommunityBalance(kv.first, subsidy); - if (!res.ok) { - return Res::ErrDbg("bad-cb-community-rewards", "can't take non-UTXO community share from coinbase"); - } else { - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(kv.first), (CBalances{{{{0}, subsidy}}}.ToString())); - } - nonUtxoTotal += subsidy; - } + + if (!res.ok) { + return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); } - blockReward -= nonUtxoTotal; + nonUtxoTotal += subsidy; } - // pre-AMK logic, compatible after prev blockReward mod: - if (cbValues.at(DCT_ID{0}) > blockReward + nFees) - return Res::ErrDbg("bad-cb-amount", "coinbase pays too much (actual=%d vs limit=%d)", cbValues.at(DCT_ID{0}), blockReward + nFees); - - return Res::Ok(); + blockReward -= nonUtxoTotal; + return finalCheckAndReturn(); } void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensus::Params& consensus) { - CAmount blockReward = GetBlockSubsidy(height, Params().GetConsensus()); - - if (height >= Params().GetConsensus().AMKHeight) - { - if (height >= Params().GetConsensus().EunosHeight) - { - for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) - { - if (kv.first == CommunityAccountType::CommunityDevFunds) { - if (height < Params().GetConsensus().GrandCentralHeight) { - continue; - } - } + CAmount blockReward = GetBlockSubsidy(height, consensus); + + if (height < consensus.AMKHeight) { + return; + } - CAmount subsidy = CalculateCoinbaseReward(blockReward, kv.second); + // TODO(legacy-cleanup): Use proper structures - // Remove Loan and Options balances from Unallocated - if ((height < Params().GetConsensus().FortCanningHeight && kv.first == CommunityAccountType::Loan) || - (height < consensus.GrandCentralHeight && kv.first == CommunityAccountType::Options)) - { - mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); - } - else - { - if (height >= consensus.GrandCentralHeight) - { - const auto attributes = mnview.GetAttributes(); - assert(attributes); + if (height < consensus.EunosHeight) { + for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) { + CAmount subsidy = blockReward * accountVal / COIN; + mnview.SubCommunityBalance(accountType, subsidy); + } + return; + } - if (kv.first == CommunityAccountType::CommunityDevFunds) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; + for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) { + if (accountType == CommunityAccountType::CommunityDevFunds) { + if (height < consensus.GrandCentralHeight) { + continue; + } + } - if (!attributes->GetValue(enabledKey, false)) - { - mnview.SubBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); + CAmount subsidy = CalculateCoinbaseReward(blockReward, accountVal); - continue; - } - } else if (kv.first == CommunityAccountType::Unallocated || kv.first == CommunityAccountType::Options) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; + // Remove Loan and Options balances from Unallocated + if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || + (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { + mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); + } else { + if (height >= consensus.GrandCentralHeight) { + const auto attributes = mnview.GetAttributes(); + assert(attributes); - if (attributes->GetValue(enabledKey, false)) { - mnview.SubBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); - } else { - mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); - } + if (accountType == CommunityAccountType::CommunityDevFunds) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; - continue; - } + if (!attributes->GetValue(enabledKey, false)) + { + mnview.SubBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); + continue; } + } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - mnview.SubCommunityBalance(kv.first, subsidy); + if (attributes->GetValue(enabledKey, false)) { + mnview.SubBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); + } else { + mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); + } + continue; } } - } - else - { - for (const auto& kv : Params().GetConsensus().nonUtxoBlockSubsidies) - { - CAmount subsidy = blockReward * kv.second / COIN; - mnview.SubCommunityBalance(kv.first, subsidy); - } + mnview.SubCommunityBalance(accountType, subsidy); } } } From bb5bf45086836f295a58b31af795fa269c75b852 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sun, 6 Aug 2023 15:13:45 +0800 Subject: [PATCH 03/17] Cleanup reverse --- src/validation.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 196d3cb08c..eeb365336a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2196,6 +2196,16 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensu { CAmount blockReward = GetBlockSubsidy(height, consensus); + auto isUnusedEmissionFundEnabled = [](const ATTRIBUTES& attrs) { + CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; + return attrs.GetValue(k, false); + }; + + auto isGovernanceEnabled = [](const ATTRIBUTES& attrs) { + CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; + return attrs.GetValue(k, false); + }; + if (height < consensus.AMKHeight) { return; } @@ -2229,17 +2239,12 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensu assert(attributes); if (accountType == CommunityAccountType::CommunityDevFunds) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; - - if (!attributes->GetValue(enabledKey, false)) - { + if (!isGovernanceEnabled(*attributes)) { mnview.SubBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); continue; } } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { - CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - - if (attributes->GetValue(enabledKey, false)) { + if (isUnusedEmissionFundEnabled(*attributes)) { mnview.SubBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); } else { mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); From c7936ad562883c34bf2686809e239ec3da630384 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sun, 6 Aug 2023 15:18:45 +0800 Subject: [PATCH 04/17] Revert "Finalize OP_RETURN default rules" This reverts commit 87d70f415245cba8f1e373bfa2c054606c70e14e. --- src/script/standard.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/script/standard.h b/src/script/standard.h index 1dcdd3fba6..9f22e5bb51 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -29,9 +29,9 @@ class CScriptID : public uint160 // While the relay options are free for interpretation to // each node, the accept values are enforced on validation -static const uint64_t MAX_OP_RETURN_CORE_ACCEPT = 1024; -static const uint64_t MAX_OP_RETURN_DVM_ACCEPT = 4096; -static const uint64_t MAX_OP_RETURN_EVM_ACCEPT = 65536; +static const uint32_t MAX_OP_RETURN_CORE_ACCEPT = 2000; +static const uint32_t MAX_OP_RETURN_DVM_ACCEPT = 4000; +static const uint32_t MAX_OP_RETURN_EVM_ACCEPT = 20000; /** * This is the check used for IsStandardChecks to allow all of the 3 above @@ -39,7 +39,7 @@ static const uint64_t MAX_OP_RETURN_EVM_ACCEPT = 65536; * Also used as default for nMaxDatacarrierBytes. * Actual data size = N - 3 // 1 for OP_RETURN, 2 for pushdata opcodes. */ -static constexpr uint64_t MAX_OP_RETURN_RELAY = std::max({MAX_OP_RETURN_CORE_ACCEPT, MAX_OP_RETURN_DVM_ACCEPT, MAX_OP_RETURN_EVM_ACCEPT}); +static constexpr uint32_t MAX_OP_RETURN_RELAY = std::max({MAX_OP_RETURN_CORE_ACCEPT, MAX_OP_RETURN_DVM_ACCEPT, MAX_OP_RETURN_EVM_ACCEPT}); /** * A data carrying output is an unspendable output containing data. The script From 5c22a625a4965a680f2660c5e632b9101a7e9a2e Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sun, 6 Aug 2023 17:44:24 +0800 Subject: [PATCH 05/17] Add ToUniValue --- src/masternodes/incentivefunding.h | 2 +- src/rpc/blockchain.cpp | 78 +++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/masternodes/incentivefunding.h b/src/masternodes/incentivefunding.h index 0fdcfe406c..f596f374ff 100644 --- a/src/masternodes/incentivefunding.h +++ b/src/masternodes/incentivefunding.h @@ -18,7 +18,7 @@ inline CommunityAccountType CommunityAccountCodeToType(unsigned char ch) { return CommunityAccountType::None; } -inline const char *GetCommunityAccountName(CommunityAccountType t) { +inline const std::string GetCommunityAccountName(const CommunityAccountType t) { switch (t) { case CommunityAccountType::IncentiveFunding: return "IncentiveFunding"; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 811b38b2e3..4ff35e9290 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -142,7 +142,7 @@ struct MinterInfo { return result; } - void PushToUniValueLegacy(UniValue& result) { + void ToUniValueLegacy(UniValue& result) { // Note: This follows legacy way of empty checks and prints to preserve // compatibility. Don't change it. Use the new method ToUniValue method // for new version. @@ -152,6 +152,19 @@ struct MinterInfo { result.pushKV("mintedBlocks", MintedBlocks); result.pushKV("stakeModifier", StakeModifier.ToString()); } + + UniValue ToUniValue() { + // Note that this breaks compatibility with the legacy version. + // Do not use this with existing RPCs + UniValue result(UniValue::VOBJ); + result.pushKV("id", Id); + result.pushKV("owner", OwnerAddress); + result.pushKV("operator", OperatorAddress); + result.pushKV("rewardAddress", RewardAddress); + result.pushKV("totalMinted", MintedBlocks); + result.pushKV("stakeModifier", StakeModifier.ToString()); + return result; + } }; struct RewardInfo { @@ -209,7 +222,7 @@ struct RewardInfo { return result; } - void PushToUniValueLegacy(UniValue& result) { + void ToUniValueLegacy(UniValue& result) { // Note: This follows legacy way of empty checks and prints to preserve // compatibility. Don't change it. Use the new method ToUniValue method // for new version. @@ -229,12 +242,34 @@ struct RewardInfo { rewards.push_back(obj); result.pushKV("nonutxo", rewards); } + + UniValue ToUniValue() { + // Note that this breaks compatibility with the legacy version. + // Do not use this with existing RPCs + UniValue obj(UniValue::VOBJ); + + auto& r = TokenRewards; + auto items = std::vector>{ + { CommunityAccountType::AnchorReward, r.AnchorReward }, + { CommunityAccountType::CommunityDevFunds, r.CommunityDevFunds }, + { CommunityAccountType::IncentiveFunding, r.IncentiveFunding }, + { CommunityAccountType::Loan, r.Loan }, + { CommunityAccountType::Options, r.Options }, + { CommunityAccountType::Unallocated, r.Burnt }}; + + obj.pushKV("block", ValueFromAmount(BlockReward)); + for (const auto& [accountName, val]: items) { + obj.pushKV(GetCommunityAccountName(accountName), ValueFromAmount(val)); + } + return obj; + } }; UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, bool xVmDetails) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons + const auto consensus = Params().GetConsensus(); UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); @@ -250,7 +285,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn // We'll add all these later. if (!xVmDetails) { auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); - if (minterInfo) { minterInfo->PushToUniValueLegacy(result); } + if (minterInfo) { minterInfo->ToUniValueLegacy(result); } } result.pushKV("version", block.nVersion); @@ -258,23 +293,21 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); if (!xVmDetails) { - auto rewardInfo = RewardInfo::TryFrom(block, blockindex, Params().GetConsensus()); - if (rewardInfo) { rewardInfo->PushToUniValueLegacy(result); } - } - - UniValue txs(UniValue::VARR); - for(const auto& tx : block.vtx) - { - if(txDetails) + auto rewardInfo = RewardInfo::TryFrom(block, blockindex, consensus); + if (rewardInfo) { rewardInfo->ToUniValueLegacy(result); } + UniValue txs(UniValue::VARR); + for(const auto& tx : block.vtx) { - UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); - txs.push_back(objTx); + if (txDetails) { + UniValue objTx(UniValue::VOBJ); + TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); + txs.push_back(objTx); + } else { + txs.push_back(tx->GetHash().GetHex()); + } } - else - txs.push_back(tx->GetHash().GetHex()); + result.pushKV("tx", txs); } - result.pushKV("tx", txs); result.pushKV("time", block.GetBlockTime()); result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast()); result.pushKV("bits", strprintf("%08x", block.nBits)); @@ -288,8 +321,17 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); if (xVmDetails) { - // TODO: Add xVM details here + auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); + if (minterInfo) { + result.pushKV("minter", minterInfo->ToUniValue()); + } + auto rewardInfo = RewardInfo::TryFrom(block, blockindex, consensus); + if (rewardInfo) { + result.pushKV("rewards", rewardInfo->ToUniValue()); + } + // TODO: Tx } + return result; } From 4e338560f808d16de3c39e23896542b73788ceac Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sun, 6 Aug 2023 19:37:24 +0800 Subject: [PATCH 06/17] Include vminfo on getblock --- src/core_write.cpp | 51 ++++++++++++++++++---------------- src/rpc/blockchain.cpp | 63 ++++++++++++++++++++++++++++++------------ src/rpc/blockchain.h | 2 +- 3 files changed, 73 insertions(+), 43 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index 12a089e647..ec5f0720ef 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -185,17 +185,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) { - entry.pushKV("txid", tx.GetHash().GetHex()); - entry.pushKV("hash", tx.GetWitnessHash().GetHex()); - entry.pushKV("version", tx.nVersion); - entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION)); - entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); - entry.pushKV("weight", GetTransactionWeight(tx)); - entry.pushKV("locktime", (int64_t)tx.nLockTime); - - UniValue vin(UniValue::VARR); - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const CTxIn& txin = tx.vin[i]; + const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int txindex) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); @@ -206,28 +196,22 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); - if (!tx.vin[i].scriptWitness.IsNull()) { + if (!tx.vin[txindex].scriptWitness.IsNull()) { UniValue txinwitness(UniValue::VARR); - for (const auto& item : tx.vin[i].scriptWitness.stack) { + for (const auto& item : tx.vin[txindex].scriptWitness.stack) { txinwitness.push_back(HexStr(item.begin(), item.end())); } in.pushKV("txinwitness", txinwitness); } } in.pushKV("sequence", (int64_t)txin.nSequence); - vin.push_back(in); - } - entry.pushKV("vin", vin); - - UniValue vout(UniValue::VARR); - for (unsigned int i = 0; i < tx.vout.size(); i++) { - const CTxOut& txout = tx.vout[i]; + return in; + }; + const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int txindex) { UniValue out(UniValue::VOBJ); - out.pushKV("value", ValueFromAmount(txout.nValue)); - out.pushKV("n", (int64_t)i); - + out.pushKV("n", (int64_t)txindex); UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(txout.scriptPubKey, o, true); out.pushKV("scriptPubKey", o); @@ -235,7 +219,26 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, if (tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { out.pushKV("tokenId", (uint64_t)txout.nTokenId.v); } - vout.push_back(out); + return out; + }; + + entry.pushKV("txid", tx.GetHash().GetHex()); + entry.pushKV("hash", tx.GetWitnessHash().GetHex()); + entry.pushKV("version", tx.nVersion); + entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION)); + entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR); + entry.pushKV("weight", GetTransactionWeight(tx)); + entry.pushKV("locktime", (int64_t)tx.nLockTime); + + UniValue vin(UniValue::VARR); + for (unsigned int i = 0; i < tx.vin.size(); i++) { + vin.push_back(txInToUniValue(tx, tx.vin[i], i)); + } + entry.pushKV("vin", vin); + + UniValue vout(UniValue::VARR); + for (unsigned int i = 0; i < tx.vout.size(); i++) { + vout.push_back(txOutToUniValue(tx, tx.vout[i], i)); } entry.pushKV("vout", vout); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 4ff35e9290..d2cf15117e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -265,12 +265,50 @@ struct RewardInfo { } }; -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, bool xVmDetails) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, bool v2) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons const auto consensus = Params().GetConsensus(); + auto txVmInfo = [](const CTransaction& tx) -> std::optional { + CustomTxType guess; + UniValue txResults(UniValue::VOBJ); + auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); + if (guess == CustomTxType::None) { + return {}; + } + UniValue result(UniValue::VOBJ); + result.pushKV("vmtype", guess == CustomTxType::EvmTx ? "evm" : "dvm"); + result.pushKV("txtype", ToString(guess)); + if (!res.ok) { + result.pushKV("error", res.msg); + } else { + result.pushKV("msg", txResults); + } + return result; + }; + + auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, bool v2) { + UniValue txs(UniValue::VARR); + for(const auto& tx : block.vtx) + { + if (txDetails) { + UniValue objTx(UniValue::VOBJ); + TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); + if (v2) { + if (auto r = txVmInfo(*tx); r) { + objTx.pushKV("vm", *r); + } + } + txs.push_back(objTx); + } else { + txs.push_back(tx->GetHash().GetHex()); + } + } + return txs; + }; + UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); const CBlockIndex* pnext; @@ -281,9 +319,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("weight", (int)::GetBlockWeight(block)); result.pushKV("height", blockindex->nHeight); - // For xVMDetails, we fix the past mistakes and don't just modify existing root schema. + // For v2, we fix the past mistakes and don't just modify existing root schema. // We'll add all these later. - if (!xVmDetails) { + if (!v2) { auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); if (minterInfo) { minterInfo->ToUniValueLegacy(result); } } @@ -292,21 +330,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("versionHex", strprintf("%08x", block.nVersion)); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); - if (!xVmDetails) { + if (!v2) { auto rewardInfo = RewardInfo::TryFrom(block, blockindex, consensus); if (rewardInfo) { rewardInfo->ToUniValueLegacy(result); } - UniValue txs(UniValue::VARR); - for(const auto& tx : block.vtx) - { - if (txDetails) { - UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); - txs.push_back(objTx); - } else { - txs.push_back(tx->GetHash().GetHex()); - } - } - result.pushKV("tx", txs); + result.pushKV("tx", txsToUniValue(block, txDetails, v2)); } result.pushKV("time", block.GetBlockTime()); result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast()); @@ -320,7 +347,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); - if (xVmDetails) { + if (v2) { auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); if (minterInfo) { result.pushKV("minter", minterInfo->ToUniValue()); @@ -329,7 +356,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (rewardInfo) { result.pushKV("rewards", rewardInfo->ToUniValue()); } - // TODO: Tx + result.pushKV("tx", txsToUniValue(block, txDetails, v2)); } return result; diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index 0d84caedac..b744e45300 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -32,7 +32,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, bool xVmDetails = false) LOCKS_EXCLUDED(cs_main); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, bool v2 = false) LOCKS_EXCLUDED(cs_main); /** Mempool information to JSON */ UniValue MempoolInfoToJSON(const CTxMemPool& pool); From de0b6bd5dfce0af7ce9b26fb57cb28c03943f866 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 05:31:27 +0800 Subject: [PATCH 07/17] Add support for Coinbase --- src/core_write.cpp | 14 ++++++++------ src/masternodes/mn_checks.cpp | 23 +++++++++++++++++++++++ src/masternodes/mn_checks.h | 2 ++ src/masternodes/validation.cpp | 26 +++++--------------------- src/rpc/blockchain.cpp | 31 +++++++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/core_write.cpp b/src/core_write.cpp index ec5f0720ef..abf0ab59ce 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -185,7 +185,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) { - const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int txindex) { + const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int txindex, bool include_hex) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); @@ -194,7 +194,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); - o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + if (include_hex) { + o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); + } in.pushKV("scriptSig", o); if (!tx.vin[txindex].scriptWitness.IsNull()) { UniValue txinwitness(UniValue::VARR); @@ -208,12 +210,12 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, return in; }; - const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int txindex) { + const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int txindex, bool include_hex) { UniValue out(UniValue::VOBJ); out.pushKV("value", ValueFromAmount(txout.nValue)); out.pushKV("n", (int64_t)txindex); UniValue o(UniValue::VOBJ); - ScriptPubKeyToUniv(txout.scriptPubKey, o, true); + ScriptPubKeyToUniv(txout.scriptPubKey, o, include_hex); out.pushKV("scriptPubKey", o); // Start to print tokenId start from version TOKENS_MIN_VERSION if (tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { @@ -232,13 +234,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, UniValue vin(UniValue::VARR); for (unsigned int i = 0; i < tx.vin.size(); i++) { - vin.push_back(txInToUniValue(tx, tx.vin[i], i)); + vin.push_back(txInToUniValue(tx, tx.vin[i], i, include_hex)); } entry.pushKV("vin", vin); UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { - vout.push_back(txOutToUniValue(tx, tx.vout[i], i)); + vout.push_back(txOutToUniValue(tx, tx.vout[i], i, include_hex)); } entry.pushKV("vout", vout); diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index b3849653aa..4cd47210ca 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -5227,6 +5227,29 @@ bool IsTransferDomainEnabled(const int height, const CCustomCSView &view, const return attributes->GetValue(enabledKey, false); } +ResVal XVM::TryFrom(const CScript &scriptPubKey) { + opcodetype opcode; + auto pc = scriptPubKey.begin(); + if (!scriptPubKey.GetOp(pc, opcode) || opcode != OP_RETURN) { + return Res::Err("Coinbase output does not contain OP_RETURN as expected"); + } + + std::vector metadata; + if (!scriptPubKey.GetOp(pc, opcode, metadata) + || (opcode > OP_PUSHDATA1 && opcode != OP_PUSHDATA2 && opcode != OP_PUSHDATA4)) { + return Res::Err("Coinbase OP_RETURN output missing push data"); + } + + XVM obj; + try { + CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION); + ss >> obj; + } catch (...) { + return Res::Err("Failed to deserialize coinbase output"); + } + return { obj, Res::Ok() }; +} + OpReturnLimits OpReturnLimits::Default() { return OpReturnLimits { diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index 1e831fb155..fc91f43c25 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -51,6 +51,8 @@ struct XVM { READWRITE(version); READWRITE(evm); } + + static ResVal TryFrom(const CScript &scriptPubKey); }; class CCustomTxVisitor { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index eb27b160d7..37208dab9d 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2380,29 +2380,13 @@ static void RevertFailedTransferDomainTxs(const std::vector &failed static Res ValidateCoinbaseXVMOutput(const CScript &scriptPubKey, const FinalizeBlockCompletion &blockResult) { const auto coinbaseBlockHash = uint256(std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end())); - - // Mine does not add output on null block + // Miner does not add output on null block if (coinbaseBlockHash.IsNull()) return Res::Ok(); - opcodetype opcode; - auto pc = scriptPubKey.begin(); - if (!scriptPubKey.GetOp(pc, opcode) || opcode != OP_RETURN) { - return Res::Err("Coinbase output does not contain OP_RETURN as expected"); - } - - std::vector metadata; - if (!scriptPubKey.GetOp(pc, opcode, metadata) - || (opcode > OP_PUSHDATA1 && opcode != OP_PUSHDATA2 && opcode != OP_PUSHDATA4)) { - return Res::Err("Coinbase OP_RETURN output missing push data"); - } - - XVM obj; - try { - CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION); - ss >> obj; - } catch (...) { - return Res::Err("Failed to deserialize coinbase output"); - } + auto res = XVM::TryFrom(scriptPubKey); + if (!res.ok) return res; + + auto obj = *res; if (obj.evm.blockHash != coinbaseBlockHash) { return Res::Err("Incorrect EVM block hash in coinbase output"); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d2cf15117e..5cac9dfdcc 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -271,9 +271,36 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn AssertLockNotHeld(cs_main); // For performance reasons const auto consensus = Params().GetConsensus(); - auto txVmInfo = [](const CTransaction& tx) -> std::optional { + auto coinbaseXVMToUniValue = [](XVM &obj) { + UniValue result(UniValue::VOBJ); + result.pushKV("version", static_cast(obj.version)); + UniValue evm(UniValue::VOBJ); + evm.pushKV("version", static_cast(obj.evm.version)); + evm.pushKV("blockHash", "0x" + obj.evm.blockHash.GetHex()); + evm.pushKV("priorityFee", obj.evm.priorityFee); + evm.pushKV("burntFee", obj.evm.burntFee); + result.pushKV("evm", evm); + return result; + }; + + auto txVmInfo = [&coinbaseXVMToUniValue](const CTransaction& tx) -> std::optional { CustomTxType guess; UniValue txResults(UniValue::VOBJ); + if (tx.IsCoinBase()) { + if (tx.vout.size() < 2) { + // TODO: Decode vout 0 to dvm + return {}; + } + auto tx1ScriptPubKey = tx.vout[1].scriptPubKey; + if (tx1ScriptPubKey.size() == 0) return {}; + auto res = XVM::TryFrom(tx1ScriptPubKey); + if (!res) return {}; + UniValue result(UniValue::VOBJ); + result.pushKV("vmtype", "coinbase"); + result.pushKV("txtype", "coinbase"); + result.pushKV("msg", coinbaseXVMToUniValue(*res)); + return result; + } auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); if (guess == CustomTxType::None) { return {}; @@ -295,7 +322,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn { if (txDetails) { UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, true, RPCSerializationFlags()); + TxToUniv(*tx, uint256(), objTx, false, RPCSerializationFlags()); if (v2) { if (auto r = txVmInfo(*tx); r) { objTx.pushKV("vm", *r); From ef4212091a842178ffe4b93d7dc039257e0a2288 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 06:20:47 +0800 Subject: [PATCH 08/17] Multi-layered verbosity --- src/rpc/blockchain.cpp | 24 +++++++++++++----------- src/rpc/blockchain.h | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 5cac9dfdcc..c96efbecdc 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -265,7 +265,7 @@ struct RewardInfo { } }; -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, bool v2) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int verbosity) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons @@ -316,14 +316,14 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return result; }; - auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, bool v2) { + auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, int verbosity) { UniValue txs(UniValue::VARR); for(const auto& tx : block.vtx) { if (txDetails) { UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, false, RPCSerializationFlags()); - if (v2) { + TxToUniv(*tx, uint256(), objTx, verbosity > 3, RPCSerializationFlags()); + if (verbosity > 2) { if (auto r = txVmInfo(*tx); r) { objTx.pushKV("vm", *r); } @@ -336,6 +336,8 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return txs; }; + auto v3plus = verbosity > 2; + UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); const CBlockIndex* pnext; @@ -346,9 +348,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("weight", (int)::GetBlockWeight(block)); result.pushKV("height", blockindex->nHeight); - // For v2, we fix the past mistakes and don't just modify existing root schema. + // For v3+, we fix the past mistakes and don't just modify existing root schema. // We'll add all these later. - if (!v2) { + if (!v3plus) { auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); if (minterInfo) { minterInfo->ToUniValueLegacy(result); } } @@ -357,10 +359,10 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn result.pushKV("versionHex", strprintf("%08x", block.nVersion)); result.pushKV("merkleroot", block.hashMerkleRoot.GetHex()); - if (!v2) { + if (!v3plus) { auto rewardInfo = RewardInfo::TryFrom(block, blockindex, consensus); if (rewardInfo) { rewardInfo->ToUniValueLegacy(result); } - result.pushKV("tx", txsToUniValue(block, txDetails, v2)); + result.pushKV("tx", txsToUniValue(block, txDetails, verbosity)); } result.pushKV("time", block.GetBlockTime()); result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast()); @@ -374,7 +376,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (pnext) result.pushKV("nextblockhash", pnext->GetBlockHash().GetHex()); - if (v2) { + if (v3plus) { auto minterInfo = MinterInfo::TryFrom(block, blockindex, *pcustomcsview); if (minterInfo) { result.pushKV("minter", minterInfo->ToUniValue()); @@ -383,7 +385,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (rewardInfo) { result.pushKV("rewards", rewardInfo->ToUniValue()); } - result.pushKV("tx", txsToUniValue(block, txDetails, v2)); + result.pushKV("tx", txsToUniValue(block, txDetails, verbosity)); } return result; @@ -1139,7 +1141,7 @@ static UniValue getblock(const JSONRPCRequest& request) return strHex; } - return blockToJSON(block, tip, pblockindex, verbosity >= 2, verbosity >= 3); + return blockToJSON(block, tip, pblockindex, verbosity >= 2, verbosity); } static UniValue pruneblockchain(const JSONRPCRequest& request) diff --git a/src/rpc/blockchain.h b/src/rpc/blockchain.h index b744e45300..4cc8de4d1b 100644 --- a/src/rpc/blockchain.h +++ b/src/rpc/blockchain.h @@ -32,7 +32,7 @@ double GetDifficulty(const CBlockIndex* blockindex); void RPCNotifyBlockChange(bool ibd, const CBlockIndex *); /** Block description to JSON */ -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, bool v2 = false) LOCKS_EXCLUDED(cs_main); +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails = false, int verbosity = 0) LOCKS_EXCLUDED(cs_main); /** Mempool information to JSON */ UniValue MempoolInfoToJSON(const CTxMemPool& pool); From b93b71d89f90de28dcd7af052feb3f9f1f0fbe3c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 07:33:15 +0800 Subject: [PATCH 09/17] Refine ToUniValue methods --- src/masternodes/mn_checks.cpp | 22 +++++++++++++++++++--- src/masternodes/mn_checks.h | 4 ++++ src/rpc/blockchain.cpp | 24 ++++++------------------ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 4cd47210ca..b968830c37 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -5227,17 +5227,33 @@ bool IsTransferDomainEnabled(const int height, const CCustomCSView &view, const return attributes->GetValue(enabledKey, false); } +UniValue EVM::ToUniValue() const { + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", static_cast(version)); + obj.pushKV("blockHash", "0x" + blockHash.GetHex()); + obj.pushKV("burntFee", burntFee); + obj.pushKV("priorityFee", priorityFee); + return obj; +} + +UniValue XVM::ToUniValue() const { + UniValue obj(UniValue::VOBJ); + obj.pushKV("version", static_cast(version)); + obj.pushKV("evm", evm.ToUniValue()); + return obj; +} + ResVal XVM::TryFrom(const CScript &scriptPubKey) { opcodetype opcode; auto pc = scriptPubKey.begin(); if (!scriptPubKey.GetOp(pc, opcode) || opcode != OP_RETURN) { - return Res::Err("Coinbase output does not contain OP_RETURN as expected"); + return Res::Err("Coinbase XVM: OP_RETURN expected"); } std::vector metadata; if (!scriptPubKey.GetOp(pc, opcode, metadata) || (opcode > OP_PUSHDATA1 && opcode != OP_PUSHDATA2 && opcode != OP_PUSHDATA4)) { - return Res::Err("Coinbase OP_RETURN output missing push data"); + return Res::Err("Coinbase XVM: OP_PUSHDATA expected"); } XVM obj; @@ -5245,7 +5261,7 @@ ResVal XVM::TryFrom(const CScript &scriptPubKey) { CDataStream ss(metadata, SER_NETWORK, PROTOCOL_VERSION); ss >> obj; } catch (...) { - return Res::Err("Failed to deserialize coinbase output"); + return Res::Err("Coinbase XVM: Deserialization failed"); } return { obj, Res::Ok() }; } diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index fc91f43c25..bfa6ff2f90 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -37,6 +37,8 @@ struct EVM { READWRITE(burntFee); READWRITE(priorityFee); } + + UniValue ToUniValue() const; }; struct XVM { @@ -53,6 +55,8 @@ struct XVM { } static ResVal TryFrom(const CScript &scriptPubKey); + UniValue ToUniValue() const; + }; class CCustomTxVisitor { diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index c96efbecdc..d526d6297e 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -142,7 +142,7 @@ struct MinterInfo { return result; } - void ToUniValueLegacy(UniValue& result) { + void ToUniValueLegacy(UniValue& result) const { // Note: This follows legacy way of empty checks and prints to preserve // compatibility. Don't change it. Use the new method ToUniValue method // for new version. @@ -153,7 +153,7 @@ struct MinterInfo { result.pushKV("stakeModifier", StakeModifier.ToString()); } - UniValue ToUniValue() { + UniValue ToUniValue() const { // Note that this breaks compatibility with the legacy version. // Do not use this with existing RPCs UniValue result(UniValue::VOBJ); @@ -222,7 +222,7 @@ struct RewardInfo { return result; } - void ToUniValueLegacy(UniValue& result) { + void ToUniValueLegacy(UniValue& result) const { // Note: This follows legacy way of empty checks and prints to preserve // compatibility. Don't change it. Use the new method ToUniValue method // for new version. @@ -243,7 +243,7 @@ struct RewardInfo { result.pushKV("nonutxo", rewards); } - UniValue ToUniValue() { + UniValue ToUniValue() const { // Note that this breaks compatibility with the legacy version. // Do not use this with existing RPCs UniValue obj(UniValue::VOBJ); @@ -271,19 +271,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn AssertLockNotHeld(cs_main); // For performance reasons const auto consensus = Params().GetConsensus(); - auto coinbaseXVMToUniValue = [](XVM &obj) { - UniValue result(UniValue::VOBJ); - result.pushKV("version", static_cast(obj.version)); - UniValue evm(UniValue::VOBJ); - evm.pushKV("version", static_cast(obj.evm.version)); - evm.pushKV("blockHash", "0x" + obj.evm.blockHash.GetHex()); - evm.pushKV("priorityFee", obj.evm.priorityFee); - evm.pushKV("burntFee", obj.evm.burntFee); - result.pushKV("evm", evm); - return result; - }; - - auto txVmInfo = [&coinbaseXVMToUniValue](const CTransaction& tx) -> std::optional { + auto txVmInfo = [](const CTransaction& tx) -> std::optional { CustomTxType guess; UniValue txResults(UniValue::VOBJ); if (tx.IsCoinBase()) { @@ -298,7 +286,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn UniValue result(UniValue::VOBJ); result.pushKV("vmtype", "coinbase"); result.pushKV("txtype", "coinbase"); - result.pushKV("msg", coinbaseXVMToUniValue(*res)); + result.pushKV("msg", res->ToUniValue()); return result; } auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); From 8ef58449405b23bdf33f033463c758ec4276c31c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 07:49:27 +0800 Subject: [PATCH 10/17] Reduce noise --- src/masternodes/mn_checks.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index b968830c37..f884706948 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -5300,22 +5300,26 @@ void OpReturnLimits::SetToAttributesIfNotExists(ATTRIBUTES& attrs) const { } Res OpReturnLimits::Validate(const CTransaction& tx, const CustomTxType txType) const { + auto err = [](const std::string area, const int voutIndex) { + return Res::ErrCode(CustomTxErrCodes::Fatal, "OP_RETURN size check: vout[%d] %s failure", voutIndex, area); + }; + // Check core OP_RETURN size on vout[0] if (txType == CustomTxType::EvmTx) { if (!CheckOPReturnSize(tx.vout[0].scriptPubKey, evmSizeBytes)) { - return Res::ErrCode(CustomTxErrCodes::Fatal, "Invalid EVM OP_RETURN data size"); + return err("EVM", 0); } } else if (txType != CustomTxType::None) { if (!CheckOPReturnSize(tx.vout[0].scriptPubKey, dvmSizeBytes)) { - return Res::ErrCode(CustomTxErrCodes::Fatal, "Invalid DVM OP_RETURN data size"); + return err("DVM", 0); } } else if (!CheckOPReturnSize(tx.vout[0].scriptPubKey, coreSizeBytes)) { - return Res::ErrCode(CustomTxErrCodes::Fatal, "Invalid core OP_RETURN data size"); + return err("Core", 0); } // Check core OP_RETURN size on vout[1] and higher outputs for (size_t i{1}; i < tx.vout.size(); ++i) { if (!CheckOPReturnSize(tx.vout[i].scriptPubKey, coreSizeBytes)) { - return Res::ErrCode(CustomTxErrCodes::Fatal, "Invalid core OP_RETURN data size"); + return err("Core", i); } } return Res::Ok(); From f7eb0e717615ac05b63d20950b0e6c033adfe6c6 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 08:28:02 +0800 Subject: [PATCH 11/17] Avoid confusing names for non UTXO rewards --- src/chainparams.cpp | 80 ++++++++++++++++---------------- src/consensus/params.h | 4 +- src/masternodes/rpc_accounts.cpp | 4 +- src/masternodes/validation.cpp | 6 +-- src/miner.cpp | 2 +- src/rpc/blockchain.cpp | 6 +-- src/test/dip1fork_tests.cpp | 4 +- src/validation.cpp | 8 ++-- 8 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index c4878e7b7f..4b1f3f9563 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -207,8 +207,8 @@ class CMainParams : public CChainParams { consensus.props.emergencyPeriod = 8640; consensus.props.feeBurnPct = COIN / 2; - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI of 200 per block (rate normalized to (COIN == 100%)) - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN /10 / 200); // 0.1 DFI of 200 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI of 200 per block (rate normalized to (COIN == 100%)) + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::AnchorReward, COIN /10 / 200); // 0.1 DFI of 200 per block // New coinbase reward distribution consensus.dist.masternode = 3333; // 33.33% @@ -219,12 +219,12 @@ class CMainParams : public CChainParams { consensus.dist.options = 988; // 9.88% consensus.dist.unallocated = 173; // 1.73% - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); + consensus.blockTokenRewards.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); + consensus.blockTokenRewards.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); + consensus.blockTokenRewards.emplace(CommunityAccountType::Loan, consensus.dist.loan); + consensus.blockTokenRewards.emplace(CommunityAccountType::Options, consensus.dist.options); + consensus.blockTokenRewards.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.blockTokenRewards.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); // EVM chain id consensus.evmChainId = 1130; // ETH main chain ID @@ -483,8 +483,8 @@ class CTestNetParams : public CChainParams { consensus.props.feeBurnPct = COIN / 2; - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block // New coinbase reward distribution consensus.dist.masternode = 3333; // 33.33% @@ -495,12 +495,12 @@ class CTestNetParams : public CChainParams { consensus.dist.options = 988; // 9.88% consensus.dist.unallocated = 173; // 1.73% - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); + consensus.blockTokenRewards.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); + consensus.blockTokenRewards.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); + consensus.blockTokenRewards.emplace(CommunityAccountType::Loan, consensus.dist.loan); + consensus.blockTokenRewards.emplace(CommunityAccountType::Options, consensus.dist.options); + consensus.blockTokenRewards.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.blockTokenRewards.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); // EVM chain id consensus.evmChainId = 1131; // test chain ID @@ -698,8 +698,8 @@ class CChangiParams : public CChainParams { consensus.props.emergencyPeriod = 8640; consensus.props.feeBurnPct = COIN / 2; - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block // New coinbase reward distribution consensus.dist.masternode = 3333; // 33.33% @@ -710,12 +710,12 @@ class CChangiParams : public CChainParams { consensus.dist.options = 988; // 9.88% consensus.dist.unallocated = 173; // 1.73% - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); + consensus.blockTokenRewards.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); + consensus.blockTokenRewards.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); + consensus.blockTokenRewards.emplace(CommunityAccountType::Loan, consensus.dist.loan); + consensus.blockTokenRewards.emplace(CommunityAccountType::Options, consensus.dist.options); + consensus.blockTokenRewards.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.blockTokenRewards.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); // EVM chain id consensus.evmChainId = 1133; // changi chain ID @@ -914,8 +914,8 @@ class CDevNetParams : public CChainParams { consensus.props.emergencyPeriod = 8640; consensus.props.feeBurnPct = COIN / 2; - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::IncentiveFunding, 45 * COIN / 200); // 45 DFI @ 200 per block (rate normalized to (COIN == 100%)) + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::AnchorReward, COIN/10 / 200); // 0.1 DFI @ 200 per block // New coinbase reward distribution consensus.dist.masternode = 3333; // 33.33% @@ -926,12 +926,12 @@ class CDevNetParams : public CChainParams { consensus.dist.options = 988; // 9.88% consensus.dist.unallocated = 173; // 1.73% - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); + consensus.blockTokenRewards.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); + consensus.blockTokenRewards.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); + consensus.blockTokenRewards.emplace(CommunityAccountType::Loan, consensus.dist.loan); + consensus.blockTokenRewards.emplace(CommunityAccountType::Options, consensus.dist.options); + consensus.blockTokenRewards.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.blockTokenRewards.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); // EVM chain id consensus.evmChainId = 1132; // dev chain ID @@ -1133,8 +1133,8 @@ class CRegTestParams : public CChainParams { consensus.vaultCreationFee = 1 * COIN; - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::IncentiveFunding, 10 * COIN / 50); // normalized to (COIN == 100%) // 10 per block - consensus.nonUtxoBlockSubsidies.emplace(CommunityAccountType::AnchorReward, COIN/10 / 50); // 0.1 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::IncentiveFunding, 10 * COIN / 50); // normalized to (COIN == 100%) // 10 per block + consensus.blockTokenRewardsLegacy.emplace(CommunityAccountType::AnchorReward, COIN/10 / 50); // 0.1 per block // New coinbase reward distribution consensus.dist.masternode = 3333; // 33.33% @@ -1145,12 +1145,12 @@ class CRegTestParams : public CChainParams { consensus.dist.options = 988; // 9.88% consensus.dist.unallocated = 173; // 1.73% - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Loan, consensus.dist.loan); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Options, consensus.dist.options); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); - consensus.newNonUTXOSubsidies.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); + consensus.blockTokenRewards.emplace(CommunityAccountType::AnchorReward, consensus.dist.anchor); + consensus.blockTokenRewards.emplace(CommunityAccountType::IncentiveFunding, consensus.dist.liquidity); + consensus.blockTokenRewards.emplace(CommunityAccountType::Loan, consensus.dist.loan); + consensus.blockTokenRewards.emplace(CommunityAccountType::Options, consensus.dist.options); + consensus.blockTokenRewards.emplace(CommunityAccountType::Unallocated, consensus.dist.unallocated); + consensus.blockTokenRewards.emplace(CommunityAccountType::CommunityDevFunds, consensus.dist.community); // EVM chain id consensus.evmChainId = 1133; // regtest chain ID diff --git a/src/consensus/params.h b/src/consensus/params.h index 5b21801430..f5393789e3 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -221,8 +221,8 @@ struct Params { }; CProposalParams props; - std::map nonUtxoBlockSubsidies; - std::map newNonUTXOSubsidies; + std::map blockTokenRewardsLegacy; + std::map blockTokenRewards; uint64_t evmChainId; }; diff --git a/src/masternodes/rpc_accounts.cpp b/src/masternodes/rpc_accounts.cpp index e24366a8b3..b51efeb4f3 100644 --- a/src/masternodes/rpc_accounts.cpp +++ b/src/masternodes/rpc_accounts.cpp @@ -1830,7 +1830,7 @@ UniValue listcommunitybalances(const JSONRPCRequest& request) { LOCK(cs_main); CAmount burnt{0}; - for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) + for (const auto& kv : Params().GetConsensus().blockTokenRewards) { // Skip these as any unused balance will be burnt. if (kv.first == CommunityAccountType::Options) { @@ -2218,7 +2218,7 @@ UniValue getburninfo(const JSONRPCRequest& request) { dfiToDUSDTokens = attributes->GetValue(liveKey, CBalances{}); } - for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) { + for (const auto& kv : Params().GetConsensus().blockTokenRewards) { if (kv.first == CommunityAccountType::Unallocated || kv.first == CommunityAccountType::IncentiveFunding || (height >= fortCanningHeight && kv.first == CommunityAccountType::Loan)) { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 37208dab9d..026641a392 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -25,7 +25,7 @@ template static void UpdateDailyGovVariables(const std::map::const_iterator& incentivePair, CCustomCSView& cache, int nHeight) { - if (incentivePair != Params().GetConsensus().newNonUTXOSubsidies.end()) + if (incentivePair != Params().GetConsensus().blockTokenRewards.end()) { CAmount subsidy = CalculateCoinbaseReward(GetBlockSubsidy(nHeight, Params().GetConsensus()), incentivePair->second); subsidy *= Params().GetConsensus().blocksPerDay(); @@ -48,14 +48,14 @@ static void ProcessRewardEvents(const CBlockIndex* pindex, CCustomCSView& cache, // Hard coded LP_DAILY_DFI_REWARD change if (pindex->nHeight >= chainparams.GetConsensus().EunosHeight) { - const auto& incentivePair = chainparams.GetConsensus().newNonUTXOSubsidies.find(CommunityAccountType::IncentiveFunding); + const auto& incentivePair = chainparams.GetConsensus().blockTokenRewards.find(CommunityAccountType::IncentiveFunding); UpdateDailyGovVariables(incentivePair, cache, pindex->nHeight); } // Hard coded LP_DAILY_LOAN_TOKEN_REWARD change if (pindex->nHeight >= chainparams.GetConsensus().FortCanningHeight) { - const auto& incentivePair = chainparams.GetConsensus().newNonUTXOSubsidies.find(CommunityAccountType::Loan); + const auto& incentivePair = chainparams.GetConsensus().blockTokenRewards.find(CommunityAccountType::Loan); UpdateDailyGovVariables(incentivePair, cache, pindex->nHeight); } diff --git a/src/miner.cpp b/src/miner.cpp index bc67a4f3d6..0677a53693 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -407,7 +407,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc __func__, blockReward, coinbaseTx.vout[0].nValue, foundationValue); } else if (nHeight >= consensus.AMKHeight) { // assume community non-utxo funding: - for (const auto& kv : consensus.nonUtxoBlockSubsidies) { + for (const auto& kv : consensus.blockTokenRewardsLegacy) { coinbaseTx.vout[0].nValue -= blockReward * kv.second / COIN; } // Pinch off foundation share diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d526d6297e..6cee53f010 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -190,11 +190,11 @@ struct RewardInfo { result.BlockReward = blockReward; if (blockindex->nHeight < consensus.EunosHeight) { - for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) + for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * accountVal / COIN; switch (accountType) { - // CommunityDevFunds, Loan, Options don't exist in nonUtxoBlockSubsidies here + // CommunityDevFunds, Loan, Options don't exist in blockTokenRewardsLegacy here case CommunityAccountType::AnchorReward:{ tokenRewards.AnchorReward = subsidy; break; } case CommunityAccountType::IncentiveFunding: { tokenRewards.IncentiveFunding = subsidy; break; } default: { tokenRewards.Burnt += subsidy; } @@ -203,7 +203,7 @@ struct RewardInfo { return result; } - for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) + for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { if (blockindex->nHeight < consensus.GrandCentralHeight && accountType == CommunityAccountType::CommunityDevFunds) { diff --git a/src/test/dip1fork_tests.cpp b/src/test/dip1fork_tests.cpp index 00cb1d2f76..ba1fed6342 100644 --- a/src/test/dip1fork_tests.cpp +++ b/src/test/dip1fork_tests.cpp @@ -70,8 +70,8 @@ BOOST_AUTO_TEST_CASE(blockreward_dfip1) CAmount const baseSubsidy = GetBlockSubsidy(height, consensus); tx.vout[1].nValue = baseSubsidy * consensus.foundationShareDFIP1 / COIN; tx.vout[0].nValue -= tx.vout[1].nValue; - tx.vout[0].nValue -= baseSubsidy * consensus.nonUtxoBlockSubsidies.at(CommunityAccountType::IncentiveFunding) / COIN; - tx.vout[0].nValue -= baseSubsidy * consensus.nonUtxoBlockSubsidies.at(CommunityAccountType::AnchorReward) / COIN; + tx.vout[0].nValue -= baseSubsidy * consensus.blockTokenRewardsLegacy.at(CommunityAccountType::IncentiveFunding) / COIN; + tx.vout[0].nValue -= baseSubsidy * consensus.blockTokenRewardsLegacy.at(CommunityAccountType::AnchorReward) / COIN; Res res = ApplyGeneralCoinbaseTx(mnview, CTransaction(tx), height, 0, consensus); BOOST_CHECK(res.ok); diff --git a/src/validation.cpp b/src/validation.cpp index eeb365336a..c3fc2fbde7 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2114,7 +2114,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int CAmount nonUtxoTotal = 0; if (height < consensus.EunosHeight) { - for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) { + for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * accountVal / COIN; Res res = mnview.AddCommunityBalance(accountType, subsidy); if (!res.ok) { @@ -2129,7 +2129,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int } CAmount subsidy; - for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) { + for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { if (accountType == CommunityAccountType::CommunityDevFunds) { if (height < consensus.GrandCentralHeight) { continue; @@ -2213,14 +2213,14 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensu // TODO(legacy-cleanup): Use proper structures if (height < consensus.EunosHeight) { - for (const auto& [accountType, accountVal] : consensus.nonUtxoBlockSubsidies) { + for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * accountVal / COIN; mnview.SubCommunityBalance(accountType, subsidy); } return; } - for (const auto& [accountType, accountVal] : consensus.newNonUTXOSubsidies) { + for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { if (accountType == CommunityAccountType::CommunityDevFunds) { if (height < consensus.GrandCentralHeight) { continue; From 0fbe762695150e03fa61d8b7d2b3faf9cfa717d1 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 08:46:36 +0800 Subject: [PATCH 12/17] Further cleanups --- src/validation.cpp | 181 +++++++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 82 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index c3fc2fbde7..6b30fed1cf 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2046,6 +2046,9 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int height, CAmount nFees, const Consensus::Params& consensus) { + // TODO(legacy-cleanup): Clean up the rest of the method with proper structures + // and a more comprehensible flow + TAmounts const cbValues = tx.GetValuesOut(); CAmount blockReward = GetBlockSubsidy(height, consensus); if (cbValues.size() != 1 || cbValues.begin()->first != DCT_ID{0}) @@ -2074,49 +2077,43 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int return attrs.GetValue(k, false); }; - if (height < consensus.AMKHeight) { - return finalCheckAndReturn(); - } - - // TODO(legacy-cleanup): Clean up the rest of the method with proper structures - // and a more comprehensible flow - - CAmount foundationReward{0}; - if (height >= consensus.GrandCentralHeight) { - // no foundation utxo reward check anymore - } - else if (height >= consensus.EunosHeight) { - foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); - } - else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { - foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; - } + auto tryVerifyUtxoRewards = [](CTransaction const & tx, const CAmount blockReward, int height, const Consensus::Params& consensus) { + CAmount foundationReward{0}; + if (height >= consensus.GrandCentralHeight) { + // no foundation utxo reward check anymore + } + else if (height >= consensus.EunosHeight) { + foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); + } + else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { + foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; + } - if (foundationReward) { - bool foundationsRewardfound = false; - for (auto& txout : tx.vout) { - if (txout.scriptPubKey == consensus.foundationShareScript) { - if (txout.nValue < foundationReward) { - return Res::ErrDbg("bad-cb-foundation-reward", - "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); + if (foundationReward) { + bool foundationsRewardfound = false; + for (auto& txout : tx.vout) { + if (txout.scriptPubKey == consensus.foundationShareScript) { + if (txout.nValue < foundationReward) { + return Res::ErrDbg("bad-cb-foundation-reward", + "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); + } + foundationsRewardfound = true; + break; } - foundationsRewardfound = true; - break; } - } - if (!foundationsRewardfound) { - return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay foundation reward!"); + if (!foundationsRewardfound) { + return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay foundation reward!"); + } } - } - - // count and subtract for non-UTXO community rewards - CAmount nonUtxoTotal = 0; + return Res::Ok(); + }; - if (height < consensus.EunosHeight) { + auto handleLegacyTokenRewards = [&finalCheckAndReturn, &logAccountChange](CTransaction const & tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus) { + CAmount nonUtxoTotal = 0; for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * accountVal / COIN; - Res res = mnview.AddCommunityBalance(accountType, subsidy); + Res res = view.AddCommunityBalance(accountType, subsidy); if (!res.ok) { return Res::ErrDbg("bad-cb-community-rewards", "can't take non-UTXO community share from coinbase"); } else { @@ -2126,69 +2123,89 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int } blockReward -= nonUtxoTotal; return finalCheckAndReturn(); - } + }; - CAmount subsidy; - for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (height < consensus.GrandCentralHeight) { - continue; + auto handleCurrentTokenRewards = [&finalCheckAndReturn, &logAccountChange, &isGovernanceEnabled, &isUnusedEmissionFundEnabled](CTransaction const & tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus, int height) { + CAmount nonUtxoTotal = 0; + CAmount subsidy; + + for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { + if (accountType == CommunityAccountType::CommunityDevFunds) { + if (height < consensus.GrandCentralHeight) { + continue; + } } - } - subsidy = CalculateCoinbaseReward(blockReward, accountVal); - Res res = Res::Ok(); + subsidy = CalculateCoinbaseReward(blockReward, accountVal); + Res res = Res::Ok(); - // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. - if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || - (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { - res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) { - logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); - } - } else { - if (height >= consensus.GrandCentralHeight) { - const auto attributes = mnview.GetAttributes(); - assert(attributes); - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (!isGovernanceEnabled(*attributes)) { - continue; - } else { - res = mnview.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); - // TODO: Result check missed; check full sync and add checks - logAccountChange(tx, subsidy, ScriptToString(consensus.foundationShareScript)); + // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. + if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || + (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { + res = view.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) { + logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); + } + } else { + if (height >= consensus.GrandCentralHeight) { + const auto attributes = view.GetAttributes(); + assert(attributes); + if (accountType == CommunityAccountType::CommunityDevFunds) { + if (!isGovernanceEnabled(*attributes)) { + continue; + } else { + res = view.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); + // TODO: Result check missed; check full sync and add checks + logAccountChange(tx, subsidy, ScriptToString(consensus.foundationShareScript)); + nonUtxoTotal += subsidy; + continue; + } + } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { + if (isUnusedEmissionFundEnabled(*attributes)) { + res = view.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); + if (res) { logAccountChange(tx, subsidy, ScriptToString(consensus.unusedEmission)); } + } else { + // Previous behaviour was for Options and Unallocated to go to Unallocated + res = view.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) { logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); } + } nonUtxoTotal += subsidy; continue; } - } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { - if (isUnusedEmissionFundEnabled(*attributes)) { - res = mnview.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); - if (res) { logAccountChange(tx, subsidy, ScriptToString(consensus.unusedEmission)); } - } else { - // Previous behaviour was for Options and Unallocated to go to Unallocated - res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) { logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); } - } - nonUtxoTotal += subsidy; - continue; + } + + res = view.AddCommunityBalance(accountType, subsidy); + if (res) { + logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); } } - res = mnview.AddCommunityBalance(accountType, subsidy); - if (res) { - logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); + if (!res.ok) { + return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); } - } - if (!res.ok) { - return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); + nonUtxoTotal += subsidy; } - nonUtxoTotal += subsidy; + blockReward -= nonUtxoTotal; + return finalCheckAndReturn(); + }; + + // Actual logic starts here + + if (height < consensus.AMKHeight) { + return finalCheckAndReturn(); + } + + if (auto r = tryVerifyUtxoRewards(tx, blockReward, height, consensus); !r) { + return r; + } + + if (height < consensus.EunosHeight) { + return handleLegacyTokenRewards(tx, blockReward, mnview, consensus); } - blockReward -= nonUtxoTotal; - return finalCheckAndReturn(); + return handleCurrentTokenRewards(tx, blockReward, mnview, consensus, height); } From fafe2f17be7db86bbebc91346f5bd9bb63c820c3 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 08:52:58 +0800 Subject: [PATCH 13/17] Minor format cleanup --- src/validation.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 6b30fed1cf..eaeb5a2b31 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2077,15 +2077,13 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int return attrs.GetValue(k, false); }; - auto tryVerifyUtxoRewards = [](CTransaction const & tx, const CAmount blockReward, int height, const Consensus::Params& consensus) { + auto tryVerifyUtxoRewards = [](const CTransaction& tx, const CAmount blockReward, int height, const Consensus::Params& consensus) { CAmount foundationReward{0}; if (height >= consensus.GrandCentralHeight) { // no foundation utxo reward check anymore - } - else if (height >= consensus.EunosHeight) { + } else if (height >= consensus.EunosHeight) { foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); - } - else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { + } else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; } @@ -2109,7 +2107,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int return Res::Ok(); }; - auto handleLegacyTokenRewards = [&finalCheckAndReturn, &logAccountChange](CTransaction const & tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus) { + auto handleLegacyTokenRewards = [&finalCheckAndReturn, &logAccountChange](const CTransaction& tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus) { CAmount nonUtxoTotal = 0; for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * accountVal / COIN; @@ -2125,7 +2123,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int return finalCheckAndReturn(); }; - auto handleCurrentTokenRewards = [&finalCheckAndReturn, &logAccountChange, &isGovernanceEnabled, &isUnusedEmissionFundEnabled](CTransaction const & tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus, int height) { + auto handleCurrentTokenRewards = [&finalCheckAndReturn, &logAccountChange, &isGovernanceEnabled, &isUnusedEmissionFundEnabled](const CTransaction& tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus, int height) { CAmount nonUtxoTotal = 0; CAmount subsidy; From 4afec3f6c33c398d71b84f48efcf1a0add833430 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 09:08:00 +0800 Subject: [PATCH 14/17] Use version terminology --- src/core_io.h | 2 +- src/core_write.cpp | 19 ++++++++++--------- src/rpc/blockchain.cpp | 18 ++++++++++-------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/core_io.h b/src/core_io.h index f0cd289bc4..0bcae456c8 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -46,6 +46,6 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags = 0); std::string SighashToStr(unsigned char sighash_type); void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); void ScriptToUniv(const CScript& script, UniValue& out, bool include_address); -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0); +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex = true, int serialize_flags = 0, int verbosity = 0); #endif // DEFI_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index abf0ab59ce..dd934d26e9 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -183,9 +183,9 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, out.pushKV("addresses", a); } -void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags) +void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, bool include_hex, int serialize_flags, int version) { - const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int txindex, bool include_hex) { + const auto txInToUniValue = [](const CTransaction& tx, const CTxIn& txin, const unsigned int index, bool include_hex) { UniValue in(UniValue::VOBJ); if (tx.IsCoinBase()) in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); @@ -198,9 +198,9 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); } in.pushKV("scriptSig", o); - if (!tx.vin[txindex].scriptWitness.IsNull()) { + if (!tx.vin[index].scriptWitness.IsNull()) { UniValue txinwitness(UniValue::VARR); - for (const auto& item : tx.vin[txindex].scriptWitness.stack) { + for (const auto& item : tx.vin[index].scriptWitness.stack) { txinwitness.push_back(HexStr(item.begin(), item.end())); } in.pushKV("txinwitness", txinwitness); @@ -210,15 +210,16 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, return in; }; - const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int txindex, bool include_hex) { + const auto txOutToUniValue = [](const CTransaction& tx, const CTxOut& txout, const unsigned int index, bool include_hex, int version) { UniValue out(UniValue::VOBJ); out.pushKV("value", ValueFromAmount(txout.nValue)); - out.pushKV("n", (int64_t)txindex); + out.pushKV("n", (int64_t)index); UniValue o(UniValue::VOBJ); ScriptPubKeyToUniv(txout.scriptPubKey, o, include_hex); out.pushKV("scriptPubKey", o); - // Start to print tokenId start from version TOKENS_MIN_VERSION - if (tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { + // We skip this for v3+ as we tokenId field is unused. + if (version <= 2 && tx.nVersion >= CTransaction::TOKENS_MIN_VERSION) { + // Start to print tokenId start from version TOKENS_MIN_VERSION out.pushKV("tokenId", (uint64_t)txout.nTokenId.v); } return out; @@ -240,7 +241,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry, UniValue vout(UniValue::VARR); for (unsigned int i = 0; i < tx.vout.size(); i++) { - vout.push_back(txOutToUniValue(tx, tx.vout[i], i, include_hex)); + vout.push_back(txOutToUniValue(tx, tx.vout[i], i, include_hex, version)); } entry.pushKV("vout", vout); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 6cee53f010..e7159b43e3 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -265,7 +265,7 @@ struct RewardInfo { } }; -UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int verbosity) +UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIndex* blockindex, bool txDetails, int version) { // Serialize passed information without accessing chain state of the active chain! AssertLockNotHeld(cs_main); // For performance reasons @@ -304,14 +304,14 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return result; }; - auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, int verbosity) { + auto txsToUniValue = [&txVmInfo](const CBlock& block, bool txDetails, int version) { UniValue txs(UniValue::VARR); for(const auto& tx : block.vtx) { if (txDetails) { UniValue objTx(UniValue::VOBJ); - TxToUniv(*tx, uint256(), objTx, verbosity > 3, RPCSerializationFlags()); - if (verbosity > 2) { + TxToUniv(*tx, uint256(), objTx, version > 3, RPCSerializationFlags(), version); + if (version > 2) { if (auto r = txVmInfo(*tx); r) { objTx.pushKV("vm", *r); } @@ -324,7 +324,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return txs; }; - auto v3plus = verbosity > 2; + auto v3plus = version > 2; UniValue result(UniValue::VOBJ); result.pushKV("hash", blockindex->GetBlockHash().GetHex()); @@ -350,7 +350,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (!v3plus) { auto rewardInfo = RewardInfo::TryFrom(block, blockindex, consensus); if (rewardInfo) { rewardInfo->ToUniValueLegacy(result); } - result.pushKV("tx", txsToUniValue(block, txDetails, verbosity)); + result.pushKV("tx", txsToUniValue(block, txDetails, version)); } result.pushKV("time", block.GetBlockTime()); result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast()); @@ -373,7 +373,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn if (rewardInfo) { result.pushKV("rewards", rewardInfo->ToUniValue()); } - result.pushKV("tx", txsToUniValue(block, txDetails, verbosity)); + result.pushKV("tx", txsToUniValue(block, txDetails, version)); } return result; @@ -1038,7 +1038,9 @@ static UniValue getblock(const JSONRPCRequest& request) RPCHelpMan{"getblock", "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbosity is 1, returns an Object with information about block .\n" - "If verbosity is 2, returns an Object with information about block and information about each transaction. \n", + "If verbosity is 2, returns an Object with information about block and information about each transaction. \n" + "If verbosity is 3, returns an Object with version 2 API (DVM, EVM, etc). \n" + "If verbosity is 4, returns an Object with version 2 API (DVM, EVM, etc with Hex) \n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, {"verbosity", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"}, From 3d01fa0d4d3b1035d4efd97a11c937eee0825efd Mon Sep 17 00:00:00 2001 From: Bushstar Date: Mon, 7 Aug 2023 07:05:36 +0100 Subject: [PATCH 15/17] Pas blockreward by value --- src/validation.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index eaeb5a2b31..3576201195 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2054,8 +2054,8 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int if (cbValues.size() != 1 || cbValues.begin()->first != DCT_ID{0}) return Res::ErrDbg("bad-cb-wrong-tokens", "coinbase should pay only Defi coins"); - auto finalCheckAndReturn = [&]() { - if (cbValues.at(DCT_ID{0}) > blockReward + nFees) + auto finalCheckAndReturn = [&](const CAmount reward) { + if (cbValues.at(DCT_ID{0}) > reward + nFees) return Res::ErrDbg("bad-cb-amount", "coinbase pays too much (actual=%d vs limit=%d)", cbValues.at(DCT_ID{0}), blockReward + nFees); return Res::Ok(); }; @@ -2120,7 +2120,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int nonUtxoTotal += subsidy; } blockReward -= nonUtxoTotal; - return finalCheckAndReturn(); + return finalCheckAndReturn(blockReward); }; auto handleCurrentTokenRewards = [&finalCheckAndReturn, &logAccountChange, &isGovernanceEnabled, &isUnusedEmissionFundEnabled](const CTransaction& tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus, int height) { @@ -2186,13 +2186,13 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int } blockReward -= nonUtxoTotal; - return finalCheckAndReturn(); + return finalCheckAndReturn(blockReward); }; // Actual logic starts here if (height < consensus.AMKHeight) { - return finalCheckAndReturn(); + return finalCheckAndReturn(blockReward); } if (auto r = tryVerifyUtxoRewards(tx, blockReward, height, consensus); !r) { From cab31e903f2f9eb599a0020ddde76b0c6ba7e147 Mon Sep 17 00:00:00 2001 From: Bushstar Date: Mon, 7 Aug 2023 08:14:54 +0100 Subject: [PATCH 16/17] Restore apply/reverse coinbase behaviour --- src/validation.cpp | 317 ++++++++++++++++++++++----------------------- 1 file changed, 155 insertions(+), 162 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 3576201195..dff65fcef6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2046,228 +2046,221 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int height, CAmount nFees, const Consensus::Params& consensus) { - // TODO(legacy-cleanup): Clean up the rest of the method with proper structures - // and a more comprehensible flow - TAmounts const cbValues = tx.GetValuesOut(); CAmount blockReward = GetBlockSubsidy(height, consensus); if (cbValues.size() != 1 || cbValues.begin()->first != DCT_ID{0}) return Res::ErrDbg("bad-cb-wrong-tokens", "coinbase should pay only Defi coins"); - auto finalCheckAndReturn = [&](const CAmount reward) { - if (cbValues.at(DCT_ID{0}) > reward + nFees) - return Res::ErrDbg("bad-cb-amount", "coinbase pays too much (actual=%d vs limit=%d)", cbValues.at(DCT_ID{0}), blockReward + nFees); - return Res::Ok(); - }; - - auto logAccountChange = [](const CTransaction& tx, const CAmount subsidy, const std::string account) { - LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", - tx.GetHash().ToString(), - account, - (CBalances{{{{0}, subsidy}}}.ToString())); - }; - - auto isUnusedEmissionFundEnabled = [](const ATTRIBUTES& attrs) { - CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - return attrs.GetValue(k, false); - }; - - auto isGovernanceEnabled = [](const ATTRIBUTES& attrs) { - CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; - return attrs.GetValue(k, false); - }; - auto tryVerifyUtxoRewards = [](const CTransaction& tx, const CAmount blockReward, int height, const Consensus::Params& consensus) { + if (height >= consensus.AMKHeight) + { CAmount foundationReward{0}; - if (height >= consensus.GrandCentralHeight) { + if (height >= consensus.GrandCentralHeight) + { // no foundation utxo reward check anymore - } else if (height >= consensus.EunosHeight) { + } + else if (height >= consensus.EunosHeight) + { foundationReward = CalculateCoinbaseReward(blockReward, consensus.dist.community); - } else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) { + } + else if (!consensus.foundationShareScript.empty() && consensus.foundationShareDFIP1) + { foundationReward = blockReward * consensus.foundationShareDFIP1 / COIN; } - if (foundationReward) { + if (foundationReward) + { bool foundationsRewardfound = false; - for (auto& txout : tx.vout) { - if (txout.scriptPubKey == consensus.foundationShareScript) { - if (txout.nValue < foundationReward) { - return Res::ErrDbg("bad-cb-foundation-reward", - "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); + for (auto& txout : tx.vout) + { + if (txout.scriptPubKey == consensus.foundationShareScript) + { + if (txout.nValue < foundationReward) + { + return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay proper foundation reward! (actual=%d vs expected=%d", txout.nValue, foundationReward); } + foundationsRewardfound = true; break; } } - if (!foundationsRewardfound) { + if (!foundationsRewardfound) + { return Res::ErrDbg("bad-cb-foundation-reward", "coinbase doesn't pay foundation reward!"); } } - return Res::Ok(); - }; - auto handleLegacyTokenRewards = [&finalCheckAndReturn, &logAccountChange](const CTransaction& tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus) { + // count and subtract for non-UTXO community rewards CAmount nonUtxoTotal = 0; - for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { - CAmount subsidy = blockReward * accountVal / COIN; - Res res = view.AddCommunityBalance(accountType, subsidy); - if (!res.ok) { - return Res::ErrDbg("bad-cb-community-rewards", "can't take non-UTXO community share from coinbase"); - } else { - logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); - } - nonUtxoTotal += subsidy; - } - blockReward -= nonUtxoTotal; - return finalCheckAndReturn(blockReward); - }; + if (height >= consensus.EunosHeight) + { + CAmount subsidy; + for (const auto& kv : consensus.newNonUTXOSubsidies) + { + if (kv.first == CommunityAccountType::CommunityDevFunds) { + if (height < consensus.GrandCentralHeight) { + continue; + } + } - auto handleCurrentTokenRewards = [&finalCheckAndReturn, &logAccountChange, &isGovernanceEnabled, &isUnusedEmissionFundEnabled](const CTransaction& tx, CAmount blockReward, CCustomCSView& view, const Consensus::Params& consensus, int height) { - CAmount nonUtxoTotal = 0; - CAmount subsidy; + subsidy = CalculateCoinbaseReward(blockReward, kv.second); - for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (height < consensus.GrandCentralHeight) { - continue; + Res res = Res::Ok(); + + // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. + if ((height < consensus.FortCanningHeight && kv.first == CommunityAccountType::Loan) || + (height < consensus.GrandCentralHeight && kv.first == CommunityAccountType::Options)) + { + res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(CommunityAccountType::Unallocated), (CBalances{{{{0}, subsidy}}}.ToString())); } - } + else + { + if (height >= consensus.GrandCentralHeight) + { + const auto attributes = mnview.GetAttributes(); + assert(attributes); - subsidy = CalculateCoinbaseReward(blockReward, accountVal); - Res res = Res::Ok(); + if (kv.first == CommunityAccountType::CommunityDevFunds) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; + + if (!attributes->GetValue(enabledKey, false)) + { + res = mnview.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", + tx.GetHash().ToString(), ScriptToString(consensus.foundationShareScript), + (CBalances{{{{0}, subsidy}}}.ToString())); + nonUtxoTotal += subsidy; + + continue; + } + } else if (kv.first == CommunityAccountType::Unallocated || kv.first == CommunityAccountType::Options) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; + + if (attributes->GetValue(enabledKey, false)) { + res = mnview.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); + if (res) { + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", + tx.GetHash().ToString(), ScriptToString(consensus.unusedEmission), + (CBalances{{{{0}, subsidy}}}.ToString())); + } + } else { + // Previous behaviour was for Options and Unallocated to go to Unallocated + res = mnview.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); + if (res) + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(CommunityAccountType::Unallocated), (CBalances{{{{0}, subsidy}}}.ToString())); + } - // Loan below FC and Options are unused and all go to Unallocated (burnt) pot. - if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || - (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { - res = view.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) { - logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); - } - } else { - if (height >= consensus.GrandCentralHeight) { - const auto attributes = view.GetAttributes(); - assert(attributes); - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (!isGovernanceEnabled(*attributes)) { - continue; - } else { - res = view.AddBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); - // TODO: Result check missed; check full sync and add checks - logAccountChange(tx, subsidy, ScriptToString(consensus.foundationShareScript)); nonUtxoTotal += subsidy; + continue; } - } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { - if (isUnusedEmissionFundEnabled(*attributes)) { - res = view.AddBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); - if (res) { logAccountChange(tx, subsidy, ScriptToString(consensus.unusedEmission)); } - } else { - // Previous behaviour was for Options and Unallocated to go to Unallocated - res = view.AddCommunityBalance(CommunityAccountType::Unallocated, subsidy); - if (res) { logAccountChange(tx, subsidy, GetCommunityAccountName(CommunityAccountType::Unallocated)); } - } - nonUtxoTotal += subsidy; - continue; } + + res = mnview.AddCommunityBalance(kv.first, subsidy); + if (res) + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(kv.first), (CBalances{{{{0}, subsidy}}}.ToString())); } - res = view.AddCommunityBalance(accountType, subsidy); - if (res) { - logAccountChange(tx, subsidy, GetCommunityAccountName(accountType)); + if (!res.ok) + { + return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); } - } - if (!res.ok) { - return Res::ErrDbg("bad-cb-community-rewards", "Cannot take non-UTXO community share from coinbase"); + nonUtxoTotal += subsidy; + } + } + else + { + for (const auto& kv : consensus.nonUtxoBlockSubsidies) { + CAmount subsidy = blockReward * kv.second / COIN; + Res res = mnview.AddCommunityBalance(kv.first, subsidy); + if (!res.ok) { + return Res::ErrDbg("bad-cb-community-rewards", "can't take non-UTXO community share from coinbase"); + } else { + LogPrint(BCLog::ACCOUNTCHANGE, "AccountChange: hash=%s fund=%s change=%s\n", tx.GetHash().ToString(), GetCommunityAccountName(kv.first), (CBalances{{{{0}, subsidy}}}.ToString())); + } + nonUtxoTotal += subsidy; } - - nonUtxoTotal += subsidy; } blockReward -= nonUtxoTotal; - return finalCheckAndReturn(blockReward); - }; - - // Actual logic starts here - - if (height < consensus.AMKHeight) { - return finalCheckAndReturn(blockReward); - } - - if (auto r = tryVerifyUtxoRewards(tx, blockReward, height, consensus); !r) { - return r; } - if (height < consensus.EunosHeight) { - return handleLegacyTokenRewards(tx, blockReward, mnview, consensus); - } + // pre-AMK logic, compatible after prev blockReward mod: + if (cbValues.at(DCT_ID{0}) > blockReward + nFees) + return Res::ErrDbg("bad-cb-amount", "coinbase pays too much (actual=%d vs limit=%d)", cbValues.at(DCT_ID{0}), blockReward + nFees); - return handleCurrentTokenRewards(tx, blockReward, mnview, consensus, height); + return Res::Ok(); } void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensus::Params& consensus) { - CAmount blockReward = GetBlockSubsidy(height, consensus); - - auto isUnusedEmissionFundEnabled = [](const ATTRIBUTES& attrs) { - CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - return attrs.GetValue(k, false); - }; + CAmount blockReward = GetBlockSubsidy(height, Params().GetConsensus()); - auto isGovernanceEnabled = [](const ATTRIBUTES& attrs) { - CDataStructureV0 k{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; - return attrs.GetValue(k, false); - }; + if (height >= Params().GetConsensus().AMKHeight) + { + if (height >= Params().GetConsensus().EunosHeight) + { + for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) + { + if (kv.first == CommunityAccountType::CommunityDevFunds) { + if (height < Params().GetConsensus().GrandCentralHeight) { + continue; + } + } - if (height < consensus.AMKHeight) { - return; - } + CAmount subsidy = CalculateCoinbaseReward(blockReward, kv.second); - // TODO(legacy-cleanup): Use proper structures + // Remove Loan and Options balances from Unallocated + if ((height < Params().GetConsensus().FortCanningHeight && kv.first == CommunityAccountType::Loan) || + (height < consensus.GrandCentralHeight && kv.first == CommunityAccountType::Options)) + { + mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); + } + else + { + if (height >= consensus.GrandCentralHeight) + { + const auto attributes = mnview.GetAttributes(); + assert(attributes); - if (height < consensus.EunosHeight) { - for (const auto& [accountType, accountVal] : consensus.blockTokenRewardsLegacy) { - CAmount subsidy = blockReward * accountVal / COIN; - mnview.SubCommunityBalance(accountType, subsidy); - } - return; - } + if (kv.first == CommunityAccountType::CommunityDevFunds) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::GovernanceEnabled}; - for (const auto& [accountType, accountVal] : consensus.blockTokenRewards) { - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (height < consensus.GrandCentralHeight) { - continue; - } - } + if (!attributes->GetValue(enabledKey, false)) + { + mnview.SubBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); - CAmount subsidy = CalculateCoinbaseReward(blockReward, accountVal); + continue; + } + } else if (kv.first == CommunityAccountType::Unallocated || kv.first == CommunityAccountType::Options) { + CDataStructureV0 enabledKey{AttributeTypes::Param, ParamIDs::Feature, DFIPKeys::EmissionUnusedFund}; - // Remove Loan and Options balances from Unallocated - if ((height < consensus.FortCanningHeight && accountType == CommunityAccountType::Loan) || - (height < consensus.GrandCentralHeight && accountType == CommunityAccountType::Options)) { - mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); - } else { - if (height >= consensus.GrandCentralHeight) { - const auto attributes = mnview.GetAttributes(); - assert(attributes); + if (attributes->GetValue(enabledKey, false)) { + mnview.SubBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); + } else { + mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); + } - if (accountType == CommunityAccountType::CommunityDevFunds) { - if (!isGovernanceEnabled(*attributes)) { - mnview.SubBalance(consensus.foundationShareScript, {DCT_ID{0}, subsidy}); - continue; - } - } else if (accountType == CommunityAccountType::Unallocated || accountType == CommunityAccountType::Options) { - if (isUnusedEmissionFundEnabled(*attributes)) { - mnview.SubBalance(consensus.unusedEmission, {DCT_ID{0}, subsidy}); - } else { - mnview.SubCommunityBalance(CommunityAccountType::Unallocated, subsidy); + continue; + } } - continue; + + mnview.SubCommunityBalance(kv.first, subsidy); } } - mnview.SubCommunityBalance(accountType, subsidy); + } + else + { + for (const auto& kv : Params().GetConsensus().nonUtxoBlockSubsidies) + { + CAmount subsidy = blockReward * kv.second / COIN; + mnview.SubCommunityBalance(kv.first, subsidy); + } } } } From 69670ceb610e6afdf879d12e1e4f9ec4a77d158a Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 16:08:33 +0800 Subject: [PATCH 17/17] Update for tokenReward renames --- src/validation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index dff65fcef6..b3cf542374 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2096,7 +2096,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int if (height >= consensus.EunosHeight) { CAmount subsidy; - for (const auto& kv : consensus.newNonUTXOSubsidies) + for (const auto& kv : consensus.blockTokenRewards) { if (kv.first == CommunityAccountType::CommunityDevFunds) { if (height < consensus.GrandCentralHeight) { @@ -2174,7 +2174,7 @@ Res ApplyGeneralCoinbaseTx(CCustomCSView & mnview, CTransaction const & tx, int } else { - for (const auto& kv : consensus.nonUtxoBlockSubsidies) { + for (const auto& kv : consensus.blockTokenRewardsLegacy) { CAmount subsidy = blockReward * kv.second / COIN; Res res = mnview.AddCommunityBalance(kv.first, subsidy); if (!res.ok) { @@ -2205,7 +2205,7 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensu { if (height >= Params().GetConsensus().EunosHeight) { - for (const auto& kv : Params().GetConsensus().newNonUTXOSubsidies) + for (const auto& kv : Params().GetConsensus().blockTokenRewards) { if (kv.first == CommunityAccountType::CommunityDevFunds) { if (height < Params().GetConsensus().GrandCentralHeight) { @@ -2256,7 +2256,7 @@ void ReverseGeneralCoinbaseTx(CCustomCSView & mnview, int height, const Consensu } else { - for (const auto& kv : Params().GetConsensus().nonUtxoBlockSubsidies) + for (const auto& kv : Params().GetConsensus().blockTokenRewardsLegacy) { CAmount subsidy = blockReward * kv.second / COIN; mnview.SubCommunityBalance(kv.first, subsidy);