Merge pull request #5253 from UdjinM6/bp_18.2.2

[v18.2.x] backport: backports and version bump to 18.2.2
This commit is contained in:
PastaPastaPasta 2023-03-20 09:57:08 -05:00 committed by GitHub
commit 1f3f0e00f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 472 additions and 188 deletions

View File

@ -1,7 +1,7 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 18)
define(_CLIENT_VERSION_MINOR, 2)
define(_CLIENT_VERSION_BUILD, 1)
define(_CLIENT_VERSION_BUILD, 2)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2023)

View File

@ -1,17 +1,15 @@
Dash Core version v18.2.1
Dash Core version v18.2.2
=========================
Release is now available from:
<https://www.dash.org/downloads/#wallets>
This is a new hotfix version release, bringing various bugfixes.
This is a new hotfix version release.
Please note that v18.2.0 was revoked due to a bug; this version fixes that bug.
This release is optional for all nodes; however, v18.2.1 is required to be
able to use both mainnet and testnet. Currently, v18.2.0 is not working on mainnet,
and v18.1.1 is not working on testnet; v18.2.1 will work on both networks.
This release is optional for all nodes; however, v18.2.2 or higher is required
to be able to use testnet right until v19 hard fork activation. Earlier
versions will not be able to sync past block 847000 on testnet.
Please report bugs using the issue tracker at GitHub:
@ -41,9 +39,9 @@ downgrade to an older version is only possible with a reindex
Downgrade warning
-----------------
### Downgrade to a version < v18.2.1
### Downgrade to a version < v18.2.2
Downgrading to a version older than v18.2.1 is supported.
Downgrading to a version older than v18.2.2 is supported.
### Downgrade to a version < v18.0.1
@ -51,35 +49,19 @@ Downgrading to a version older than v18.0.1 is not supported due to changes in
the indexes database folder. If you need to use an older version, you must
either reindex or re-sync the whole chain.
### Downgrade of masternodes to < 18.2.1
It is highly recommended not to downgrade masternodes below 18.2.1, as 18.2.1 (and 18.1.1)
fix important bugs which may result in your masternode being PoSe banned.
### Downgrade of masternodes to < v18.0.1
Starting with the 0.16 release, masternodes verify the protocol version of other
masternodes. This results in PoSe punishment/banning for outdated masternodes,
so downgrading even prior to the activation of the introduced hard-fork changes
is not recommended.
Versioning
----------
Dash Core imperfectly follows semantic versioning. Breaking changes should be
expected in a major release. The number and severity of breaking changes in minor
releases are minimized, however we do not guarantee there are no breaking changes.
Bitcoin backports often introduce breaking changes, and are a likely source of
breaking changes in minor releases. Patch releases should never contain breaking changes.
Notable changes
===============
See #5145 and #5142; these 2 PR fix important bugs in previous versions. Specifically,
#5145 fixes an issue where qfcommit messages can be replayed from the past, then are
validated and propagated to other nodes. This patch prevents old qfcommits
from being relayed. #5142 is a fix which enables this version to function both on testnet
and mainnet.
Testnet Breaking Changes
------------------------
A new testnet only LLMQ has been added. This LLMQ is of the type LLMQ_25_67; this LLMQ is only active on testnet.
This LLMQ will not remove the LLMQ_100_67 from testnet; however that quorum (likely) will not form and will perform no role.
See the [diff](https://github.com/dashpay/dash/pull/5225/files#diff-e70a38a3e8c2a63ca0494627301a5c7042141ad301193f78338d97cb1b300ff9R451-R469) for specific parameters of the LLMQ.
This LLMQ will become active at the height of 847000. **This will be a breaking change and a hard fork for testnet**
This LLMQ is not activated with the v19 hardfork; as such testnet will experience two hardforks. One at height 847000,
and the other to be determined by the BIP9 hard fork process.
Remote Procedure Call (RPC) Changes
-----------------------------------
@ -109,20 +91,21 @@ Backports from Bitcoin Core
---------------------------
None
v18.2.1 Change log
Other changes
-------------
#5247 is backported to improve debugging experience.
v18.2.2 Change log
==================
See detailed [set of changes](https://github.com/dashpay/dash/compare/v18.2.0...dashpay:v18.2.1).
See detailed [set of changes](https://github.com/dashpay/dash/compare/v18.2.1...dashpay:v18.2.2).
Credits
=======
Thanks to everyone who directly contributed to this release:
- Kittywhiskers Van Gogh
- Konstantin Akimov
- Odysseas Gabrielides
- PastaPastaPasta
- UdjinM6
As well as everyone that submitted issues, reviewed pull requests, helped debug the release candidates, and write DIPs that were implemented in this release.
@ -150,6 +133,7 @@ Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12.
These release are considered obsolete. Old release notes can be found here:
- [v18.2.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.2.md) released Jan/17/2023
- [v18.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.0.md) released Jan/01/2023
- [v18.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.1.md) released January/08/2023
- [v18.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.0.md) released October/09/2022

View File

@ -0,0 +1,187 @@
Dash Core version v18.2.1
=========================
Release is now available from:
<https://www.dash.org/downloads/#wallets>
This is a new hotfix version release, bringing various bugfixes.
Please note that v18.2.0 was revoked due to a bug; this version fixes that bug.
This release is optional for all nodes; however, v18.2.1 is required to be
able to use both mainnet and testnet. Currently, v18.2.0 is not working on mainnet,
and v18.1.1 is not working on testnet; v18.2.1 will work on both networks.
Please report bugs using the issue tracker at GitHub:
<https://github.com/dashpay/dash/issues>
Upgrading and downgrading
=========================
How to Upgrade
--------------
If you are running an older version, shut it down. Wait until it has completely
shut down (which might take a few minutes for older versions), then run the
installer (on Windows) or just copy over /Applications/Dash-Qt (on Mac) or
dashd/dash-qt (on Linux). If you upgrade after DIP0003 activation and you were
using version < 0.13 you will have to reindex (start with -reindex-chainstate
or -reindex) to make sure your wallet has all the new data synced. Upgrading
from version 0.13 should not require any additional actions.
When upgrading from a version prior to 18.0.1, the
first startup of Dash Core will run a migration process which can take anywhere
from a few minutes to thirty minutes to finish. After the migration, a
downgrade to an older version is only possible with a reindex
(or reindex-chainstate).
Downgrade warning
-----------------
### Downgrade to a version < v18.2.1
Downgrading to a version older than v18.2.1 is supported.
### Downgrade to a version < v18.0.1
Downgrading to a version older than v18.0.1 is not supported due to changes in
the indexes database folder. If you need to use an older version, you must
either reindex or re-sync the whole chain.
### Downgrade of masternodes to < 18.2.1
It is highly recommended not to downgrade masternodes below 18.2.1, as 18.2.1 (and 18.1.1)
fix important bugs which may result in your masternode being PoSe banned.
### Downgrade of masternodes to < v18.0.1
Starting with the 0.16 release, masternodes verify the protocol version of other
masternodes. This results in PoSe punishment/banning for outdated masternodes,
so downgrading even prior to the activation of the introduced hard-fork changes
is not recommended.
Versioning
----------
Dash Core imperfectly follows semantic versioning. Breaking changes should be
expected in a major release. The number and severity of breaking changes in minor
releases are minimized, however we do not guarantee there are no breaking changes.
Bitcoin backports often introduce breaking changes, and are a likely source of
breaking changes in minor releases. Patch releases should never contain breaking changes.
Notable changes
===============
See #5145 and #5142; these 2 PR fix important bugs in previous versions. Specifically,
#5145 fixes an issue where qfcommit messages can be replayed from the past, then are
validated and propagated to other nodes. This patch prevents old qfcommits
from being relayed. #5142 is a fix which enables this version to function both on testnet
and mainnet.
Remote Procedure Call (RPC) Changes
-----------------------------------
### The new RPCs are:
None
### The removed RPCs are:
None
### Changes in existing RPCs introduced through bitcoin backports:
None
### Dash-specific changes in existing RPCs:
None
Please check `help <command>` for more detailed information on specific RPCs.
Command-line options
--------------------
None
Please check `Help -> Command-line options` in Qt wallet or `dashd --help` for
more information.
Backports from Bitcoin Core
---------------------------
None
v18.2.1 Change log
==================
See detailed [set of changes](https://github.com/dashpay/dash/compare/v18.2.0...dashpay:v18.2.1).
Credits
=======
Thanks to everyone who directly contributed to this release:
- Kittywhiskers Van Gogh
- Konstantin Akimov
- Odysseas Gabrielides
- PastaPastaPasta
- UdjinM6
As well as everyone that submitted issues, reviewed pull requests, helped debug the release candidates, and write DIPs that were implemented in this release.
Older releases
==============
Dash was previously known as Darkcoin.
Darkcoin tree 0.8.x was a fork of Litecoin tree 0.8, original name was XCoin
which was first released on Jan/18/2014.
Darkcoin tree 0.9.x was the open source implementation of masternodes based on
the 0.8.x tree and was first released on Mar/13/2014.
Darkcoin tree 0.10.x used to be the closed source implementation of Darksend
which was released open source on Sep/25/2014.
Dash Core tree 0.11.x was a fork of Bitcoin Core tree 0.9,
Darkcoin was rebranded to Dash.
Dash Core tree 0.12.0.x was a fork of Bitcoin Core tree 0.10.
Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12.
These release are considered obsolete. Old release notes can be found here:
- [v18.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.0.md) released Jan/01/2023
- [v18.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.1.md) released January/08/2023
- [v18.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.0.md) released October/09/2022
- [v18.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.2.md) released October/09/2022
- [v18.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.1.md) released August/17/2022
- [v0.17.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.3.md) released June/07/2021
- [v0.17.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.2.md) released May/19/2021
- [v0.16.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.1.md) released November/17/2020
- [v0.16.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.0.md) released November/14/2020
- [v0.16.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.0.1.md) released September/30/2020
- [v0.15.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.15.0.0.md) released Febrary/18/2020
- [v0.14.0.5](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.5.md) released December/08/2019
- [v0.14.0.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.4.md) released November/22/2019
- [v0.14.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.3.md) released August/15/2019
- [v0.14.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.2.md) released July/4/2019
- [v0.14.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.1.md) released May/31/2019
- [v0.14.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.md) released May/22/2019
- [v0.13.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.3.md) released Apr/04/2019
- [v0.13.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.2.md) released Mar/15/2019
- [v0.13.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.1.md) released Feb/9/2019
- [v0.13.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.0.md) released Jan/14/2019
- [v0.12.3.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.4.md) released Dec/14/2018
- [v0.12.3.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.3.md) released Sep/19/2018
- [v0.12.3.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.2.md) released Jul/09/2018
- [v0.12.3.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.1.md) released Jul/03/2018
- [v0.12.2.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.3.md) released Jan/12/2018
- [v0.12.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.2.md) released Dec/17/2017
- [v0.12.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.md) released Nov/08/2017
- [v0.12.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.1.md) released Feb/06/2017
- [v0.12.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.0.md) released Aug/15/2015
- [v0.11.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.2.md) released Mar/04/2015
- [v0.11.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.1.md) released Feb/10/2015
- [v0.11.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.0.md) released Jan/15/2015
- [v0.10.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.10.0.md) released Sep/25/2014
- [v0.9.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.9.0.md) released Mar/13/2014

View File

@ -110,7 +110,7 @@ static CBlock FindDevNetGenesisBlock(const CBlock &prevBlock, const CAmount& rew
void CChainParams::AddLLMQ(Consensus::LLMQType llmqType)
{
assert(!HasLLMQ(llmqType));
assert(!GetLLMQ(llmqType).has_value());
for (const auto& llmq_param : Consensus::available_llmqs) {
if (llmq_param.type == llmqType) {
consensus.llmqs.push_back(llmq_param);
@ -121,25 +121,14 @@ void CChainParams::AddLLMQ(Consensus::LLMQType llmqType)
assert(false);
}
const Consensus::LLMQParams& CChainParams::GetLLMQ(Consensus::LLMQType llmqType) const
std::optional<Consensus::LLMQParams> CChainParams::GetLLMQ(Consensus::LLMQType llmqType) const
{
for (const auto& llmq_param : consensus.llmqs) {
if (llmq_param.type == llmqType) {
return llmq_param;
return std::make_optional(llmq_param);
}
}
error("CChainParams::%s: unknown LLMQ type %d", __func__, static_cast<uint8_t>(llmqType));
assert(false);
}
bool CChainParams::HasLLMQ(Consensus::LLMQType llmqType) const
{
for (const auto& llmq_param : consensus.llmqs) {
if (llmq_param.type == llmqType) {
return true;
}
}
return false;
return std::nullopt;
}
/**
@ -523,10 +512,11 @@ public:
AddLLMQ(Consensus::LLMQType::LLMQ_400_60);
AddLLMQ(Consensus::LLMQType::LLMQ_400_85);
AddLLMQ(Consensus::LLMQType::LLMQ_100_67);
AddLLMQ(Consensus::LLMQType::LLMQ_25_67);
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_25_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60;
fDefaultConsistencyChecks = false;
@ -1230,7 +1220,10 @@ void CDevNetParams::UpdateDevnetLLMQChainLocksFromArgs(const ArgsManager& args)
{
if (!args.IsArgSet("-llmqchainlocks")) return;
std::string strLLMQType = gArgs.GetArg("-llmqchainlocks", std::string(GetLLMQ(consensus.llmqTypeChainLocks).name));
const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeChainLocks);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqchainlocks", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) {
@ -1252,7 +1245,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendFromArgs(const ArgsManager& args)
{
if (!args.IsArgSet("-llmqinstantsend")) return;
std::string strLLMQType = gArgs.GetArg("-llmqinstantsend", std::string(GetLLMQ(consensus.llmqTypeInstantSend).name));
const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeInstantSend);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqinstantsend", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) {
@ -1274,7 +1270,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendDIP0024FromArgs(const ArgsManager
{
if (!args.IsArgSet("-llmqinstantsenddip0024")) return;
std::string strLLMQType = gArgs.GetArg("-llmqinstantsenddip0024", std::string(GetLLMQ(consensus.llmqTypeDIP0024InstantSend).name));
const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeDIP0024InstantSend);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqinstantsenddip0024", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) {

View File

@ -110,8 +110,7 @@ public:
const std::vector<std::string>& SporkAddresses() const { return vSporkAddresses; }
int MinSporkKeys() const { return nMinSporkKeys; }
bool BIP9CheckMasternodesUpgraded() const { return fBIP9CheckMasternodesUpgraded; }
const Consensus::LLMQParams& GetLLMQ(Consensus::LLMQType llmqType) const;
bool HasLLMQ(Consensus::LLMQType llmqType) const;
std::optional<Consensus::LLMQParams> GetLLMQ(Consensus::LLMQType llmqType) const;
protected:
CChainParams() {}

View File

@ -188,7 +188,9 @@ auto CachedGetQcHashesQcIndexedHashes(const CBlockIndex* pindexPrev, const llmq:
qcIndexedHashes_cached.clear();
for (const auto& [llmqType, vecBlockIndexes] : quorums) {
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmqType, pindexPrev);
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindexPrev);
auto& vec_hashes = qcHashes_cached[llmqType];
vec_hashes.reserve(vecBlockIndexes.size());
auto& map_indexed_hashes = qcIndexedHashes_cached[llmqType];
@ -252,12 +254,16 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
// having null commitments is ok but we don't use them here, move to the next tx
continue;
}
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
}
const auto& llmq_params = llmq_params_opt.value();
auto qcHash = ::SerializeHash(qc.commitment);
if (llmq::utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindexPrev)) {
if (llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexPrev)) {
auto& map_indexed_hashes = qcIndexedHashes[qc.commitment.llmqType];
map_indexed_hashes[qc.commitment.quorumIndex] = qcHash;
} else {
const auto& llmq_params = llmq::GetLLMQParams(qc.commitment.llmqType);
auto& vec_hashes = qcHashes[llmq_params.type];
if (vec_hashes.size() == size_t(llmq_params.signingActiveQuorumCount)) {
// we pop the last entry, which is actually the oldest quorum as GetMinedAndActiveCommitmentsUntilBlock
@ -281,8 +287,9 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
vec_hashes_final.reserve(CalcHashCountFromQCHashes(qcHashes));
for (const auto& [llmqType, vec_hashes] : qcHashes) {
const auto& llmq_params = llmq::GetLLMQParams(llmqType);
if (vec_hashes.size() > size_t(llmq_params.signingActiveQuorumCount)) {
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot");
}
// Copy vec_hashes into vec_hashes_final

View File

@ -829,9 +829,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
}
if (!qc.commitment.IsNull()) {
const auto& llmq_params = llmq::GetLLMQParams(qc.commitment.llmqType);
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
int qcnHeight = int(qc.nHeight);
int quorumHeight = qcnHeight - (qcnHeight % llmq_params.dkgInterval) + int(qc.commitment.quorumIndex);
int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
// we should actually never get into this case as validation should have caught it...but let's be sure

View File

@ -25,7 +25,9 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
}
Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeMnhf;
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval};
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
int signOffset{llmq_params_opt->dkgInterval};
const uint256 requestId = ::SerializeHash(std::make_pair(CBLSIG_REQUESTID_PREFIX, pQuorumIndex->nHeight));
return llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, 0) ||
@ -53,7 +55,7 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
}
if (!Params().HasLLMQ(Params().GetConsensus().llmqTypeMnhf)) {
if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type");
}

View File

@ -58,7 +58,8 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
return;
}
if (!Params().HasLLMQ(qc.llmqType)) {
const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__,
uint8_t(qc.llmqType), peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100));
@ -84,14 +85,14 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
// same, can't punish
return;
}
int quorumHeight = pQuorumBaseBlockIndex->nHeight - (pQuorumBaseBlockIndex->nHeight % GetLLMQParams(type).dkgInterval) + int(qc.quorumIndex);
int quorumHeight = pQuorumBaseBlockIndex->nHeight - (pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval) + int(qc.quorumIndex);
if (quorumHeight != pQuorumBaseBlockIndex->nHeight) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is not the first block in the DKG interval, peer=%d\n", __func__,
qc.quorumHash.ToString(), peer.GetId());
Misbehaving(peer.GetId(), 100);
return;
}
if (pQuorumBaseBlockIndex->nHeight < (::ChainActive().Height() - GetLLMQParams(type).dkgInterval)) {
if (pQuorumBaseBlockIndex->nHeight < (::ChainActive().Height() - llmq_params_opt->dkgInterval)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is too old, peer=%d\n", __func__,
qc.quorumHash.ToString(), peer.GetId());
// TODO: enable punishment in some future version when all/most nodes are running with this fix
@ -173,7 +174,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
if (numCommitmentsRequired > numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing");
}
if (llmq::utils::IsQuorumRotationEnabled(params.type, pindex)) {
if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
}
}
@ -209,7 +210,12 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
{
AssertLockHeld(cs_main);
const auto& llmq_params = GetLLMQParams(qc.llmqType);
const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d\n", __func__, static_cast<uint8_t>(qc.llmqType));
return false;
}
const auto& llmq_params = llmq_params_opt.value();
uint256 quorumHash = GetQuorumBlockHash(llmq_params, nHeight, qc.quorumIndex);
@ -263,7 +269,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
return true;
}
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params.type, pQuorumBaseBlockIndex);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex);
if (rotation_enabled) {
LogPrint(BCLog::LLMQ, "[ProcessCommitment] height[%d] pQuorumBaseBlockIndex[%d] quorumIndex[%d] qversion[%d] Built\n",
@ -313,7 +319,10 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)));
if (llmq::utils::IsQuorumRotationEnabled(qc.llmqType, pindex)) {
const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
assert(llmq_params_opt.has_value());
if (llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
evoDb.Erase(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex)));
} else {
evoDb.Erase(BuildInversedHeightKey(qc.llmqType, pindex->nHeight));
@ -372,7 +381,9 @@ bool CQuorumBlockProcessor::UpgradeDB()
}
const auto* pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash);
evoDb.GetRawDB().Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)), std::make_pair(qc, pindex->GetBlockHash()));
if (llmq::utils::IsQuorumRotationEnabled(qc.llmqType, pQuorumBaseBlockIndex)) {
const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
assert(llmq_params_opt.has_value());
if (llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pQuorumBaseBlockIndex)) {
evoDb.GetRawDB().Write(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex)), pQuorumBaseBlockIndex->nHeight);
} else {
evoDb.GetRawDB().Write(BuildInversedHeightKey(qc.llmqType, pindex->nHeight), pQuorumBaseBlockIndex->nHeight);
@ -406,8 +417,14 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
}
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
// should not happen as it was verified before processing the block
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
// only allow one commitment per type and per block (This was changed with rotation)
if (!utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindex)) {
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
if (ret.count(qc.commitment.llmqType) != 0) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
}
@ -454,7 +471,7 @@ size_t CQuorumBlockProcessor::GetNumCommitmentsRequired(const Consensus::LLMQPar
assert(nHeight <= ::ChainActive().Height() + 1);
const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams.type, pindex);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex);
size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1;
size_t ret{0};
@ -607,10 +624,11 @@ std::optional<const CBlockIndex*> CQuorumBlockProcessor::GetLastMinedCommitments
std::vector<std::pair<int, const CBlockIndex*>> CQuorumBlockProcessor::GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const
{
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
std::vector<std::pair<int, const CBlockIndex*>> ret;
for (const auto quorumIndex : irange::range(llmqParams.signingActiveQuorumCount)) {
for (const auto quorumIndex : irange::range(llmq_params_opt->signingActiveQuorumCount)) {
std::optional<const CBlockIndex*> q = GetLastMinedCommitmentsByQuorumIndexUntilBlock(llmqType, pindex, quorumIndex, cycle);
if (q.has_value()) {
ret.emplace_back(quorumIndex, q.value());
@ -658,7 +676,7 @@ std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> CQuorumBlockProce
for (const auto& params : Params().GetConsensus().llmqs) {
auto& v = ret[params.type];
v.reserve(params.signingActiveQuorumCount);
if (utils::IsQuorumRotationEnabled(params.type, pindex)) {
if (utils::IsQuorumRotationEnabled(params, pindex)) {
std::vector<std::pair<int, const CBlockIndex*>> commitments = GetLastMinedCommitmentsPerQuorumIndexUntilBlock(params.type, pindex, 0);
std::transform(commitments.begin(), commitments.end(), std::back_inserter(v),
[](const std::pair<int, const CBlockIndex*>& p) { return p.second; });
@ -737,7 +755,7 @@ std::optional<std::vector<CFinalCommitment>> CQuorumBlockProcessor::GetMineableC
assert(nHeight <= ::ChainActive().Height() + 1);
const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams.type, pindex);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex);
size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1;
std::stringstream ss;

View File

@ -30,16 +30,17 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui
bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool checkSigs) const
{
if (nVersion == 0 || nVersion != (utils::IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex) ? INDEXED_QUORUM_VERSION : CURRENT_VERSION)) {
LogPrintfFinalCommitment("q[%s] invalid nVersion=%d\n", quorumHash.ToString(), nVersion);
return false;
}
if (!Params().HasLLMQ(llmqType)) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
return false;
}
const auto& llmq_params = GetLLMQParams(llmqType);
const auto& llmq_params = llmq_params_opt.value();
if (nVersion == 0 || nVersion != (utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ? INDEXED_QUORUM_VERSION : CURRENT_VERSION)) {
LogPrintfFinalCommitment("q[%s] invalid nVersion=%d\n", quorumHash.ToString(), nVersion);
return false;
}
if (pQuorumBaseBlockIndex->GetBlockHash() != quorumHash) {
LogPrintfFinalCommitment("q[%s] invalid quorumHash\n", quorumHash.ToString());
@ -138,12 +139,13 @@ bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool che
bool CFinalCommitment::VerifyNull() const
{
if (!Params().HasLLMQ(llmqType)) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
return false;
}
if (!IsNull() || !VerifySizes(GetLLMQParams(llmqType))) {
if (!IsNull() || !VerifySizes(llmq_params_opt.value())) {
return false;
}
@ -170,10 +172,16 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
}
const auto& llmq_params = GetLLMQParams(qcTx.commitment.llmqType);
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, static_cast<uint8_t>(qcTx.commitment.llmqType));
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
if (LogAcceptCategory(BCLog::LLMQ)) {
std::stringstream ss;
for (const auto i: irange::range(llmq_params.size)) {
for (const auto i: irange::range(llmq_params_opt->size)) {
ss << "v[" << i << "]=" << qcTx.commitment.validMembers[i];
}
LogPrintfFinalCommitment("%s llmqType[%d] validMembers[%s] signers[]\n", __func__,
@ -201,10 +209,6 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
}
if (!Params().HasLLMQ(qcTx.commitment.llmqType)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-type");
}
if (qcTx.commitment.IsNull()) {
if (!qcTx.commitment.VerifyNull()) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());

View File

@ -18,7 +18,7 @@ UniValue CDKGDebugSessionStatus::ToJson(int quorumIndex, int detailLevel) const
{
UniValue ret(UniValue::VOBJ);
if (!Params().HasLLMQ(llmqType) || quorumHash.IsNull()) {
if (!GetLLMQParams(llmqType).has_value() || quorumHash.IsNull()) {
return ret;
}
@ -117,11 +117,12 @@ UniValue CDKGDebugStatus::ToJson(int detailLevel) const
// TODO Support array of sessions
UniValue sessionsArrJson(UniValue::VARR);
for (const auto& p : sessions) {
if (!Params().HasLLMQ(p.first.first)) {
const auto& llmq_params_opt = GetLLMQParams(p.first.first);
if (!llmq_params_opt.has_value()) {
continue;
}
UniValue s(UniValue::VOBJ);
s.pushKV("llmqType", std::string(GetLLMQParams(p.first.first).name));
s.pushKV("llmqType", std::string(llmq_params_opt->name));
s.pushKV("quorumIndex", p.first.second);
s.pushKV("status", p.second.ToJson(p.first.second, detailLevel));

View File

@ -85,7 +85,7 @@ bool CDKGSession::Init(const CBlockIndex* _pQuorumBaseBlockIndex, const std::vec
CDKGLogger logger(*this, __func__);
if (LogAcceptCategory(BCLog::LLMQ) && utils::IsQuorumRotationEnabled(params.type, m_quorum_base_block_index)) {
if (LogAcceptCategory(BCLog::LLMQ) && utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)) {
int cycleQuorumBaseHeight = m_quorum_base_block_index->nHeight - quorumIndex;
const CBlockIndex* pCycleQuorumBaseBlockIndex = m_quorum_base_block_index->GetAncestor(cycleQuorumBaseHeight);
std::stringstream ss;
@ -1206,7 +1206,7 @@ std::vector<CFinalCommitment> CDKGSession::FinalizeCommitments()
fqc.quorumPublicKey = first.quorumPublicKey;
fqc.quorumVvecHash = first.quorumVvecHash;
if (utils::IsQuorumRotationEnabled(fqc.llmqType, m_quorum_base_block_index)) {
if (utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)) {
fqc.nVersion = CFinalCommitment::INDEXED_QUORUM_VERSION;
fqc.quorumIndex = quorumIndex;
} else {

View File

@ -256,7 +256,7 @@ class CDKGSession
friend class CDKGLogger;
private:
const Consensus::LLMQParams& params;
const Consensus::LLMQParams params;
CBLSWorker& blsWorker;
CBLSWorkerCache cache;

View File

@ -84,7 +84,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
{
//AssertLockNotHeld(cs_main);
//Indexed quorums (greater than 0) are enabled with Quorum Rotation
if (quorumIndex > 0 && !utils::IsQuorumRotationEnabled(params.type, pindexNew)) {
if (quorumIndex > 0 && !utils::IsQuorumRotationEnabled(params, pindexNew)) {
return;
}
LOCK(cs);

View File

@ -109,7 +109,7 @@ private:
mutable CCriticalSection cs;
std::atomic<bool> stopRequested{false};
const Consensus::LLMQParams& params;
const Consensus::LLMQParams params;
CConnman& connman;
const int quorumIndex;
CBLSWorker& blsWorker;

View File

@ -196,12 +196,14 @@ void CDKGSessionManager::ProcessMessage(CNode* pfrom, const CQuorumManager& quor
vRecv.Rewind(sizeof(uint256));
vRecv.Rewind(sizeof(uint8_t));
if (!Params().HasLLMQ(llmqType)) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", uint8_t(llmqType));
Misbehaving(pfrom->GetId(), 100);
return;
}
const auto& llmq_params = llmq_params_opt.value();
int quorumIndex{-1};
@ -232,10 +234,9 @@ void CDKGSessionManager::ProcessMessage(CNode* pfrom, const CQuorumManager& quor
return;
}
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
quorumIndex = pQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval;
int quorumIndexMax = utils::IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex) ?
llmqParams.signingActiveQuorumCount - 1 : 0;
quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
int quorumIndexMax = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ?
llmq_params.signingActiveQuorumCount - 1 : 0;
if (quorumIndex > quorumIndexMax) {
LOCK(cs_main);

View File

@ -706,8 +706,10 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx)
// compute and set cycle hash if islock is deterministic
if (islock.IsDeterministic()) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
LOCK(cs_main);
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval;
const auto dkgInterval = llmq_params_opt->dkgInterval;
const auto quorumHeight = ::ChainActive().Height() - (::ChainActive().Height() % dkgInterval);
islock.cycleHash = ::ChainActive()[quorumHeight]->GetBlockHash();
}
@ -804,7 +806,9 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode* pfrom, cons
// Deterministic islocks MUST use rotation based llmq
auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend;
if (blockIndex->nHeight % GetLLMQParams(llmqType).dkgInterval != 0) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
if (blockIndex->nHeight % llmq_params_opt->dkgInterval != 0) {
WITH_LOCK(cs_main, Misbehaving(pfrom->GetId(), 100));
return;
}
@ -905,10 +909,13 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(bool deterministic)
//TODO Investigate if leaving this is ok
auto llmqType = utils::GetInstantSendLLMQType(deterministic);
auto dkgInterval = GetLLMQParams(llmqType).dkgInterval;
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
const auto& llmq_params = llmq_params_opt.value();
auto dkgInterval = llmq_params.dkgInterval;
// First check against the current active set and don't ban
auto badISLocks = ProcessPendingInstantSendLocks(llmqType, 0, pend, false);
auto badISLocks = ProcessPendingInstantSendLocks(llmq_params, 0, pend, false);
if (!badISLocks.empty()) {
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__);
@ -921,13 +928,13 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(bool deterministic)
}
}
// Now check against the previous active set and perform banning if this fails
ProcessPendingInstantSendLocks(llmqType, dkgInterval, pend, true);
ProcessPendingInstantSendLocks(llmq_params, dkgInterval, pend, true);
}
return fMoreWork;
}
std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPendingInstantSendLocks(const Consensus::LLMQType llmqType, int signOffset, const std::unordered_map<uint256, std::pair<NodeId, CInstantSendLockPtr>, StaticSaltedHasher>& pend, bool ban)
std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, const std::unordered_map<uint256, std::pair<NodeId, CInstantSendLockPtr>, StaticSaltedHasher>& pend, bool ban)
{
CBLSBatchVerifier<NodeId, uint256> batchVerifier(false, true, 8);
std::unordered_map<uint256, CRecoveredSig, StaticSaltedHasher> recSigs;
@ -951,7 +958,7 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
auto id = islock->GetRequestId();
// no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it
if (sigman.HasRecoveredSig(llmqType, id, islock->txid)) {
if (sigman.HasRecoveredSig(llmq_params.type, id, islock->txid)) {
alreadyVerified++;
continue;
}
@ -966,26 +973,26 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
continue;
}
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval;
const auto dkgInterval = llmq_params.dkgInterval;
if (blockIndex->nHeight + dkgInterval < ::ChainActive().Height()) {
nSignHeight = blockIndex->nHeight + dkgInterval - 1;
}
}
auto quorum = llmq::CSigningManager::SelectQuorumForSigning(llmqType, qman, id, nSignHeight, signOffset);
auto quorum = llmq::CSigningManager::SelectQuorumForSigning(llmq_params, qman, id, nSignHeight, signOffset);
if (!quorum) {
// should not happen, but if one fails to select, all others will also fail to select
return {};
}
uint256 signHash = utils::BuildSignHash(llmqType, quorum->qc->quorumHash, id, islock->txid);
uint256 signHash = utils::BuildSignHash(llmq_params.type, quorum->qc->quorumHash, id, islock->txid);
batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey);
verifyCount++;
// We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which
// avoids unnecessary double-verification of the signature. We however only do this when verification here
// turns out to be good (which is checked further down)
if (!sigman.HasRecoveredSigForId(llmqType, id)) {
recSigs.try_emplace(hash, CRecoveredSig(llmqType, quorum->qc->quorumHash, id, islock->txid, islock->sig));
if (!sigman.HasRecoveredSigForId(llmq_params.type, id)) {
recSigs.try_emplace(hash, CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, islock->sig));
}
}
@ -1025,7 +1032,7 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
auto it = recSigs.find(hash);
if (it != recSigs.end()) {
auto recSig = std::make_shared<CRecoveredSig>(std::move(it->second));
if (!sigman.HasRecoveredSigForId(llmqType, recSig->getId())) {
if (!sigman.HasRecoveredSigForId(llmq_params.type, recSig->getId())) {
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__,
islock->txid.ToString(), hash.ToString(), nodeId);
sigman.PushReconstructedRecoveredSig(recSig);

View File

@ -284,7 +284,7 @@ private:
bool ProcessPendingInstantSendLocks();
bool ProcessPendingInstantSendLocks(bool deterministic) LOCKS_EXCLUDED(cs_pendingLocks);
std::unordered_set<uint256, StaticSaltedHasher> ProcessPendingInstantSendLocks(const Consensus::LLMQType llmqType,
std::unordered_set<uint256, StaticSaltedHasher> ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params,
int signOffset,
const std::unordered_map<uint256,
std::pair<NodeId, CInstantSendLockPtr>,

View File

@ -19,6 +19,7 @@ enum class LLMQType : uint8_t {
LLMQ_400_85 = 3, // 400 members, 340 (85%) threshold, one every 24 hours
LLMQ_100_67 = 4, // 100 members, 67 (67%) threshold, one per hour
LLMQ_60_75 = 5, // 60 members, 45 (75%) threshold, one every 12 hours
LLMQ_25_67 = 6, // 25 members, 67 (67%) threshold, one per hour
// for testing only
LLMQ_TEST = 100, // 3 members, 2 (66%) threshold, one per hour. Params might differ when -llmqtestparams is used
@ -105,8 +106,13 @@ struct LLMQParams {
int recoveryMembers;
};
//static_assert(std::is_trivial_v<Consensus::LLMQParams>, "LLMQParams is not a trivial type");
static_assert(std::is_trivially_copyable_v<Consensus::LLMQParams>, "LLMQParams is not trivially copyable");
//static_assert(std::is_trivially_default_constructible_v<Consensus::LLMQParams>, "LLMQParams is not trivially default constructible");
static_assert(std::is_trivially_assignable_v<Consensus::LLMQParams, Consensus::LLMQParams>, "LLMQParams is not trivially assignable");
static constexpr std::array<LLMQParams, 11> available_llmqs = {
static constexpr std::array<LLMQParams, 12> available_llmqs = {
/**
* llmq_test
@ -388,6 +394,33 @@ static constexpr std::array<LLMQParams, 11> available_llmqs = {
.recoveryMembers = 50,
},
/**
* llmq_25_67
* This quorum is deployed on Testnet and requires
* 25 participants
*
* Used by Dash Platform
*/
LLMQParams{
.type = LLMQType::LLMQ_25_67,
.name = "llmq_25_67",
.useRotation = false,
.size = 25,
.minSize = 22,
.threshold = 17,
.dkgInterval = 24, // one DKG per hour
.dkgPhaseBlocks = 2,
.dkgMiningWindowStart = 10, // dkgPhaseBlocks * 5 = after finalization
.dkgMiningWindowEnd = 18,
.dkgBadVotesThreshold = 22,
.signingActiveQuorumCount = 24, // a full day worth of LLMQs
.keepOldConnections = 25,
.recoveryMembers = 12,
},
}; // available_llmqs
} // namespace Consensus

View File

@ -299,7 +299,7 @@ void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqPar
auto connmanQuorumsToDelete = connman.GetMasternodeQuorums(llmqParams.type);
// don't remove connections for the currently in-progress DKG round
if (utils::IsQuorumRotationEnabled(llmqParams.type, pindexNew)) {
if (utils::IsQuorumRotationEnabled(llmqParams, pindexNew)) {
int cycleIndexTipHeight = pindexNew->nHeight % llmqParams.dkgInterval;
int cycleQuorumBaseHeight = pindexNew->nHeight - cycleIndexTipHeight;
std::stringstream ss;
@ -371,7 +371,9 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l
}
assert(qc->quorumHash == pQuorumBaseBlockIndex->GetBlockHash());
auto quorum = std::make_shared<CQuorum>(llmq::GetLLMQParams(llmqType), blsWorker);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorum = std::make_shared<CQuorum>(llmq_params_opt.value(), blsWorker);
auto members = utils::GetAllQuorumMembers(qc->llmqType, pQuorumBaseBlockIndex);
quorum->Init(std::move(qc), pQuorumBaseBlockIndex, minedBlockHash, members);
@ -450,7 +452,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pFrom is neither a verified masternode nor a qwatch connection\n", __func__);
return false;
}
if (!Params().HasLLMQ(llmqType)) {
if (!GetLLMQParams(llmqType).has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid llmqType: %d\n", __func__, static_cast<uint8_t>(llmqType));
return false;
}
@ -523,7 +525,9 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
}
// Get the block indexes of the mined commitments to build the required quorums from
std::vector<const CBlockIndex*> pQuorumBaseBlockIndexes{ GetLLMQParams(llmqType).useRotation ?
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
std::vector<const CBlockIndex*> pQuorumBaseBlockIndexes{ llmq_params_opt->useRotation ?
quorumBlockProcessor.GetMinedCommitmentsIndexedUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments) :
quorumBlockProcessor.GetMinedCommitmentsUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments)
};
@ -648,7 +652,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& msg_type, C
}
}
if (!Params().HasLLMQ(request.GetLLMQType())) {
if (!GetLLMQParams(request.GetLLMQType()).has_value()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID);
return;
}

View File

@ -158,7 +158,7 @@ class CQuorum
{
friend class CQuorumManager;
public:
const Consensus::LLMQParams& params;
const Consensus::LLMQParams params;
CFinalCommitmentPtr qc;
const CBlockIndex* m_quorum_base_block_index{nullptr};
uint256 minedBlockHash;

View File

@ -606,7 +606,7 @@ bool CSigningManager::PreVerifyRecoveredSig(const CQuorumManager& quorum_manager
retBan = false;
auto llmqType = recoveredSig.getLlmqType();
if (!Params().HasLLMQ(llmqType)) {
if (!GetLLMQParams(llmqType).has_value()) {
retBan = true;
return false;
}
@ -882,7 +882,9 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares
// This gives a slight risk of not getting enough shares to recover a signature
// But at least it shouldn't be possible to get conflicting recovered signatures
// TODO fix this by re-signing when the next block arrives, but only when that block results in a change of the quorum list and no recovered signature has been created in the mean time
quorum = SelectQuorumForSigning(llmqType, qman, id);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
quorum = SelectQuorumForSigning(llmq_params_opt.value(), qman, id);
} else {
quorum = qman.GetQuorum(llmqType, quorumHash);
}
@ -979,9 +981,9 @@ bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256&
return db.GetVoteForId(llmqType, id, msgHashRet);
}
CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight, int signOffset)
CQuorumCPtr CSigningManager::SelectQuorumForSigning(const Consensus::LLMQParams& llmq_params, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight, int signOffset)
{
size_t poolSize = GetLLMQParams(llmqType).signingActiveQuorumCount;
size_t poolSize = llmq_params.signingActiveQuorumCount;
CBlockIndex* pindexStart;
{
@ -996,13 +998,13 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
pindexStart = ::ChainActive()[startBlockHeight];
}
if (utils::IsQuorumRotationEnabled(llmqType, pindexStart)) {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize);
if (utils::IsQuorumRotationEnabled(llmq_params, pindexStart)) {
auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) {
return nullptr;
}
//log2 int
int n = std::log2(GetLLMQParams(llmqType).signingActiveQuorumCount);
int n = std::log2(llmq_params.signingActiveQuorumCount);
//Extract last 64 bits of selectionHash
uint64_t b = selectionHash.GetUint64(3);
//Take last n bits of b
@ -1021,7 +1023,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
}
return *itQuorum;
} else {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize);
auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) {
return nullptr;
}
@ -1030,7 +1032,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
scores.reserve(quorums.size());
for (const auto i : irange::range(quorums.size())) {
CHashWriter h(SER_NETWORK, 0);
h << llmqType;
h << llmq_params.type;
h << quorums[i]->qc->quorumHash;
h << selectionHash;
scores.emplace_back(h.GetHash(), i);
@ -1042,7 +1044,9 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, const int signOffset)
{
auto quorum = SelectQuorumForSigning(llmqType, quorum_manager, id, signedAtHeight, signOffset);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), quorum_manager, id, signedAtHeight, signOffset);
if (!quorum) {
return false;
}

