add ehf special tx (#4577)

This commit is contained in:
pravblockc 2021-12-11 16:00:27 -04:00 committed by GitHub
parent 06ebacbb9a
commit 459bc3ee7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 263 additions and 6 deletions

View File

@ -169,6 +169,7 @@ BITCOIN_CORE_H = \
evo/deterministicmns.h \ evo/deterministicmns.h \
evo/evodb.h \ evo/evodb.h \
evo/mnauth.h \ evo/mnauth.h \
evo/mnhftx.h \
evo/providertx.h \ evo/providertx.h \
evo/simplifiedmns.h \ evo/simplifiedmns.h \
evo/specialtx.h \ evo/specialtx.h \
@ -356,6 +357,7 @@ libdash_server_a_SOURCES = \
evo/deterministicmns.cpp \ evo/deterministicmns.cpp \
evo/evodb.cpp \ evo/evodb.cpp \
evo/mnauth.cpp \ evo/mnauth.cpp \
evo/mnhftx.cpp \
evo/providertx.cpp \ evo/providertx.cpp \
evo/simplifiedmns.cpp \ evo/simplifiedmns.cpp \
evo/specialtx.cpp \ evo/specialtx.cpp \

View File

@ -181,6 +181,7 @@ BITCOIN_TESTS =\
test/sighash_tests.cpp \ test/sighash_tests.cpp \
test/sigopcount_tests.cpp \ test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \ test/skiplist_tests.cpp \
test/specialtx_tests.cpp \
test/streams_tests.cpp \ test/streams_tests.cpp \
test/subsidy_tests.cpp \ test/subsidy_tests.cpp \
test/sync_tests.cpp \ test/sync_tests.cpp \

View File

@ -212,6 +212,7 @@ bool CBloomFilter::CheckSpecialTransactionMatchesAndUpdate(const CTransaction &t
} }
case(TRANSACTION_COINBASE): case(TRANSACTION_COINBASE):
case(TRANSACTION_QUORUM_COMMITMENT): case(TRANSACTION_QUORUM_COMMITMENT):
case(TRANSACTION_MNHF_SIGNAL):
// No additional checks for this transaction types // No additional checks for this transaction types
return false; return false;
} }

View File

@ -281,6 +281,7 @@ public:
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_400_60; consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_400_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60; consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_400_85;
fDefaultConsistencyChecks = false; fDefaultConsistencyChecks = false;
fRequireStandard = true; fRequireStandard = true;
@ -492,6 +493,7 @@ public:
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60; consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60; consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60;
fDefaultConsistencyChecks = false; fDefaultConsistencyChecks = false;
fRequireStandard = false; fRequireStandard = false;
@ -685,6 +687,7 @@ public:
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60; consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60; consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_50_60;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60;
UpdateDevnetLLMQChainLocksFromArgs(args); UpdateDevnetLLMQChainLocksFromArgs(args);
UpdateDevnetLLMQInstantSendFromArgs(args); UpdateDevnetLLMQInstantSendFromArgs(args);
@ -922,6 +925,7 @@ public:
consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_TEST; consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_TEST; consensus.llmqTypeInstantSend = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_TEST; consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_TEST;
consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_TEST;
UpdateLLMQTestParametersFromArgs(args); UpdateLLMQTestParametersFromArgs(args);
} }

View File

@ -116,6 +116,7 @@ struct Params {
LLMQType llmqTypeChainLocks; LLMQType llmqTypeChainLocks;
LLMQType llmqTypeInstantSend{LLMQType::LLMQ_NONE}; LLMQType llmqTypeInstantSend{LLMQType::LLMQ_NONE};
LLMQType llmqTypePlatform{LLMQType::LLMQ_NONE}; LLMQType llmqTypePlatform{LLMQType::LLMQ_NONE};
LLMQType llmqTypeMnhf{LLMQType::LLMQ_NONE};
}; };
} // namespace Consensus } // namespace Consensus

View File

