diff --git a/src/masternodes/errors.h b/src/masternodes/errors.h index 62b7606c0d..1c736aaf1c 100644 --- a/src/masternodes/errors.h +++ b/src/masternodes/errors.h @@ -530,8 +530,12 @@ class DeFiErrors { return Res::Err("Accounting mistmatch %s - Old: %s New: %s Accounting: %s", direction, oldBalance, newBalance, accounting); } - static Res AccountingMissmatchEVM(const std::string &token, const std::string &address, const CAmount oldBalance, const CAmount newBalance, const CAmount currentBalance) { - return Res::Err("Accounting mistmatch on EVM side for token on %s: Old: %lld New: %lld Current: %lld", address, oldBalance, newBalance, currentBalance); + static Res AccountingMissmatchEVM(const std::string &address, const CAmount oldBalance, const CAmount newBalance, const CAmount currentBalance) { + return Res::Err("Accounting mistmatch on EVM side for DFI token on %s: Old: %lld New: %lld Current: %lld", address, oldBalance, newBalance, currentBalance); + } + + static Res AccountingMissmatchEVMDST20(const std::string &token, const CAmount oldBalance, const CAmount newBalance, const CAmount currentBalance) { + return Res::Err("Accounting mistmatch on EVM side for DST20 token on %s: Old: %lld New: %lld Current: %lld", token, oldBalance, newBalance, currentBalance); } static Res SettingEVMAttributeFailure() { diff --git a/src/masternodes/govvariables/attributes.h b/src/masternodes/govvariables/attributes.h index 4cdebaad16..75c1c5d432 100644 --- a/src/masternodes/govvariables/attributes.h +++ b/src/masternodes/govvariables/attributes.h @@ -315,6 +315,7 @@ struct CEVMInitialState { CTransferDomainStatsLive transferDomainState; std::map evmBalances; + CStatsTokenBalances dst20EvmTotalSupply; ADD_SERIALIZE_METHODS; @@ -322,6 +323,7 @@ struct CEVMInitialState inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(transferDomainState); READWRITE(evmBalances); + READWRITE(dst20EvmTotalSupply); } }; diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index aa8111fc89..69d9db2dbf 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -1061,7 +1061,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { return Res::Err("tx not from foundation member"); } - if (static_cast(height) >= consensus.BayfrontHeight) { + if (static_cast(height) >= consensus.BayfrontHeight) { if (token.IsPoolShare()) { return Res::Err("Can't manually create 'Liquidity Pool Share' token; use poolpair creation"); } @@ -3897,7 +3897,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { ExtractDestination(dst.address, dest); const auto toAddress = std::get(dest); - // Safety: Safe since validate checks for < 0 + // Safety: Safe since validate checks for < 0 const auto balanceIn = static_cast(dst.amount.nValue); auto tokenId = dst.amount.nTokenId; CrossBoundaryResult result; @@ -3908,7 +3908,6 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { } } else { - CrossBoundaryResult result; evm_try_bridge_dst20(result, evmQueueId, toAddress.ToHexString(), balanceIn, tx.GetHash().GetHex(), tokenId.v, false); if (!result.ok) { return Res::Err("Error bridging DST20: %s", result.reason); @@ -3923,7 +3922,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { ExtractDestination(src.address, dest); const auto fromAddress = std::get(dest); - // Safety: Safe since validate checks for < 0 + // Safety: Safe since validate checks for < 0 const auto balanceIn = static_cast(src.amount.nValue); auto tokenId = dst.amount.nTokenId; if (tokenId == DCT_ID{0}) { diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index a46725df90..a8b80f6b7f 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2413,10 +2413,35 @@ CTransferDomainMessage DecodeTransferDomainMessage(const CTransactionRef& tx, co return CTransferDomainMessage{}; } -void ProcessAccountingStateBeforeBlock(const CBlock &block, const CBlockIndex* pindex, const CChainParams& chainparams, std::map &evmBalances) { +CAmount GetEvmDST20TotalSupply(const DCT_ID& id) { + auto result = XResultValue(evm_try_get_dst20_total_supply(result, id.v)); + if (result) + if (auto balance = *result) + return static_cast(balance); + + return -1; +} + +CAmount GetEvmDFIBalance(const CScript& address, const std::string &stateRoot = std::string()) { + CTxDestination dest; + if (ExtractDestination(address, dest) && dest.index() == WitV16KeyEthHashType) { + const auto keyID = std::get(dest); + auto result = XResultValue(stateRoot.empty() ? evm_try_get_balance(result, keyID.ToHexString()) : evm_try_get_balance_at_state_root(result, keyID.ToHexString(), stateRoot)); + if (result) + if (auto balance = *result) + return static_cast(balance); + } + + return -1; +} + +void ProcessAccountingStateBeforeBlock(const CBlock &block, const CBlockIndex* pindex, CCustomCSView &mnview, const CChainParams& chainparams, CEVMInitialState& evmInitialState) { + std::map &evmBalances = evmInitialState.evmBalances; + CStatsTokenBalances& dst20EvmTotalSupply = evmInitialState.dst20EvmTotalSupply; + + // Storing inital EVM address balances for (const auto &tx : block.vtx) { auto txMessage = DecodeTransferDomainMessage(tx, pindex, chainparams); - CTxDestination dest; for (auto const &[src, dst]: txMessage.transfers){ if (src.amount.nTokenId == DCT_ID{0}) { std::vector> balanceList{ @@ -2425,19 +2450,24 @@ void ProcessAccountingStateBeforeBlock(const CBlock &block, const CBlockIndex* p }; for (auto [domain, domainTarget, address, amount, condition]: balanceList) { if (domain == static_cast(domainTarget) && condition) { - if (ExtractDestination(address, dest) && dest.index() == WitV16KeyEthHashType) { - const auto keyID = std::get(dest); - auto result = XResultValue(evm_try_get_balance(result, keyID.ToHexString())); - if (result) - if (auto balance = *result) { - evmBalances[address].Add({amount.nTokenId, static_cast(balance)}); - } + if (amount.nTokenId == DCT_ID{0}) { + auto balance = GetEvmDFIBalance(address); + if (balance > -1) evmBalances[address].Add({amount.nTokenId, balance}); } } } } } } + + // Storing inital EVM DST20 total supply + mnview.ForEachToken([&](DCT_ID const& id, CTokenImplementation token) { + auto supply = GetEvmDST20TotalSupply(id); + if (supply != -1) + dst20EvmTotalSupply.Add({id, supply}); + + return true; + }); } static Res ProcessAccountingConsensusChecks(const CBlock &block, const CBlockIndex* pindex, CCustomCSView& cache, const CChainParams& chainparams, CEVMInitialState& evmInitialState, const CEvmBlockStatsLive& evmStats, const std::string &stateRoot) { @@ -2446,6 +2476,9 @@ static Res ProcessAccountingConsensusChecks(const CBlock &block, const CBlockInd CStatsTokenBalances totalBlockDVMOut, totalBlockEVMOut, totalBlockDVMIn, totalBlockEVMIn; std::map deltaEvmBalances; + CStatsTokenBalances deltaDST20EvmTotalSupply; + + // Calculating delta balances and supply for (const auto &tx : block.vtx) { auto txMessage = DecodeTransferDomainMessage(tx, pindex, chainparams); for (auto const &[src, dst]: txMessage.transfers){ @@ -2464,21 +2497,33 @@ static Res ProcessAccountingConsensusChecks(const CBlock &block, const CBlockInd if (src.amount.nTokenId == DCT_ID{0}) { if (src.domain == static_cast(VMDomain::EVM)) { deltaEvmBalances[src.address].Sub(src.amount); - } else + } else if (dst.domain == static_cast(VMDomain::EVM)) deltaEvmBalances[dst.address].Add(dst.amount); + } else { + if (src.domain == static_cast(VMDomain::EVM)) { + deltaDST20EvmTotalSupply.Sub(src.amount); + } else if (dst.domain == static_cast(VMDomain::EVM)) { + deltaDST20EvmTotalSupply.Add(dst.amount); + } } } } auto transferDomainStats = attributes->GetValue(CTransferDomainStatsLive::Key, CTransferDomainStatsLive{}); - for (const auto &[id, amount] : transferDomainStats.dvmCurrent.balances) { - if ((id.v == 0 && amount + evmStats.feeBurnt + evmStats.feePriority > 0) || amount > 0) - return DeFiErrors::AccountingMoreDVMInThanOut(id.ToString(), GetDecimalString(amount)); + // Consensus check of sum balance in/out for both domains + // DVM + for (const auto &[id, current] : transferDomainStats.dvmCurrent.balances) { + // Must be less or equal zero + // Only for DFI token - dvmOut must be greater or equal to dvmIn + fees_burnt + fees_priority, dvmCurrent = dvmIn - dvmOut + if ((id.v == 0 && current + evmStats.feeBurnt + evmStats.feePriority > 0) || (id.v !=0 && current > 0)) + return DeFiErrors::AccountingMoreDVMInThanOut(id.ToString(), GetDecimalString(current)); } - for (const auto &[id, amount] : transferDomainStats.evmCurrent.balances) { - if (amount < 0) - return DeFiErrors::AccountingMoreDVMInThanOut(id.ToString(), GetDecimalString(amount)); + // EVM + for (const auto &[id, current] : transferDomainStats.evmCurrent.balances) { + // Must be greater or equal to zero - evmOut must be less then evmIn, evmCurrent = evmIn - evmOut + if (current < 0) + return DeFiErrors::AccountingMoreEVMOurThanIn(id.ToString(), GetDecimalString(current)); } auto totalBlockDVMCurrent = totalBlockDVMIn; @@ -2494,6 +2539,7 @@ static Res ProcessAccountingConsensusChecks(const CBlock &block, const CBlockInd { evmInitialState.transferDomainState.evmCurrent, totalBlockEVMCurrent, transferDomainStats.evmCurrent, "evmCurrent" }, }; + // Transfer accounting tally for (auto [oldState, totalBlock, stats, direction]: statsList) { auto newState = oldState; newState.AddBalances(totalBlock.balances); @@ -2501,25 +2547,34 @@ static Res ProcessAccountingConsensusChecks(const CBlock &block, const CBlockInd return DeFiErrors::AccountingMissmatch(direction, evmInitialState.transferDomainState.ToUniValue().write(), newState.ToString(), transferDomainStats.ToUniValue().write()); } - CTxDestination dest; + // DFI token EVM address balance tally for (auto &[address, delta]: deltaEvmBalances) { auto DFIToken = DCT_ID{0}; auto oldBalance = (evmInitialState.evmBalances.find(address) != evmInitialState.evmBalances.end()) ? evmInitialState.evmBalances[address] : CStatsTokenBalances{}; auto newBalance = oldBalance; + auto balance = GetEvmDFIBalance(address,stateRoot); + newBalance.AddBalances(delta.balances); - if (ExtractDestination(address, dest) && dest.index() == WitV16KeyEthHashType) { - const auto keyID = std::get(dest); - auto result = XResultValue(evm_try_get_balance_at_state_root(result, keyID.ToHexString(), stateRoot)); - if (result) - if (auto balance = *result) { - if (newBalance.balances[DFIToken] != balance) - return DeFiErrors::AccountingMissmatchEVM(DFIToken.ToString(), ScriptToString(address), oldBalance.balances[DFIToken], newBalance.balances[DFIToken], balance); - } - } - } + if (balance > -1 && newBalance.balances[DFIToken] != balance) + return DeFiErrors::AccountingMissmatchEVM(ScriptToString(address), oldBalance.balances[DFIToken], newBalance.balances[DFIToken], balance); + } + + // DST20 token EVM totaly supply tally + deltaDST20EvmTotalSupply.AddBalances(evmInitialState.dst20EvmTotalSupply.balances); + auto res = Res::Ok(); + cache.ForEachToken([&](DCT_ID const& id, CTokenImplementation token) { + auto supply = GetEvmDST20TotalSupply(id); + if (supply != -1) + if (deltaDST20EvmTotalSupply.balances[id] != supply || deltaDST20EvmTotalSupply.balances[id] < 0) { + res = DeFiErrors::AccountingMissmatchEVMDST20(id.ToString(), evmInitialState.dst20EvmTotalSupply.balances[id], deltaDST20EvmTotalSupply.balances[id], supply); + return false; + } - return Res::Ok(); + return true; + }); + + return res; } static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCustomCSView &cache, const CChainParams& chainparams, const uint64_t evmQueueId, CEVMInitialState& evmInitialState) { diff --git a/src/masternodes/validation.h b/src/masternodes/validation.h index 99b82696ca..7563afda39 100644 --- a/src/masternodes/validation.h +++ b/src/masternodes/validation.h @@ -19,7 +19,7 @@ using CreationTxs = std::map &evmBalances); +void ProcessAccountingStateBeforeBlock(const CBlock &block, const CBlockIndex* pindex, CCustomCSView &mnview, const CChainParams& chainparams, CEVMInitialState& evmInitialState); Res ProcessDeFiEventFallible(const CBlock &block, const CBlockIndex *pindex, CCustomCSView &mnview, const CChainParams& chainparams, const uint64_t evmQueueId, const bool isEvmEnabledForBlock, CEVMInitialState& evmInitialState); diff --git a/src/validation.cpp b/src/validation.cpp index ce3a1552c4..44492a049a 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2619,7 +2619,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl if (isEvmEnabledForBlock) { evmInitialState.transferDomainState = attributes->GetValue(CTransferDomainStatsLive::Key, CTransferDomainStatsLive{}); - ProcessAccountingStateBeforeBlock(block, pindex, chainparams, evmInitialState.evmBalances); + ProcessAccountingStateBeforeBlock(block, pindex, mnview, chainparams, evmInitialState); } // Execute TXs