View File

@ -223,7 +223,7 @@ public:
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const;
static std::vector<CQuorumCPtr> GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight);
static CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight = -1 /*chain tip*/, int signOffset = SIGN_HEIGHT_OFFSET);
static CQuorumCPtr SelectQuorumForSigning(const Consensus::LLMQParams& llmq_params, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight = -1 /*chain tip*/, int signOffset = SIGN_HEIGHT_OFFSET);
// Verifies a recovered sig that was signed while the chain tip was at signedAtTip
static bool VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, int signOffset = SIGN_HEIGHT_OFFSET);

View File

@ -96,7 +96,9 @@ std::string CBatchedSigShares::ToInvString() const
static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, CSigBase from)
{
const auto& llmq_params = GetLLMQParams((Consensus::LLMQType)from.getLlmqType());
const auto& llmq_params_opt = GetLLMQParams((Consensus::LLMQType)from.getLlmqType());
assert(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
s.llmqType = from.getLlmqType();
s.quorumHash = from.getQuorumHash();
@ -296,7 +298,7 @@ void CSigSharesManager::ProcessMessage(const CNode* pfrom, const std::string& ms
bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode* pfrom, const CSigSesAnn& ann)
{
auto llmqType = ann.getLlmqType();
if (!Params().HasLLMQ(llmqType)) {
if (!GetLLMQParams(llmqType).has_value()) {
return false;
}
if (ann.getSessionId() == UNINITIALIZED_SESSION_ID || ann.getQuorumHash().IsNull() || ann.getId().IsNull() || ann.getMsgHash().IsNull()) {
@ -327,7 +329,8 @@ bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode* pfrom, const CSigSe
bool CSigSharesManager::VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv)
{
return inv.inv.size() == size_t(GetLLMQParams(llmqType).size);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
return llmq_params_opt.has_value() && (inv.inv.size() == size_t(llmq_params_opt->size));
}
bool CSigSharesManager::ProcessMessageSigSharesInv(const CNode* pfrom, const CSigSharesInv& inv)
@ -899,7 +902,9 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
}
auto& inv = (*invMap)[signHash];
if (inv.inv.empty()) {
inv.Init(GetLLMQParams(session.llmqType).size);
const auto& llmq_params_opt = GetLLMQParams(session.llmqType);
assert(llmq_params_opt.has_value());
inv.Init(llmq_params_opt->size);
}
inv.inv[k.second] = true;
@ -1046,7 +1051,9 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, st
auto& inv = sigSharesToAnnounce[nodeId][signHash];
if (inv.inv.empty()) {
inv.Init(GetLLMQParams(sigShare->getLlmqType()).size);
const auto& llmq_params_opt = GetLLMQParams(sigShare->getLlmqType());
assert(llmq_params_opt.has_value());
inv.Init(llmq_params_opt->size);
}
inv.inv[quorumMember] = true;
session.knows.inv[quorumMember] = true;

View File

@ -168,8 +168,10 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
Consensus::LLMQType llmqType = utils::GetInstantSendLLMQType(qman, blockIndex);
// Since the returned quorums are in reversed order, the most recent one is at index 0
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
const int cycleLength = llmqParams.dkgInterval;
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
const int cycleLength = llmq_params_opt->dkgInterval;
constexpr int workDiff = 8;
const CBlockIndex* hBlockIndex = blockIndex->GetAncestor(blockIndex->nHeight - (blockIndex->nHeight % cycleLength));
@ -307,7 +309,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
}
response.lastCommitmentPerIndex.push_back(*qc);
int quorumCycleStartHeight = obj.second->nHeight - (obj.second->nHeight % llmqParams.dkgInterval);
int quorumCycleStartHeight = obj.second->nHeight - (obj.second->nHeight % llmq_params_opt->dkgInterval);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - cycleLength);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - 2 * cycleLength);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - 3 * cycleLength);