@ -20,6 +20,7 @@
#include <spentindex.h> #include <spentindex.h>
#include <evo/cbtx.h> #include <evo/cbtx.h>
#include <evo/mnhftx.h>
#include <evo/providertx.h> #include <evo/providertx.h>
#include <evo/specialtx.h> #include <evo/specialtx.h>
#include <llmq/commitment.h> #include <llmq/commitment.h>
@ -305,6 +306,13 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
qcTx.ToJson(obj); qcTx.ToJson(obj);
entry.pushKV("qcTx", 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()) if (!hashBlock.IsNull())

70
src/evo/mnhftx.cpp Normal file
View File

@ -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
src/evo/mnhftx.h Normal file
View File

@ -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

View File

@ -6,16 +6,19 @@
#include <chainparams.h> #include <chainparams.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <hash.h>
#include <primitives/block.h>
#include <validation.h>
#include <evo/cbtx.h> #include <evo/cbtx.h>
#include <evo/deterministicmns.h> #include <evo/deterministicmns.h>
#include <llmq/commitment.h> #include <evo/mnhftx.h>
#include <hash.h>
#include <llmq/blockprocessor.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) bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state, const CCoinsViewCache& view)
{ {
AssertLockHeld(cs_main);
if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL) if (tx.nVersion != 3 || tx.nType == TRANSACTION_NORMAL)
return true; return true;
@ -37,6 +40,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
return CheckCbTx(tx, pindexPrev, state); return CheckCbTx(tx, pindexPrev, state);
case TRANSACTION_QUORUM_COMMITMENT: case TRANSACTION_QUORUM_COMMITMENT:
return llmq::CheckLLMQCommitment(tx, pindexPrev, state); 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) { } catch (const std::exception& e) {
LogPrintf("%s -- failed: %s\n", __func__, e.what()); LogPrintf("%s -- failed: %s\n", __func__, e.what());
@ -62,6 +67,8 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
return true; // nothing to do return true; // nothing to do
case TRANSACTION_QUORUM_COMMITMENT: case TRANSACTION_QUORUM_COMMITMENT:
return true; // handled per block 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"); return state.DoS(100, false, REJECT_INVALID, "bad-tx-type-proc");
@ -83,6 +90,8 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
return true; // nothing to do return true; // nothing to do
case TRANSACTION_QUORUM_COMMITMENT: case TRANSACTION_QUORUM_COMMITMENT:
return true; // handled per block return true; // handled per block
case TRANSACTION_MNHF_SIGNAL:
return true; // handled per block
} }
return false; return false;

View File

@ -18,7 +18,7 @@ class CValidationState;
extern CCriticalSection cs_main; 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 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); bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

View File

@ -21,6 +21,7 @@ enum {
TRANSACTION_PROVIDER_UPDATE_REVOKE = 4, TRANSACTION_PROVIDER_UPDATE_REVOKE = 4,
TRANSACTION_COINBASE = 5, TRANSACTION_COINBASE = 5,
TRANSACTION_QUORUM_COMMITMENT = 6, TRANSACTION_QUORUM_COMMITMENT = 6,
TRANSACTION_MNHF_SIGNAL = 7,
}; };
/** An outpoint - a combination of a transaction hash and an index n into its vout */ /** An outpoint - a combination of a transaction hash and an index n into its vout */

View File

@ -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()

View File

@ -378,7 +378,8 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR && tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR &&
tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE && tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE &&
tx.nType != TRANSACTION_COINBASE && tx.nType != TRANSACTION_COINBASE &&
tx.nType != TRANSACTION_QUORUM_COMMITMENT) { tx.nType != TRANSACTION_QUORUM_COMMITMENT &&
tx.nType != TRANSACTION_MNHF_SIGNAL) {
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type"); return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
} }
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE) if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)

View File

@ -105,6 +105,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"coinjoin/coinjoin -> llmq/chainlocks -> net -> coinjoin/coinjoin" "coinjoin/coinjoin -> llmq/chainlocks -> net -> coinjoin/coinjoin"
"evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns" "evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns"
"evo/deterministicmns -> llmq/utils -> net -> masternode/sync -> evo/deterministicmns" "evo/deterministicmns -> llmq/utils -> net -> masternode/sync -> evo/deterministicmns"
"evo/mnhftx -> evo/specialtx -> evo/mnhftx"
) )
EXIT_CODE=0 EXIT_CODE=0