LCOV - code coverage report
Current view: top level - src/llmq - params.h (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 3 4 75.0 %
Date: 2026-06-25 07:23:51 Functions: 4 5 80.0 %

          Line data    Source code
       1             : // Copyright (c) 2021-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_LLMQ_PARAMS_H
       6             : #define BITCOIN_LLMQ_PARAMS_H
       7             : 
       8             : #include <array>
       9             : #include <cstdint>
      10             : #include <string_view>
      11             : 
      12             : namespace Consensus {
      13             : 
      14             : enum class LLMQType : uint8_t {
      15             :     LLMQ_NONE = 0xff,
      16             : 
      17             :     LLMQ_50_60 = 1,  // 50 members, 30 (60%) threshold, one per hour
      18             :     LLMQ_400_60 = 2, // 400 members, 240 (60%) threshold, one every 12 hours
      19             :     LLMQ_400_85 = 3, // 400 members, 340 (85%) threshold, one every 24 hours
      20             :     LLMQ_100_67 = 4, // 100 members, 67 (67%) threshold, one per hour
      21             :     LLMQ_60_75 = 5,  // 60 members, 45 (75%) threshold, one every 12 hours
      22             :     LLMQ_25_67 = 6, // 25 members, 17 (67%) threshold, one per hour
      23             : 
      24             :     // for testing only
      25             :     LLMQ_TEST = 100, // 3 members, 2 (66%) threshold, one per hour. Params might differ when -llmqtestparams is used
      26             : 
      27             :     // for devnets only
      28             :     LLMQ_DEVNET = 101, // 12 members, 6 (50%) threshold, one per hour. Params might differ when -llmqdevnetparams is used
      29             :     LLMQ_DEVNET_PLATFORM = 107, // 12 members, 8 (67%) threshold, one per hour.
      30             : 
      31             :     // for testing activation of new quorums only
      32             :     LLMQ_TEST_V17 = 102, // 3 members, 2 (66%) threshold, one per hour. Params might differ when -llmqtestparams is used
      33             : 
      34             :     // for testing only
      35             :     LLMQ_TEST_DIP0024 = 103,     // 4 members, 3 (75%) threshold, one per hour.
      36             :     LLMQ_TEST_INSTANTSEND = 104, // 3 members, 2 (66%) threshold, one per hour. Params might differ when -llmqtestinstantsendparams is used
      37             :     LLMQ_TEST_PLATFORM = 106,    // 3 members, 2 (66%) threshold, one per hour.
      38             : 
      39             :     // for devnets only. rotated version (v2) for devnets
      40             :     LLMQ_DEVNET_DIP0024 = 105, // 8 members, 4 (50%) threshold, one per hour. Params might differ when -llmqdevnetparams is used
      41             : };
      42             : 
      43             : // Configures a LLMQ and its DKG
      44             : // See https://github.com/dashpay/dips/blob/master/dip-0006.md for more details
      45             : struct LLMQParams {
      46             :     LLMQType type;
      47             : 
      48             :     // not consensus critical, only used in logging, RPC and UI
      49             :     std::string_view name;
      50             : 
      51             :     // Whether this is a DIP0024 quorum or not
      52             :     bool useRotation;
      53             : 
      54             :     // the size of the quorum, e.g. 50 or 400
      55             :     int size;
      56             : 
      57             :     // The minimum number of valid members after the DKG. If less members are determined valid, no commitment can be
      58             :     // created. Should be higher then the threshold to allow some room for failing nodes, otherwise quorum might end up
      59             :     // not being able to ever created a recovered signature if more nodes fail after the DKG
      60             :     int minSize;
      61             : 
      62             :     // The threshold required to recover a final signature. Should be at least 50%+1 of the quorum size. This value
      63             :     // also controls the size of the public key verification vector and has a large influence on the performance of
      64             :     // recovery. It also influences the amount of minimum messages that need to be exchanged for a single signing session.
      65             :     // This value has the most influence on the security of the quorum. The number of total malicious masternodes
      66             :     // required to negatively influence signing sessions highly correlates to the threshold percentage.
      67             :     int threshold;
      68             : 
      69             :     // The interval in number blocks for DKGs and the creation of LLMQs. If set to 24 for example, a DKG will start
      70             :     // every 24 blocks, which is approximately once every hour.
      71             :     int dkgInterval;
      72             : 
      73             :     // The number of blocks per phase in a DKG session. There are 6 phases plus the mining phase that need to be processed
      74             :     // per DKG. Set this value to a number of blocks so that each phase has enough time to propagate all required
      75             :     // messages to all members before the next phase starts. If blocks are produced too fast, whole DKG sessions will
      76             :     // fail.
      77             :     int dkgPhaseBlocks;
      78             : 
      79             :     // The starting block inside the DKG interval for when mining of commitments starts. The value is inclusive.
      80             :     // Starting from this block, the inclusion of (possibly null) commitments is enforced until the first non-null
      81             :     // commitment is mined. The chosen value should be at least 5 * dkgPhaseBlocks so that it starts right after the
      82             :     // finalization phase.
      83             :     int dkgMiningWindowStart;
      84             : 
      85             :     // The ending block inside the DKG interval for when mining of commitments ends. The value is inclusive.
      86             :     // Choose a value so that miners have enough time to receive the commitment and mine it. Also take into consideration
      87             :     // that miners might omit real commitments and revert to always including null commitments. The mining window should
      88             :     // be large enough so that other miners have a chance to produce a block containing a non-null commitment. The window
      89             :     // should at the same time not be too large so that not too much space is wasted with null commitments in case a DKG
      90             :     // session failed.
      91             :     int dkgMiningWindowEnd;
      92             : 
      93             :     // In the complaint phase, members will vote on other members being bad (missing valid contribution). If at least
      94             :     // dkgBadVotesThreshold have voted for another member to be bad, it will considered to be bad by all other members
      95             :     // as well. This serves as a protection against late-comers who send their contribution on the bring of
      96             :     // phase-transition, which would otherwise result in inconsistent views of the valid members set
      97             :     int dkgBadVotesThreshold;
      98             : 
      99             :     // Number of quorums to consider "active" for signing sessions
     100             :     int signingActiveQuorumCount;
     101             : 
     102             :     // Used for intra-quorum communication. This is the number of quorums for which we should keep old connections.
     103             :     // For non-rotated quorums it should be at least one more than the active quorums set.
     104             :     // For rotated quorums it should be equal to 2 x active quorums set.
     105             :     int keepOldConnections;
     106             : 
     107             :     // The number of quorums for which we should keep keys. Usually it's equal to signingActiveQuorumCount * 2.
     108             :     // Unlike for other quorum types we want to keep data (secret key shares and vvec)
     109             :     // for Platform quorums for much longer because Platform can be restarted and
     110             :     // it must be able to re-sign stuff.
     111             : 
     112             :     int keepOldKeys;
     113             : 
     114             :     // How many members should we try to send all sigShares to before we give up.
     115             :     int recoveryMembers;
     116             : public:
     117          21 :     [[nodiscard]] constexpr int max_cycles(int quorums_count) const
     118             :     {
     119          21 :         return useRotation ? quorums_count / signingActiveQuorumCount : quorums_count;
     120             :     }
     121             : 
     122             :     // For how many blocks recent DKG info should be kept
     123           8 :     [[nodiscard]] constexpr int max_store_depth() const { return max_cycles(keepOldKeys) * dkgInterval; }
     124           0 :     [[nodiscard]] constexpr bool is_single_member() const { return size == 1; }
     125             : };
     126             : 
     127             : //static_assert(std::is_trivial_v<Consensus::LLMQParams>, "LLMQParams is not a trivial type");
     128             : static_assert(std::is_trivially_copyable_v<Consensus::LLMQParams>, "LLMQParams is not trivially copyable");
     129             : //static_assert(std::is_trivially_default_constructible_v<Consensus::LLMQParams>, "LLMQParams is not trivially default constructible");
     130             : static_assert(std::is_trivially_assignable_v<Consensus::LLMQParams, Consensus::LLMQParams>, "LLMQParams is not trivially assignable");
     131             : 
     132             : 
     133             : static constexpr std::array<LLMQParams, 14> available_llmqs = {
     134             : 
     135             :     /**
     136             :      * llmq_test
     137             :      * This quorum is only used for testing
     138             :      *
     139             :      */
     140             :     LLMQParams{
     141             :         .type = LLMQType::LLMQ_TEST,
     142             :         .name = "llmq_test",
     143             :         .useRotation = false,
     144             :         .size = 3,
     145             :         .minSize = 2,
     146             :         .threshold = 2,
     147             : 
     148             :         .dkgInterval = 24, // one DKG per hour
     149             :         .dkgPhaseBlocks = 2,
     150             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     151             :         .dkgMiningWindowEnd = 18,
     152             :         .dkgBadVotesThreshold = 2,
     153             : 
     154             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     155             : 
     156             :         .keepOldConnections = 3,
     157             :         .keepOldKeys = 4,
     158             :         .recoveryMembers = 3,
     159             :     },
     160             : 
     161             :     /**
     162             :      * llmq_test_instantsend (same as llmq_test but used for InstantSend exclusively)
     163             :      * This quorum is only used for testing
     164             :      *
     165             :      */
     166             :     LLMQParams{
     167             :         .type = LLMQType::LLMQ_TEST_INSTANTSEND,
     168             :         .name = "llmq_test_instantsend",
     169             :         .useRotation = false,
     170             :         .size = 3,
     171             :         .minSize = 2,
     172             :         .threshold = 2,
     173             : 
     174             :         .dkgInterval = 24, // one DKG per hour
     175             :         .dkgPhaseBlocks = 2,
     176             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     177             :         .dkgMiningWindowEnd = 18,
     178             :         .dkgBadVotesThreshold = 2,
     179             : 
     180             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     181             : 
     182             :         .keepOldConnections = 3,
     183             :         .keepOldKeys = 4,
     184             :         .recoveryMembers = 3,
     185             :     },
     186             : 
     187             :     /**
     188             :      * llmq_test (Dash Core 0.17) aka llmq_test_v17
     189             :      * This quorum is only used for testing
     190             :      *
     191             :      */
     192             :     LLMQParams{
     193             :         .type = LLMQType::LLMQ_TEST_V17,
     194             :         .name = "llmq_test_v17",
     195             :         .useRotation = false,
     196             :         .size = 3,
     197             :         .minSize = 2,
     198             :         .threshold = 2,
     199             : 
     200             :         .dkgInterval = 24, // one DKG per hour
     201             :         .dkgPhaseBlocks = 2,
     202             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     203             :         .dkgMiningWindowEnd = 18,
     204             :         .dkgBadVotesThreshold = 2,
     205             : 
     206             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     207             : 
     208             :         .keepOldConnections = 3,
     209             :         .keepOldKeys = 4,
     210             :         .recoveryMembers = 3,
     211             :     },
     212             : 
     213             :     /**
     214             :      * llmq_test_dip0024
     215             :      * This quorum is only used for testing
     216             :      *
     217             :      */
     218             :     LLMQParams{
     219             :         .type = LLMQType::LLMQ_TEST_DIP0024,
     220             :         .name = "llmq_test_dip0024",
     221             :         .useRotation = true,
     222             :         .size = 4,
     223             :         .minSize = 4,
     224             :         .threshold = 3,
     225             : 
     226             :         .dkgInterval = 24, // DKG cycle
     227             :         .dkgPhaseBlocks = 2,
     228             :         .dkgMiningWindowStart = 12, // signingActiveQuorumCount + dkgPhaseBlocks * 5 = after finalization
     229             :         .dkgMiningWindowEnd = 20,
     230             :         .dkgBadVotesThreshold = 2,
     231             : 
     232             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     233             : 
     234             :         .keepOldConnections = 4,
     235             :         .keepOldKeys = 4,
     236             :         .recoveryMembers = 3,
     237             :     },
     238             : 
     239             :     /**
     240             :      * llmq_test_platform
     241             :      * This quorum is only used for testing
     242             :      *
     243             :      */
     244             :     LLMQParams{
     245             :         .type = LLMQType::LLMQ_TEST_PLATFORM,
     246             :         .name = "llmq_test_platform",
     247             :         .useRotation = false,
     248             :         .size = 3,
     249             :         .minSize = 2,
     250             :         .threshold = 2,
     251             : 
     252             :         .dkgInterval = 24, // DKG cycle
     253             :         .dkgPhaseBlocks = 2,
     254             :         .dkgMiningWindowStart = 10, // signingActiveQuorumCount + dkgPhaseBlocks * 5 = after finalization
     255             :         .dkgMiningWindowEnd = 18,
     256             :         .dkgBadVotesThreshold = 2,
     257             : 
     258             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     259             : 
     260             :         .keepOldConnections = 4,
     261             :         .keepOldKeys = 24 * 30 * 2, // 2 months of quorums
     262             :         .recoveryMembers = 3,
     263             :     },
     264             : 
     265             :     /**
     266             :      * llmq_devnet
     267             :      * This quorum is only used for testing on devnets
     268             :      *
     269             :      */
     270             :     LLMQParams{
     271             :         .type = LLMQType::LLMQ_DEVNET,
     272             :         .name = "llmq_devnet",
     273             :         .useRotation = false,
     274             :         .size = 12,
     275             :         .minSize = 7,
     276             :         .threshold = 6,
     277             : 
     278             :         .dkgInterval = 24, // one DKG per hour
     279             :         .dkgPhaseBlocks = 2,
     280             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     281             :         .dkgMiningWindowEnd = 18,
     282             :         .dkgBadVotesThreshold = 7,
     283             : 
     284             :         .signingActiveQuorumCount = 4, // just a few ones to allow easier testing
     285             : 
     286             :         .keepOldConnections = 5,
     287             :         .keepOldKeys = 8,
     288             :         .recoveryMembers = 6,
     289             :     },
     290             : 
     291             :     /**
     292             :      * llmq_devnet_dip0024
     293             :      * This quorum is only used for testing on devnets
     294             :      *
     295             :      */
     296             :     LLMQParams{
     297             :         .type = LLMQType::LLMQ_DEVNET_DIP0024,
     298             :         .name = "llmq_devnet_dip0024",
     299             :         .useRotation = true,
     300             :         .size = 8,
     301             :         .minSize = 6,
     302             :         .threshold = 4,
     303             : 
     304             :         .dkgInterval = 48, // DKG cycle
     305             :         .dkgPhaseBlocks = 2,
     306             :         .dkgMiningWindowStart = 12, // signingActiveQuorumCount + dkgPhaseBlocks * 5 = after finalization
     307             :         .dkgMiningWindowEnd = 20,
     308             :         .dkgBadVotesThreshold = 7,
     309             : 
     310             :         .signingActiveQuorumCount = 2, // just a few ones to allow easier testing
     311             : 
     312             :         .keepOldConnections = 4,
     313             :         .keepOldKeys = 4,
     314             :         .recoveryMembers = 4,
     315             :     },
     316             : 
     317             :     /**
     318             :      * llmq_devnet_platform
     319             :      * This quorum is only used for testing on devnets
     320             :      *
     321             :      */
     322             :     LLMQParams{
     323             :         .type = LLMQType::LLMQ_DEVNET_PLATFORM,
     324             :         .name = "llmq_devnet_platform",
     325             :         .useRotation = false,
     326             :         .size = 12,
     327             :         .minSize = 9,
     328             :         .threshold = 8,
     329             : 
     330             :         .dkgInterval = 24, // one DKG per hour
     331             :         .dkgPhaseBlocks = 2,
     332             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     333             :         .dkgMiningWindowEnd = 18,
     334             :         .dkgBadVotesThreshold = 7,
     335             : 
     336             :         .signingActiveQuorumCount = 4, // just a few ones to allow easier testing
     337             : 
     338             :         .keepOldConnections = 5,
     339             :         .keepOldKeys = 24 * 30 * 2, // 2 months of quorums
     340             :         .recoveryMembers = 6,
     341             :     },
     342             : 
     343             :     /**
     344             :      * llmq_50_60
     345             :      * This quorum is deployed on mainnet and requires
     346             :      * 40 - 50 participants
     347             :      *
     348             :      */
     349             :     LLMQParams{
     350             :         .type = LLMQType::LLMQ_50_60,
     351             :         .name = "llmq_50_60",
     352             :         .useRotation = false,
     353             :         .size = 50,
     354             :         .minSize = 40,
     355             :         .threshold = 30,
     356             : 
     357             :         .dkgInterval = 24, // one DKG per hour
     358             :         .dkgPhaseBlocks = 2,
     359             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     360             :         .dkgMiningWindowEnd = 18,
     361             :         .dkgBadVotesThreshold = 40,
     362             : 
     363             :         .signingActiveQuorumCount = 24, // a full day worth of LLMQs
     364             :         .keepOldConnections = 25,
     365             :         .keepOldKeys = 48,
     366             :         .recoveryMembers = 25,
     367             :     },
     368             : 
     369             :     /**
     370             :      * llmq_60_75
     371             :      * This quorum is deployed on mainnet and requires
     372             :      * 50 - 60 participants
     373             :      *
     374             :      */
     375             :     LLMQParams{
     376             :         .type = LLMQType::LLMQ_60_75,
     377             :         .name = "llmq_60_75",
     378             :         .useRotation = true,
     379             :         .size = 60,
     380             :         .minSize = 50,
     381             :         .threshold = 45,
     382             : 
     383             :         .dkgInterval = 24 * 12, // DKG cycle every 12 hours
     384             :         .dkgPhaseBlocks = 2,
     385             :         .dkgMiningWindowStart = 42, // signingActiveQuorumCount + dkgPhaseBlocks * 5 = after finalization
     386             :         .dkgMiningWindowEnd = 50,
     387             :         .dkgBadVotesThreshold = 48,
     388             : 
     389             :         .signingActiveQuorumCount = 32,
     390             :         .keepOldConnections = 64,
     391             :         .keepOldKeys = 64,
     392             :         .recoveryMembers = 25,
     393             :     },
     394             : 
     395             :     /**
     396             :      * llmq_400_60
     397             :      * This quorum is deployed on mainnet and requires
     398             :      * 300 - 400 participants
     399             :      *
     400             :      */
     401             :     LLMQParams{
     402             :         .type = LLMQType::LLMQ_400_60,
     403             :         .name = "llmq_400_60",
     404             :         .useRotation = false,
     405             :         .size = 400,
     406             :         .minSize = 300,
     407             :         .threshold = 240,
     408             : 
     409             :         .dkgInterval = 24 * 12, // one DKG every 12 hours
     410             :         .dkgPhaseBlocks = 4,
     411             :         .dkgMiningWindowStart = 20, // dkgPhaseBlocks * 5 = after finalization
     412             :         .dkgMiningWindowEnd = 28,
     413             :         .dkgBadVotesThreshold = 300,
     414             : 
     415             :         .signingActiveQuorumCount = 4, // two days worth of LLMQs
     416             : 
     417             :         .keepOldConnections = 5,
     418             :         .keepOldKeys = 8,
     419             :         .recoveryMembers = 100,
     420             :     },
     421             : 
     422             :     /**
     423             :      * llmq_400_85
     424             :      * This quorum is deployed on mainnet and requires
     425             :      * 300 - 400 participants _with_ a supermajority
     426             :      *
     427             :      * Used for deployment and min-proto-version signalling
     428             :      */
     429             :     LLMQParams{
     430             :         .type = LLMQType::LLMQ_400_85,
     431             :         .name = "llmq_400_85",
     432             :         .useRotation = false,
     433             :         .size = 400,
     434             :         .minSize = 350,
     435             :         .threshold = 340,
     436             : 
     437             :         .dkgInterval = 24 * 24, // one DKG every 24 hours
     438             :         .dkgPhaseBlocks = 4,
     439             :         .dkgMiningWindowStart = 20, // dkgPhaseBlocks * 5 = after finalization
     440             :         .dkgMiningWindowEnd = 48,   // give it a larger mining window to make sure it is mined
     441             :         .dkgBadVotesThreshold = 300,
     442             : 
     443             :         .signingActiveQuorumCount = 4, // four days worth of LLMQs
     444             : 
     445             :         .keepOldConnections = 5,
     446             :         .keepOldKeys = 8,
     447             :         .recoveryMembers = 100,
     448             :     },
     449             : 
     450             :     /**
     451             :      * llmq_100_67
     452             :      * This quorum is deployed on mainnet and requires
     453             :      * 80 - 100 participants
     454             :      *
     455             :      * Used by Dash Platform
     456             :      */
     457             :     LLMQParams{
     458             :         .type = LLMQType::LLMQ_100_67,
     459             :         .name = "llmq_100_67",
     460             :         .useRotation = false,
     461             :         .size = 100,
     462             :         .minSize = 80,
     463             :         .threshold = 67,
     464             : 
     465             :         .dkgInterval = 24, // one DKG per hour
     466             :         .dkgPhaseBlocks = 2,
     467             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     468             :         .dkgMiningWindowEnd = 18,
     469             :         .dkgBadVotesThreshold = 80,
     470             : 
     471             :         .signingActiveQuorumCount = 24, // a full day worth of LLMQs
     472             : 
     473             :         .keepOldConnections = 25,
     474             :         .keepOldKeys = 24 * 30 * 2, // 2 months of quorums
     475             :         .recoveryMembers = 50,
     476             :     },
     477             : 
     478             :     /**
     479             :      * llmq_25_67
     480             :      * This quorum is deployed on Testnet and requires
     481             :      * 25 participants
     482             :      *
     483             :      * Used by Dash Platform
     484             :      */
     485             :     LLMQParams{
     486             :         .type = LLMQType::LLMQ_25_67,
     487             :         .name = "llmq_25_67",
     488             :         .useRotation = false,
     489             :         .size = 25,
     490             :         .minSize = 22,
     491             :         .threshold = 17,
     492             : 
     493             :         .dkgInterval = 24, // one DKG per hour
     494             :         .dkgPhaseBlocks = 2,
     495             :         .dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
     496             :         .dkgMiningWindowEnd = 18,
     497             :         .dkgBadVotesThreshold = 22,
     498             : 
     499             :         .signingActiveQuorumCount = 24, // a full day worth of LLMQs
     500             : 
     501             :         .keepOldConnections = 25,
     502             :         .keepOldKeys = 24 * 30 * 2, // 2 months of quorums
     503             :         .recoveryMembers = 12,
     504             :     },
     505             : 
     506             : }; // available_llmqs
     507             : 
     508             : } // namespace Consensus
     509             : 
     510             : // This must be outside of all namespaces. We must also duplicate the forward declaration of is_serializable_enum to
     511             : // avoid inclusion of serialize.h here.
     512             : template<typename T> struct is_serializable_enum;
     513             : template<> struct is_serializable_enum<Consensus::LLMQType> : std::true_type {};
     514             : 
     515             : #endif // BITCOIN_LLMQ_PARAMS_H

Generated by: LCOV version 1.16