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: 1 addition & 1 deletion src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ BITCOIN_TESTS =\
test/evo_assetlocks_tests.cpp \
test/evo_deterministicmns_tests.cpp \
test/evo_instantsend_tests.cpp \
test/evo_mnhf_tests.cpp \
test/evo_simplifiedmns_tests.cpp \
test/evo_trivialvalidation.cpp \
test/evo_utils_tests.cpp \
Expand Down Expand Up @@ -146,7 +147,6 @@ BITCOIN_TESTS =\
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/sock_tests.cpp \
test/specialtx_tests.cpp \
test/streams_tests.cpp \
test/subsidy_tests.cpp \
test/sync_tests.cpp \
Expand Down
2 changes: 1 addition & 1 deletion src/consensus/tx_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
{
bool allowEmptyTxIn = false;
bool allowEmptyTxOut = false;
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
if (tx.nType == TRANSACTION_QUORUM_COMMITMENT || tx.nType == TRANSACTION_MNHF_SIGNAL) {
allowEmptyTxIn = true;
allowEmptyTxOut = true;
}
Expand Down
50 changes: 34 additions & 16 deletions src/evo/mnhftx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,39 @@
#include <chain.h>
#include <chainparams.h>
#include <validation.h>
#include <versionbits.h>

#include <string>

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

bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex, const uint256& msgHash, TxValidationState& state) const
{
if (nVersion == 0 || nVersion > (llmq::utils::IsV19Active(pQuorumIndex) ? BASIC_BLS_VERSION : LEGACY_BLS_VERSION)) {
return false;
if (versionBit >= VERSIONBITS_NUM_BITS) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-nbit-out-of-bounds");
}

Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeMnhf;
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
if (!llmq_params_opt.has_value()) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-type");
}
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) ||
llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, signOffset);
const uint256 requestId = ::SerializeHash(std::make_pair(MNEHF_REQUESTID_PREFIX, int64_t{versionBit}));

if (!llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight + signOffset, requestId, msgHash, sig)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
}
return true;
}

bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (tx.nVersion != 3 || tx.nType != TRANSACTION_MNHF_SIGNAL) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-type");
}

MNHFTxPayload mnhfTx;
if (!GetTxPayload(tx, mnhfTx)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload");
Expand All @@ -55,20 +65,28 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValida
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash");
}

if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-type");
}
// Copy transaction except `quorumSig` field to calculate hash
CMutableTransaction tx_copy(tx);
auto payload_copy = mnhfTx;
payload_copy.signal.sig = CBLSSignature();
SetTxPayload(tx_copy, payload_copy);
uint256 msgHash = tx_copy.GetHash();

if (!mnhfTx.signal.Verify(pindexQuorum)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
if (!mnhfTx.signal.Verify(pindexQuorum, msgHash, state)) {
// set up inside Verify
return false;
}

return true;
}

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

17 changes: 8 additions & 9 deletions src/evo/mnhftx.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,17 @@ extern RecursiveMutex cs_main;
class MNHFTx
{
public:
static constexpr uint16_t LEGACY_BLS_VERSION = 1;
static constexpr uint16_t BASIC_BLS_VERSION = 2;

uint16_t nVersion{LEGACY_BLS_VERSION};
uint8_t versionBit{0};
Comment thread
knst marked this conversation as resolved.
Outdated
uint256 quorumHash;
CBLSSignature sig;

MNHFTx() = default;
bool Verify(const CBlockIndex* pQuorumIndex) const;
bool Verify(const CBlockIndex* pQuorumIndex, const uint256& msgHash, TxValidationState& state) const;

SERIALIZE_METHODS(MNHFTx, obj)
{
READWRITE(obj.nVersion, obj.quorumHash);
READWRITE(CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.sig), (obj.nVersion == LEGACY_BLS_VERSION)));
READWRITE(obj.versionBit, obj.quorumHash);
READWRITE(CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.sig), /* fLegacy= */ false));
}

std::string ToString() const;
Expand All @@ -41,7 +38,7 @@ class MNHFTx
{
obj.clear();
obj.setObject();
obj.pushKV("version", (int)nVersion);
obj.pushKV("versionBit", (int)versionBit);
obj.pushKV("quorumHash", quorumHash.ToString());
obj.pushKV("sig", sig.ToString());
}
Expand All @@ -53,14 +50,16 @@ class MNHFTxPayload
static constexpr auto SPECIALTX_TYPE = TRANSACTION_MNHF_SIGNAL;
static constexpr uint16_t CURRENT_VERSION = 1;

