Line data Source code
1 : // Copyright (c) 2023-2025 The Dash Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #ifndef BITCOIN_EVO_CREDITPOOL_H 6 : #define BITCOIN_EVO_CREDITPOOL_H 7 : 8 : #include <consensus/amount.h> 9 : #include <saltedhasher.h> 10 : #include <serialize.h> 11 : #include <sync.h> 12 : #include <threadsafety.h> 13 : #include <tinyformat.h> 14 : #include <unordered_lru_cache.h> 15 : #include <util/ranges_set.h> 16 : 17 : #include <evo/assetlocktx.h> 18 : 19 : #include <gsl/pointers.h> 20 : 21 : #include <optional> 22 : #include <unordered_set> 23 : 24 : class BlockValidationState; 25 : class CBlock; 26 : class CBlockIndex; 27 : class ChainstateManager; 28 : class CEvoDB; 29 : class TxValidationState; 30 : namespace Consensus { 31 : struct Params; 32 : } // namespace Consensus 33 : namespace llmq { 34 : class CQuorumManager; 35 : } // namespace llmq 36 : 37 399460 : struct CCreditPool { 38 399460 : CAmount locked{0}; 39 : 40 : // needs for logic of limits of unlocks 41 399460 : CAmount currentLimit{0}; 42 399460 : CAmount latelyUnlocked{0}; 43 399460 : CRangesSet indexes{}; 44 : 45 : std::string ToString() const; 46 : 47 315 : SERIALIZE_METHODS(CCreditPool, obj) 48 : { 49 105 : READWRITE( 50 : obj.locked, 51 : obj.currentLimit, 52 : obj.latelyUnlocked, 53 : obj.indexes 54 : ); 55 105 : } 56 : }; 57 : 58 : /** 59 : * The class CCreditPoolDiff has 2 purposes: 60 : * - it helps to determine which transaction can be included in new mined block 61 : * within current limits for Asset Unlock transactions and filter duplicated indexes 62 : * - to validate Asset Unlock transaction in mined block. The standalone checks of tx 63 : * such as CheckSpecialTx is not able to do so because at that moment there is no full 64 : * information about Credit Pool limits. 65 : * 66 : * CCreditPoolDiff temporary stores new values `lockedAmount` and `indexes` while 67 : * limits should stay same and depends only on the previous block. 68 : */ 69 : class CCreditPoolDiff { 70 : public: 71 : const CCreditPool pool; 72 : private: 73 : std::unordered_set<uint64_t> newIndexes; 74 : 75 : CAmount sessionLocked{0}; 76 : CAmount sessionUnlocked{0}; 77 : CAmount platformReward{0}; 78 : 79 : public: 80 : explicit CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindexPrev, 81 : const Consensus::Params& consensusParams, 82 : const CAmount blockSubsidy); 83 : 84 : /** 85 : * This function should be called for each Asset Lock/Unlock tx 86 : * to change amount of credit pool 87 : * @return true if transaction can be included in this block 88 : */ 89 : bool ProcessLockUnlockTransaction(const CTransaction& tx, TxValidationState& state); 90 : 91 : /** 92 : * this function returns total amount of credits for the next block 93 : */ 94 135371 : CAmount GetTotalLocked() const { 95 135371 : return pool.locked + sessionLocked - sessionUnlocked + platformReward; 96 : } 97 : 98 : std::string ToString() const { 99 : return strprintf("CCreditPoolDiff(sessionLocked=%lld, sessionUnlocked=%lld, platforomReward=%lld, newIndexes=%lld, pool=%s)", sessionLocked, sessionUnlocked, platformReward, newIndexes.size(), pool.ToString()); 100 : } 101 : 102 : private: 103 : bool Lock(const CTransaction& tx, TxValidationState& state); 104 : bool Unlock(const CTransaction& tx, TxValidationState& state); 105 : }; 106 : 107 : class CCreditPoolManager 108 : { 109 : private: 110 : static constexpr size_t CreditPoolCacheSize = 1000; 111 : Mutex cache_mutex; 112 : Uint256LruHashMap<CCreditPool> creditPoolCache GUARDED_BY(cache_mutex){CreditPoolCacheSize}; 113 : 114 : CEvoDB& evoDb; 115 : const ChainstateManager& m_chainman; 116 : 117 : static constexpr int DISK_SNAPSHOT_PERIOD = 576; // once per day 118 : 119 : public: 120 : static constexpr CAmount LimitAmountLow = 100 * COIN; 121 : static constexpr CAmount LimitAmountHigh = 1000 * COIN; 122 : static constexpr CAmount LimitAmountV22 = 2000 * COIN; 123 : static constexpr CAmount LimitAmountV24 = 4000 * COIN; 124 : 125 : CCreditPoolManager() = delete; 126 : CCreditPoolManager(const CCreditPoolManager&) = delete; 127 : CCreditPoolManager& operator=(const CCreditPoolManager&) = delete; 128 : explicit CCreditPoolManager(CEvoDB& _evoDb, const ChainstateManager& chainman); 129 : ~CCreditPoolManager(); 130 : 131 : /** 132 : * @return CCreditPool with data or with empty depends on activation V19 at that block 133 : * In case if block is invalid the function GetCreditPool throws an exception 134 : * it can happen if there limits of withdrawal (unlock) exceed 135 : */ 136 : CCreditPool GetCreditPool(const CBlockIndex* block) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); 137 : 138 : private: 139 : std::optional<CCreditPool> GetFromCache(const CBlockIndex& block_index) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); 140 : void AddToCache(const uint256& block_hash, int height, const CCreditPool& pool) EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); 141 : 142 : CCreditPool ConstructCreditPool(const gsl::not_null<const CBlockIndex*> block_index, CCreditPool prev) 143 : EXCLUSIVE_LOCKS_REQUIRED(!cache_mutex); 144 : }; 145 : 146 : std::optional<CCreditPoolDiff> GetCreditPoolDiffForBlock(CCreditPoolManager& cpoolman, 147 : const CBlock& block, const CBlockIndex* pindexPrev, const Consensus::Params& consensusParams, 148 : const CAmount blockSubsidy, BlockValidationState& state); 149 : 150 : #endif // BITCOIN_EVO_CREDITPOOL_H