neobytes/src/llmq/quorums_commitment.cpp

181 lines
5.7 KiB
C++
Raw Normal View History

// Copyright (c) 2018-2019 The Dash Core developers
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "quorums_commitment.h"
#include "quorums_utils.h"
#include "chainparams.h"
#include "validation.h"
#include "evo/specialtx.h"
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
namespace llmq
{
CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const uint256& _quorumHash) :
llmqType(params.type),
quorumHash(_quorumHash),
signers(params.size),
validMembers(params.size)
{
}
#define LogPrintfFinalCommitment(...) do { \
LogPrintStr(strprintf("CFinalCommitment::%s -- %s", __func__, tinyformat::format(__VA_ARGS__))); \
} while(0)
bool CFinalCommitment::Verify(const std::vector<CDeterministicMNCPtr>& members, bool checkSigs) const
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
{
if (nVersion == 0 || nVersion > CURRENT_VERSION) {
return false;
}
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)llmqType)) {
LogPrintfFinalCommitment("invalid llmqType=%d\n", llmqType);
return false;
}
const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)llmqType);
if (!VerifySizes(params)) {
return false;
}
if (CountValidMembers() < params.minSize) {
LogPrintfFinalCommitment("invalid validMembers count. validMembersCount=%d\n", CountValidMembers());
return false;
}
if (CountSigners() < params.minSize) {
LogPrintfFinalCommitment("invalid signers count. signersCount=%d\n", CountSigners());
return false;
}
if (!quorumPublicKey.IsValid()) {
LogPrintfFinalCommitment("invalid quorumPublicKey\n");
return false;
}
if (quorumVvecHash.IsNull()) {
LogPrintfFinalCommitment("invalid quorumVvecHash\n");
return false;
}
if (!membersSig.IsValid()) {
LogPrintfFinalCommitment("invalid membersSig\n");
return false;
}
if (!quorumSig.IsValid()) {
LogPrintfFinalCommitment("invalid vvecSig\n");
return false;
}
for (size_t i = members.size(); i < params.size; i++) {
if (validMembers[i]) {
LogPrintfFinalCommitment("invalid validMembers bitset. bit %d should not be set\n", i);
return false;
}
if (signers[i]) {
LogPrintfFinalCommitment("invalid signers bitset. bit %d should not be set\n", i);
return false;
}
}
// sigs are only checked when the block is processed
if (checkSigs) {
uint256 commitmentHash = CLLMQUtils::BuildCommitmentHash(params.type, quorumHash, validMembers, quorumPublicKey, quorumVvecHash);
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
std::vector<CBLSPublicKey> memberPubKeys;
for (size_t i = 0; i < members.size(); i++) {
if (!signers[i]) {
continue;
}
memberPubKeys.emplace_back(members[i]->pdmnState->pubKeyOperator.Get());
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
}
if (!membersSig.VerifySecureAggregated(memberPubKeys, commitmentHash)) {
LogPrintfFinalCommitment("invalid aggregated members signature\n");
return false;
}
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
if (!quorumSig.VerifyInsecure(quorumPublicKey, commitmentHash)) {
LogPrintfFinalCommitment("invalid quorum signature\n");
return false;
}
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
}
return true;
}
bool CFinalCommitment::VerifyNull() const
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
{
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)llmqType)) {
LogPrintfFinalCommitment("invalid llmqType=%d\n", llmqType);
return false;
}
const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)llmqType);
if (!IsNull() || !VerifySizes(params)) {
return false;
}
return true;
}
bool CFinalCommitment::VerifySizes(const Consensus::LLMQParams& params) const
{
if (signers.size() != params.size) {
LogPrintfFinalCommitment("invalid signers.size=%d\n", signers.size());
return false;
}
if (validMembers.size() != params.size) {
LogPrintfFinalCommitment("invalid signers.size=%d\n", signers.size());
return false;
}
return true;
}
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
CFinalCommitmentTxPayload qcTx;
if (!GetTxPayload(tx, qcTx)) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
}
if (qcTx.nVersion == 0 || qcTx.nVersion > CFinalCommitmentTxPayload::CURRENT_VERSION) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-version");
}
if (qcTx.nHeight != pindexPrev->nHeight + 1) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-height");
}
if (!mapBlockIndex.count(qcTx.commitment.quorumHash)) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash");
}
const CBlockIndex* pindexQuorum = mapBlockIndex[qcTx.commitment.quorumHash];
if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
// not part of active chain
return state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash");
}
if (!Params().GetConsensus().llmqs.count((Consensus::LLMQType)qcTx.commitment.llmqType)) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-type");
}
const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)qcTx.commitment.llmqType);
if (qcTx.commitment.IsNull()) {
if (!qcTx.commitment.VerifyNull()) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid-null");
}
return true;
}
Optimize on-disk deterministic masternode storage to reduce size of evodb (#3017) * Implement CompactFull() in CDBWrapper This allows to compact the whole DB in one go. * Implement more compact version of CDeterministicMNListDiff This introduces CDeterministicMNStateDiff which requires to only store fields on-disk which actually changed. * Avoid writing mnUniquePropertyMap to disk when storing snapshots This map can be rebuilt by simply using AddMN for each deserialized MN. * Implement Serialize/Unserialize in CScript This allows us to directly use READWRITE() on scripts and removes the need for the ugly cast to CScriptBase. This commit also changes all Dash specific uses of CScript to not use the cast. * Keep track of registeration counts and introduce internalID for masternodes The "internalId" is simply the number of MNs registered so far when the new MN is added. It is deterministic and stays the same forever. * Use internalId as keys in MN list diffs This reduces the used size on-disk. * Two simple speedups in MN list diff handling 1. Avoid full compare if dmn or state pointers match in BuildDiff 2. Use std::move when adding diff to listDiff in GetListForBlock * Implement upgrade code for old CDeterministicMNListDiff format to new format * Track tipIndex instead of tipHeight/tipBlockHash * Store and pass around CBlockIndex* instead of block hash and height This allows us to switch CDeterministicMNManager::GetListForBlock to work with CBlockIndex. * Refactor CDeterministicMNManager::GetListForBlock to require CBlockIndex* Instead of requiring a block hash. This allows us to remove blockHash and prevBlockHash from CDeterministicMNListDiff without the use of cs_main locks in GetListForBlock. * Remove prevBlockHash, blockHash and nHeight from CDeterministicMNListDiff * Remove access to determinisitcMNManager in CMasternodeMetaMan::ToString() The deterministic MN manager is not fully initialized yet at the time this is called, which results in an empty list being returned everytime. * Better logic to determine if an upgrade is needed Reuse the "best block" logic to figure out if an upgrade is needed. Also use it to ensure that older nodes are unable to start after the upgrade was performed. * Return null block hash if it was requested with getmnlistdiff * bump CGovernanceManager::SERIALIZATION_VERSION_STRING * Check SERIALIZATION_VERSION_STRING before deserializing anything else * Invoke Clear() before deserializing just to be sure
2019-07-09 07:59:57 +02:00
auto members = CLLMQUtils::GetAllQuorumMembers(params.type, pindexQuorum);
if (!qcTx.commitment.Verify(members, false)) {
return state.DoS(100, false, REJECT_INVALID, "bad-qc-invalid");
}
return true;
}
Implement and enforce DIP6 commitments (#2477) * Add LLMQ parameters to consensus params * Add DIP6 quorum commitment special TX * Implement CQuorumBlockProcessor which validates and handles commitments * Add quorum commitments to new blocks * Propagate QFCOMMITMENT messages to all nodes * Allow special transactions in blocks which have no inputs/outputs But only for TRANSACTION_QUORUM_COMMITMENT for now. * Add quorum commitments to self-crafted blocks in DIP3 tests * Add simple fork logic for current testnet This should avoid a fork on the current testnet. It only applies to the current chain which activated DIP3 at height 264000 and block 00000048e6e71d4bd90e7c456dcb94683ae832fcad13e1760d8283f7e89f332f. When we revert the chain to retest the DIP3 deployment, this fork logic can be removed again. * Use quorumVvecHash instead of quorumHash to make null commitments unique Implementation of https://github.com/dashpay/dips/pull/31 * Re-add quorum commitments after pruning mempool selected blocks * Refactor CQuorumBlockProcessor::ProcessBlock to have less nested if/else statements Also add BEGIN/END markers for temporary code. * Add comments/documentation to LLMQParams * Move code which determines if a commitment is required into IsCommitmentRequired This should make the code easier to read and also removes some duplication. The also changes the error types that are possible from 3 to 2 now. Instead of having "bad-qc-already-mined" and "bad-qc-not-mining-phase", there is only "bad-qc-not-allowed" now. * Use new parameter from consensus parames for the temporary fork
2018-11-23 15:42:09 +01:00
}