uint16_t nVersion{CURRENT_VERSION};
uint8_t nVersion{CURRENT_VERSION};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint16_t in DIP

Suggested change
uint8_t nVersion{CURRENT_VERSION};
uint16_t nVersion{CURRENT_VERSION};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MNHFTx signal;

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

std::string ToString() const;

void ToJson(UniValue& obj) const
{
obj.setObject();
Expand Down
5 changes: 4 additions & 1 deletion src/evo/specialtxman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const
case TRANSACTION_QUORUM_COMMITMENT:
return llmq::CheckLLMQCommitment(tx, pindexPrev, state);
case TRANSACTION_MNHF_SIGNAL:
return pindexPrev->nHeight + 1 >= Params().GetConsensus().DIP0024Height && CheckMNHFTx(tx, pindexPrev, state);
if (!llmq::utils::IsV20Active(pindexPrev)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "mnhf-before-v20");
}
return CheckMNHFTx(tx, pindexPrev, state);
case TRANSACTION_ASSET_LOCK:
case TRANSACTION_ASSET_UNLOCK:
if (!llmq::utils::IsV20Active(pindexPrev)) {
Expand Down
4 changes: 2 additions & 2 deletions src/test/specialtx_tests.cpp → src/test/evo_mnhf_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ static CMutableTransaction CreateMNHFTx(const uint256& mnhfTxHash, const CBLSSig
{
MNHFTxPayload extraPayload;
extraPayload.nVersion = 1;
extraPayload.signal.nVersion = versionBit;
extraPayload.signal.versionBit = versionBit;
extraPayload.signal.quorumHash = mnhfTxHash;
extraPayload.signal.sig = cblSig;

Expand All @@ -48,7 +48,7 @@ static CMutableTransaction CreateMNHFTx(const uint256& mnhfTxHash, const CBLSSig
return tx;
}

BOOST_FIXTURE_TEST_SUITE(specialtx_tests, BasicTestingSetup)
BOOST_FIXTURE_TEST_SUITE(evo_mnhf_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests)
{
Expand Down
2 changes: 2 additions & 0 deletions src/txmempool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
bool ok = GetTxPayload(tx, assetUnlockTx);
assert(ok);
mapAssetUnlockExpiry.insert({tx.GetHash(), assetUnlockTx.getHeightToExpiry()});
} else if (tx.nType == TRANSACTION_MNHF_SIGNAL) {
PrioritiseTransaction(tx.GetHash(), 0.1 * COIN);
}
}

Expand Down
39 changes: 39 additions & 0 deletions test/functional/test_framework/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,45 @@ def __repr__(self):
.format(self.version, self.index, self.fee, self.requestedHeight, self.quorumHash, self.quorumSig.hex())


class CMnEhf:
__slots__ = ("version", "versionBit", "quorumHash", "quorumSig")

def __init__(self, version=None, versionBit=None, quorumHash = 0, quorumSig = None):
self.set_null()
if version is not None:
self.version = version
if versionBit is not None:
self.versionBit = versionBit
if quorumHash is not None:
self.quorumHash = quorumHash
if quorumSig is not None:
self.quorumSig = quorumSig

def set_null(self):
self.version = 0
self.versionBit = 0
self.quorumHash = 0
self.quorumSig = b'\x00' * 96

def deserialize(self, f):
self.version = struct.unpack("<B", f.read(1))[0]
self.versionBit = struct.unpack("<B", f.read(1))[0]
self.quorumHash = deser_uint256(f)
self.quorumSig = f.read(96)

def serialize(self):
r = b""
r += struct.pack("<B", self.version)
r += struct.pack("<B", self.versionBit)
r += ser_uint256(self.quorumHash)
r += self.quorumSig
return r

def __repr__(self):
return "CMnEhf(version={} versionBit={} quorumHash={:x} quorumSig={}" \
.format(self.version, self.versionBit, self.quorumHash, self.quorumSig.hex())


class CSimplifiedMNListEntry:
__slots__ = ("proRegTxHash", "confirmedHash", "service", "pubKeyOperator", "keyIDVoting", "isValid", "nVersion", "type", "platformHTTPPort", "platformNodeID")

Expand Down