Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ BITCOIN_CORE_H = \
evo/deterministicmns.h \
evo/evodb.h \
evo/mnauth.h \
evo/mnhftx.h \
evo/providertx.h \
evo/simplifiedmns.h \
evo/specialtx.h \
Expand Down Expand Up @@ -356,6 +357,7 @@ libdash_server_a_SOURCES = \
evo/deterministicmns.cpp \
evo/evodb.cpp \
evo/mnauth.cpp \
evo/mnhftx.cpp \
evo/providertx.cpp \
evo/simplifiedmns.cpp \
evo/specialtx.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ BITCOIN_TESTS =\
test/sighash_tests.cpp \
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/specialtx_tests.cpp \
test/streams_tests.cpp \
test/subsidy_tests.cpp \
test/sync_tests.cpp \
Expand Down
1 change: 1 addition & 0 deletions src/bloom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
}
case(TRANSACTION_COINBASE):
case(TRANSACTION_QUORUM_COMMITMENT):
case(TRANSACTION_MNHF_SIGNAL):
// No additional checks for this transaction types
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ class CMainParams : public CChainParams {
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_400_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_400_85;
Comment thread
pravblockc marked this conversation as resolved.
Outdated

fDefaultConsistencyChecks = false;
fRequireStandard = true;
Expand Down Expand Up @@ -493,6 +494,7 @@ class CTestNetParams : public CChainParams {
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60;

fDefaultConsistencyChecks = false;
fRequireStandard = false;
Expand Down Expand Up @@ -686,6 +688,7 @@ class CDevNetParams : public CChainParams {
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60;

UpdateDevnetLLMQChainLocksFromArgs(args);
UpdateDevnetLLMQInstantSendFromArgs(args);
Expand Down Expand Up @@ -923,6 +926,7 @@ class CRegTestParams : public CChainParams {
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_TEST;

UpdateLLMQTestParametersFromArgs(args);
}
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct Params {
LLMQType llmqTypeChainLocks;
LLMQType llmqTypeInstantSend{LLMQType::LLMQ_NONE};
LLMQType llmqTypePlatform{LLMQType::LLMQ_NONE};
LLMQType llmqTypeMnhf{LLMQType::LLMQ_NONE};
};
} // namespace Consensus

Expand Down
8 changes: 8 additions & 0 deletions src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <spentindex.h>

#include <evo/cbtx.h>
#include <evo/mnhftx.h>
#include <evo/providertx.h>
#include <evo/specialtx.h>
#include <llmq/commitment.h>
Expand Down Expand Up @@ -305,6 +306,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
qcTx.ToJson(obj);
entry.pushKV("qcTx", obj);
}
} else if (tx.nType == TRANSACTION_MNHF_SIGNAL) {
MNHFTxPayload mnhfTx;
if (GetTxPayload(tx, mnhfTx)) {
UniValue obj;
mnhfTx.ToJson(obj);
entry.pushKV("mnhfTx", obj);
}
}

if (!hashBlock.IsNull())
Expand Down
70 changes: 70 additions & 0 deletions src/evo/mnhftx.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2021-2022 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <consensus/validation.h>
#include <evo/mnhftx.h>
#include <evo/specialtx.h>
#include <llmq/commitment.h>
#include <llmq/signing.h>

#include <chain.h>
#include <chainparams.h>
#include <validation.h>

#include <string>

extern const std::string CBLSIG_REQUESTID_PREFIX = "clsig";

bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
{
if (nVersion == 0 || nVersion > CURRENT_VERSION) {
return false;
}

Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeMnhf;
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval};

const uint256 requestId = ::SerializeHash(std::make_pair(CBLSIG_REQUESTID_PREFIX, pQuorumIndex->nHeight));
return llmq::CSigningManager::VerifyRecoveredSig(llmqType, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, 0) ||
llmq::CSigningManager::VerifyRecoveredSig(llmqType, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset);
}

bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
MNHFTxPayload mnhfTx;
if (!GetTxPayload(tx, mnhfTx)) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-payload");
}

if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-version");
}

const CBlockIndex* pindexQuorum = LookupBlockIndex(mnhfTx.signal.quorumHash);
if (!pindexQuorum) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
}

if (pindexQuorum != pindexPrev->GetAncestor(pindexQuorum->nHeight)) {
// not part of active chain
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
}

if (!Params().GetConsensus().llmqs.count(Params().GetConsensus().llmqTypeMnhf)) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-type");
}

if (!mnhfTx.signal.Verify(pindexQuorum)) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-invalid");
}

return true;
}

std::string MNHFTx::ToString() const
{
return strprintf("MNHFTx(nVersion=%d, quorumHash=%s, sig=%s)",
nVersion, quorumHash.ToString(), sig.ToString());
}

74 changes: 74 additions & 0 deletions src/evo/mnhftx.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2021-2022 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_EVO_MNHFTX_H
#define BITCOIN_EVO_MNHFTX_H

#include <bls/bls.h>
#include <primitives/transaction.h>
#include <sync.h>
#include <threadsafety.h>
#include <univalue.h>

class CBlockIndex;
class CValidationState;
extern CCriticalSection cs_main;

// mnhf signal special transaction
class MNHFTx
{
public:
static constexpr uint16_t CURRENT_VERSION = 1;

uint16_t nVersion{CURRENT_VERSION};
uint256 quorumHash;
CBLSSignature sig;

MNHFTx() = default;
bool Verify(const CBlockIndex* pQuorumIndex) const;

SERIALIZE_METHODS(MNHFTx, obj)
{
READWRITE(obj.nVersion, obj.quorumHash, obj.sig);
}

std::string ToString() const;

void ToJson(UniValue& obj) const
{
obj.clear();
obj.setObject();
obj.pushKV("version", (int)nVersion);
obj.pushKV("quorumHash", quorumHash.ToString());
obj.pushKV("sig", sig.ToString());
}
};

