2023-01-12 22:26:21 +01:00
// Copyright (c) 2018-2023 The Dash Core developers
2018-11-23 15:42:09 +01:00
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2021-10-25 15:55:34 +02:00
# include <llmq/utils.h>
2020-03-19 23:46:56 +01:00
# include <llmq/quorums.h>
2022-04-16 16:46:04 +02:00
# include <llmq/snapshot.h>
2018-11-23 15:42:09 +01:00
2021-04-16 05:41:16 +02:00
# include <bls/bls.h>
2021-10-25 15:55:34 +02:00
# include <chainparams.h>
2023-12-04 09:40:01 +01:00
# include <deploymentstatus.h>
2021-04-16 05:41:16 +02:00
# include <evo/deterministicmns.h>
# include <evo/evodb.h>
2021-10-25 15:55:34 +02:00
# include <masternode/meta.h>
# include <net.h>
2020-03-19 23:46:56 +01:00
# include <random.h>
2020-03-16 11:09:54 +01:00
# include <spork.h>
2022-04-26 01:40:41 +02:00
# include <util/irange.h>
2021-12-21 13:05:29 +01:00
# include <util/ranges.h>
2023-10-23 17:39:39 +02:00
# include <util/time.h>
2023-02-20 11:12:12 +01:00
# include <util/underlying.h>
2020-03-19 23:46:56 +01:00
# include <validation.h>
2021-04-16 05:41:16 +02:00
# include <versionbits.h>
2018-11-23 15:42:09 +01:00
fix: add missing includes and remove obsolete includes (#5562)
## Issue being fixed or feature implemented
Some headers or modules are used objects from STL without including it
directly, it cause compilation failures on some platforms for some
specific compilers such as #5554
## What was done?
Added missing includes and removed obsolete includes for `optional`,
`deque`, `tuple`, `unordered_set`, `unordered_map`, `set` and `atomic`.
Please, note, that this PR doesn't cover all cases, only cases when it
is obviously missing or obviously obsolete.
Also most of changes belongs to to dash specific code; but for cases of
original bitcoin code I keep it untouched, such as missing <map> in
`src/psbt.h`
I used this script to get a list of files/headers which looks suspicious
`./headers-scanner.sh std::optional optional`:
```bash
#!/bin/bash
set -e
function check_includes() {
obj=$1
header=$2
file=$3
used=0
included=0
grep "$obj" "$file" >/dev/null 2>/dev/null && used=1
grep "include <$header>" $file >/dev/null 2>/dev/null && included=1
if [ $used == 1 ] && [ $included == 0 ]
then echo "missing <$header> in $file"
fi
if [ $used == 0 ] && [ $included == 1 ]
then echo "obsolete <$header> in $file"
fi
}
export -f check_includes
obj=$1
header=$2
find src \( -name '*.h' -or -name '*.cpp' -or -name '*.hpp' \) -exec bash -c 'check_includes "$0" "$1" "$2"' "$obj" "$header" {} \;
```
## How Has This Been Tested?
Built code locally
## Breaking Changes
n/a
## Checklist:
- [x] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation
- [x] I have assigned this pull request to a milestone
2023-09-07 16:07:02 +02:00
# include <atomic>
2022-04-16 16:46:04 +02:00
# include <optional>
2023-12-04 09:03:51 +01:00
// TODO remove this const
2023-03-01 18:42:33 +01:00
static constexpr int TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT = 847000 ;
2023-05-17 19:27:15 +02:00
/**
* Forward declarations
*/
std : : optional < std : : pair < CBLSSignature , uint32_t > > GetNonNullCoinbaseChainlock ( const CBlockIndex * pindex ) ;
2018-11-23 15:42:09 +01:00
namespace llmq
{
2020-12-29 11:30:50 +01:00
VersionBitsCache llmq_versionbitscache ;
2022-08-02 19:14:25 +02:00
namespace utils
{
2023-07-10 17:13:42 +02:00
//QuorumMembers per quorumIndex at heights H-Cycle, H-2Cycles, H-3Cycles
struct PreviousQuorumQuarters {
std : : vector < std : : vector < CDeterministicMNCPtr > > quarterHMinusC ;
std : : vector < std : : vector < CDeterministicMNCPtr > > quarterHMinus2C ;
std : : vector < std : : vector < CDeterministicMNCPtr > > quarterHMinus3C ;
explicit PreviousQuorumQuarters ( size_t s ) :
quarterHMinusC ( s ) , quarterHMinus2C ( s ) , quarterHMinus3C ( s ) { }
} ;
2023-02-11 03:25:11 +01:00
// Forward declarations
static std : : vector < CDeterministicMNCPtr > ComputeQuorumMembers ( Consensus : : LLMQType llmqType , const CBlockIndex * pQuorumBaseBlockIndex ) ;
2023-02-20 11:12:49 +01:00
static std : : vector < std : : vector < CDeterministicMNCPtr > > ComputeQuorumMembersByQuarterRotation ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pCycleQuorumBaseBlockIndex ) ;
2023-02-11 03:25:11 +01:00
2023-05-20 16:21:21 +02:00
static std : : vector < std : : vector < CDeterministicMNCPtr > > BuildNewQuorumQuarterMembers ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pCycleQuorumBaseBlockIndex , const PreviousQuorumQuarters & quarters ) ;
2023-02-11 03:25:11 +01:00
static PreviousQuorumQuarters GetPreviousQuorumQuarterMembers ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pBlockHMinusCIndex , const CBlockIndex * pBlockHMinus2CIndex , const CBlockIndex * pBlockHMinus3CIndex , int nHeight ) ;
2023-05-20 16:21:21 +02:00
static std : : vector < std : : vector < CDeterministicMNCPtr > > GetQuorumQuarterMembersBySnapshot ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pCycleQuorumBaseBlockIndex , const llmq : : CQuorumSnapshot & snapshot , int nHeights ) ;
static std : : pair < CDeterministicMNList , CDeterministicMNList > GetMNUsageBySnapshot ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pCycleQuorumBaseBlockIndex , const llmq : : CQuorumSnapshot & snapshot , int nHeight ) ;
2023-02-11 03:25:11 +01:00
2023-05-20 16:21:21 +02:00
static void BuildQuorumSnapshot ( const Consensus : : LLMQParams & llmqParams , const CDeterministicMNList & allMns , const CDeterministicMNList & mnUsedAtH , std : : vector < CDeterministicMNCPtr > & sortedCombinedMns , CQuorumSnapshot & quorumSnapshot , int nHeight , std : : vector < int > & skipList , const CBlockIndex * pCycleQuorumBaseBlockIndex ) ;
2023-02-11 03:25:11 +01:00
2023-11-10 15:33:21 +01:00
uint256 GetHashModifier ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pCycleQuorumBaseBlockIndex )
2023-05-17 19:27:15 +02:00
{
2023-05-20 16:21:21 +02:00
ASSERT_IF_DEBUG ( pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval = = 0 ) ;
const CBlockIndex * pWorkBlockIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 8 ) ;
2023-05-17 19:27:15 +02:00
if ( IsV20Active ( pWorkBlockIndex ) ) {
// v20 is active: calculate modifier using the new way.
auto cbcl = GetNonNullCoinbaseChainlock ( pWorkBlockIndex ) ;
if ( cbcl . has_value ( ) ) {
// We have a non-null CL signature: calculate modifier using this CL signature
auto & [ bestCLSignature , bestCLHeightDiff ] = cbcl . value ( ) ;
return : : SerializeHash ( std : : make_tuple ( llmqParams . type , pWorkBlockIndex - > nHeight , bestCLSignature ) ) ;
}
// No non-null CL signature found in coinbase: calculate modifier using block hash only
return : : SerializeHash ( std : : make_pair ( llmqParams . type , pWorkBlockIndex - > GetBlockHash ( ) ) ) ;
}
// v20 isn't active yet: calculate modifier using the usual way
if ( llmqParams . useRotation ) {
return : : SerializeHash ( std : : make_pair ( llmqParams . type , pWorkBlockIndex - > GetBlockHash ( ) ) ) ;
}
2023-05-20 16:21:21 +02:00
return : : SerializeHash ( std : : make_pair ( llmqParams . type , pCycleQuorumBaseBlockIndex - > GetBlockHash ( ) ) ) ;
2023-05-17 19:27:15 +02:00
}
2023-11-10 15:33:21 +01:00
std : : vector < CDeterministicMNCPtr > GetAllQuorumMembers ( Consensus : : LLMQType llmqType , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex , bool reset_cache )
2022-04-16 16:46:04 +02:00
{
2023-04-25 13:51:26 +02:00
static RecursiveMutex cs_members ;
2022-04-16 16:46:04 +02:00
static std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , std : : vector < CDeterministicMNCPtr > , StaticSaltedHasher > > mapQuorumMembers GUARDED_BY ( cs_members ) ;
2023-04-25 13:51:26 +02:00
static RecursiveMutex cs_indexed_members ;
2022-04-16 16:46:04 +02:00
static std : : map < Consensus : : LLMQType , unordered_lru_cache < std : : pair < uint256 , int > , std : : vector < CDeterministicMNCPtr > , StaticSaltedHasher > > mapIndexedQuorumMembers GUARDED_BY ( cs_indexed_members ) ;
2022-09-22 13:14:48 +02:00
if ( ! IsQuorumTypeEnabled ( llmqType , * llmq : : quorumManager , pQuorumBaseBlockIndex - > pprev ) ) {
2020-12-10 00:08:05 +01:00
return { } ;
}
2021-03-29 20:11:26 +02:00
std : : vector < CDeterministicMNCPtr > quorumMembers ;
{
LOCK ( cs_members ) ;
if ( mapQuorumMembers . empty ( ) ) {
InitQuorumsCache ( mapQuorumMembers ) ;
}
2022-08-13 18:10:32 +02:00
if ( reset_cache ) {
mapQuorumMembers [ llmqType ] . clear ( ) ;
} else if ( mapQuorumMembers [ llmqType ] . get ( pQuorumBaseBlockIndex - > GetBlockHash ( ) , quorumMembers ) ) {
2021-03-29 20:11:26 +02:00
return quorumMembers ;
}
}
2023-03-13 17:11:17 +01:00
const auto & llmq_params_opt = GetLLMQParams ( llmqType ) ;
assert ( llmq_params_opt . has_value ( ) ) ;
const auto & llmq_params = llmq_params_opt . value ( ) ;
if ( IsQuorumRotationEnabled ( llmq_params , pQuorumBaseBlockIndex ) ) {
2022-04-16 16:46:04 +02:00
if ( LOCK ( cs_indexed_members ) ; mapIndexedQuorumMembers . empty ( ) ) {
InitQuorumsCache ( mapIndexedQuorumMembers ) ;
}
/*
* Quorums created with rotation are now created in a different way . All signingActiveQuorumCount are created during the period of dkgInterval .
2022-04-25 21:13:24 +02:00
* But they are not created exactly in the same block , they are spread overtime : one quorum in each block until all signingActiveQuorumCount are created .
2022-04-16 16:46:04 +02:00
* The new concept of quorumIndex is introduced in order to identify them .
2022-04-25 21:13:24 +02:00
* In every dkgInterval blocks ( also called CycleQuorumBaseBlock ) , the spread quorum creation starts like this :
2022-04-16 16:46:04 +02:00
* For quorumIndex = 0 : signingActiveQuorumCount
* Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex
*/
2023-03-13 17:11:17 +01:00
int quorumIndex = pQuorumBaseBlockIndex - > nHeight % llmq_params . dkgInterval ;
if ( quorumIndex > = llmq_params . signingActiveQuorumCount ) {
2022-04-16 16:46:04 +02:00
return { } ;
}
int cycleQuorumBaseHeight = pQuorumBaseBlockIndex - > nHeight - quorumIndex ;
const CBlockIndex * pCycleQuorumBaseBlockIndex = pQuorumBaseBlockIndex - > GetAncestor ( cycleQuorumBaseHeight ) ;
/*
* Since mapQuorumMembers stores Quorum members per block hash , and we don ' t know yet the block hashes of blocks for all quorumIndexes ( since these blocks are not created yet )
* We store them in a second cache mapIndexedQuorumMembers which stores them by { CycleQuorumBaseBlockHash , quorumIndex }
*/
2022-08-13 18:10:32 +02:00
if ( reset_cache ) {
LOCK ( cs_indexed_members ) ;
mapIndexedQuorumMembers [ llmqType ] . clear ( ) ;
} else if ( LOCK ( cs_indexed_members ) ; mapIndexedQuorumMembers [ llmqType ] . get ( std : : pair ( pCycleQuorumBaseBlockIndex - > GetBlockHash ( ) , quorumIndex ) , quorumMembers ) ) {
2022-06-15 23:00:43 +02:00
LOCK ( cs_members ) ;
mapQuorumMembers [ llmqType ] . insert ( pQuorumBaseBlockIndex - > GetBlockHash ( ) , quorumMembers ) ;
return quorumMembers ;
}
2022-04-16 16:46:04 +02:00
2023-03-13 17:11:17 +01:00
auto q = ComputeQuorumMembersByQuarterRotation ( llmq_params , pCycleQuorumBaseBlockIndex ) ;
2022-04-16 16:46:04 +02:00
LOCK ( cs_indexed_members ) ;
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( q . size ( ) ) ) {
2022-04-16 16:46:04 +02:00
mapIndexedQuorumMembers [ llmqType ] . insert ( std : : make_pair ( pCycleQuorumBaseBlockIndex - > GetBlockHash ( ) , i ) , q [ i ] ) ;
}
quorumMembers = q [ quorumIndex ] ;
} else {
quorumMembers = ComputeQuorumMembers ( llmqType , pQuorumBaseBlockIndex ) ;
}
2021-03-29 20:11:26 +02:00
LOCK ( cs_members ) ;
2022-04-16 16:46:04 +02:00
mapQuorumMembers [ llmqType ] . insert ( pQuorumBaseBlockIndex - > GetBlockHash ( ) , quorumMembers ) ;
2021-03-29 20:11:26 +02:00
return quorumMembers ;
2018-11-23 15:42:09 +01:00
}
2022-08-02 19:14:25 +02:00
std : : vector < CDeterministicMNCPtr > ComputeQuorumMembers ( Consensus : : LLMQType llmqType , const CBlockIndex * pQuorumBaseBlockIndex )
2022-04-16 16:46:04 +02:00
{
2023-08-17 21:01:12 +02:00
bool EvoOnly = ( Params ( ) . GetConsensus ( ) . llmqTypePlatform = = llmqType ) & & IsV19Active ( pQuorumBaseBlockIndex ) ;
2023-03-13 17:11:17 +01:00
const auto & llmq_params_opt = GetLLMQParams ( llmqType ) ;
assert ( llmq_params_opt . has_value ( ) ) ;
2023-05-20 16:21:21 +02:00
if ( llmq_params_opt - > useRotation | | pQuorumBaseBlockIndex - > nHeight % llmq_params_opt - > dkgInterval ! = 0 ) {
2023-05-17 19:27:15 +02:00
ASSERT_IF_DEBUG ( false ) ;
return { } ;
}
const CBlockIndex * pWorkBlockIndex = IsV20Active ( pQuorumBaseBlockIndex ) ?
pQuorumBaseBlockIndex - > GetAncestor ( pQuorumBaseBlockIndex - > nHeight - 8 ) :
pQuorumBaseBlockIndex ;
const auto modifier = GetHashModifier ( llmq_params_opt . value ( ) , pQuorumBaseBlockIndex ) ;
auto allMns = deterministicMNManager - > GetListForBlock ( pWorkBlockIndex ) ;
2023-08-17 21:01:12 +02:00
return allMns . CalculateQuorum ( llmq_params_opt - > size , modifier , EvoOnly ) ;
2022-04-16 16:46:04 +02:00
}
2023-02-20 11:12:49 +01:00
std : : vector < std : : vector < CDeterministicMNCPtr > > ComputeQuorumMembersByQuarterRotation ( const Consensus : : LLMQParams & llmqParams , const CBlockIndex * pCycleQuorumBaseBlockIndex )
2022-04-16 16:46:04 +02:00
{
2023-02-20 11:12:49 +01:00
const Consensus : : LLMQType llmqType = llmqParams . type ;
2022-04-16 16:46:04 +02:00
const int cycleLength = llmqParams . dkgInterval ;
2023-05-20 16:21:21 +02:00
if ( ! llmqParams . useRotation | | pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval ! = 0 ) {
ASSERT_IF_DEBUG ( false ) ;
return { } ;
}
2022-04-16 16:46:04 +02:00
const CBlockIndex * pBlockHMinusCIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - cycleLength ) ;
const CBlockIndex * pBlockHMinus2CIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 2 * cycleLength ) ;
const CBlockIndex * pBlockHMinus3CIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 3 * cycleLength ) ;
const CBlockIndex * pWorkBlockIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 8 ) ;
auto allMns = deterministicMNManager - > GetListForBlock ( pWorkBlockIndex ) ;
2023-02-20 11:12:12 +01:00
LogPrint ( BCLog : : LLMQ , " ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d] \n " , ToUnderlying ( llmqType ) , pCycleQuorumBaseBlockIndex - > nHeight , allMns . GetValidMNsCount ( ) ) ;
2022-04-16 16:46:04 +02:00
PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers ( llmqParams , pBlockHMinusCIndex , pBlockHMinus2CIndex , pBlockHMinus3CIndex , pCycleQuorumBaseBlockIndex - > nHeight ) ;
2023-02-11 03:25:11 +01:00
size_t nQuorums = static_cast < size_t > ( llmqParams . signingActiveQuorumCount ) ;
std : : vector < std : : vector < CDeterministicMNCPtr > > quorumMembers { nQuorums } ;
2022-04-16 16:46:04 +02:00
2022-08-02 19:14:25 +02:00
auto newQuarterMembers = BuildNewQuorumQuarterMembers ( llmqParams , pCycleQuorumBaseBlockIndex , previousQuarters ) ;
2022-04-16 16:46:04 +02:00
//TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice
//assert (!newQuarterMembers.empty());
2022-06-07 23:32:37 +02:00
if ( LogAcceptCategory ( BCLog : : LLMQ ) ) {
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( nQuorums ) ) {
2022-06-07 23:32:37 +02:00
std : : stringstream ss ;
2022-04-16 16:46:04 +02:00
2022-06-07 23:32:37 +02:00
ss < < " 3Cmns[ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinus3C [ i ] ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] 2Cmns[ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinus2C [ i ] ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] Cmns[ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinusC [ i ] ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] new[ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : newQuarterMembers [ i ] ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] " ;
LogPrint ( BCLog : : LLMQ , " QuarterComposition h[%d] i[%d]:%s \n " , pCycleQuorumBaseBlockIndex - > nHeight , i ,
ss . str ( ) ) ;
2022-04-16 16:46:04 +02:00
}
2022-07-27 22:34:29 +02:00
}
2022-04-16 16:46:04 +02:00
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( nQuorums ) ) {
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinus3C [ i ] ) {
2022-07-27 22:34:29 +02:00
quorumMembers [ i ] . push_back ( std : : move ( m ) ) ;
}
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinus2C [ i ] ) {
2022-07-27 22:34:29 +02:00
quorumMembers [ i ] . push_back ( std : : move ( m ) ) ;
}
2022-10-18 12:24:00 +02:00
for ( const auto & m : previousQuarters . quarterHMinusC [ i ] ) {
2022-07-27 22:34:29 +02:00
quorumMembers [ i ] . push_back ( std : : move ( m ) ) ;
}
2022-10-18 12:24:00 +02:00
for ( const auto & m : newQuarterMembers [ i ] ) {
2022-07-27 22:34:29 +02:00
quorumMembers [ i ] . push_back ( std : : move ( m ) ) ;
}
2022-04-16 16:46:04 +02:00
2022-07-27 22:34:29 +02:00
if ( LogAcceptCategory ( BCLog : : LLMQ ) ) {
2022-06-07 23:32:37 +02:00
std : : stringstream ss ;
ss < < " [ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : quorumMembers [ i ] ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] " ;
LogPrint ( BCLog : : LLMQ , " QuorumComposition h[%d] i[%d]:%s \n " , pCycleQuorumBaseBlockIndex - > nHeight , i ,
ss . str ( ) ) ;
2022-04-16 16:46:04 +02:00
}
}
return quorumMembers ;
}
2022-08-02 19:14:25 +02:00
PreviousQuorumQuarters GetPreviousQuorumQuarterMembers ( const Consensus : : LLMQParams & llmqParams ,
2022-06-15 23:00:43 +02:00
const CBlockIndex * pBlockHMinusCIndex ,
const CBlockIndex * pBlockHMinus2CIndex ,
const CBlockIndex * pBlockHMinus3CIndex ,
int nHeight )
2022-04-16 16:46:04 +02:00
{
2023-02-11 03:25:11 +01:00
size_t nQuorums = static_cast < size_t > ( llmqParams . signingActiveQuorumCount ) ;
PreviousQuorumQuarters quarters { nQuorums } ;
2022-04-16 16:46:04 +02:00
std : : optional < llmq : : CQuorumSnapshot > quSnapshotHMinusC = quorumSnapshotManager - > GetSnapshotForBlock ( llmqParams . type , pBlockHMinusCIndex ) ;
if ( quSnapshotHMinusC . has_value ( ) ) {
2022-08-02 19:14:25 +02:00
quarters . quarterHMinusC = GetQuorumQuarterMembersBySnapshot ( llmqParams , pBlockHMinusCIndex , quSnapshotHMinusC . value ( ) , nHeight ) ;
2022-04-16 16:46:04 +02:00
//TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice
//assert (!quarterHMinusC.empty());
std : : optional < llmq : : CQuorumSnapshot > quSnapshotHMinus2C = quorumSnapshotManager - > GetSnapshotForBlock ( llmqParams . type , pBlockHMinus2CIndex ) ;
if ( quSnapshotHMinus2C . has_value ( ) ) {
2022-08-02 19:14:25 +02:00
quarters . quarterHMinus2C = GetQuorumQuarterMembersBySnapshot ( llmqParams , pBlockHMinus2CIndex , quSnapshotHMinus2C . value ( ) , nHeight ) ;
2022-04-16 16:46:04 +02:00
//TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice
//assert (!quarterHMinusC.empty());
std : : optional < llmq : : CQuorumSnapshot > quSnapshotHMinus3C = quorumSnapshotManager - > GetSnapshotForBlock ( llmqParams . type , pBlockHMinus3CIndex ) ;
if ( quSnapshotHMinus3C . has_value ( ) ) {
2022-08-02 19:14:25 +02:00
quarters . quarterHMinus3C = GetQuorumQuarterMembersBySnapshot ( llmqParams , pBlockHMinus3CIndex , quSnapshotHMinus3C . value ( ) , nHeight ) ;
2022-04-16 16:46:04 +02:00
//TODO Check if it is triggered from outside (P2P, block validation). Throwing an exception is probably a wiser choice
//assert (!quarterHMinusC.empty());
}
}
}
return quarters ;
}
2022-08-02 19:14:25 +02:00
std : : vector < std : : vector < CDeterministicMNCPtr > > BuildNewQuorumQuarterMembers ( const Consensus : : LLMQParams & llmqParams ,
2023-05-20 16:21:21 +02:00
const CBlockIndex * pCycleQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
const PreviousQuorumQuarters & previousQuarters )
2022-04-16 16:46:04 +02:00
{
2023-05-20 16:21:21 +02:00
if ( ! llmqParams . useRotation | | pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval ! = 0 ) {
ASSERT_IF_DEBUG ( false ) ;
return { } ;
}
2023-02-11 03:25:11 +01:00
size_t nQuorums = static_cast < size_t > ( llmqParams . signingActiveQuorumCount ) ;
std : : vector < std : : vector < CDeterministicMNCPtr > > quarterQuorumMembers { nQuorums } ;
2022-04-16 16:46:04 +02:00
2023-02-11 03:25:11 +01:00
size_t quorumSize = static_cast < size_t > ( llmqParams . size ) ;
auto quarterSize { quorumSize / 4 } ;
2023-05-20 16:21:21 +02:00
const CBlockIndex * pWorkBlockIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 8 ) ;
const auto modifier = GetHashModifier ( llmqParams , pCycleQuorumBaseBlockIndex ) ;
2022-04-16 16:46:04 +02:00
auto allMns = deterministicMNManager - > GetListForBlock ( pWorkBlockIndex ) ;
2022-06-15 23:00:43 +02:00
if ( allMns . GetValidMNsCount ( ) < quarterSize ) {
return quarterQuorumMembers ;
}
2022-04-16 16:46:04 +02:00
auto MnsUsedAtH = CDeterministicMNList ( ) ;
auto MnsNotUsedAtH = CDeterministicMNList ( ) ;
2023-02-11 03:25:11 +01:00
std : : vector < CDeterministicMNList > MnsUsedAtHIndexed { nQuorums } ;
2022-04-16 16:46:04 +02:00
2023-05-20 16:21:21 +02:00
bool skipRemovedMNs = IsV19Active ( pCycleQuorumBaseBlockIndex ) | | ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : TESTNET ) ;
2023-01-10 22:14:27 +01:00
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( nQuorums ) ) {
2022-04-16 16:46:04 +02:00
for ( const auto & mn : previousQuarters . quarterHMinusC [ i ] ) {
2023-01-10 22:14:27 +01:00
if ( skipRemovedMNs & & ! allMns . HasMN ( mn - > proTxHash ) ) {
2022-12-01 17:33:47 +01:00
continue ;
}
2022-06-07 23:32:37 +02:00
if ( allMns . IsMNPoSeBanned ( mn - > proTxHash ) ) {
continue ;
}
2022-04-16 16:46:04 +02:00
try {
MnsUsedAtH . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
try {
MnsUsedAtHIndexed [ i ] . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
}
for ( const auto & mn : previousQuarters . quarterHMinus2C [ i ] ) {
2023-01-10 22:14:27 +01:00
if ( skipRemovedMNs & & ! allMns . HasMN ( mn - > proTxHash ) ) {
2022-12-01 17:33:47 +01:00
continue ;
}
2022-06-07 23:32:37 +02:00
if ( allMns . IsMNPoSeBanned ( mn - > proTxHash ) ) {
continue ;
}
2022-04-16 16:46:04 +02:00
try {
MnsUsedAtH . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
try {
MnsUsedAtHIndexed [ i ] . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
}
for ( const auto & mn : previousQuarters . quarterHMinus3C [ i ] ) {
2023-01-10 22:14:27 +01:00
if ( skipRemovedMNs & & ! allMns . HasMN ( mn - > proTxHash ) ) {
2022-12-01 17:33:47 +01:00
continue ;
}
2022-06-07 23:32:37 +02:00
if ( allMns . IsMNPoSeBanned ( mn - > proTxHash ) ) {
continue ;
}
2022-04-16 16:46:04 +02:00
try {
MnsUsedAtH . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
try {
MnsUsedAtHIndexed [ i ] . AddMN ( mn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
}
}
2022-06-07 23:32:37 +02:00
allMns . ForEachMNShared ( false , [ & MnsUsedAtH , & MnsNotUsedAtH ] ( const CDeterministicMNCPtr & dmn ) {
2022-04-16 16:46:04 +02:00
if ( ! MnsUsedAtH . HasMN ( dmn - > proTxHash ) ) {
2022-06-07 23:32:37 +02:00
if ( ! dmn - > pdmnState - > IsBanned ( ) ) {
try {
MnsNotUsedAtH . AddMN ( dmn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-06-07 23:32:37 +02:00
}
2022-04-16 16:46:04 +02:00
}
}
} ) ;
auto sortedMnsUsedAtHM = MnsUsedAtH . CalculateQuorum ( MnsUsedAtH . GetAllMNsCount ( ) , modifier ) ;
auto sortedMnsNotUsedAtH = MnsNotUsedAtH . CalculateQuorum ( MnsNotUsedAtH . GetAllMNsCount ( ) , modifier ) ;
auto sortedCombinedMnsList = std : : move ( sortedMnsNotUsedAtH ) ;
for ( auto & m : sortedMnsUsedAtHM ) {
sortedCombinedMnsList . push_back ( std : : move ( m ) ) ;
}
2022-06-07 23:32:37 +02:00
if ( LogAcceptCategory ( BCLog : : LLMQ ) ) {
std : : stringstream ss ;
ss < < " [ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : sortedCombinedMnsList ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] " ;
2022-12-01 17:33:47 +01:00
LogPrint ( BCLog : : LLMQ , " BuildNewQuorumQuarterMembers h[%d] sortedCombinedMns[%s] \n " ,
2023-05-20 16:21:21 +02:00
pCycleQuorumBaseBlockIndex - > nHeight , ss . str ( ) ) ;
2022-04-16 16:46:04 +02:00
}
std : : vector < int > skipList ;
2023-02-11 03:25:11 +01:00
size_t firstSkippedIndex = 0 ;
size_t idx { 0 } ;
for ( const size_t i : irange : : range ( nQuorums ) ) {
2022-04-16 16:46:04 +02:00
auto usedMNsCount = MnsUsedAtHIndexed [ i ] . GetAllMNsCount ( ) ;
2023-02-11 03:25:11 +01:00
bool updated { false } ;
size_t initial_loop_idx = idx ;
2022-04-16 16:46:04 +02:00
while ( quarterQuorumMembers [ i ] . size ( ) < quarterSize & & ( usedMNsCount + quarterQuorumMembers [ i ] . size ( ) < sortedCombinedMnsList . size ( ) ) ) {
2022-12-01 17:34:11 +01:00
bool skip { true } ;
2022-04-16 16:46:04 +02:00
if ( ! MnsUsedAtHIndexed [ i ] . HasMN ( sortedCombinedMnsList [ idx ] - > proTxHash ) ) {
2022-12-01 17:34:11 +01:00
try {
// NOTE: AddMN is the one that can throw exceptions, must be exicuted first
MnsUsedAtHIndexed [ i ] . AddMN ( sortedCombinedMnsList [ idx ] ) ;
quarterQuorumMembers [ i ] . push_back ( sortedCombinedMnsList [ idx ] ) ;
updated = true ;
skip = false ;
} catch ( const std : : runtime_error & e ) {
}
}
if ( skip ) {
2022-04-16 16:46:04 +02:00
if ( firstSkippedIndex = = 0 ) {
firstSkippedIndex = idx ;
skipList . push_back ( idx ) ;
} else {
skipList . push_back ( idx - firstSkippedIndex ) ;
}
}
if ( + + idx = = sortedCombinedMnsList . size ( ) ) {
idx = 0 ;
}
2022-12-01 17:34:11 +01:00
if ( idx = = initial_loop_idx ) {
// we made full "while" loop
if ( ! updated ) {
// there are not enough MNs, there is nothing we can do here
return std : : vector < std : : vector < CDeterministicMNCPtr > > ( nQuorums ) ;
}
// reset and try again
updated = false ;
}
2022-04-16 16:46:04 +02:00
}
}
CQuorumSnapshot quorumSnapshot = { } ;
2023-05-20 16:21:21 +02:00
BuildQuorumSnapshot ( llmqParams , allMns , MnsUsedAtH , sortedCombinedMnsList , quorumSnapshot , pCycleQuorumBaseBlockIndex - > nHeight , skipList , pCycleQuorumBaseBlockIndex ) ;
2022-04-16 16:46:04 +02:00
2023-05-20 16:21:21 +02:00
quorumSnapshotManager - > StoreSnapshotForBlock ( llmqParams . type , pCycleQuorumBaseBlockIndex , quorumSnapshot ) ;
2022-04-16 16:46:04 +02:00
return quarterQuorumMembers ;
}
2022-08-02 19:14:25 +02:00
void BuildQuorumSnapshot ( const Consensus : : LLMQParams & llmqParams , const CDeterministicMNList & allMns ,
2022-06-15 23:00:43 +02:00
const CDeterministicMNList & mnUsedAtH , std : : vector < CDeterministicMNCPtr > & sortedCombinedMns ,
2023-05-20 16:21:21 +02:00
CQuorumSnapshot & quorumSnapshot , int nHeight , std : : vector < int > & skipList , const CBlockIndex * pCycleQuorumBaseBlockIndex )
2022-04-16 16:46:04 +02:00
{
2023-05-20 16:21:21 +02:00
if ( ! llmqParams . useRotation | | pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval ! = 0 ) {
ASSERT_IF_DEBUG ( false ) ;
return ;
}
2022-06-07 23:32:37 +02:00
quorumSnapshot . activeQuorumMembers . resize ( allMns . GetAllMNsCount ( ) ) ;
2023-05-20 16:21:21 +02:00
const auto modifier = GetHashModifier ( llmqParams , pCycleQuorumBaseBlockIndex ) ;
2022-06-07 23:32:37 +02:00
auto sortedAllMns = allMns . CalculateQuorum ( allMns . GetAllMNsCount ( ) , modifier ) ;
2023-05-20 16:21:21 +02:00
LogPrint ( BCLog : : LLMQ , " BuildQuorumSnapshot h[%d] numMns[%d] \n " , pCycleQuorumBaseBlockIndex - > nHeight , allMns . GetAllMNsCount ( ) ) ;
2022-04-16 16:46:04 +02:00
std : : fill ( quorumSnapshot . activeQuorumMembers . begin ( ) ,
quorumSnapshot . activeQuorumMembers . end ( ) ,
false ) ;
size_t index = { } ;
for ( const auto & dmn : sortedAllMns ) {
if ( mnUsedAtH . HasMN ( dmn - > proTxHash ) ) {
quorumSnapshot . activeQuorumMembers [ index ] = true ;
}
index + + ;
}
if ( skipList . empty ( ) ) {
quorumSnapshot . mnSkipListMode = SnapshotSkipMode : : MODE_NO_SKIPPING ;
quorumSnapshot . mnSkipList . clear ( ) ;
} else {
quorumSnapshot . mnSkipListMode = SnapshotSkipMode : : MODE_SKIPPING_ENTRIES ;
quorumSnapshot . mnSkipList = std : : move ( skipList ) ;
}
}
2022-08-02 19:14:25 +02:00
std : : vector < std : : vector < CDeterministicMNCPtr > > GetQuorumQuarterMembersBySnapshot ( const Consensus : : LLMQParams & llmqParams ,
2023-05-20 16:21:21 +02:00
const CBlockIndex * pCycleQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
const llmq : : CQuorumSnapshot & snapshot ,
int nHeight )
2022-04-16 16:46:04 +02:00
{
2023-05-20 16:21:21 +02:00
if ( ! llmqParams . useRotation | | pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval ! = 0 ) {
ASSERT_IF_DEBUG ( false ) ;
return { } ;
}
2022-04-25 21:11:44 +02:00
std : : vector < CDeterministicMNCPtr > sortedCombinedMns ;
{
2023-05-20 16:21:21 +02:00
const auto modifier = GetHashModifier ( llmqParams , pCycleQuorumBaseBlockIndex ) ;
const auto [ MnsUsedAtH , MnsNotUsedAtH ] = GetMNUsageBySnapshot ( llmqParams , pCycleQuorumBaseBlockIndex , snapshot , nHeight ) ;
2022-04-25 21:11:44 +02:00
// the list begins with all the unused MNs
auto sortedMnsNotUsedAtH = MnsNotUsedAtH . CalculateQuorum ( MnsNotUsedAtH . GetAllMNsCount ( ) , modifier ) ;
sortedCombinedMns = std : : move ( sortedMnsNotUsedAtH ) ;
// Now add the already used MNs to the end of the list
auto sortedMnsUsedAtH = MnsUsedAtH . CalculateQuorum ( MnsUsedAtH . GetAllMNsCount ( ) , modifier ) ;
std : : move ( sortedMnsUsedAtH . begin ( ) , sortedMnsUsedAtH . end ( ) , std : : back_inserter ( sortedCombinedMns ) ) ;
}
2022-04-16 16:46:04 +02:00
2022-06-07 23:32:37 +02:00
if ( LogAcceptCategory ( BCLog : : LLMQ ) ) {
std : : stringstream ss ;
ss < < " [ " ;
2022-10-18 12:24:00 +02:00
for ( const auto & m : sortedCombinedMns ) {
2022-06-07 23:32:37 +02:00
ss < < m - > proTxHash . ToString ( ) . substr ( 0 , 4 ) < < " | " ;
}
ss < < " ] " ;
LogPrint ( BCLog : : LLMQ , " GetQuorumQuarterMembersBySnapshot h[%d] from[%d] sortedCombinedMns[%s] \n " ,
2023-05-20 16:21:21 +02:00
pCycleQuorumBaseBlockIndex - > nHeight , nHeight , ss . str ( ) ) ;
2022-06-07 23:32:37 +02:00
}
2023-02-11 03:25:11 +01:00
size_t numQuorums = static_cast < size_t > ( llmqParams . signingActiveQuorumCount ) ;
size_t quorumSize = static_cast < size_t > ( llmqParams . size ) ;
auto quarterSize { quorumSize / 4 } ;
2022-04-16 16:46:04 +02:00
2022-04-25 21:11:44 +02:00
std : : vector < std : : vector < CDeterministicMNCPtr > > quarterQuorumMembers ( numQuorums ) ;
2022-04-16 16:46:04 +02:00
2022-06-15 23:00:43 +02:00
if ( sortedCombinedMns . empty ( ) ) {
return quarterQuorumMembers ;
}
2022-04-26 19:23:52 +02:00
2022-04-25 21:11:44 +02:00
switch ( snapshot . mnSkipListMode ) {
case SnapshotSkipMode : : MODE_NO_SKIPPING :
{
auto itm = sortedCombinedMns . begin ( ) ;
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( numQuorums ) ) {
2022-04-25 21:11:44 +02:00
while ( quarterQuorumMembers [ i ] . size ( ) < quarterSize ) {
quarterQuorumMembers [ i ] . push_back ( * itm ) ;
itm + + ;
if ( itm = = sortedCombinedMns . end ( ) ) {
itm = sortedCombinedMns . begin ( ) ;
}
}
2022-04-16 16:46:04 +02:00
}
2022-04-25 21:11:44 +02:00
return quarterQuorumMembers ;
2022-04-16 16:46:04 +02:00
}
2022-04-25 21:11:44 +02:00
case SnapshotSkipMode : : MODE_SKIPPING_ENTRIES : // List holds entries to be skipped
{
size_t first_entry_index { 0 } ;
std : : vector < int > processesdSkipList ;
for ( const auto & s : snapshot . mnSkipList ) {
if ( first_entry_index = = 0 ) {
first_entry_index = s ;
processesdSkipList . push_back ( s ) ;
} else {
processesdSkipList . push_back ( first_entry_index + s ) ;
}
}
2022-04-16 16:46:04 +02:00
2023-02-11 03:25:11 +01:00
int idx = 0 ;
2022-04-25 21:11:44 +02:00
auto itsk = processesdSkipList . begin ( ) ;
2023-02-11 03:25:11 +01:00
for ( const size_t i : irange : : range ( numQuorums ) ) {
2022-04-25 21:11:44 +02:00
while ( quarterQuorumMembers [ i ] . size ( ) < quarterSize ) {
if ( itsk ! = processesdSkipList . end ( ) & & idx = = * itsk ) {
itsk + + ;
} else {
quarterQuorumMembers [ i ] . push_back ( sortedCombinedMns [ idx ] ) ;
}
idx + + ;
2023-02-11 03:25:11 +01:00
if ( idx = = static_cast < int > ( sortedCombinedMns . size ( ) ) ) {
2022-04-25 21:11:44 +02:00
idx = 0 ;
}
}
2022-04-16 16:46:04 +02:00
}
2022-04-25 21:11:44 +02:00
return quarterQuorumMembers ;
2022-04-16 16:46:04 +02:00
}
2022-04-25 21:11:44 +02:00
case SnapshotSkipMode : : MODE_NO_SKIPPING_ENTRIES : // List holds entries to be kept
case SnapshotSkipMode : : MODE_ALL_SKIPPED : // Every node was skipped. Returning empty quarterQuorumMembers
default :
2022-04-26 19:23:52 +02:00
return quarterQuorumMembers ;
2022-04-16 16:46:04 +02:00
}
}
2023-05-17 19:27:15 +02:00
std : : pair < CDeterministicMNList , CDeterministicMNList > GetMNUsageBySnapshot ( const Consensus : : LLMQParams & llmqParams ,
2023-05-20 16:21:21 +02:00
const CBlockIndex * pCycleQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
const llmq : : CQuorumSnapshot & snapshot ,
int nHeight )
2022-04-16 16:46:04 +02:00
{
2023-05-20 16:21:21 +02:00
if ( ! llmqParams . useRotation | | pCycleQuorumBaseBlockIndex - > nHeight % llmqParams . dkgInterval ! = 0 ) {
ASSERT_IF_DEBUG ( false ) ;
return { } ;
}
2022-04-16 16:46:04 +02:00
CDeterministicMNList usedMNs ;
CDeterministicMNList nonUsedMNs ;
2023-05-20 16:21:21 +02:00
const CBlockIndex * pWorkBlockIndex = pCycleQuorumBaseBlockIndex - > GetAncestor ( pCycleQuorumBaseBlockIndex - > nHeight - 8 ) ;
const auto modifier = GetHashModifier ( llmqParams , pCycleQuorumBaseBlockIndex ) ;
2022-04-16 16:46:04 +02:00
2022-06-07 23:32:37 +02:00
auto allMns = deterministicMNManager - > GetListForBlock ( pWorkBlockIndex ) ;
auto sortedAllMns = allMns . CalculateQuorum ( allMns . GetAllMNsCount ( ) , modifier ) ;
2022-04-16 16:46:04 +02:00
size_t i { 0 } ;
for ( const auto & dmn : sortedAllMns ) {
if ( snapshot . activeQuorumMembers [ i ] ) {
try {
usedMNs . AddMN ( dmn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-04-16 16:46:04 +02:00
}
} else {
2022-06-07 23:32:37 +02:00
if ( ! dmn - > pdmnState - > IsBanned ( ) ) {
try {
nonUsedMNs . AddMN ( dmn ) ;
2022-10-18 12:24:00 +02:00
} catch ( const std : : runtime_error & e ) {
2022-06-07 23:32:37 +02:00
}
2022-04-16 16:46:04 +02:00
}
}
i + + ;
}
return std : : make_pair ( usedMNs , nonUsedMNs ) ;
}
2022-08-02 19:14:25 +02:00
uint256 BuildCommitmentHash ( Consensus : : LLMQType llmqType , const uint256 & blockHash ,
2022-06-15 23:00:43 +02:00
const std : : vector < bool > & validMembers , const CBLSPublicKey & pubKey ,
const uint256 & vvecHash )
2018-11-23 15:42:09 +01:00
{
2023-06-10 22:14:28 +02:00
CHashWriter hw ( SER_GETHASH , 0 ) ;
2018-11-23 15:42:09 +01:00
hw < < llmqType ;
hw < < blockHash ;
hw < < DYNBITSET ( validMembers ) ;
hw < < pubKey ;
hw < < vvecHash ;
return hw . GetHash ( ) ;
}
2022-08-02 19:14:25 +02:00
uint256 BuildSignHash ( Consensus : : LLMQType llmqType , const uint256 & quorumHash , const uint256 & id , const uint256 & msgHash )
2019-01-15 15:35:26 +01:00
{
CHashWriter h ( SER_GETHASH , 0 ) ;
2019-05-28 15:34:41 +02:00
h < < llmqType ;
2019-01-15 15:35:26 +01:00
h < < quorumHash ;
h < < id ;
h < < msgHash ;
return h . GetHash ( ) ;
}
2021-01-11 04:23:01 +01:00
static bool EvalSpork ( Consensus : : LLMQType llmqType , int64_t spork_value )
2020-06-25 09:47:24 +02:00
{
2021-01-11 04:23:01 +01:00
if ( spork_value = = 0 ) {
2020-06-25 09:47:24 +02:00
return true ;
}
2021-10-15 12:28:19 +02:00
if ( spork_value = = 1 & & llmqType ! = Consensus : : LLMQType : : LLMQ_100_67 & & llmqType ! = Consensus : : LLMQType : : LLMQ_400_60 & & llmqType ! = Consensus : : LLMQType : : LLMQ_400_85 ) {
2020-06-25 09:47:24 +02:00
return true ;
}
return false ;
}
2022-08-02 19:14:25 +02:00
bool IsAllMembersConnectedEnabled ( Consensus : : LLMQType llmqType )
2021-01-11 04:23:01 +01:00
{
2022-08-26 23:52:53 +02:00
return EvalSpork ( llmqType , sporkManager - > GetSporkValue ( SPORK_21_QUORUM_ALL_CONNECTED ) ) ;
2021-01-11 04:23:01 +01:00
}
2022-08-02 19:14:25 +02:00
bool IsQuorumPoseEnabled ( Consensus : : LLMQType llmqType )
2021-01-11 04:23:01 +01:00
{
2022-08-26 23:52:53 +02:00
return EvalSpork ( llmqType , sporkManager - > GetSporkValue ( SPORK_23_QUORUM_POSE ) ) ;
2021-01-11 04:23:01 +01:00
}
2023-11-10 15:33:21 +01:00
bool IsQuorumRotationEnabled ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pindex )
2022-04-16 16:46:04 +02:00
{
2023-02-20 11:12:49 +01:00
if ( ! llmqParams . useRotation ) {
2022-04-16 16:46:04 +02:00
return false ;
}
2023-02-20 11:12:49 +01:00
int cycleQuorumBaseHeight = pindex - > nHeight - ( pindex - > nHeight % llmqParams . dkgInterval ) ;
2022-04-16 16:46:04 +02:00
if ( cycleQuorumBaseHeight < 1 ) {
return false ;
}
// It should activate at least 1 block prior to the cycle start
2023-12-04 09:40:01 +01:00
return DeploymentActiveAfter ( pindex - > GetAncestor ( cycleQuorumBaseHeight - 1 ) , Params ( ) . GetConsensus ( ) , Consensus : : DEPLOYMENT_DIP0024 ) ;
2022-04-16 16:46:04 +02:00
}
2023-11-10 15:33:21 +01:00
bool IsV19Active ( gsl : : not_null < const CBlockIndex * > pindex )
2022-11-22 18:34:21 +01:00
{
2023-07-23 22:19:38 +02:00
return pindex - > nHeight + 1 > = Params ( ) . GetConsensus ( ) . V19Height ;
2023-06-13 16:24:19 +02:00
}
2023-11-10 15:33:21 +01:00
bool IsV20Active ( gsl : : not_null < const CBlockIndex * > pindex )
2023-04-15 00:01:46 +02:00
{
2021-07-01 19:15:03 +02:00
return llmq_versionbitscache . State ( pindex , Params ( ) . GetConsensus ( ) , Consensus : : DEPLOYMENT_V20 ) = = ThresholdState : : ACTIVE ;
2023-04-15 00:01:46 +02:00
}
2022-08-02 19:14:25 +02:00
uint256 DeterministicOutboundConnection ( const uint256 & proTxHash1 , const uint256 & proTxHash2 )
2020-04-16 13:57:32 +02:00
{
// We need to deterministically select who is going to initiate the connection. The naive way would be to simply
// return the min(proTxHash1, proTxHash2), but this would create a bias towards MNs with a numerically low
// hash. To fix this, we return the proTxHash that has the lowest value of:
// hash(min(proTxHash1, proTxHash2), max(proTxHash1, proTxHash2), proTxHashX)
// where proTxHashX is the proTxHash to compare
uint256 h1 ;
uint256 h2 ;
if ( proTxHash1 < proTxHash2 ) {
h1 = : : SerializeHash ( std : : make_tuple ( proTxHash1 , proTxHash2 , proTxHash1 ) ) ;
h2 = : : SerializeHash ( std : : make_tuple ( proTxHash1 , proTxHash2 , proTxHash2 ) ) ;
} else {
h1 = : : SerializeHash ( std : : make_tuple ( proTxHash2 , proTxHash1 , proTxHash1 ) ) ;
h2 = : : SerializeHash ( std : : make_tuple ( proTxHash2 , proTxHash1 , proTxHash2 ) ) ;
}
if ( h1 < h2 ) {
return proTxHash1 ;
}
return proTxHash2 ;
}
2023-11-10 15:33:21 +01:00
std : : set < uint256 > GetQuorumConnections ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
const uint256 & forMember , bool onlyOutbound )
2018-05-24 16:14:55 +02:00
{
2021-10-28 21:10:43 +02:00
if ( IsAllMembersConnectedEnabled ( llmqParams . type ) ) {
2022-04-16 16:46:04 +02:00
auto mns = GetAllQuorumMembers ( llmqParams . type , pQuorumBaseBlockIndex ) ;
2020-06-18 10:40:33 +02:00
std : : set < uint256 > result ;
2021-06-26 15:10:53 +02:00
for ( const auto & dmn : mns ) {
2020-04-21 16:43:59 +02:00
if ( dmn - > proTxHash = = forMember ) {
continue ;
}
2020-04-16 13:57:32 +02:00
// Determine which of the two MNs (forMember vs dmn) should initiate the outbound connection and which
// one should wait for the inbound connection. We do this in a deterministic way, so that even when we
// end up with both connecting to each other, we know which one to disconnect
uint256 deterministicOutbound = DeterministicOutboundConnection ( forMember , dmn - > proTxHash ) ;
if ( ! onlyOutbound | | deterministicOutbound = = dmn - > proTxHash ) {
2020-03-16 11:09:54 +01:00
result . emplace ( dmn - > proTxHash ) ;
}
}
return result ;
}
2022-06-15 23:00:43 +02:00
return GetQuorumRelayMembers ( llmqParams , pQuorumBaseBlockIndex , forMember , onlyOutbound ) ;
2020-06-18 10:40:33 +02:00
}
2020-03-16 11:09:54 +01:00
2023-11-10 15:33:21 +01:00
std : : set < uint256 > GetQuorumRelayMembers ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
const uint256 & forMember , bool onlyOutbound )
2020-06-18 10:40:33 +02:00
{
2022-04-16 16:46:04 +02:00
auto mns = GetAllQuorumMembers ( llmqParams . type , pQuorumBaseBlockIndex ) ;
2020-06-18 10:40:33 +02:00
std : : set < uint256 > result ;
2020-03-16 11:09:54 +01:00
2021-06-26 15:10:53 +02:00
auto calcOutbound = [ & ] ( size_t i , const uint256 & proTxHash ) {
2022-04-26 19:22:56 +02:00
if ( mns . size ( ) = = 1 ) {
// No outbound connections are needed when there is one MN only.
// Also note that trying to calculate results via the algorithm below
// would result in an endless loop.
return std : : set < uint256 > ( ) ;
}
2020-06-18 10:40:33 +02:00
// Relay to nodes at indexes (i+2^k)%n, where
2020-03-27 15:09:15 +01:00
// k: 0..max(1, floor(log2(n-1))-1)
// n: size of the quorum/ring
std : : set < uint256 > r ;
int gap = 1 ;
int gap_max = ( int ) mns . size ( ) - 1 ;
int k = 0 ;
while ( ( gap_max > > = 1 ) | | k < = 1 ) {
size_t idx = ( i + gap ) % mns . size ( ) ;
2022-06-27 12:02:46 +02:00
// It doesn't matter if this node is going to be added to the resulting set or not,
// we should always bump the gap and the k (step count) regardless.
// Refusing to bump the gap results in an incomplete set in the best case scenario
// (idx won't ever change again once we hit `==`). Not bumping k guarantees an endless
// loop when the first or the second node we check is the one that should be skipped
// (k <= 1 forever).
gap < < = 1 ;
k + + ;
2021-06-26 15:10:53 +02:00
const auto & otherDmn = mns [ idx ] ;
2020-03-27 15:09:15 +01:00
if ( otherDmn - > proTxHash = = proTxHash ) {
continue ;
}
r . emplace ( otherDmn - > proTxHash ) ;
}
return r ;
} ;
2022-04-26 01:40:41 +02:00
for ( const auto i : irange : : range ( mns . size ( ) ) ) {
2021-06-26 15:10:53 +02:00
const auto & dmn = mns [ i ] ;
2018-05-24 16:14:55 +02:00
if ( dmn - > proTxHash = = forMember ) {
2020-03-27 15:09:15 +01:00
auto r = calcOutbound ( i , dmn - > proTxHash ) ;
result . insert ( r . begin ( ) , r . end ( ) ) ;
2020-03-27 15:11:13 +01:00
} else if ( ! onlyOutbound ) {
auto r = calcOutbound ( i , dmn - > proTxHash ) ;
if ( r . count ( forMember ) ) {
result . emplace ( dmn - > proTxHash ) ;
}
2018-05-24 16:14:55 +02:00
}
}
2020-03-27 15:11:13 +01:00
2018-05-24 16:14:55 +02:00
return result ;
}
2023-11-10 15:33:21 +01:00
std : : set < size_t > CalcDeterministicWatchConnections ( Consensus : : LLMQType llmqType , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
size_t memberCount , size_t connectionCount )
2018-05-24 16:14:55 +02:00
{
static uint256 qwatchConnectionSeed ;
static std : : atomic < bool > qwatchConnectionSeedGenerated { false } ;
2023-04-25 13:51:26 +02:00
static RecursiveMutex qwatchConnectionSeedCs ;
2018-05-24 16:14:55 +02:00
if ( ! qwatchConnectionSeedGenerated ) {
LOCK ( qwatchConnectionSeedCs ) ;
2021-08-06 23:55:51 +02:00
qwatchConnectionSeed = GetRandHash ( ) ;
qwatchConnectionSeedGenerated = true ;
2018-05-24 16:14:55 +02:00
}
std : : set < size_t > result ;
uint256 rnd = qwatchConnectionSeed ;
2022-04-26 01:40:41 +02:00
for ( [[maybe_unused]] const auto _ : irange : : range ( connectionCount ) ) {
2021-10-26 18:08:38 +02:00
rnd = : : SerializeHash ( std : : make_pair ( rnd , std : : make_pair ( llmqType , pQuorumBaseBlockIndex - > GetBlockHash ( ) ) ) ) ;
2018-05-24 16:14:55 +02:00
result . emplace ( rnd . GetUint64 ( 0 ) % memberCount ) ;
}
return result ;
}
2018-11-23 15:42:09 +01:00
2023-11-10 15:33:21 +01:00
bool EnsureQuorumConnections ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex ,
2022-06-15 23:00:43 +02:00
CConnman & connman , const uint256 & myProTxHash )
2020-03-16 10:54:59 +01:00
{
2022-08-02 19:14:25 +02:00
if ( ! fMasternodeMode & & ! IsWatchQuorumsEnabled ( ) ) {
2022-07-18 21:26:51 +02:00
return false ;
}
2022-04-16 16:46:04 +02:00
auto members = GetAllQuorumMembers ( llmqParams . type , pQuorumBaseBlockIndex ) ;
2022-07-18 21:26:51 +02:00
if ( members . empty ( ) ) {
return false ;
}
2022-06-15 23:00:43 +02:00
bool isMember = ranges : : find_if ( members , [ & ] ( const auto & dmn ) { return dmn - > proTxHash = = myProTxHash ; } ) ! = members . end ( ) ;
2020-03-16 10:54:59 +01:00
2022-08-02 19:14:25 +02:00
if ( ! isMember & & ! IsWatchQuorumsEnabled ( ) ) {
2021-03-29 20:09:09 +02:00
return false ;
2020-03-16 10:54:59 +01:00
}
2022-08-02 19:14:25 +02:00
LogPrint ( BCLog : : NET_NETCONN , " %s -- isMember=%d for quorum %s: \n " ,
2022-07-18 21:26:51 +02:00
__func__ , isMember , pQuorumBaseBlockIndex - > GetBlockHash ( ) . ToString ( ) ) ;
2020-03-16 10:54:59 +01:00
std : : set < uint256 > connections ;
2021-03-15 03:49:38 +01:00
std : : set < uint256 > relayMembers ;
2020-03-16 10:54:59 +01:00
if ( isMember ) {
2022-08-02 19:14:25 +02:00
connections = GetQuorumConnections ( llmqParams , pQuorumBaseBlockIndex , myProTxHash , true ) ;
relayMembers = GetQuorumRelayMembers ( llmqParams , pQuorumBaseBlockIndex , myProTxHash , true ) ;
2020-03-16 10:54:59 +01:00
} else {
2022-08-02 19:14:25 +02:00
auto cindexes = CalcDeterministicWatchConnections ( llmqParams . type , pQuorumBaseBlockIndex , members . size ( ) , 1 ) ;
2020-03-16 10:54:59 +01:00
for ( auto idx : cindexes ) {
connections . emplace ( members [ idx ] - > proTxHash ) ;
}
2021-03-15 03:49:38 +01:00
relayMembers = connections ;
2020-03-16 10:54:59 +01:00
}
if ( ! connections . empty ( ) ) {
2022-01-09 12:38:21 +01:00
if ( ! connman . HasMasternodeQuorumNodes ( llmqParams . type , pQuorumBaseBlockIndex - > GetBlockHash ( ) ) & & LogAcceptCategory ( BCLog : : LLMQ ) ) {
2020-03-16 10:54:59 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
2022-08-02 19:14:25 +02:00
std : : string debugMsg = strprintf ( " %s -- adding masternodes quorum connections for quorum %s: \n " , __func__ , pQuorumBaseBlockIndex - > GetBlockHash ( ) . ToString ( ) ) ;
2022-06-15 23:00:43 +02:00
for ( const auto & c : connections ) {
2020-03-16 10:54:59 +01:00
auto dmn = mnList . GetValidMN ( c ) ;
if ( ! dmn ) {
debugMsg + = strprintf ( " %s (not in valid MN set anymore) \n " , c . ToString ( ) ) ;
} else {
debugMsg + = strprintf ( " %s (%s) \n " , c . ToString ( ) , dmn - > pdmnState - > addr . ToString ( false ) ) ;
}
}
2020-07-29 13:50:36 +02:00
LogPrint ( BCLog : : NET_NETCONN , debugMsg . c_str ( ) ) ; /* Continued */
2020-03-16 10:54:59 +01:00
}
2022-01-09 12:38:21 +01:00
connman . SetMasternodeQuorumNodes ( llmqParams . type , pQuorumBaseBlockIndex - > GetBlockHash ( ) , connections ) ;
2020-03-16 10:54:59 +01:00
}
2021-03-15 03:49:38 +01:00
if ( ! relayMembers . empty ( ) ) {
2022-01-09 12:38:21 +01:00
connman . SetMasternodeQuorumRelayMembers ( llmqParams . type , pQuorumBaseBlockIndex - > GetBlockHash ( ) , relayMembers ) ;
2021-03-15 03:49:38 +01:00
}
2021-03-29 20:09:09 +02:00
return true ;
2020-03-16 10:54:59 +01:00
}
2023-11-10 15:33:21 +01:00
void AddQuorumProbeConnections ( const Consensus : : LLMQParams & llmqParams , gsl : : not_null < const CBlockIndex * > pQuorumBaseBlockIndex ,
refactor: decouple db hooks from CFlatDB-based C*Manager objects, migrate to *Store structs (#5555)
## Motivation
As highlighted in https://github.com/dashpay/dash-issues/issues/52,
decoupling of `CFlatDB`-interacting components from managers of objects
like `CGovernanceManager` and `CSporkManager` is a key task for
achieving deglobalization of Dash-specific components.
The design of `CFlatDB` as a flat database agent relies on hooking into
the object's state its meant to load and store, using its
(de)serialization routines and other miscellaneous functions (notably,
without defining an interface) to achieve those ends. This approach was
taken predominantly for components that want a single-file cache.
Because of the method it uses to hook into the object (templates and the
use of temporary objects), it explicitly prevented passing arguments
into the object constructor, an explicit requirement for storing
references to other components during construction. This, in turn,
created an explicit dependency on those same components being available
in the global context, which would block the backport of bitcoin#21866,
a requirement for future backports meant to achieve parity in
`assumeutxo` support.
The design of these objects made no separation between persistent (i.e.
cached) and ephemeral (i.e. generated/fetched during initialization or
state transitions) data and the design of `CFlatDB` attempts to "clean"
the database by breaching this separation and attempting to access this
ephemeral data.
This might be acceptable if it is contained within the manager itself,
like `CSporkManager`'s `CheckAndRemove()` but is utterly unacceptable
when it relies on other managers (that, as a reminder, are only
accessible through the global state because of restrictions caused by
existing design), like `CGovernanceManager`'s `UpdateCachesAndClean()`.
This pull request aims to separate the `CFlatDB`-interacting portions of
these managers into a struct, with `CFlatDB` interacting only with this
struct, while the manager inherits the struct and manages
load/store/update of the database through the `CFlatDB` instance
initialized within its scope, though the instance only has knowledge of
what is exposed through the limited parent struct.
## Additional information
* As regards to existing behaviour, `CFlatDB` is written entirely as a
header as it relies on templates to specialize itself for the object it
hooks into. Attempting to split the logic and function definitions into
separate files will require you to explicitly define template
specializations, which is tedious.
* `m_db` is defined as a pointer as you cannot instantiate a
forward-declared template (see [this Stack Overflow
answer](https://stackoverflow.com/a/12797282) for more information),
which is done when defined as a member in the object scope.
* The conditional cache flush predicating on RPC _not_ being in the
warm-up state has been replaced with unconditional flushing of the
database on object destruction (@UdjinM6, is this acceptable?)
## TODOs
This is a list of things that aren't within the scope of this pull
request but should be addressed in subsequent pull requests
* [ ] Definition of an interface that `CFlatDB` stores are expected to
implement
* [ ] Lock annotations for all potential uses of members protected by
the `cs` mutex in each manager object and store
* [ ] Additional comments documenting what each function and member does
* [ ] Deglobalization of affected managers
---------
Co-authored-by: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
2023-09-24 16:50:21 +02:00
CConnman & connman , const uint256 & myProTxHash )
2020-03-17 10:04:31 +01:00
{
2022-08-02 19:14:25 +02:00
if ( ! IsQuorumPoseEnabled ( llmqParams . type ) ) {
2021-01-11 04:23:01 +01:00
return ;
}
2022-04-16 16:46:04 +02:00
auto members = GetAllQuorumMembers ( llmqParams . type , pQuorumBaseBlockIndex ) ;
2023-10-23 17:39:39 +02:00
auto curTime = GetTime < std : : chrono : : seconds > ( ) . count ( ) ;
2020-03-17 10:04:31 +01:00
std : : set < uint256 > probeConnections ;
2021-06-26 15:10:53 +02:00
for ( const auto & dmn : members ) {
2020-03-17 10:04:31 +01:00
if ( dmn - > proTxHash = = myProTxHash ) {
continue ;
}
refactor: decouple db hooks from CFlatDB-based C*Manager objects, migrate to *Store structs (#5555)
## Motivation
As highlighted in https://github.com/dashpay/dash-issues/issues/52,
decoupling of `CFlatDB`-interacting components from managers of objects
like `CGovernanceManager` and `CSporkManager` is a key task for
achieving deglobalization of Dash-specific components.
The design of `CFlatDB` as a flat database agent relies on hooking into
the object's state its meant to load and store, using its
(de)serialization routines and other miscellaneous functions (notably,
without defining an interface) to achieve those ends. This approach was
taken predominantly for components that want a single-file cache.
Because of the method it uses to hook into the object (templates and the
use of temporary objects), it explicitly prevented passing arguments
into the object constructor, an explicit requirement for storing
references to other components during construction. This, in turn,
created an explicit dependency on those same components being available
in the global context, which would block the backport of bitcoin#21866,
a requirement for future backports meant to achieve parity in
`assumeutxo` support.
The design of these objects made no separation between persistent (i.e.
cached) and ephemeral (i.e. generated/fetched during initialization or
state transitions) data and the design of `CFlatDB` attempts to "clean"
the database by breaching this separation and attempting to access this
ephemeral data.
This might be acceptable if it is contained within the manager itself,
like `CSporkManager`'s `CheckAndRemove()` but is utterly unacceptable
when it relies on other managers (that, as a reminder, are only
accessible through the global state because of restrictions caused by
existing design), like `CGovernanceManager`'s `UpdateCachesAndClean()`.
This pull request aims to separate the `CFlatDB`-interacting portions of
these managers into a struct, with `CFlatDB` interacting only with this
struct, while the manager inherits the struct and manages
load/store/update of the database through the `CFlatDB` instance
initialized within its scope, though the instance only has knowledge of
what is exposed through the limited parent struct.
## Additional information
* As regards to existing behaviour, `CFlatDB` is written entirely as a
header as it relies on templates to specialize itself for the object it
hooks into. Attempting to split the logic and function definitions into
separate files will require you to explicitly define template
specializations, which is tedious.
* `m_db` is defined as a pointer as you cannot instantiate a
forward-declared template (see [this Stack Overflow
answer](https://stackoverflow.com/a/12797282) for more information),
which is done when defined as a member in the object scope.
* The conditional cache flush predicating on RPC _not_ being in the
warm-up state has been replaced with unconditional flushing of the
database on object destruction (@UdjinM6, is this acceptable?)
## TODOs
This is a list of things that aren't within the scope of this pull
request but should be addressed in subsequent pull requests
* [ ] Definition of an interface that `CFlatDB` stores are expected to
implement
* [ ] Lock annotations for all potential uses of members protected by
the `cs` mutex in each manager object and store
* [ ] Additional comments documenting what each function and member does
* [ ] Deglobalization of affected managers
---------
Co-authored-by: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com>
2023-09-24 16:50:21 +02:00
auto lastOutbound = mmetaman - > GetMetaInfo ( dmn - > proTxHash ) - > GetLastOutboundSuccess ( ) ;
2022-07-06 23:24:34 +02:00
if ( curTime - lastOutbound < 10 * 60 ) {
// avoid re-probing nodes too often
continue ;
2020-03-17 10:04:31 +01:00
}
2022-07-06 23:24:34 +02:00
probeConnections . emplace ( dmn - > proTxHash ) ;
2020-03-17 10:04:31 +01:00
}
if ( ! probeConnections . empty ( ) ) {
if ( LogAcceptCategory ( BCLog : : LLMQ ) ) {
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
2022-08-02 19:14:25 +02:00
std : : string debugMsg = strprintf ( " %s -- adding masternodes probes for quorum %s: \n " , __func__ , pQuorumBaseBlockIndex - > GetBlockHash ( ) . ToString ( ) ) ;
2022-06-15 23:00:43 +02:00
for ( const auto & c : probeConnections ) {
2020-03-17 10:04:31 +01:00
auto dmn = mnList . GetValidMN ( c ) ;
if ( ! dmn ) {
debugMsg + = strprintf ( " %s (not in valid MN set anymore) \n " , c . ToString ( ) ) ;
} else {
debugMsg + = strprintf ( " %s (%s) \n " , c . ToString ( ) , dmn - > pdmnState - > addr . ToString ( false ) ) ;
}
}
2020-07-29 13:50:36 +02:00
LogPrint ( BCLog : : NET_NETCONN , debugMsg . c_str ( ) ) ; /* Continued */
2020-03-17 10:04:31 +01:00
}
2022-01-09 12:38:21 +01:00
connman . AddPendingProbeConnections ( probeConnections ) ;
2020-03-17 10:04:31 +01:00
}
}
2022-09-22 13:14:48 +02:00
bool IsQuorumActive ( Consensus : : LLMQType llmqType , const CQuorumManager & qman , const uint256 & quorumHash )
2019-01-15 15:35:26 +01:00
{
// sig shares and recovered sigs are only accepted from recent/active quorums
// we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
// fail while we are on the brink of a new quorum
2023-03-13 17:11:17 +01:00
const auto & llmq_params_opt = GetLLMQParams ( llmqType ) ;
assert ( llmq_params_opt . has_value ( ) ) ;
auto quorums = qman . ScanQuorums ( llmqType , llmq_params_opt - > keepOldConnections ) ;
2021-12-21 13:05:29 +01:00
return ranges : : any_of ( quorums , [ & quorumHash ] ( const auto & q ) { return q - > qc - > quorumHash = = quorumHash ; } ) ;
2019-01-15 15:35:26 +01:00
}
2023-12-04 09:40:01 +01:00
bool IsQuorumTypeEnabled ( Consensus : : LLMQType llmqType , const CQuorumManager & qman , gsl : : not_null < const CBlockIndex * > pindexPrev )
2022-04-16 16:46:04 +02:00
{
2023-12-04 09:40:01 +01:00
return IsQuorumTypeEnabledInternal ( llmqType , qman , pindexPrev , std : : nullopt , std : : nullopt ) ;
2022-04-16 16:46:04 +02:00
}
2023-12-04 09:40:01 +01:00
bool IsQuorumTypeEnabledInternal ( Consensus : : LLMQType llmqType , const CQuorumManager & qman , gsl : : not_null < const CBlockIndex * > pindexPrev ,
2022-09-22 13:14:48 +02:00
std : : optional < bool > optDIP0024IsActive , std : : optional < bool > optHaveDIP0024Quorums )
2020-12-10 00:08:05 +01:00
{
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2023-12-18 09:17:13 +01:00
const bool fDIP0024IsActive { optDIP0024IsActive . value_or ( DeploymentActiveAfter ( pindexPrev , consensusParams , Consensus : : DEPLOYMENT_DIP0024 ) ) } ;
2020-12-10 00:08:05 +01:00
switch ( llmqType )
{
2022-06-29 02:14:09 +02:00
case Consensus : : LLMQType : : LLMQ_DEVNET :
2023-11-20 17:17:04 +01:00
return true ;
case Consensus : : LLMQType : : LLMQ_50_60 :
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : TESTNET ) return true ;
// fall through
case Consensus : : LLMQType : : LLMQ_TEST_INSTANTSEND : {
2023-05-17 13:11:33 +02:00
if ( ! fDIP0024IsActive ) return true ;
2023-12-18 09:17:13 +01:00
const bool fHaveDIP0024Quorums { optHaveDIP0024Quorums . value_or ( ! qman . ScanQuorums (
consensusParams . llmqTypeDIP0024InstantSend , pindexPrev , 1 ) . empty ( ) ) } ;
2023-05-17 13:11:33 +02:00
return ! fHaveDIP0024Quorums ;
2022-04-16 16:46:04 +02:00
}
case Consensus : : LLMQType : : LLMQ_TEST :
2023-02-14 19:48:33 +01:00
case Consensus : : LLMQType : : LLMQ_TEST_PLATFORM :
2021-10-15 12:28:19 +02:00
case Consensus : : LLMQType : : LLMQ_400_60 :
case Consensus : : LLMQType : : LLMQ_400_85 :
2023-02-19 17:53:29 +01:00
case Consensus : : LLMQType : : LLMQ_DEVNET_PLATFORM :
2023-05-17 13:11:33 +02:00
return true ;
case Consensus : : LLMQType : : LLMQ_TEST_V17 : {
2023-12-04 09:40:01 +01:00
return llmq_versionbitscache . State ( pindexPrev , consensusParams , Consensus : : DEPLOYMENT_TESTDUMMY ) = = ThresholdState : : ACTIVE ;
2023-05-17 13:11:33 +02:00
}
2021-10-15 12:28:19 +02:00
case Consensus : : LLMQType : : LLMQ_100_67 :
2023-12-04 09:40:01 +01:00
return pindexPrev - > nHeight + 1 > = consensusParams . DIP0020Height ;
2023-05-17 13:11:33 +02:00
2022-04-16 16:46:04 +02:00
case Consensus : : LLMQType : : LLMQ_60_75 :
2022-06-29 02:14:09 +02:00
case Consensus : : LLMQType : : LLMQ_DEVNET_DIP0024 :
2022-04-16 16:46:04 +02:00
case Consensus : : LLMQType : : LLMQ_TEST_DIP0024 : {
2023-05-17 13:11:33 +02:00
return fDIP0024IsActive ;
2022-04-16 16:46:04 +02:00
}
2023-03-01 18:42:33 +01:00
case Consensus : : LLMQType : : LLMQ_25_67 :
2023-12-04 09:40:01 +01:00
return pindexPrev - > nHeight > = TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT ;
2023-05-17 13:11:33 +02:00
2020-12-10 00:08:05 +01:00
default :
2023-02-20 11:12:12 +01:00
throw std : : runtime_error ( strprintf ( " %s: Unknown LLMQ type %d " , __func__ , ToUnderlying ( llmqType ) ) ) ;
2020-12-10 00:08:05 +01:00
}
2023-05-17 13:11:33 +02:00
// Something wrong with conditions above, they are not consistent
assert ( false ) ;
2020-12-10 00:08:05 +01:00
}
2023-11-10 15:33:21 +01:00
std : : vector < Consensus : : LLMQType > GetEnabledQuorumTypes ( gsl : : not_null < const CBlockIndex * > pindex )
2020-12-10 00:08:05 +01:00
{
std : : vector < Consensus : : LLMQType > ret ;
2021-10-28 21:10:43 +02:00
ret . reserve ( Params ( ) . GetConsensus ( ) . llmqs . size ( ) ) ;
2022-01-10 19:36:18 +01:00
for ( const auto & params : Params ( ) . GetConsensus ( ) . llmqs ) {
2022-09-22 13:14:48 +02:00
if ( IsQuorumTypeEnabled ( params . type , * llmq : : quorumManager , pindex ) ) {
2022-01-10 19:36:18 +01:00
ret . push_back ( params . type ) ;
2021-10-28 21:10:43 +02:00
}
}
return ret ;
}
2023-11-10 15:33:21 +01:00
std : : vector < std : : reference_wrapper < const Consensus : : LLMQParams > > GetEnabledQuorumParams ( gsl : : not_null < const CBlockIndex * > pindex )
2021-10-28 21:10:43 +02:00
{
std : : vector < std : : reference_wrapper < const Consensus : : LLMQParams > > ret ;
ret . reserve ( Params ( ) . GetConsensus ( ) . llmqs . size ( ) ) ;
2022-01-10 19:36:18 +01:00
std : : copy_if ( Params ( ) . GetConsensus ( ) . llmqs . begin ( ) , Params ( ) . GetConsensus ( ) . llmqs . end ( ) , std : : back_inserter ( ret ) ,
2022-09-22 13:14:48 +02:00
[ & pindex ] ( const auto & params ) { return IsQuorumTypeEnabled ( params . type , * llmq : : quorumManager , pindex ) ; } ) ;
2022-01-10 19:36:18 +01:00
2020-12-10 00:08:05 +01:00
return ret ;
}
2022-08-02 19:14:25 +02:00
bool QuorumDataRecoveryEnabled ( )
2021-02-01 17:10:19 +01:00
{
return gArgs . GetBoolArg ( " -llmq-data-recovery " , DEFAULT_ENABLE_QUORUM_DATA_RECOVERY ) ;
}
2022-08-02 19:14:25 +02:00
bool IsWatchQuorumsEnabled ( )
2021-03-29 20:09:09 +02:00
{
static bool fIsWatchQuroumsEnabled = gArgs . GetBoolArg ( " -watchquorums " , DEFAULT_WATCH_QUORUMS ) ;
return fIsWatchQuroumsEnabled ;
}
2022-08-02 19:14:25 +02:00
std : : map < Consensus : : LLMQType , QvvecSyncMode > GetEnabledQuorumVvecSyncEntries ( )
2021-02-01 17:10:19 +01:00
{
2021-03-16 23:50:41 +01:00
std : : map < Consensus : : LLMQType , QvvecSyncMode > mapQuorumVvecSyncEntries ;
for ( const auto & strEntry : gArgs . GetArgs ( " -llmq-qvvec-sync " ) ) {
2021-10-15 12:28:19 +02:00
Consensus : : LLMQType llmqType = Consensus : : LLMQType : : LLMQ_NONE ;
2021-03-16 23:50:41 +01:00
QvvecSyncMode mode { QvvecSyncMode : : Invalid } ;
std : : istringstream ssEntry ( strEntry ) ;
std : : string strLLMQType , strMode , strTest ;
const bool fLLMQTypePresent = std : : getline ( ssEntry , strLLMQType , ' : ' ) & & strLLMQType ! = " " ;
const bool fModePresent = std : : getline ( ssEntry , strMode , ' : ' ) & & strMode ! = " " ;
const bool fTooManyEntries = static_cast < bool > ( std : : getline ( ssEntry , strTest , ' : ' ) ) ;
if ( ! fLLMQTypePresent | | ! fModePresent | | fTooManyEntries ) {
throw std : : invalid_argument ( strprintf ( " Invalid format in -llmq-qvvec-sync: %s " , strEntry ) ) ;
}
2021-12-21 13:05:29 +01:00
if ( auto optLLMQParams = ranges : : find_if_opt ( Params ( ) . GetConsensus ( ) . llmqs ,
2022-01-10 19:36:18 +01:00
[ & strLLMQType ] ( const auto & params ) { return params . name = = strLLMQType ; } ) ) {
llmqType = optLLMQParams - > type ;
2021-12-21 13:05:29 +01:00
} else {
2021-03-16 23:50:41 +01:00
throw std : : invalid_argument ( strprintf ( " Invalid llmqType in -llmq-qvvec-sync: %s " , strEntry ) ) ;
}
if ( mapQuorumVvecSyncEntries . count ( llmqType ) > 0 ) {
throw std : : invalid_argument ( strprintf ( " Duplicated llmqType in -llmq-qvvec-sync: %s " , strEntry ) ) ;
}
int32_t nMode ;
if ( ParseInt32 ( strMode , & nMode ) ) {
switch ( nMode ) {
case ( int32_t ) QvvecSyncMode : : Always :
mode = QvvecSyncMode : : Always ;
break ;
case ( int32_t ) QvvecSyncMode : : OnlyIfTypeMember :
mode = QvvecSyncMode : : OnlyIfTypeMember ;
break ;
default :
mode = QvvecSyncMode : : Invalid ;
break ;
}
2021-02-01 17:10:19 +01:00
}
2021-03-16 23:50:41 +01:00
if ( mode = = QvvecSyncMode : : Invalid ) {
throw std : : invalid_argument ( strprintf ( " Invalid mode in -llmq-qvvec-sync: %s " , strEntry ) ) ;
2021-02-01 17:10:19 +01:00
}
2021-03-16 23:50:41 +01:00
mapQuorumVvecSyncEntries . emplace ( llmqType , mode ) ;
2021-02-01 17:10:19 +01:00
}
2021-03-16 23:50:41 +01:00
return mapQuorumVvecSyncEntries ;
2021-02-01 17:10:19 +01:00
}
2021-10-25 15:55:34 +02:00
template < typename CacheType >
2023-11-29 15:17:58 +01:00
void InitQuorumsCache ( CacheType & cache , bool limit_by_connections )
2021-10-25 15:55:34 +02:00
{
2022-06-15 23:00:43 +02:00
for ( const auto & llmq : Params ( ) . GetConsensus ( ) . llmqs ) {
2022-01-10 19:36:18 +01:00
cache . emplace ( std : : piecewise_construct , std : : forward_as_tuple ( llmq . type ) ,
2023-11-29 15:17:58 +01:00
std : : forward_as_tuple ( limit_by_connections ? llmq . keepOldConnections : llmq . keepOldKeys ) ) ;
2021-10-25 15:55:34 +02:00
}
}
2023-11-29 15:17:58 +01:00
template void InitQuorumsCache < std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , bool , StaticSaltedHasher > > > ( std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , bool , StaticSaltedHasher > > & cache , bool limit_by_connections ) ;
template void InitQuorumsCache < std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , std : : vector < CQuorumCPtr > , StaticSaltedHasher > > > ( std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , std : : vector < CQuorumCPtr > , StaticSaltedHasher > > & cache , bool limit_by_connections ) ;
template void InitQuorumsCache < std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , std : : shared_ptr < llmq : : CQuorum > , StaticSaltedHasher , 0ul , 0ul > , std : : less < Consensus : : LLMQType > , std : : allocator < std : : pair < Consensus : : LLMQType const , unordered_lru_cache < uint256 , std : : shared_ptr < llmq : : CQuorum > , StaticSaltedHasher , 0ul , 0ul > > > > > ( std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , std : : shared_ptr < llmq : : CQuorum > , StaticSaltedHasher , 0ul , 0ul > , std : : less < Consensus : : LLMQType > , std : : allocator < std : : pair < Consensus : : LLMQType const , unordered_lru_cache < uint256 , std : : shared_ptr < llmq : : CQuorum > , StaticSaltedHasher , 0ul , 0ul > > > > & cache , bool limit_by_connections ) ;
template void InitQuorumsCache < std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , int , StaticSaltedHasher > > > ( std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , int , StaticSaltedHasher > > & cache , bool limit_by_connections ) ;
2023-12-20 16:54:00 +01:00
template void InitQuorumsCache < std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , uint256 , StaticSaltedHasher > > > ( std : : map < Consensus : : LLMQType , unordered_lru_cache < uint256 , uint256 , StaticSaltedHasher > > & cache , bool limit_by_connections ) ;
2022-08-02 19:14:25 +02:00
} // namespace utils
2021-10-25 15:55:34 +02:00
2023-03-13 17:11:17 +01:00
const std : : optional < Consensus : : LLMQParams > GetLLMQParams ( Consensus : : LLMQType llmqType )
2020-12-10 00:08:05 +01:00
{
2022-01-10 19:36:18 +01:00
return Params ( ) . GetLLMQ ( llmqType ) ;
2020-12-10 00:08:05 +01:00
}
2019-01-15 15:35:26 +01:00
2019-07-15 20:55:01 +02:00
} // namespace llmq