From 87d70f415245cba8f1e373bfa2c054606c70e14e Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Sat, 5 Aug 2023 19:03:21 +0800 Subject: [PATCH 01/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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 6c816d040fea2f7f45cf0c03db6ea4a0f6d1cb8c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 10:59:54 +0800 Subject: [PATCH 15/25] Mark items as unsafe, rename queue --- lib/ain-evm/src/core.rs | 16 +++--- lib/ain-evm/src/evm.rs | 14 +++--- lib/ain-evm/src/txqueue.rs | 20 ++++---- lib/ain-rs-exports/src/evm.rs | 92 +++++++++++++++++++---------------- lib/ain-rs-exports/src/lib.rs | 4 +- src/masternodes/mn_checks.cpp | 4 +- src/miner.cpp | 2 +- src/validation.cpp | 2 +- 8 files changed, 80 insertions(+), 74 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 28cefd311d..58e6b7e161 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -181,7 +181,7 @@ impl EVMCoreService { /// # Returns /// /// Returns the signed tx, tx prepay gas fees and the gas used to call the tx. - pub fn validate_raw_tx( + pub unsafe fn validate_raw_tx( &self, tx: &str, queue_id: u64, @@ -276,7 +276,7 @@ impl EVMCoreService { debug!("[validate_raw_tx] used_gas: {:#?}", used_gas); let total_current_gas_used = self .tx_queues - .get_total_gas_used(queue_id) + .get_total_gas_used_in(queue_id) .unwrap_or_default(); if total_current_gas_used + U256::from(used_gas) > MAX_GAS_PER_BLOCK { @@ -312,7 +312,7 @@ impl EVMCoreService { ) -> Result<(), EVMError> { let queue_tx = QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })); self.tx_queues - .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; + .push_in(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) } @@ -338,13 +338,13 @@ impl EVMCoreService { } else { let queue_tx = QueueTx::SystemTx(SystemTx::EvmOut(BalanceUpdate { address, amount })); self.tx_queues - .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; + .push_in(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) } } pub fn get_queue_id(&self) -> u64 { - self.tx_queues.get_queue_id() + self.tx_queues.create() } pub fn remove(&self, queue_id: u64) { @@ -352,7 +352,7 @@ impl EVMCoreService { } pub fn remove_txs_by_sender(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { - self.tx_queues.remove_txs_by_sender(queue_id, address)?; + self.tx_queues.remove_by_sender_in(queue_id, address)?; Ok(()) } @@ -375,14 +375,14 @@ impl EVMCoreService { /// # Returns /// /// Returns the next valid nonce as a `U256`. Defaults to U256::zero() - pub fn get_next_valid_nonce_in_queue( + pub unsafe fn get_next_valid_nonce_in_queue( &self, queue_id: u64, address: H160, ) -> Result { let nonce = self .tx_queues - .get_next_valid_nonce(queue_id, address)? + .get_next_valid_nonce_in(queue_id, address)? .unwrap_or_else(|| { let latest_block = self .storage diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 521c1bb278..ab2a4b8cb9 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -107,12 +107,12 @@ impl EVMServices { timestamp: u64, dvm_block_number: u64, ) -> Result> { - let tx_queue = self.core.tx_queues.get_queue(queue_id)?; + let tx_queue = self.core.tx_queues.get(queue_id)?; let mut queue = tx_queue.data.lock().unwrap(); - let queue_len = queue.transactions.len(); - let mut all_transactions = Vec::with_capacity(queue_len); - let mut failed_transactions = Vec::with_capacity(queue_len); - let mut receipts_v3: Vec = Vec::with_capacity(queue_len); + let queue_txs_len = queue.transactions.len(); + let mut all_transactions = Vec::with_capacity(queue_txs_len); + let mut failed_transactions = Vec::with_capacity(queue_txs_len); + let mut receipts_v3: Vec = Vec::with_capacity(queue_txs_len); let mut total_gas_used = 0u64; let mut total_gas_fees = U256::zero(); let mut logs_bloom: Bloom = Bloom::default(); @@ -342,7 +342,7 @@ impl EVMServices { pub fn finalize_block(&self, queue_id: u64) -> Result<(), Box> { { - let tx_queue = self.core.tx_queues.get_queue(queue_id)?; + let tx_queue = self.core.tx_queues.get(queue_id)?; let queue = tx_queue.data.lock().unwrap(); let Some(BlockData { block, receipts }) = queue.block_data.clone() else { return Err(format_err!("no constructed EVM block exist in queue id").into()); @@ -399,7 +399,7 @@ impl EVMServices { self.core .tx_queues - .queue_tx(queue_id, tx.clone(), hash, gas_used, base_fee)?; + .push_in(queue_id, tx.clone(), hash, gas_used, base_fee)?; if let QueueTx::SignedTx(signed_tx) = tx { self.filters.add_tx_to_filters(signed_tx.transaction.hash()); diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index ae54083272..a826e20e81 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -37,7 +37,7 @@ impl TransactionQueueMap { /// `get_queue_id` generates a unique random ID, creates a new `TransactionQueue` for that ID, /// and then returns the ID. - pub fn get_queue_id(&self) -> u64 { + pub fn create(&self) -> u64 { let mut rng = rand::thread_rng(); loop { let queue_id = rng.gen(); @@ -69,7 +69,7 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn get_queue(&self, queue_id: u64) -> Result> { + pub fn get(&self, queue_id: u64) -> Result> { Ok(Arc::clone( self.queues .read() @@ -93,7 +93,7 @@ impl TransactionQueueMap { /// previous nonce of transactions from the same sender in the queue. /// Returns `QueueError::InvalidFee` if the fee calculation overflows. /// - pub fn queue_tx( + pub fn push_in( &self, queue_id: u64, tx: QueueTx, @@ -112,12 +112,12 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn remove_txs_by_sender(&self, queue_id: u64, sender: H160) -> Result<()> { + pub fn remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } - pub fn get_tx_queue_items(&self, queue_id: u64) -> Result> { - self.with_transaction_queue(queue_id, TransactionQueue::get_tx_queue_items) + pub fn get_txs_cloned_in(&self, queue_id: u64) -> Result> { + self.with_transaction_queue(queue_id, TransactionQueue::get_queue_txs_cloned) } /// `get_next_valid_nonce` returns the next valid nonce for the account with the provided address @@ -131,11 +131,11 @@ impl TransactionQueueMap { /// Returns None when the address does not have any transaction queued or /// Some(nonce) with the next valid nonce (current + 1) for the associated address /// - pub fn get_next_valid_nonce(&self, queue_id: u64, address: H160) -> Result> { + pub unsafe fn get_next_valid_nonce_in(&self, queue_id: u64, address: H160) -> Result> { self.with_transaction_queue(queue_id, |queue| queue.get_next_valid_nonce(address)) } - pub fn get_total_gas_used(&self, queue_id: u64) -> Result { + pub unsafe fn get_total_gas_used_in(&self, queue_id: u64) -> Result { self.with_transaction_queue(queue_id, |queue| queue.get_total_gas_used()) } @@ -143,7 +143,7 @@ impl TransactionQueueMap { /// # Errors /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. - pub fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result + fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result where F: FnOnce(&TransactionQueue) -> T, { @@ -271,7 +271,7 @@ impl TransactionQueue { data.account_nonces.remove(&sender); } - pub fn get_tx_queue_items(&self) -> Vec { + pub fn get_queue_txs_cloned(&self) -> Vec { self.data.lock().unwrap().transactions.clone() } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 59cb207c92..c85d897261 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -111,13 +111,15 @@ pub fn evm_try_get_next_valid_nonce_in_queue( address: [u8; 20], ) -> u64 { let address = H160::from(address); - match SERVICES - .evm - .core - .get_next_valid_nonce_in_queue(queue_id, address) - { - Ok(nonce) => cross_boundary_success_return(result, nonce.as_u64()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .core + .get_next_valid_nonce_in_queue(queue_id, address) + { + Ok(nonce) => cross_boundary_success_return(result, nonce.as_u64()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -232,27 +234,29 @@ pub fn evm_try_sub_balance( /// /// Returns the transaction nonce, sender address and transaction fees if valid. /// Logs and set the error reason to result object otherwise. -pub fn evm_try_prevalidate_raw_tx( +pub fn evm_unsafe_try_prevalidate_raw_tx( result: &mut ffi::CrossBoundaryResult, tx: &str, ) -> ffi::PreValidateTxCompletion { let queue_id = 0; - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, false) { - Ok(ValidateTxInfo { - signed_tx, - prepay_fee, - used_gas: _, - }) => cross_boundary_success_return( - result, - ffi::PreValidateTxCompletion { - nonce: signed_tx.nonce().as_u64(), - sender: signed_tx.sender.to_fixed_bytes(), - prepay_fee: prepay_fee.try_into().unwrap_or_default(), - }, - ), - Err(e) => { - debug!("evm_try_prevalidate_raw_tx failed with error: {e}"); - cross_boundary_error_return(result, e.to_string()) + unsafe { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id, false) { + Ok(ValidateTxInfo { + signed_tx, + prepay_fee, + used_gas: _, + }) => cross_boundary_success_return( + result, + ffi::PreValidateTxCompletion { + nonce: signed_tx.nonce().as_u64(), + sender: signed_tx.sender.to_fixed_bytes(), + prepay_fee: prepay_fee.try_into().unwrap_or_default(), + }, + ), + Err(e) => { + debug!("evm_try_prevalidate_raw_tx failed with error: {e}"); + cross_boundary_error_return(result, e.to_string()) + } } } } @@ -281,7 +285,7 @@ pub fn evm_try_prevalidate_raw_tx( /// /// Returns the transaction nonce, sender address, transaction fees and gas used /// if valid. Logs and set the error reason to result object otherwise. -pub fn evm_try_validate_raw_tx( +pub fn evm_unsafe_try_validate_raw_tx( result: &mut ffi::CrossBoundaryResult, tx: &str, queue_id: u64, @@ -293,26 +297,28 @@ pub fn evm_try_validate_raw_tx( return cross_boundary_error_return(result, e.to_string()); } } - - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, true) { - Ok(ValidateTxInfo { - signed_tx, - prepay_fee, - used_gas, - }) => cross_boundary_success_return( - result, - ffi::ValidateTxCompletion { - nonce: signed_tx.nonce().as_u64(), - sender: signed_tx.sender.to_fixed_bytes(), - prepay_fee: prepay_fee.try_into().unwrap_or_default(), - gas_used: used_gas, - }, - ), - Err(e) => { - debug!("evm_try_validate_raw_tx failed with error: {e}"); - cross_boundary_error_return(result, e.to_string()) + unsafe { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id, true) { + Ok(ValidateTxInfo { + signed_tx, + prepay_fee, + used_gas, + }) => cross_boundary_success_return( + result, + ffi::ValidateTxCompletion { + nonce: signed_tx.nonce().as_u64(), + sender: signed_tx.sender.to_fixed_bytes(), + prepay_fee: prepay_fee.try_into().unwrap_or_default(), + gas_used: used_gas, + }, + ), + Err(e) => { + debug!("evm_try_validate_raw_tx failed with error: {e}"); + cross_boundary_error_return(result, e.to_string()) + } } } + } /// Retrieves the EVM queue ID. diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 01164cf645..cf8ff451af 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -100,11 +100,11 @@ pub mod ffi { amount: [u8; 32], native_tx_hash: [u8; 32], ) -> bool; - fn evm_try_prevalidate_raw_tx( + fn evm_unsafe_try_prevalidate_raw_tx( result: &mut CrossBoundaryResult, tx: &str, ) -> PreValidateTxCompletion; - fn evm_try_validate_raw_tx( + fn evm_unsafe_try_validate_raw_tx( result: &mut CrossBoundaryResult, tx: &str, queue_id: u64, diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index f884706948..24c04e911c 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3975,7 +3975,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CrossBoundaryResult result; if (!prevalidateEvm) { - const auto validateResults = evm_try_validate_raw_tx(result, HexStr(obj.evmTx), evmQueueId); + const auto validateResults = evm_unsafe_try_validate_raw_tx(result, HexStr(obj.evmTx), evmQueueId); // Completely remove this fork guard on mainnet upgrade to restore nonce check from EVM activation if (!result.ok) { LogPrintf("[evm_try_validate_raw_tx] failed, reason : %s\n", result.reason); @@ -3989,7 +3989,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { } } else { - evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { LogPrintf("[evm_try_prevalidate_raw_tx] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to validate %s", result.reason); diff --git a/src/miner.cpp b/src/miner.cpp index 0677a53693..59f0109ec0 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -658,7 +658,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) const auto obj = std::get(txMessage); CrossBoundaryResult result; - const auto txResult = evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + const auto txResult = evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { return false; } diff --git a/src/validation.cpp b/src/validation.cpp index eaeb5a2b31..9320acfeb1 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -918,7 +918,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool const auto obj = std::get(txMessage); CrossBoundaryResult result; - const auto txResult = evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + const auto txResult = evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { return state.Invalid(ValidationInvalidReason::CONSENSUS, error("evm tx failed to validate %s", result.reason.c_str()), REJECT_INVALID, "evm-validate-failed"); } From 421ac9716d6a0702da3400cf242840abc7e28d3f Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 11:07:28 +0800 Subject: [PATCH 16/25] More changes --- lib/ain-evm/src/core.rs | 6 +++--- lib/ain-rs-exports/src/evm.rs | 10 +++++----- lib/ain-rs-exports/src/lib.rs | 4 ++-- src/masternodes/mn_checks.cpp | 8 ++++---- src/miner.cpp | 4 ++-- src/validation.cpp | 4 ++-- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 58e6b7e161..5e56a59859 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -343,15 +343,15 @@ impl EVMCoreService { } } - pub fn get_queue_id(&self) -> u64 { + pub fn create_queue(&self) -> u64 { self.tx_queues.create() } - pub fn remove(&self, queue_id: u64) { + pub fn remove_queue(&self, queue_id: u64) { self.tx_queues.remove(queue_id); } - pub fn remove_txs_by_sender(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { + pub fn remove_by_sender_in(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { self.tx_queues.remove_by_sender_in(queue_id, address)?; Ok(()) } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index c85d897261..93ad1b3810 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -136,7 +136,7 @@ pub fn evm_try_remove_txs_by_sender( address: [u8; 20], ) { let address = H160::from(address); - match SERVICES.evm.core.remove_txs_by_sender(queue_id, address) { + match SERVICES.evm.core.remove_by_sender_in(queue_id, address) { Ok(_) => cross_boundary_success_return(result, ()), Err(e) => cross_boundary_error_return(result, e.to_string()), } @@ -326,8 +326,8 @@ pub fn evm_unsafe_try_validate_raw_tx( /// # Returns /// /// Returns the EVM queue ID as a `u64`. -pub fn evm_get_queue_id() -> u64 { - SERVICES.evm.core.get_queue_id() +pub fn evm_create_queue() -> u64 { + SERVICES.evm.core.create_queue() } /// /// Discards an EVM queue. @@ -336,8 +336,8 @@ pub fn evm_get_queue_id() -> u64 { /// /// * `queue_id` - The queue ID. /// -pub fn evm_discard_context(queue_id: u64) { - SERVICES.evm.core.remove(queue_id) +pub fn evm_destroy_queue(queue_id: u64) { + SERVICES.evm.core.remove_queue(queue_id) } /// Add an EVM transaction to a specific queue. diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index cf8ff451af..bedc277d34 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -69,8 +69,8 @@ pub mod ffi { // If they are fallible, it's a TODO to changed and move later // so errors are propogated up properly. fn evm_get_balance(address: [u8; 20]) -> u64; - fn evm_get_queue_id() -> u64; - fn evm_discard_context(queue_id: u64); + fn evm_create_queue() -> u64; + fn evm_destroy_queue(queue_id: u64); fn evm_disconnect_latest_block(); // Failible functions diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 24c04e911c..d08c96810f 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4250,15 +4250,15 @@ Res CustomTxVisit(CCustomCSView &mnview, return Res::ErrCode(CustomTxErrCodes::Fatal, "Disabled custom transaction"); } - auto context = evmQueueId; + auto q = evmQueueId; bool prevalidateEvm = false; - if (context == 0) { + if (q == 0) { prevalidateEvm = true; - context = evm_get_queue_id(); + q = evm_create_queue(); } try { - return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, context, prevalidateEvm), txMessage); + return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, q, prevalidateEvm), txMessage); } catch (const std::bad_variant_access &e) { return Res::Err(e.what()); } catch (...) { diff --git a/src/miner.cpp b/src/miner.cpp index 59f0109ec0..62679c7680 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -272,7 +272,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc timeOrdering = false; } - const auto evmQueueId = evm_get_queue_id(); + const auto evmQueueId = evm_create_queue(); std::map txFees; if (timeOrdering) { @@ -287,7 +287,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; auto blockResult = evm_try_construct_block(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); - evm_discard_context(evmQueueId); + evm_destroy_queue(evmQueueId); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); diff --git a/src/validation.cpp b/src/validation.cpp index 9320acfeb1..2103c5400d 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3333,11 +3333,11 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp CCustomCSView mnview(*pcustomcsview, paccountHistoryDB.get(), pburnHistoryDB.get(), pvaultHistoryDB.get()); bool rewardedAnchors{}; std::array beneficiary{}; - const auto evmQueueId = evm_get_queue_id(); + const auto evmQueueId = evm_create_queue(); bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, beneficiary, false, evmQueueId); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { - evm_discard_context(evmQueueId); + evm_destroy_queue(evmQueueId); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } From 22fe4e377c380c989b4cf74c316188b5db56f2ab Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 11:37:23 +0800 Subject: [PATCH 17/25] More changes --- lib/ain-evm/src/core.rs | 8 ++++---- lib/ain-evm/src/txqueue.rs | 2 +- lib/ain-rs-exports/src/evm.rs | 24 +++++++++++++----------- lib/ain-rs-exports/src/lib.rs | 12 ++++++------ src/masternodes/mn_checks.cpp | 6 +++--- src/miner.cpp | 6 +++--- src/validation.cpp | 2 +- 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 5e56a59859..0de219a307 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -185,7 +185,6 @@ impl EVMCoreService { &self, tx: &str, queue_id: u64, - use_context: bool, ) -> Result> { debug!("[validate_raw_tx] raw transaction : {:#?}", tx); let signed_tx = SignedTx::try_from(tx) @@ -256,7 +255,8 @@ impl EVMCoreService { return Err(format_err!("gas limit higher than MAX_GAS_PER_BLOCK").into()); } - let used_gas = if use_context { + let use_queue = queue_id != 0; + let used_gas = if use_queue { let TxResponse { used_gas, .. } = self.call(EthCallArgs { caller: Some(signed_tx.sender), to: signed_tx.to(), @@ -272,7 +272,7 @@ impl EVMCoreService { }; // Validate total gas usage in queued txs exceeds block size - if use_context { + if use_queue { debug!("[validate_raw_tx] used_gas: {:#?}", used_gas); let total_current_gas_used = self .tx_queues @@ -351,7 +351,7 @@ impl EVMCoreService { self.tx_queues.remove(queue_id); } - pub fn remove_by_sender_in(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { + pub unsafe fn remove_txs_by_sender_in(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { self.tx_queues.remove_by_sender_in(queue_id, address)?; Ok(()) } diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index a826e20e81..b67f285f7b 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -112,7 +112,7 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { + pub unsafe fn remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 93ad1b3810..6114cee649 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -105,7 +105,7 @@ pub fn evm_get_balance(address: [u8; 20]) -> u64 { /// # Returns /// /// Returns the next valid nonce of the account in a specific queue_id as a `u64` -pub fn evm_try_get_next_valid_nonce_in_queue( +pub fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: [u8; 20], @@ -130,15 +130,17 @@ pub fn evm_try_get_next_valid_nonce_in_queue( /// * `queue_id` - The queue ID. /// * `address` - The EVM address of the account. /// -pub fn evm_try_remove_txs_by_sender( +pub fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: [u8; 20], ) { let address = H160::from(address); - match SERVICES.evm.core.remove_by_sender_in(queue_id, address) { - Ok(_) => cross_boundary_success_return(result, ()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES.evm.core.remove_txs_by_sender_in(queue_id, address) { + Ok(_) => cross_boundary_success_return(result, ()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -151,7 +153,7 @@ pub fn evm_try_remove_txs_by_sender( /// * `amount` - The amount to add as a byte array. /// * `hash` - The hash value as a byte array. /// -pub fn evm_try_add_balance( +pub fn evm_try_add_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -191,7 +193,7 @@ pub fn evm_try_add_balance( /// # Returns /// /// Returns `true` if the balance subtraction is successful, `false` otherwise. -pub fn evm_try_sub_balance( +pub fn evm_try_sub_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -240,7 +242,7 @@ pub fn evm_unsafe_try_prevalidate_raw_tx( ) -> ffi::PreValidateTxCompletion { let queue_id = 0; unsafe { - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, false) { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id) { Ok(ValidateTxInfo { signed_tx, prepay_fee, @@ -285,7 +287,7 @@ pub fn evm_unsafe_try_prevalidate_raw_tx( /// /// Returns the transaction nonce, sender address, transaction fees and gas used /// if valid. Logs and set the error reason to result object otherwise. -pub fn evm_unsafe_try_validate_raw_tx( +pub fn evm_unsafe_try_validate_raw_tx_in_q( result: &mut ffi::CrossBoundaryResult, tx: &str, queue_id: u64, @@ -298,7 +300,7 @@ pub fn evm_unsafe_try_validate_raw_tx( } } unsafe { - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, true) { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id) { Ok(ValidateTxInfo { signed_tx, prepay_fee, @@ -336,7 +338,7 @@ pub fn evm_create_queue() -> u64 { /// /// * `queue_id` - The queue ID. /// -pub fn evm_destroy_queue(queue_id: u64) { +pub fn evm_remove_queue(queue_id: u64) { SERVICES.evm.core.remove_queue(queue_id) } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index bedc277d34..27a8b34a87 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -70,30 +70,30 @@ pub mod ffi { // so errors are propogated up properly. fn evm_get_balance(address: [u8; 20]) -> u64; fn evm_create_queue() -> u64; - fn evm_destroy_queue(queue_id: u64); + fn evm_remove_queue(queue_id: u64); fn evm_disconnect_latest_block(); // Failible functions // Has to take CrossBoundaryResult as first param // Has to start with try_ / evm_try - fn evm_try_get_next_valid_nonce_in_queue( + fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: [u8; 20], ) -> u64; - fn evm_try_remove_txs_by_sender( + fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: [u8; 20], ); - fn evm_try_add_balance( + fn evm_try_add_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, amount: [u8; 32], native_tx_hash: [u8; 32], ); - fn evm_try_sub_balance( + fn evm_try_sub_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, @@ -104,7 +104,7 @@ pub mod ffi { result: &mut CrossBoundaryResult, tx: &str, ) -> PreValidateTxCompletion; - fn evm_unsafe_try_validate_raw_tx( + fn evm_unsafe_try_validate_raw_tx_in_q( result: &mut CrossBoundaryResult, tx: &str, queue_id: u64, diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index d08c96810f..52883b53e2 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3905,7 +3905,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; if (tokenId == DCT_ID{0}) { CrossBoundaryResult result; - if (!evm_try_sub_balance(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), + if (!evm_try_sub_balance_in_q(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); } @@ -3940,7 +3940,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; CrossBoundaryResult result; if (tokenId == DCT_ID{0}) { - evm_try_add_balance(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), + evm_try_add_balance_in_q(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); if (!result.ok) { return Res::Err("Error bridging DFI: %s", result.reason); @@ -3975,7 +3975,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CrossBoundaryResult result; if (!prevalidateEvm) { - const auto validateResults = evm_unsafe_try_validate_raw_tx(result, HexStr(obj.evmTx), evmQueueId); + const auto validateResults = evm_unsafe_try_validate_raw_tx_in_q(result, HexStr(obj.evmTx), evmQueueId); // Completely remove this fork guard on mainnet upgrade to restore nonce check from EVM activation if (!result.ok) { LogPrintf("[evm_try_validate_raw_tx] failed, reason : %s\n", result.reason); diff --git a/src/miner.cpp b/src/miner.cpp index 62679c7680..dd459afaa8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -287,7 +287,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; auto blockResult = evm_try_construct_block(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); - evm_destroy_queue(evmQueueId); + evm_remove_queue(evmQueueId); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); @@ -689,7 +689,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) } } evmAddressTxsMap.erase(addrKey.address); - evm_try_remove_txs_by_sender(result, evmQueueId, addrKey.address); + evm_unsafe_try_remove_txs_by_sender_in_q(result, evmQueueId, addrKey.address); // TODO handle missing evmQueueId error if (!result.ok) { return false; @@ -699,7 +699,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) } } - const auto nonce = evm_try_get_next_valid_nonce_in_queue(result, evmQueueId, txResult.sender); + const auto nonce = evm_unsafe_try_get_next_valid_nonce_in_q(result, evmQueueId, txResult.sender); if (!result.ok) { return false; } diff --git a/src/validation.cpp b/src/validation.cpp index 2103c5400d..18d59f5420 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3337,7 +3337,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, beneficiary, false, evmQueueId); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { - evm_destroy_queue(evmQueueId); + evm_remove_queue(evmQueueId); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } From d849a2271cd85eb77a255d7f20b250ef21bc73fd Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 11:47:59 +0800 Subject: [PATCH 18/25] And more --- lib/ain-evm/src/evm.rs | 2 +- lib/ain-rs-exports/src/evm.rs | 8 ++++---- lib/ain-rs-exports/src/lib.rs | 6 +++--- src/masternodes/mn_checks.cpp | 4 ++-- src/masternodes/validation.cpp | 2 +- src/miner.cpp | 2 +- src/validation.cpp | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index ab2a4b8cb9..c6289c804b 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -340,7 +340,7 @@ impl EVMServices { }) } - pub fn finalize_block(&self, queue_id: u64) -> Result<(), Box> { + pub fn commit_queue(&self, queue_id: u64) -> Result<(), Box> { { let tx_queue = self.core.tx_queues.get(queue_id)?; let queue = tx_queue.data.lock().unwrap(); diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 6114cee649..ff5b20db3f 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -356,7 +356,7 @@ pub fn evm_remove_queue(queue_id: u64) { /// - The `raw_tx` is in invalid format /// - The queue does not exists. /// -pub fn evm_try_queue_tx( +pub fn evm_try_push_tx_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, raw_tx: &str, @@ -390,7 +390,7 @@ pub fn evm_try_queue_tx( /// # Returns /// /// Returns a `FinalizeBlockResult` containing the block hash, failed transactions, burnt fees and priority fees (in satoshis) on success. -pub fn evm_try_construct_block( +pub fn evm_try_construct_block_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -424,8 +424,8 @@ pub fn evm_try_construct_block( } } -pub fn evm_try_finalize_block(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { - match SERVICES.evm.finalize_block(queue_id) { +pub fn evm_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { + match SERVICES.evm.commit_queue(queue_id) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 27a8b34a87..0a9e9195d2 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -109,14 +109,14 @@ pub mod ffi { tx: &str, queue_id: u64, ) -> ValidateTxCompletion; - fn evm_try_queue_tx( + fn evm_try_push_tx_in_q( result: &mut CrossBoundaryResult, queue_id: u64, raw_tx: &str, hash: [u8; 32], gas_used: u64, ); - fn evm_try_construct_block( + fn evm_try_construct_block_in_q( result: &mut CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -124,7 +124,7 @@ pub mod ffi { timestamp: u64, dvm_block_number: u64, ) -> FinalizeBlockCompletion; - fn evm_try_finalize_block(result: &mut CrossBoundaryResult, queue_id: u64); + fn evm_try_commit_queue(result: &mut CrossBoundaryResult, queue_id: u64); fn evm_try_create_and_sign_tx( result: &mut CrossBoundaryResult, ctx: CreateTransactionContext, diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 52883b53e2..379f8a7e84 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3982,9 +3982,9 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { return Res::Err("evm tx failed to validate %s", result.reason); } - evm_try_queue_tx(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); + evm_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); if (!result.ok) { - LogPrintf("[evm_try_queue_tx] failed, reason : %s\n", result.reason); + LogPrintf("[evm_try_push_tx_in_q] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to queue %s\n", result.reason); } } diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 026641a392..9c5aee9f39 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2447,7 +2447,7 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust } CrossBoundaryResult result; - const auto blockResult = evm_try_construct_block(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); + const auto blockResult = evm_try_construct_block_in_q(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); if (!result.ok) { return Res::Err(result.reason.c_str()); } diff --git a/src/miner.cpp b/src/miner.cpp index dd459afaa8..1d498cc163 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -286,7 +286,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::array beneficiary{}; std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; - auto blockResult = evm_try_construct_block(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); + auto blockResult = evm_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); evm_remove_queue(evmQueueId); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); diff --git a/src/validation.cpp b/src/validation.cpp index 18d59f5420..48fbcbc8c8 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3348,7 +3348,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); if (IsEVMEnabled(pindexNew->nHeight, mnview, chainparams.GetConsensus())) { CrossBoundaryResult result; - evm_try_finalize_block(result, evmQueueId); + evm_try_commit_queue(result, evmQueueId); if (!result.ok) { state.Invalid(ValidationInvalidReason::CONSENSUS, error("EVM finalization failed: %s", result.reason.c_str()), From 248353d49727d6d917afa1e4644614d3f25a9578 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 11:58:40 +0800 Subject: [PATCH 19/25] And then some more --- lib/ain-evm/src/evm.rs | 4 ++-- lib/ain-rs-exports/src/evm.rs | 12 ++++++------ lib/ain-rs-exports/src/lib.rs | 4 ++-- src/masternodes/mn_checks.cpp | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index c6289c804b..23b4a2c035 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -99,7 +99,7 @@ impl EVMServices { } } - pub fn construct_block( + pub fn construct_block_in_queue( &self, queue_id: u64, difficulty: u32, @@ -383,7 +383,7 @@ impl EVMServices { Ok(()) } - pub fn queue_tx( + pub fn push_tx_in_queue( &self, queue_id: u64, tx: QueueTx, diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index ff5b20db3f..3b25c07a20 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -153,7 +153,7 @@ pub fn evm_unsafe_try_remove_txs_by_sender_in_q( /// * `amount` - The amount to add as a byte array. /// * `hash` - The hash value as a byte array. /// -pub fn evm_try_add_balance_in_q( +pub fn evm_unsafe_try_add_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -193,7 +193,7 @@ pub fn evm_try_add_balance_in_q( /// # Returns /// /// Returns `true` if the balance subtraction is successful, `false` otherwise. -pub fn evm_try_sub_balance_in_q( +pub fn evm_unsafe_try_sub_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -368,7 +368,7 @@ pub fn evm_try_push_tx_in_q( Ok(signed_tx) => { match SERVICES .evm - .queue_tx(queue_id, signed_tx.into(), hash, U256::from(gas_used)) + .push_tx_in_queue(queue_id, signed_tx.into(), hash, U256::from(gas_used)) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -399,7 +399,7 @@ pub fn evm_try_construct_block_in_q( dvm_block_number: u64, ) -> ffi::FinalizeBlockCompletion { let eth_address = H160::from(miner_address); - match SERVICES.evm.construct_block( + match SERVICES.evm.construct_block_in_queue( queue_id, difficulty, eth_address, @@ -506,7 +506,7 @@ pub fn evm_try_create_dst20( match SERVICES .evm - .queue_tx(queue_id, system_tx, native_hash, U256::zero()) + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -537,7 +537,7 @@ pub fn evm_try_bridge_dst20( match SERVICES .evm - .queue_tx(queue_id, system_tx, native_hash, U256::zero()) + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 0a9e9195d2..0b4080648c 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -86,14 +86,14 @@ pub mod ffi { queue_id: u64, address: [u8; 20], ); - fn evm_try_add_balance_in_q( + fn evm_unsafe_try_add_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, amount: [u8; 32], native_tx_hash: [u8; 32], ); - fn evm_try_sub_balance_in_q( + fn evm_unsafe_try_sub_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 379f8a7e84..6c5855e808 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -3905,7 +3905,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; if (tokenId == DCT_ID{0}) { CrossBoundaryResult result; - if (!evm_try_sub_balance_in_q(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), + if (!evm_unsafe_try_sub_balance_in_q(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); } @@ -3940,7 +3940,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; CrossBoundaryResult result; if (tokenId == DCT_ID{0}) { - evm_try_add_balance_in_q(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), + evm_unsafe_try_add_balance_in_q(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); if (!result.ok) { return Res::Err("Error bridging DFI: %s", result.reason); From cbd13b8eb0714c3eaf01db6e17635fbab8556e63 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 12:00:29 +0800 Subject: [PATCH 20/25] fmt --- lib/ain-evm/src/core.rs | 6 +++++- lib/ain-evm/src/txqueue.rs | 6 +++++- lib/ain-rs-exports/src/evm.rs | 11 ++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 0de219a307..f1fbf046db 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -351,7 +351,11 @@ impl EVMCoreService { self.tx_queues.remove(queue_id); } - pub unsafe fn remove_txs_by_sender_in(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { + pub unsafe fn remove_txs_by_sender_in( + &self, + queue_id: u64, + address: H160, + ) -> Result<(), EVMError> { self.tx_queues.remove_by_sender_in(queue_id, address)?; Ok(()) } diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index b67f285f7b..8af01a2edb 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -131,7 +131,11 @@ impl TransactionQueueMap { /// Returns None when the address does not have any transaction queued or /// Some(nonce) with the next valid nonce (current + 1) for the associated address /// - pub unsafe fn get_next_valid_nonce_in(&self, queue_id: u64, address: H160) -> Result> { + pub unsafe fn get_next_valid_nonce_in( + &self, + queue_id: u64, + address: H160, + ) -> Result> { self.with_transaction_queue(queue_id, |queue| queue.get_next_valid_nonce(address)) } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 3b25c07a20..5c494b4e4d 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -320,7 +320,6 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q( } } } - } /// Retrieves the EVM queue ID. @@ -366,10 +365,12 @@ pub fn evm_try_push_tx_in_q( let signed_tx: Result = raw_tx.try_into(); match signed_tx { Ok(signed_tx) => { - match SERVICES - .evm - .push_tx_in_queue(queue_id, signed_tx.into(), hash, U256::from(gas_used)) - { + match SERVICES.evm.push_tx_in_queue( + queue_id, + signed_tx.into(), + hash, + U256::from(gas_used), + ) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), } From 9c9d9e166e74854afdc5de5bf5ff095f1e6fb7c0 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 12:06:53 +0800 Subject: [PATCH 21/25] Resolve lints --- lib/ain-evm/src/core.rs | 18 ++++++++++++++++++ lib/ain-evm/src/txqueue.rs | 15 +++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index f1fbf046db..1d06ab40b0 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -181,6 +181,12 @@ impl EVMCoreService { /// # Returns /// /// Returns the signed tx, tx prepay gas fees and the gas used to call the tx. + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn validate_raw_tx( &self, tx: &str, @@ -351,6 +357,12 @@ impl EVMCoreService { self.tx_queues.remove(queue_id); } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn remove_txs_by_sender_in( &self, queue_id: u64, @@ -379,6 +391,12 @@ impl EVMCoreService { /// # Returns /// /// Returns the next valid nonce as a `U256`. Defaults to U256::zero() + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn get_next_valid_nonce_in_queue( &self, queue_id: u64, diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 8af01a2edb..e73fb0eecf 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -112,6 +112,11 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } @@ -131,6 +136,11 @@ impl TransactionQueueMap { /// Returns None when the address does not have any transaction queued or /// Some(nonce) with the next valid nonce (current + 1) for the associated address /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn get_next_valid_nonce_in( &self, queue_id: u64, @@ -139,6 +149,11 @@ impl TransactionQueueMap { self.with_transaction_queue(queue_id, |queue| queue.get_next_valid_nonce(address)) } + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn get_total_gas_used_in(&self, queue_id: u64) -> Result { self.with_transaction_queue(queue_id, |queue| queue.get_total_gas_used()) } From 376b897fca82ed8d3e113241ce3b1ec5fae35b37 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 12:22:07 +0800 Subject: [PATCH 22/25] And more unsafe marks --- lib/ain-evm/src/core.rs | 8 +-- lib/ain-evm/src/evm.rs | 6 +- lib/ain-evm/src/txqueue.rs | 12 ++-- lib/ain-rs-exports/src/evm.rs | 104 ++++++++++++++++++++-------------- lib/ain-rs-exports/src/lib.rs | 4 +- src/masternodes/mn_checks.cpp | 2 +- src/miner.cpp | 4 +- src/validation.cpp | 4 +- 8 files changed, 81 insertions(+), 63 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 1d06ab40b0..616283daa8 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -309,7 +309,7 @@ impl EVMCoreService { // Transaction queue methods impl EVMCoreService { - pub fn add_balance( + pub unsafe fn add_balance( &self, queue_id: u64, address: H160, @@ -322,7 +322,7 @@ impl EVMCoreService { Ok(()) } - pub fn sub_balance( + pub unsafe fn sub_balance( &self, queue_id: u64, address: H160, @@ -349,11 +349,11 @@ impl EVMCoreService { } } - pub fn create_queue(&self) -> u64 { + pub unsafe fn create_queue(&self) -> u64 { self.tx_queues.create() } - pub fn remove_queue(&self, queue_id: u64) { + pub unsafe fn remove_queue(&self, queue_id: u64) { self.tx_queues.remove(queue_id); } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 23b4a2c035..1f2373efd6 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -99,7 +99,7 @@ impl EVMServices { } } - pub fn construct_block_in_queue( + pub unsafe fn construct_block_in_queue( &self, queue_id: u64, difficulty: u32, @@ -340,7 +340,7 @@ impl EVMServices { }) } - pub fn commit_queue(&self, queue_id: u64) -> Result<(), Box> { + pub unsafe fn commit_queue(&self, queue_id: u64) -> Result<(), Box> { { let tx_queue = self.core.tx_queues.get(queue_id)?; let queue = tx_queue.data.lock().unwrap(); @@ -383,7 +383,7 @@ impl EVMServices { Ok(()) } - pub fn push_tx_in_queue( + pub unsafe fn push_tx_in_queue( &self, queue_id: u64, tx: QueueTx, diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index e73fb0eecf..3aa319e8b1 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -37,7 +37,7 @@ impl TransactionQueueMap { /// `get_queue_id` generates a unique random ID, creates a new `TransactionQueue` for that ID, /// and then returns the ID. - pub fn create(&self) -> u64 { + pub unsafe fn create(&self) -> u64 { let mut rng = rand::thread_rng(); loop { let queue_id = rng.gen(); @@ -56,7 +56,7 @@ impl TransactionQueueMap { /// Try to remove and return the `TransactionQueue` associated with the provided /// queue ID. - pub fn remove(&self, queue_id: u64) -> Option> { + pub unsafe fn remove(&self, queue_id: u64) -> Option> { self.queues.write().unwrap().remove(&queue_id) } @@ -69,7 +69,7 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn get(&self, queue_id: u64) -> Result> { + pub unsafe fn get(&self, queue_id: u64) -> Result> { Ok(Arc::clone( self.queues .read() @@ -93,7 +93,7 @@ impl TransactionQueueMap { /// previous nonce of transactions from the same sender in the queue. /// Returns `QueueError::InvalidFee` if the fee calculation overflows. /// - pub fn push_in( + pub unsafe fn push_in( &self, queue_id: u64, tx: QueueTx, @@ -121,7 +121,7 @@ impl TransactionQueueMap { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } - pub fn get_txs_cloned_in(&self, queue_id: u64) -> Result> { + pub unsafe fn get_txs_cloned_in(&self, queue_id: u64) -> Result> { self.with_transaction_queue(queue_id, TransactionQueue::get_queue_txs_cloned) } @@ -162,7 +162,7 @@ impl TransactionQueueMap { /// # Errors /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. - fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result + unsafe fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result where F: FnOnce(&TransactionQueue) -> T, { diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 5c494b4e4d..85deac16fd 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -164,13 +164,15 @@ pub fn evm_unsafe_try_add_balance_in_q( return cross_boundary_error_return(result, "Invalid address"); }; - match SERVICES + unsafe { + match SERVICES .evm .core .add_balance(queue_id, address, amount.into(), hash) - { - Ok(_) => cross_boundary_success_return(result, ()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + { + Ok(_) => cross_boundary_success_return(result, ()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -204,7 +206,8 @@ pub fn evm_unsafe_try_sub_balance_in_q( return cross_boundary_error_return(result, "Invalid address"); }; - match SERVICES + unsafe { + match SERVICES .evm .core .sub_balance(queue_id, address, amount.into(), hash) @@ -212,6 +215,7 @@ pub fn evm_unsafe_try_sub_balance_in_q( Ok(_) => cross_boundary_success_return(result, true), Err(e) => cross_boundary_error_return(result, e.to_string()), } + } } /// Pre-validates a raw EVM transaction. @@ -327,8 +331,10 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q( /// # Returns /// /// Returns the EVM queue ID as a `u64`. -pub fn evm_create_queue() -> u64 { - SERVICES.evm.core.create_queue() +pub fn evm_unsafe_try_create_queue() -> u64 { + unsafe { + SERVICES.evm.core.create_queue() + } } /// /// Discards an EVM queue. @@ -337,8 +343,10 @@ pub fn evm_create_queue() -> u64 { /// /// * `queue_id` - The queue ID. /// -pub fn evm_remove_queue(queue_id: u64) { - SERVICES.evm.core.remove_queue(queue_id) +pub fn evm_unsafe_try_remove_queue(queue_id: u64) { + unsafe { + SERVICES.evm.core.remove_queue(queue_id) + } } /// Add an EVM transaction to a specific queue. @@ -363,19 +371,21 @@ pub fn evm_try_push_tx_in_q( gas_used: u64, ) { let signed_tx: Result = raw_tx.try_into(); - match signed_tx { - Ok(signed_tx) => { - match SERVICES.evm.push_tx_in_queue( - queue_id, - signed_tx.into(), - hash, - U256::from(gas_used), - ) { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match signed_tx { + Ok(signed_tx) => { + match SERVICES.evm.push_tx_in_queue( + queue_id, + signed_tx.into(), + hash, + U256::from(gas_used), + ) { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } + Err(e) => cross_boundary_error_return(result, e.to_string()), } - Err(e) => cross_boundary_error_return(result, e.to_string()), } } @@ -400,35 +410,39 @@ pub fn evm_try_construct_block_in_q( dvm_block_number: u64, ) -> ffi::FinalizeBlockCompletion { let eth_address = H160::from(miner_address); - match SERVICES.evm.construct_block_in_queue( - queue_id, - difficulty, - eth_address, - timestamp, - dvm_block_number, - ) { - Ok(FinalizedBlockInfo { - block_hash, - failed_transactions, - total_burnt_fees, - total_priority_fees, - }) => { - cross_boundary_success(result); - ffi::FinalizeBlockCompletion { + unsafe { + match SERVICES.evm.construct_block_in_queue( + queue_id, + difficulty, + eth_address, + timestamp, + dvm_block_number, + ) { + Ok(FinalizedBlockInfo { block_hash, failed_transactions, - total_burnt_fees: WeiAmount(total_burnt_fees).to_satoshi().as_u64(), - total_priority_fees: WeiAmount(total_priority_fees).to_satoshi().as_u64(), + total_burnt_fees, + total_priority_fees, + }) => { + cross_boundary_success(result); + ffi::FinalizeBlockCompletion { + block_hash, + failed_transactions, + total_burnt_fees: WeiAmount(total_burnt_fees).to_satoshi().as_u64(), + total_priority_fees: WeiAmount(total_priority_fees).to_satoshi().as_u64(), + } } + Err(e) => cross_boundary_error_return(result, e.to_string()), } - Err(e) => cross_boundary_error_return(result, e.to_string()), } } pub fn evm_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { - match SERVICES.evm.commit_queue(queue_id) { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES.evm.commit_queue(queue_id) { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -505,13 +519,15 @@ pub fn evm_try_create_dst20( address, })); - match SERVICES + unsafe { + match SERVICES .evm .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), } + } } pub fn evm_try_bridge_dst20( @@ -536,11 +552,13 @@ pub fn evm_try_bridge_dst20( out, })); - match SERVICES + unsafe { + match SERVICES .evm .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) { Ok(_) => cross_boundary_success(result), Err(e) => cross_boundary_error_return(result, e.to_string()), } + } } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 0b4080648c..ab9048aa8e 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -69,8 +69,8 @@ pub mod ffi { // If they are fallible, it's a TODO to changed and move later // so errors are propogated up properly. fn evm_get_balance(address: [u8; 20]) -> u64; - fn evm_create_queue() -> u64; - fn evm_remove_queue(queue_id: u64); + fn evm_unsafe_try_create_queue() -> u64; + fn evm_unsafe_try_remove_queue(queue_id: u64); fn evm_disconnect_latest_block(); // Failible functions diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 6c5855e808..93067686dc 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -4254,7 +4254,7 @@ Res CustomTxVisit(CCustomCSView &mnview, bool prevalidateEvm = false; if (q == 0) { prevalidateEvm = true; - q = evm_create_queue(); + q = evm_unsafe_try_create_queue(); } try { diff --git a/src/miner.cpp b/src/miner.cpp index 1d498cc163..f5de1cd3e9 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -272,7 +272,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc timeOrdering = false; } - const auto evmQueueId = evm_create_queue(); + const auto evmQueueId = evm_unsafe_try_create_queue(); std::map txFees; if (timeOrdering) { @@ -287,7 +287,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; auto blockResult = evm_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); - evm_remove_queue(evmQueueId); + evm_unsafe_try_remove_queue(evmQueueId); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); diff --git a/src/validation.cpp b/src/validation.cpp index 48fbcbc8c8..09f32da339 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3333,11 +3333,11 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp CCustomCSView mnview(*pcustomcsview, paccountHistoryDB.get(), pburnHistoryDB.get(), pvaultHistoryDB.get()); bool rewardedAnchors{}; std::array beneficiary{}; - const auto evmQueueId = evm_create_queue(); + const auto evmQueueId = evm_unsafe_try_create_queue(); bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, beneficiary, false, evmQueueId); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { - evm_remove_queue(evmQueueId); + evm_unsafe_try_remove_queue(evmQueueId); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } From 9cfa962481224519e6b2abf58869d993ac4b21a9 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 13:09:05 +0800 Subject: [PATCH 23/25] More changes, use results, add CrossBoundaryResVal variants --- lib/ain-evm/src/core.rs | 22 +++++----- lib/ain-evm/src/txqueue.rs | 18 ++++---- lib/ain-rs-exports/src/evm.rs | 74 ++++++++++++++++---------------- lib/ain-rs-exports/src/lib.rs | 14 +++--- src/ffi/ffihelpers.h | 20 +++++++++ src/masternodes/mn_checks.cpp | 6 ++- src/masternodes/rpc_accounts.cpp | 14 ++++-- src/masternodes/validation.cpp | 2 +- src/miner.cpp | 10 +++-- src/validation.cpp | 12 +++--- 10 files changed, 115 insertions(+), 77 deletions(-) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 616283daa8..715348d34d 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -181,12 +181,12 @@ impl EVMCoreService { /// # Returns /// /// Returns the signed tx, tx prepay gas fees and the gas used to call the tx. - /// - /// # Safety - /// + /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn validate_raw_tx( &self, tx: &str, @@ -358,11 +358,11 @@ impl EVMCoreService { } /// - /// # Safety - /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn remove_txs_by_sender_in( &self, queue_id: u64, @@ -391,12 +391,12 @@ impl EVMCoreService { /// # Returns /// /// Returns the next valid nonce as a `U256`. Defaults to U256::zero() - /// - /// # Safety - /// + /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn get_next_valid_nonce_in_queue( &self, queue_id: u64, diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 3aa319e8b1..7091c7ca72 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -112,11 +112,11 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - /// # Safety - /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } @@ -136,11 +136,11 @@ impl TransactionQueueMap { /// Returns None when the address does not have any transaction queued or /// Some(nonce) with the next valid nonce (current + 1) for the associated address /// - /// # Safety - /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn get_next_valid_nonce_in( &self, queue_id: u64, @@ -149,11 +149,11 @@ impl TransactionQueueMap { self.with_transaction_queue(queue_id, |queue| queue.get_next_valid_nonce(address)) } - /// # Safety - /// + /// # Safety + /// /// Result cannot be used safety unless cs_main lock is taken on C++ side /// across all usages. Note: To be replaced with a proper lock flow later. - /// + /// pub unsafe fn get_total_gas_used_in(&self, queue_id: u64) -> Result { self.with_transaction_queue(queue_id, |queue| queue.get_total_gas_used()) } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 85deac16fd..b4e74deec8 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -78,7 +78,7 @@ pub fn evm_try_create_and_sign_tx( /// # Returns /// /// Returns the balance of the account as a `u64` on success. -pub fn evm_get_balance(address: [u8; 20]) -> u64 { +pub fn evm_try_get_balance(result: &mut ffi::CrossBoundaryResult, address: [u8; 20]) -> u64 { let account = H160::from(address); let (_, latest_block_number) = SERVICES .evm @@ -91,7 +91,8 @@ pub fn evm_get_balance(address: [u8; 20]) -> u64 { .core .get_balance(account, latest_block_number) .unwrap_or_default(), - ); // convert to try_evm_get_balance - Default to 0 for now + ); // convert to evm_try_get_balance - Default to 0 for now + cross_boundary_success(result); balance.to_satoshi().as_u64() } @@ -166,9 +167,9 @@ pub fn evm_unsafe_try_add_balance_in_q( unsafe { match SERVICES - .evm - .core - .add_balance(queue_id, address, amount.into(), hash) + .evm + .core + .add_balance(queue_id, address, amount.into(), hash) { Ok(_) => cross_boundary_success_return(result, ()), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -208,13 +209,13 @@ pub fn evm_unsafe_try_sub_balance_in_q( unsafe { match SERVICES - .evm - .core - .sub_balance(queue_id, address, amount.into(), hash) - { - Ok(_) => cross_boundary_success_return(result, true), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } + .evm + .core + .sub_balance(queue_id, address, amount.into(), hash) + { + Ok(_) => cross_boundary_success_return(result, true), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -331,10 +332,11 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q( /// # Returns /// /// Returns the EVM queue ID as a `u64`. -pub fn evm_unsafe_try_create_queue() -> u64 { - unsafe { - SERVICES.evm.core.create_queue() - } +pub fn evm_unsafe_try_create_queue(result: &mut ffi::CrossBoundaryResult) -> u64 { + let q; + unsafe { q = SERVICES.evm.core.create_queue() } + cross_boundary_success(result); + q } /// /// Discards an EVM queue. @@ -343,10 +345,9 @@ pub fn evm_unsafe_try_create_queue() -> u64 { /// /// * `queue_id` - The queue ID. /// -pub fn evm_unsafe_try_remove_queue(queue_id: u64) { - unsafe { - SERVICES.evm.core.remove_queue(queue_id) - } +pub fn evm_unsafe_try_remove_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { + unsafe { SERVICES.evm.core.remove_queue(queue_id) } + cross_boundary_success(result); } /// Add an EVM transaction to a specific queue. @@ -363,7 +364,7 @@ pub fn evm_unsafe_try_remove_queue(queue_id: u64) { /// - The `raw_tx` is in invalid format /// - The queue does not exists. /// -pub fn evm_try_push_tx_in_q( +pub fn evm_unsafe_try_push_tx_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, raw_tx: &str, @@ -401,7 +402,7 @@ pub fn evm_try_push_tx_in_q( /// # Returns /// /// Returns a `FinalizeBlockResult` containing the block hash, failed transactions, burnt fees and priority fees (in satoshis) on success. -pub fn evm_try_construct_block_in_q( +pub fn evm_unsafe_try_construct_block_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -437,7 +438,7 @@ pub fn evm_try_construct_block_in_q( } } -pub fn evm_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { +pub fn evm_unsafe_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { unsafe { match SERVICES.evm.commit_queue(queue_id) { Ok(_) => cross_boundary_success(result), @@ -446,8 +447,9 @@ pub fn evm_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64 } } -pub fn evm_disconnect_latest_block() { +pub fn evm_disconnect_latest_block(result: &mut ffi::CrossBoundaryResult) { SERVICES.evm.storage.disconnect_latest_block(); + cross_boundary_success(result); } /// Return the block for a given height. @@ -521,12 +523,12 @@ pub fn evm_try_create_dst20( unsafe { match SERVICES - .evm - .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) - { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } + .evm + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) + { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -554,11 +556,11 @@ pub fn evm_try_bridge_dst20( unsafe { match SERVICES - .evm - .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) - { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), - } + .evm + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) + { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index ab9048aa8e..07cab96882 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -68,10 +68,10 @@ pub mod ffi { // // If they are fallible, it's a TODO to changed and move later // so errors are propogated up properly. - fn evm_get_balance(address: [u8; 20]) -> u64; - fn evm_unsafe_try_create_queue() -> u64; - fn evm_unsafe_try_remove_queue(queue_id: u64); - fn evm_disconnect_latest_block(); + fn evm_try_get_balance(result: &mut CrossBoundaryResult, address: [u8; 20]) -> u64; + fn evm_unsafe_try_create_queue(result: &mut CrossBoundaryResult) -> u64; + fn evm_unsafe_try_remove_queue(result: &mut CrossBoundaryResult, queue_id: u64); + fn evm_disconnect_latest_block(result: &mut CrossBoundaryResult); // Failible functions // Has to take CrossBoundaryResult as first param @@ -109,14 +109,14 @@ pub mod ffi { tx: &str, queue_id: u64, ) -> ValidateTxCompletion; - fn evm_try_push_tx_in_q( + fn evm_unsafe_try_push_tx_in_q( result: &mut CrossBoundaryResult, queue_id: u64, raw_tx: &str, hash: [u8; 32], gas_used: u64, ); - fn evm_try_construct_block_in_q( + fn evm_unsafe_try_construct_block_in_q( result: &mut CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -124,7 +124,7 @@ pub mod ffi { timestamp: u64, dvm_block_number: u64, ) -> FinalizeBlockCompletion; - fn evm_try_commit_queue(result: &mut CrossBoundaryResult, queue_id: u64); + fn evm_unsafe_try_commit_queue(result: &mut CrossBoundaryResult, queue_id: u64); fn evm_try_create_and_sign_tx( result: &mut CrossBoundaryResult, ctx: CreateTransactionContext, diff --git a/src/ffi/ffihelpers.h b/src/ffi/ffihelpers.h index 10edb2848e..7d1240aa7a 100644 --- a/src/ffi/ffihelpers.h +++ b/src/ffi/ffihelpers.h @@ -1,6 +1,7 @@ #ifndef DEFI_FFI_FFIHELPERS_H #define DEFI_FFI_FFIHELPERS_H +#include #include #define CrossBoundaryCheckedThrow(x) { \ @@ -21,5 +22,24 @@ return true; \ }(); +#define CrossBoundaryResVal(x) [&]() { \ + CrossBoundaryResult result; \ + auto res = x; \ + if (!result.ok) { \ + return ResVal(Res::Err("%s\n", result.reason.c_str())); \ + } \ + return ResVal(std::move(res), Res::Ok()); \ +}(); + +#define CrossBoundaryResValChecked(x) [&]() { \ + CrossBoundaryResult result; \ + auto res = x; \ + if (!result.ok) { \ + LogPrintf("%s\n", result.reason.c_str()); \ + return ResVal(Res::Err("%s\n", result.reason.c_str())); \ + } \ + return ResVal(std::move(res), Res::Ok()); \ +}(); + #endif // DEFI_FFI_FFIHELPERS_H diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 93067686dc..ccf4761e57 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -3982,7 +3983,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { return Res::Err("evm tx failed to validate %s", result.reason); } - evm_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); + evm_unsafe_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); if (!result.ok) { LogPrintf("[evm_try_push_tx_in_q] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to queue %s\n", result.reason); @@ -4254,7 +4255,8 @@ Res CustomTxVisit(CCustomCSView &mnview, bool prevalidateEvm = false; if (q == 0) { prevalidateEvm = true; - q = evm_unsafe_try_create_queue(); + auto r = CrossBoundaryResVal(evm_unsafe_try_create_queue(result)); + if (r) { q = *r; } else { return r; } } try { diff --git a/src/masternodes/rpc_accounts.cpp b/src/masternodes/rpc_accounts.cpp index b51efeb4f3..b3e1be827c 100644 --- a/src/masternodes/rpc_accounts.cpp +++ b/src/masternodes/rpc_accounts.cpp @@ -5,6 +5,7 @@ #include #include #include +#include std::string tokenAmountString(const CTokenAmount &amount, AmountFormat format = AmountFormat::Symbol) { const auto token = pcustomcsview->GetToken(amount.nTokenId); @@ -478,7 +479,9 @@ UniValue getaccount(const JSONRPCRequest& request) { const auto keyID = std::get(dest); std::array address{}; std::copy(keyID.begin(), keyID.end(), address.begin()); - if (const auto balance = evm_get_balance(address)) { + auto r = CrossBoundaryResVal(evm_try_get_balance(result, address)); + if (!r) throw JSONRPCError(RPC_MISC_ERROR, r.msg); + if (const auto balance = *r) { balances[DCT_ID{}] = balance; } } @@ -605,8 +608,13 @@ UniValue gettokenbalances(const JSONRPCRequest& request) { for (const auto keyID : pwallet->GetKeys()) { std::array address{}; std::copy(keyID.begin(), keyID.end(), address.begin()); - const auto evmAmount = evm_get_balance(address); - totalBalances.Add({{}, static_cast(evmAmount)}); + auto res = CrossBoundaryResVal(evm_try_get_balance(result, address)); + if (res) { + auto evmAmount = *res; + totalBalances.Add({{}, static_cast(evmAmount)}); + } else { + throw JSONRPCError(RPC_MISC_ERROR, res.msg); + } } } diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 9c5aee9f39..16b47d3a09 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2447,7 +2447,7 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust } CrossBoundaryResult result; - const auto blockResult = evm_try_construct_block_in_q(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); + const auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); if (!result.ok) { return Res::Err(result.reason.c_str()); } diff --git a/src/miner.cpp b/src/miner.cpp index f5de1cd3e9..60116f2953 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -272,7 +273,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc timeOrdering = false; } - const auto evmQueueId = evm_unsafe_try_create_queue(); + auto r = CrossBoundaryResValChecked(evm_unsafe_try_create_queue(result)); + if (!r) return nullptr; + const auto evmQueueId = *r; std::map txFees; if (timeOrdering) { @@ -286,8 +289,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::array beneficiary{}; std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; - auto blockResult = evm_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); - evm_unsafe_try_remove_queue(evmQueueId); + auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); + + CrossBoundaryChecked(evm_unsafe_try_remove_queue(result, evmQueueId)); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); diff --git a/src/validation.cpp b/src/validation.cpp index 09f32da339..77d40fc300 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -55,7 +55,7 @@ #include #include #include - +#include #include #include @@ -3190,7 +3190,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha mnview.GetHistoryWriters().DiscardDB(); return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); } - evm_disconnect_latest_block(); + CrossBoundaryChecked(evm_disconnect_latest_block(result)); bool flushed = view.Flush() && mnview.Flush(); assert(flushed); mnview.GetHistoryWriters().FlushDB(); @@ -3333,11 +3333,13 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp CCustomCSView mnview(*pcustomcsview, paccountHistoryDB.get(), pburnHistoryDB.get(), pvaultHistoryDB.get()); bool rewardedAnchors{}; std::array beneficiary{}; - const auto evmQueueId = evm_unsafe_try_create_queue(); + uint64_t evmQueueId{}; + auto r = CrossBoundaryResValChecked(evm_unsafe_try_create_queue(result)); + if (r) { evmQueueId = *r; } bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, beneficiary, false, evmQueueId); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { - evm_unsafe_try_remove_queue(evmQueueId); + CrossBoundaryChecked(evm_unsafe_try_remove_queue(result, evmQueueId)); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } @@ -3348,7 +3350,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); if (IsEVMEnabled(pindexNew->nHeight, mnview, chainparams.GetConsensus())) { CrossBoundaryResult result; - evm_try_commit_queue(result, evmQueueId); + CrossBoundaryChecked(evm_unsafe_try_commit_queue(result, evmQueueId)); if (!result.ok) { state.Invalid(ValidationInvalidReason::CONSENSUS, error("EVM finalization failed: %s", result.reason.c_str()), From 40c8f347a258bcd2275d7146a87877924cb1d488 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Mon, 7 Aug 2023 15:20:51 +0800 Subject: [PATCH 24/25] Fix lints --- lib/ain-evm/src/core.rs | 24 ++++++++++++++++++++++++ lib/ain-evm/src/evm.rs | 18 ++++++++++++++++++ lib/ain-evm/src/txqueue.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 715348d34d..439d10f05d 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -309,6 +309,12 @@ impl EVMCoreService { // Transaction queue methods impl EVMCoreService { + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn add_balance( &self, queue_id: u64, @@ -322,6 +328,12 @@ impl EVMCoreService { Ok(()) } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn sub_balance( &self, queue_id: u64, @@ -349,10 +361,22 @@ impl EVMCoreService { } } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn create_queue(&self) -> u64 { self.tx_queues.create() } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn remove_queue(&self, queue_id: u64) { self.tx_queues.remove(queue_id); } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 1f2373efd6..7bbbd7a46e 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -99,6 +99,12 @@ impl EVMServices { } } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn construct_block_in_queue( &self, queue_id: u64, @@ -340,6 +346,12 @@ impl EVMServices { }) } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn commit_queue(&self, queue_id: u64) -> Result<(), Box> { { let tx_queue = self.core.tx_queues.get(queue_id)?; @@ -383,6 +395,12 @@ impl EVMServices { Ok(()) } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn push_tx_in_queue( &self, queue_id: u64, diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index 7091c7ca72..37881813cf 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -37,6 +37,12 @@ impl TransactionQueueMap { /// `get_queue_id` generates a unique random ID, creates a new `TransactionQueue` for that ID, /// and then returns the ID. + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn create(&self) -> u64 { let mut rng = rand::thread_rng(); loop { @@ -56,6 +62,12 @@ impl TransactionQueueMap { /// Try to remove and return the `TransactionQueue` associated with the provided /// queue ID. + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn remove(&self, queue_id: u64) -> Option> { self.queues.write().unwrap().remove(&queue_id) } @@ -69,6 +81,11 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn get(&self, queue_id: u64) -> Result> { Ok(Arc::clone( self.queues @@ -93,6 +110,11 @@ impl TransactionQueueMap { /// previous nonce of transactions from the same sender in the queue. /// Returns `QueueError::InvalidFee` if the fee calculation overflows. /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn push_in( &self, queue_id: u64, @@ -121,6 +143,12 @@ impl TransactionQueueMap { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } + /// + /// # Safety + /// + /// Result cannot be used safety unless cs_main lock is taken on C++ side + /// across all usages. Note: To be replaced with a proper lock flow later. + /// pub unsafe fn get_txs_cloned_in(&self, queue_id: u64) -> Result> { self.with_transaction_queue(queue_id, TransactionQueue::get_queue_txs_cloned) } From ef163e34d972a3d4cda7c3bd3e1edf21684c6e6c Mon Sep 17 00:00:00 2001 From: Bushstar Date: Mon, 7 Aug 2023 08:51:45 +0100 Subject: [PATCH 25/25] 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 77d40fc300..38dc1d5cab 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 = [&]() { - 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(); - }; - - 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(); - }; + if (height >= consensus.EunosHeight) + { + CAmount subsidy; + for (const auto& kv : consensus.blockTokenRewards) + { + 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.blockTokenRewardsLegacy) { + 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(); - }; - - // 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); - } + // 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().blockTokenRewards) + { + 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().blockTokenRewardsLegacy) + { + CAmount subsidy = blockReward * kv.second / COIN; + mnview.SubCommunityBalance(kv.first, subsidy); + } } } }