class MNHFTxPayload
{
public:
static constexpr uint16_t CURRENT_VERSION = 1;

uint16_t nVersion{CURRENT_VERSION};
MNHFTx signal;

SERIALIZE_METHODS(MNHFTxPayload, obj)
{
READWRITE(obj.nVersion, obj.signal);
}

void ToJson(UniValue& obj) const
{
obj.setObject();
obj.pushKV("version", (int)nVersion);

UniValue mnhfObj;
signal.ToJson(mnhfObj);
obj.pushKV("signal", mnhfObj);
}
};

bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

#endif // BITCOIN_EVO_MNHFTX_H
17 changes: 13 additions & 4 deletions src/evo/specialtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@

#include <chainparams.h>
#include <consensus/validation.h>
#include <hash.h>
#include <primitives/block.h>
#include <validation.h>
#include <evo/cbtx.h>
#include <evo/deterministicmns.h>
#include <llmq/commitment.h>
#include <evo/mnhftx.h>
#include <hash.h>
#include <llmq/blockprocessor.h>
#include <llmq/commitment.h>
#include <primitives/block.h>
#include <validation.h>

bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view)
{
AssertLockHeld(cs_main);

if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL)
return true;

Expand All @@ -37,6 +40,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
return CheckCbTx(tx, pindexPrev, state);
case TRANSACTION_QUORUM_COMMITMENT:
return llmq::CheckLLMQCommitment(tx, pindexPrev, state);
case TRANSACTION_MNHF_SIGNAL:
return VersionBitsTipState(Params().GetConsensus(), Consensus::DEPLOYMENT_GOV_FEE) == ThresholdState::ACTIVE && CheckMNHFTx(tx, pindexPrev, state);
}
} catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what());
Expand All @@ -62,6 +67,8 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
return true; // nothing to do
case TRANSACTION_QUORUM_COMMITMENT:
return true; // handled per block
case TRANSACTION_MNHF_SIGNAL:
return true; // handled per block
}

return state.DoS(100, false, REJECT_INVALID, "bad-tx-type-proc");
Expand All @@ -83,6 +90,8 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
return true; // nothing to do
case TRANSACTION_QUORUM_COMMITMENT:
return true; // handled per block
case TRANSACTION_MNHF_SIGNAL:
return true; // handled per block
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/evo/specialtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CValidationState;

extern CCriticalSection cs_main;

bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view);
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

Expand Down
1 change: 1 addition & 0 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum {
TRANSACTION_PROVIDER_UPDATE_REVOKE = 4,
TRANSACTION_COINBASE = 5,
TRANSACTION_QUORUM_COMMITMENT = 6,
TRANSACTION_MNHF_SIGNAL = 7,
};

/** An outpoint - a combination of a transaction hash and an index n into its vout */
Expand Down
84 changes: 84 additions & 0 deletions src/test/specialtx_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) 2021 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <bls/bls.h>
#include <consensus/validation.h>
#include <evo/mnhftx.h>
#include <evo/specialtx.h>
#include <primitives/transaction.h>
#include <uint256.h>
#include <util/strencodings.h>

#include <boost/test/unit_test.hpp>
#include <test/setup_common.h>

#include <cstdint>
#include <vector>


bool VerifyMNHFTx(const CTransaction& tx, CValidationState& state)
{
MNHFTxPayload mnhfTx;
if (!GetTxPayload(tx, mnhfTx)) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-payload");
}

if (mnhfTx.nVersion == 0 || mnhfTx.nVersion > MNHFTxPayload::CURRENT_VERSION) {
return state.DoS(100, false, REJECT_INVALID, "bad-mnhf-version");
}

return true;
}

static CMutableTransaction CreateMNHFTx(const uint256& mnhfTxHash, const CBLSSignature& cblSig, const uint16_t& versionBit)
{
MNHFTxPayload extraPayload;
extraPayload.nVersion = 1;
extraPayload.signal.nVersion = versionBit;
extraPayload.signal.quorumHash = mnhfTxHash;
extraPayload.signal.sig = cblSig;

CMutableTransaction tx;
tx.nVersion = 3;
tx.nType = TRANSACTION_MNHF_SIGNAL;
SetTxPayload(tx, extraPayload);

return tx;
}

BOOST_FIXTURE_TEST_SUITE(specialtx_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests)
{
int count = 10;
uint16_t ver = 2;

std::vector<CBLSSignature> vec_sigs;
std::vector<CBLSPublicKey> vec_pks;
std::vector<CBLSSecretKey> vec_sks;

CBLSSecretKey sk;
uint256 hash = GetRandHash();
for (int i = 0; i < count; i++) {
sk.MakeNewKey();
vec_pks.push_back(sk.GetPublicKey());
vec_sks.push_back(sk);
}

CBLSSecretKey ag_sk = CBLSSecretKey::AggregateInsecure(vec_sks);
CBLSPublicKey ag_pk = CBLSPublicKey::AggregateInsecure(vec_pks);

BOOST_CHECK(ag_sk.IsValid());
BOOST_CHECK(ag_pk.IsValid());

uint256 verHash = uint256S(itostr(ver));
auto sig = ag_sk.Sign(verHash);
BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash));

const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver);
CValidationState state;
BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state));
}

BOOST_AUTO_TEST_SUITE_END()
Loading