View File

@ -23,6 +23,8 @@
#include <optional>
static constexpr int TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT = 847000;
namespace llmq
{
@ -36,7 +38,7 @@ namespace utils
void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache)
{
for (const Consensus::LLMQParams& params : GetEnabledQuorumParams(pQuorumBaseBlockIndex->pprev)) {
if (IsQuorumRotationEnabled(params.type, pQuorumBaseBlockIndex) && (pQuorumBaseBlockIndex->nHeight % params.dkgInterval == 0)) {
if (IsQuorumRotationEnabled(params, pQuorumBaseBlockIndex) && (pQuorumBaseBlockIndex->nHeight % params.dkgInterval == 0)) {
GetAllQuorumMembers(params.type, pQuorumBaseBlockIndex, reset_cache);
}
}
@ -64,7 +66,11 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
}
}
if (IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex)) {
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)) {
if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) {
InitQuorumsCache(mapIndexedQuorumMembers);
}
@ -77,9 +83,8 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
* Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex
*/
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval;
if (quorumIndex >= llmqParams.signingActiveQuorumCount) {
int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
if (quorumIndex >= llmq_params.signingActiveQuorumCount) {
return {};
}
int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex;
@ -98,7 +103,7 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
return quorumMembers;
}
auto q = ComputeQuorumMembersByQuarterRotation(llmqType, pCycleQuorumBaseBlockIndex);
auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, pCycleQuorumBaseBlockIndex);
LOCK(cs_indexed_members);
for (int i = 0; i < static_cast<int>(q.size()); ++i) {
mapIndexedQuorumMembers[llmqType].insert(std::make_pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), i), q[i]);
@ -118,13 +123,13 @@ std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqT
{
auto allMns = deterministicMNManager->GetListForBlock(pQuorumBaseBlockIndex);
auto modifier = ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash()));
return allMns.CalculateQuorum(GetLLMQParams(llmqType).size, modifier);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
return allMns.CalculateQuorum(llmq_params_opt->size, modifier);
}
std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(Consensus::LLMQType llmqType, const CBlockIndex* pCycleQuorumBaseBlockIndex)
std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pCycleQuorumBaseBlockIndex)
{
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
const int cycleLength = llmqParams.dkgInterval;
assert(pCycleQuorumBaseBlockIndex->nHeight % cycleLength == 0);
@ -134,7 +139,7 @@ std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRota
LOCK(deterministicMNManager->cs);
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex);
LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", static_cast<int>(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount());
LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", static_cast<int>(llmqParams.type), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount());
PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, pBlockHMinusCIndex, pBlockHMinus2CIndex, pBlockHMinus3CIndex, pCycleQuorumBaseBlockIndex->nHeight);
@ -591,16 +596,16 @@ bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType)
return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_23_QUORUM_POSE));
}
bool IsQuorumRotationEnabled(Consensus::LLMQType llmqType, const CBlockIndex* pindex)
bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindex)
{
assert(pindex);
if (!GetLLMQParams(llmqType).useRotation) {
if (!llmqParams.useRotation) {
return false;
}
LOCK(cs_llmq_vbc);
int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % GetLLMQParams(llmqType).dkgInterval);
int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval);
if (cycleQuorumBaseHeight < 1) {
return false;
}
@ -863,7 +868,9 @@ bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, co
// 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
auto quorums = qman.ScanQuorums(llmqType, GetLLMQParams(llmqType).keepOldConnections);
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections);
return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; });
}
@ -915,6 +922,11 @@ bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumMana
}
break;
}
case Consensus::LLMQType::LLMQ_25_67:
if (pindex->nHeight < TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT) {
return false;
}
break;
default:
throw std::runtime_error(strprintf("%s: Unknown LLMQ type %d", __func__, static_cast<uint8_t>(llmqType)));
}
@ -1018,7 +1030,7 @@ template void InitQuorumsCache<std::map<Consensus::LLMQType, unordered_lru_cache
} // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType)
const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType llmqType)
{
return Params().GetLLMQ(llmqType);
}

