dash/src/llmq/commitment.h
Wladimir J. van der Laan eec81f7b33 Merge #15921: validation: Tidy up ValidationState interface
3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf [validation] Remove fMissingInputs from AcceptToMemoryPool() (John Newbery)
c428622a5bb1e37b2e6ab2c52791ac05d9271238 [validation] Remove unused first_invalid parameter from ProcessNewBlockHeaders() (John Newbery)
7204c6434b944f6ad51b3c895837729d3aa56eea [validation] Remove useless ret parameter from Invalid() (John Newbery)
1a37de4b3174d19a6d8691ae07e92b32fdfaef11 [validation] Remove error() calls from Invalid() calls (John Newbery)
067981e49246822421a7bcc720491427e1dba8a3 [validation] Tidy Up ValidationResult class (John Newbery)
a27a2957ed9afbe5a96caa5f0f4cbec730d27460 [validation] Add CValidationState subclasses (John Newbery)

Pull request description:

  Carries out some remaining tidy-ups remaining after PR 15141:

  - split ValidationState into TxValidationState and BlockValidationState (commit from ajtowns)
  - various minor code style tidy-ups to the ValidationState class
  - remove the useless `ret` parameter from `ValidationState::Invalid()`
  - remove the now unused `first_invalid` parameter from `ProcessNewBlockHeaders()`
  - remove the `fMissingInputs` parameter from `AcceptToMemoryPool()`, and deal with missing inputs the same way as other errors by using the `TxValidationState` object.

  Tip for reviewers (thanks ryanofsky!): The first commit ("[validation] Add CValidationState subclasses" ) is huge and can be easier to start reviewing if you revert the rote, mechanical changes:

  Substitute the commit hash of commit "[validation] Add CValidationState subclasses" for <CommitHash> in the commands below.

  ```sh
  git checkout <CommitHash>
  git grep -l ValidationState | xargs sed -i 's/BlockValidationState\|TxValidationState/CValidationState/g'
  git grep -l ValidationResult | xargs sed -i 's/BlockValidationResult\|TxValidationResult/ValidationInvalidReason/g'
  git grep -l MaybePunish | xargs sed -i 's/MaybePunishNode\(ForBlock\|ForTx\)/MaybePunishNode/g'
  git diff HEAD^
  ```

  After that it's possible to easily see the mechanical changes with:

  ```sh
  git log -p -n1 -U0 --word-diff-regex=. <CommitHash>
  ```

ACKs for top commit:
  laanwj:
    ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf
  amitiuttarwar:
    code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf. Also built & ran tests locally.
  fjahr:
    Code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf . Only nit style change and pure virtual destructor added since my last review.
  ryanofsky:
    Code review ACK 3004d5a12d09d94bfc4dee2a8e8f2291996a4aaf. Just whitespace change and pure virtual destructor added since last review.

Tree-SHA512: 511de1fb380a18bec1944ea82b513b6192df632ee08bb16344a2df3c40811a88f3872f04df24bc93a41643c96c48f376a04551840fd804a961490d6c702c3d36
2023-04-17 10:42:25 -05:00

176 lines
6.3 KiB
C++

