Skip to content

Commit

Permalink
Calculate and enforce DIP4 masternodes merkle root in CbTx
Browse files Browse the repository at this point in the history
Also add "coinbase_payload" field to block templates
  • Loading branch information
codablock committed Sep 3, 2018
1 parent 0a08689 commit bcc0719
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 0 deletions.
28 changes: 28 additions & 0 deletions qa/rpc-tests/test_framework/mininode.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,34 @@ def __repr__(self):
return "BlockTransactions(hash=%064x transactions=%s)" % (self.blockhash, repr(self.transactions))


class CCbTx(object):
def __init__(self, version=None, height=None, merkleRootMNList=None):
self.set_null()
if version is not None:
self.version = version
if height is not None:
self.height = height
if merkleRootMNList is not None:
self.merkleRootMNList = merkleRootMNList

def set_null(self):
self.version = 0
self.height = 0
self.merkleRootMNList = None

def deserialize(self, f):
self.version = struct.unpack("<H", f.read(2))[0]
self.height = struct.unpack("<i", f.read(4))[0]
self.merkleRootMNList = deser_uint256(f)

def serialize(self):
r = b""
r += struct.pack("<H", self.version)
r += struct.pack("<i", self.height)
r += ser_uint256(self.merkleRootMNList)
return r


# Objects that correspond to messages on the wire
class msg_version(object):
command = b"version"
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ BITCOIN_CORE_H = \
evo/providertx.h \
evo/deterministicmns.h \
evo/cbtx.h \
evo/simplifiedmns.h \
privatesend.h \
privatesend-client.h \
privatesend-server.h \
Expand Down Expand Up @@ -226,6 +227,7 @@ libdash_server_a_SOURCES = \
evo/providertx.cpp \
evo/deterministicmns.cpp \
evo/cbtx.cpp \
evo/simplifiedmns.cpp \
httprpc.cpp \
httpserver.cpp \
init.cpp \
Expand Down
42 changes: 42 additions & 0 deletions src/evo/cbtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "cbtx.h"
#include "specialtx.h"
#include "deterministicmns.h"
#include "simplifiedmns.h"

#include "validation.h"
#include "univalue.h"
Expand All @@ -31,6 +32,47 @@ bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidatio
return true;
}

// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
bool CheckCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindex, CValidationState& state)
{
AssertLockHeld(cs_main);

if (block.vtx[0]->nType != TRANSACTION_COINBASE)
return true;

CCbTx cbTx;
if (!GetTxPayload(*block.vtx[0], cbTx))
return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");

if (pindex) {
uint256 calculatedMerkleRoot;
if (!CalcCbTxMerkleRootMNList(block, pindex->pprev, calculatedMerkleRoot, state)) {
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
}
if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
}
}

return true;
}

bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state)
{
AssertLockHeld(cs_main);
LOCK(deterministicMNManager->cs);

CDeterministicMNList tmpMNList;
if (!deterministicMNManager->BuildNewListFromBlock(block, pindexPrev, state, tmpMNList)) {
return false;
}

CSimplifiedMNList sml(tmpMNList);
bool mutated = false;
merkleRootRet = sml.CalcMerkleRoot(&mutated);
return !mutated;
}

std::string CCbTx::ToString() const
{
return strprintf("CCbTx(nHeight=%d, nVersion=%d, merkleRootMNList=%s)",
Expand Down
4 changes: 4 additions & 0 deletions src/evo/cbtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "primitives/transaction.h"
#include "consensus/validation.h"

class CBlock;
class CBlockIndex;
class UniValue;

Expand Down Expand Up @@ -39,4 +40,7 @@ class CCbTx

bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state);

bool CheckCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindex, CValidationState& state);
bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state);

#endif//DASH_CBTX_H
67 changes: 67 additions & 0 deletions src/evo/simplifiedmns.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2017 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 "simplifiedmns.h"
#include "specialtx.h"
#include "deterministicmns.h"

#include "validation.h"
#include "univalue.h"
#include "consensus/merkle.h"

CSimplifiedMNListEntry::CSimplifiedMNListEntry(const CDeterministicMN& dmn) :
proRegTxHash(dmn.proTxHash),
service(dmn.pdmnState->addr),
keyIDOperator(dmn.pdmnState->keyIDOperator),
keyIDVoting(dmn.pdmnState->keyIDVoting),
isValid(dmn.pdmnState->nPoSeBanHeight == -1)
{
}

uint256 CSimplifiedMNListEntry::CalcHash() const
{
CHashWriter hw(SER_GETHASH, CLIENT_VERSION);
hw << *this;
return hw.GetHash();
}

std::string CSimplifiedMNListEntry::ToString() const
{
return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, service=%s, keyIDOperator=%s, keyIDVoting=%s, isValie=%d)",
proRegTxHash.ToString(), service.ToString(false), keyIDOperator.ToString(), keyIDVoting.ToString(), isValid);
}