View File

@ -59,7 +59,7 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false);
static std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex);
static std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(Consensus::LLMQType llmqType, const CBlockIndex* pCycleQuorumBaseBlockIndex);
static std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pCycleQuorumBaseBlockIndex);
static std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const PreviousQuorumQuarters& quarters);
@ -89,7 +89,7 @@ bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumMana
std::vector<Consensus::LLMQType> GetEnabledQuorumTypes(const CBlockIndex* pindex);
std::vector<std::reference_wrapper<const Consensus::LLMQParams>> GetEnabledQuorumParams(const CBlockIndex* pindex);
bool IsQuorumRotationEnabled(Consensus::LLMQType llmqType, const CBlockIndex* pindex);
bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindex);
Consensus::LLMQType GetInstantSendLLMQType(const CQuorumManager& qman, const CBlockIndex* pindex);
Consensus::LLMQType GetInstantSendLLMQType(bool deterministic);
bool IsDIP0024Active(const CBlockIndex* pindex);
@ -139,7 +139,7 @@ void InitQuorumsCache(CacheType& cache);
} // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType);
[[ nodiscard ]] const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType llmqType);
} // namespace llmq

View File

@ -70,15 +70,16 @@ static UniValue quorum_list(const JSONRPCRequest& request)
CBlockIndex* pindexTip = WITH_LOCK(cs_main, return ::ChainActive().Tip());
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
UniValue v(UniValue::VARR);
auto quorums = llmq_ctx.qman->ScanQuorums(type, pindexTip, count > -1 ? count : llmq_params.signingActiveQuorumCount);
auto quorums = llmq_ctx.qman->ScanQuorums(type, pindexTip, count > -1 ? count : llmq_params_opt->signingActiveQuorumCount);
for (const auto& q : quorums) {
v.push_back(q->qc->quorumHash.ToString());
}
ret.pushKV(std::string(llmq_params.name), v);
ret.pushKV(std::string(llmq_params_opt->name), v);
}
return ret;
@ -135,7 +136,9 @@ static UniValue quorum_list_extended(const JSONRPCRequest& request)
CBlockIndex* pblockindex = nHeight != -1 ? WITH_LOCK(cs_main, return ::ChainActive()[nHeight]) : WITH_LOCK(cs_main, return ::ChainActive().Tip());
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pblockindex)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
UniValue v(UniValue::VARR);
auto quorums = llmq_ctx.qman->ScanQuorums(type, pblockindex, llmq_params.signingActiveQuorumCount);
@ -222,7 +225,7 @@ static UniValue quorum_info(const JSONRPCRequest& request)
quorum_info_help(request);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) {
if (!llmq::GetLLMQParams(llmqType).has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
@ -282,8 +285,10 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
UniValue minableCommitments(UniValue::VARR);
UniValue quorumArrConnections(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(type, pindexTip);
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexTip);
size_t quorums_num = rotation_enabled ? llmq_params.signingActiveQuorumCount : 1;
for (int quorumIndex = 0; quorumIndex < quorums_num; ++quorumIndex) {
@ -386,12 +391,13 @@ static UniValue quorum_memberof(const JSONRPCRequest& request)
UniValue result(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
size_t count = llmq_params.signingActiveQuorumCount;
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
size_t count = llmq_params_opt->signingActiveQuorumCount;
if (scanQuorumsCount != -1) {
count = (size_t)scanQuorumsCount;
}
auto quorums = llmq_ctx.qman->ScanQuorums(llmq_params.type, count);
auto quorums = llmq_ctx.qman->ScanQuorums(llmq_params_opt->type, count);
for (auto& quorum : quorums) {
if (quorum->IsMember(dmn->proTxHash)) {
auto json = BuildQuorumInfo(quorum, false, false);
@ -508,7 +514,8 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
LLMQContext& llmq_ctx = EnsureLLMQContext(request.context);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) {
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
@ -530,7 +537,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
llmq::CQuorumCPtr pQuorum;
if (quorumHash.IsNull()) {
pQuorum = llmq_ctx.sigman->SelectQuorumForSigning(llmqType, *llmq_ctx.qman, id);
pQuorum = llmq_ctx.sigman->SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
} else {
pQuorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
}
@ -568,7 +575,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
signHeight = ParseInt32V(request.params[5], "signHeight");
}
// First check against the current active set, if it fails check against the last active set
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval};
int signOffset{llmq_params_opt->dkgInterval};
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
} else {
@ -619,7 +626,8 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
quorum_selectquorum_help(request);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) {
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
}
@ -628,7 +636,7 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
LLMQContext& llmq_ctx = EnsureLLMQContext(request.context);
auto quorum = llmq_ctx.sigman->SelectQuorumForSigning(llmqType, *llmq_ctx.qman, id);
auto quorum = llmq_ctx.sigman->SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
if (!quorum) {
throw JSONRPCError(RPC_MISC_ERROR, "no quorums active");
}
@ -944,7 +952,9 @@ static UniValue verifyislock(const JSONRPCRequest& request)
auto llmqType = llmq::utils::GetInstantSendLLMQType(*llmq_ctx.qman, pBlockIndex);
// First check against the current active set, if it fails check against the last active set
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval};
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
CHECK_NONFATAL(llmq_params_opt.has_value());
int signOffset{llmq_params_opt->dkgInterval};
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
}