// Copyright (c) 2018-2022 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_LLMQ_COMMITMENT_H
#define BITCOIN_LLMQ_COMMITMENT_H
#include <bls/bls.h>
#include <consensus/params.h>
#include <primitives/transaction.h>
#include <util/irange.h>
#include <util/strencodings.h>
#include <util/underlying.h>
#include <univalue.h>
class CBlockIndex;
class TxValidationState;
namespace llmq
{
// This message is an aggregation of all received premature commitments and only valid if
// enough (>=threshold) premature commitments were aggregated
// This is mined on-chain as part of TRANSACTION_QUORUM_COMMITMENT
class CFinalCommitment
{
public:
static constexpr auto SPECIALTX_TYPE = TRANSACTION_PROVIDER_REGISTER;
static constexpr uint16_t LEGACY_BLS_NON_INDEXED_QUORUM_VERSION = 1;
static constexpr uint16_t LEGACY_BLS_INDEXED_QUORUM_VERSION = 2;
static constexpr uint16_t BASIC_BLS_NON_INDEXED_QUORUM_VERSION = 3;
static constexpr uint16_t BASIC_BLS_INDEXED_QUORUM_VERSION = 4;
uint16_t nVersion{LEGACY_BLS_NON_INDEXED_QUORUM_VERSION};
Consensus::LLMQType llmqType{Consensus::LLMQType::LLMQ_NONE};
uint256 quorumHash;
int16_t quorumIndex{0};
std::vector<bool> signers;
std::vector<bool> validMembers;
CBLSPublicKey quorumPublicKey;
uint256 quorumVvecHash;
CBLSSignature quorumSig; // recovered threshold sig of blockHash+validMembers+pubKeyHash+vvecHash
CBLSSignature membersSig; // aggregated member sig of blockHash+validMembers+pubKeyHash+vvecHash
public:
CFinalCommitment() = default;
CFinalCommitment(const Consensus::LLMQParams& params, const uint256& _quorumHash);
int CountSigners() const
{
return int(std::count(signers.begin(), signers.end(), true));
}
int CountValidMembers() const
{
return int(std::count(validMembers.begin(), validMembers.end(), true));
}
bool Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool checkSigs) const;
bool VerifyNull() const;
bool VerifySizes(const Consensus::LLMQParams& params) const;
[[nodiscard]] static constexpr uint16_t GetVersion(const bool is_rotation_enabled, const bool is_basic_scheme_active)
{
if (is_rotation_enabled)
return is_basic_scheme_active ? BASIC_BLS_INDEXED_QUORUM_VERSION : LEGACY_BLS_INDEXED_QUORUM_VERSION;
else
return is_basic_scheme_active ? BASIC_BLS_NON_INDEXED_QUORUM_VERSION : LEGACY_BLS_NON_INDEXED_QUORUM_VERSION;
}
public:
SERIALIZE_METHODS(CFinalCommitment, obj)
{
READWRITE(
obj.nVersion,
obj.llmqType,
obj.quorumHash
);
if (obj.nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION || obj.nVersion == BASIC_BLS_INDEXED_QUORUM_VERSION) {
READWRITE(
obj.quorumIndex
);
}
READWRITE(
DYNBITSET(obj.signers),
DYNBITSET(obj.validMembers),
CBLSPublicKeyVersionWrapper(const_cast<CBLSPublicKey&>(obj.quorumPublicKey), (obj.nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || obj.nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)),
obj.quorumVvecHash,
CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.quorumSig), (obj.nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || obj.nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION)),
CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.membersSig), (obj.nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || obj.nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION))
);
}
public:
bool IsNull() const
{
if (std::count(signers.begin(), signers.end(), true) ||
std::count(validMembers.begin(), validMembers.end(), true)) {
return false;
}
if (quorumPublicKey.IsValid() ||
!quorumVvecHash.IsNull() ||
membersSig.IsValid() ||
quorumSig.IsValid()) {
return false;
}
return true;
}
void ToJson(UniValue& obj) const
{
obj.setObject();
obj.pushKV("version", int{nVersion});
obj.pushKV("llmqType", ToUnderlying(llmqType));
obj.pushKV("quorumHash", quorumHash.ToString());
obj.pushKV("quorumIndex", quorumIndex);
obj.pushKV("signersCount", CountSigners());
obj.pushKV("signers", BitsVectorToHexStr(signers));
obj.pushKV("validMembersCount", CountValidMembers());
obj.pushKV("validMembers", BitsVectorToHexStr(validMembers));
obj.pushKV("quorumPublicKey", quorumPublicKey.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION));
obj.pushKV("quorumVvecHash", quorumVvecHash.ToString());
obj.pushKV("quorumSig", quorumSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION));
obj.pushKV("membersSig", membersSig.ToString(nVersion == LEGACY_BLS_NON_INDEXED_QUORUM_VERSION || nVersion == LEGACY_BLS_INDEXED_QUORUM_VERSION));
}
private:
static std::string BitsVectorToHexStr(const std::vector<bool>& vBits)
{
std::vector<uint8_t> vBytes((vBits.size() + 7) / 8);
for (const auto i : irange::range(vBits.size())) {
vBytes[i / 8] |= vBits[i] << (i % 8);
}
return HexStr(vBytes);
}
};
using CFinalCommitmentPtr = std::unique_ptr<CFinalCommitment>;
class CFinalCommitmentTxPayload
{
public:
static constexpr auto SPECIALTX_TYPE = TRANSACTION_QUORUM_COMMITMENT;
static constexpr uint16_t CURRENT_VERSION = 1;
public:
uint16_t nVersion{CURRENT_VERSION};
uint32_t nHeight{std::numeric_limits<uint32_t>::max()};
CFinalCommitment commitment;
public:
SERIALIZE_METHODS(CFinalCommitmentTxPayload, obj)
{
READWRITE(obj.nVersion, obj.nHeight, obj.commitment);
}
void ToJson(UniValue& obj) const
{
obj.setObject();
obj.pushKV("version", int{nVersion});
obj.pushKV("height", int(nHeight));
UniValue qcObj;
commitment.ToJson(qcObj);
obj.pushKV("commitment", qcObj);
}
};
bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state);
} // namespace llmq
#endif // BITCOIN_LLMQ_COMMITMENT_H