void CSimplifiedMNListEntry::ToJson(UniValue& obj) const
{
obj.clear();
obj.setObject();
obj.push_back(Pair("proRegTxHash", proRegTxHash.ToString()));
obj.push_back(Pair("service", service.ToString(false)));
obj.push_back(Pair("keyIDOperator", keyIDOperator.ToString()));
obj.push_back(Pair("keyIDVoting", keyIDOperator.ToString()));
obj.push_back(Pair("isValid", isValid));
}

CSimplifiedMNList::CSimplifiedMNList(const CDeterministicMNList& dmnList)
{
mnList.reserve(dmnList.all_count());

for (const auto& dmn : dmnList.all_range()) {
mnList.emplace_back(*dmn);
}

std::sort(mnList.begin(), mnList.end(), [&](const CSimplifiedMNListEntry& a, const CSimplifiedMNListEntry& b) {
return a.proRegTxHash.Compare(b.proRegTxHash) < 0;
});
}

uint256 CSimplifiedMNList::CalcMerkleRoot(bool *pmutated) const
{
std::vector<uint256> leaves;
leaves.reserve(mnList.size());
for (const auto& e : mnList) {
leaves.emplace_back(e.CalcHash());
}
return ComputeMerkleRoot(leaves, pmutated);
}
61 changes: 61 additions & 0 deletions src/evo/simplifiedmns.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) 2017 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 DASH_SIMPLIFIEDMNS_H
#define DASH_SIMPLIFIEDMNS_H

#include "serialize.h"
#include "pubkey.h"
#include "netaddress.h"

class UniValue;
class CDeterministicMNList;
class CDeterministicMN;

class CSimplifiedMNListEntry
{
public:
uint256 proRegTxHash;
CService service;
CKeyID keyIDOperator;
CKeyID keyIDVoting;
bool isValid;

public:
CSimplifiedMNListEntry() {}
CSimplifiedMNListEntry(const CDeterministicMN& dmn);

public:
ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(proRegTxHash);
READWRITE(service);
READWRITE(keyIDOperator);
READWRITE(keyIDVoting);
READWRITE(isValid);
}

public:
uint256 CalcHash() const;

std::string ToString() const;
void ToJson(UniValue& obj) const;
};

class CSimplifiedMNList
{
public:
std::vector<CSimplifiedMNListEntry> mnList;

public:
CSimplifiedMNList() {}
CSimplifiedMNList(const CDeterministicMNList& dmnList);

uint256 CalcMerkleRoot(bool *pmutated = NULL) const;
};

#endif//DASH_SIMPLIFIEDMNS_H
3 changes: 3 additions & 0 deletions src/evo/specialtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CV
if (!deterministicMNManager->ProcessBlock(block, pindex->pprev, state))
return false;

if (!CheckCbTxMerkleRootMNList(block, pindex, state))
return false;

return true;
}

Expand Down
8 changes: 8 additions & 0 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

#include "evo/specialtx.h"
#include "evo/cbtx.h"
#include "evo/simplifiedmns.h"
#include "evo/deterministicmns.h"

#include <algorithm>
#include <boost/thread.hpp>
Expand Down Expand Up @@ -183,6 +185,12 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc

CCbTx cbTx;
cbTx.nHeight = nHeight;

CValidationState state;
if (!CalcCbTxMerkleRootMNList(*pblock, pindexPrev, cbTx.merkleRootMNList, state)) {
throw std::runtime_error(strprintf("%s: CalcSMLMerkleRootForNewBlock failed: %s", __func__, FormatStateMessage(state)));
}

SetTxPayload(coinbaseTx, cbTx);
}

Expand Down
11 changes: 11 additions & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "utilstrencodings.h"
#include "hash.h"

#include "evo/specialtx.h"
#include "evo/cbtx.h"

#include <stdint.h>

#include <univalue.h>
Expand Down Expand Up @@ -131,6 +134,14 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
txs.push_back(tx->GetHash().GetHex());
}
result.push_back(Pair("tx", txs));
if (!block.vtx[0]->vExtraPayload.empty()) {
CCbTx cbTx;
if (GetTxPayload(block.vtx[0]->vExtraPayload, cbTx)) {
UniValue cbTxObj;
cbTx.ToJson(cbTxObj);
result.push_back(Pair("cbTx", cbTxObj));
}
}
result.push_back(Pair("time", block.GetBlockTime()));
result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
Expand Down
5 changes: 5 additions & 0 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "masternode-payments.h"
#include "masternode-sync.h"

#include "evo/specialtx.h"
#include "evo/cbtx.h"

#include <memory>
#include <stdint.h>

Expand Down Expand Up @@ -736,6 +739,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request)
result.push_back(Pair("superblocks_started", pindexPrev->nHeight + 1 > consensusParams.nSuperblockStartBlock));
result.push_back(Pair("superblocks_enabled", sporkManager.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED)));

result.push_back(Pair("coinbase_payload", HexStr(pblock->vtx[0]->vExtraPayload)));

return result;
}

Expand Down

0 comments on commit bcc0719

Please sign in to comment.