commit
2900760dac
@ -113,7 +113,8 @@ class NULLDUMMYTest(BitcoinTestFramework):
|
||||
|
||||
|
||||
def block_submit(self, node, txs, accept = False):
|
||||
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1), self.lastblocktime + 1)
|
||||
dip4_activated = self.lastblockheight + 1 >= 432
|
||||
block = create_block(self.tip, create_coinbase(self.lastblockheight + 1, dip4_activated=dip4_activated), self.lastblocktime + 1)
|
||||
block.nVersion = 4
|
||||
for tx in txs:
|
||||
tx.rehash()
|
||||
|
@ -40,7 +40,7 @@ def serialize_script_num(value):
|
||||
# Create a coinbase transaction, assuming no miner fees.
|
||||
# If pubkey is passed in, the coinbase output will be a P2PK output;
|
||||
# otherwise an anyone-can-spend output.
|
||||
def create_coinbase(height, pubkey = None):
|
||||
def create_coinbase(height, pubkey = None, dip4_activated=False):
|
||||
coinbase = CTransaction()
|
||||
coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff),
|
||||
ser_string(serialize_script_num(height)), 0xffffffff))
|
||||
@ -53,6 +53,11 @@ def create_coinbase(height, pubkey = None):
|
||||
else:
|
||||
coinbaseoutput.scriptPubKey = CScript([OP_TRUE])
|
||||
coinbase.vout = [ coinbaseoutput ]
|
||||
if dip4_activated:
|
||||
coinbase.nVersion = 3
|
||||
coinbase.nType = 5
|
||||
cbtx_payload = CCbTx(1, height, 0)
|
||||
coinbase.vExtraPayload = cbtx_payload.serialize()
|
||||
coinbase.calc_sha256()
|
||||
return coinbase
|
||||
|
||||
|
@ -793,6 +793,34 @@ class BlockTransactions(object):
|
||||
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"
|
||||
|
@ -110,6 +110,8 @@ BITCOIN_CORE_H = \
|
||||
evo/specialtx.h \
|
||||
evo/providertx.h \
|
||||
evo/deterministicmns.h \
|
||||
evo/cbtx.h \
|
||||
evo/simplifiedmns.h \
|
||||
privatesend.h \
|
||||
privatesend-client.h \
|
||||
privatesend-server.h \
|
||||
@ -224,6 +226,8 @@ libdash_server_a_SOURCES = \
|
||||
evo/specialtx.cpp \
|
||||
evo/providertx.cpp \
|
||||
evo/deterministicmns.cpp \
|
||||
evo/cbtx.cpp \
|
||||
evo/simplifiedmns.cpp \
|
||||
httprpc.cpp \
|
||||
httpserver.cpp \
|
||||
init.cpp \
|
||||
|
89
src/evo/cbtx.cpp
Normal file
89
src/evo/cbtx.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
// 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 "cbtx.h"
|
||||
#include "specialtx.h"
|
||||
#include "deterministicmns.h"
|
||||
#include "simplifiedmns.h"
|
||||
|
||||
#include "validation.h"
|
||||
#include "univalue.h"
|
||||
|
||||
bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-invalid");
|
||||
|
||||
CCbTx cbTx;
|
||||
if (!GetTxPayload(tx, cbTx))
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-tx-payload");
|
||||
|
||||
if (cbTx.nVersion > CCbTx::CURRENT_VERSION)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
|
||||
|
||||
if (pindexPrev) {
|
||||
if (pindexPrev->nHeight + 1 != cbTx.nHeight)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-height");
|
||||
}
|
||||
|
||||
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)",
|
||||
nVersion, nHeight, merkleRootMNList.ToString());
|
||||
}
|
||||
|
||||
void CCbTx::ToJson(UniValue& obj) const
|
||||
{
|
||||
obj.clear();
|
||||
obj.setObject();
|
||||
obj.push_back(Pair("version", (int)nVersion));
|
||||
obj.push_back(Pair("height", (int)nHeight));
|
||||
obj.push_back(Pair("merkleRootMNList", merkleRootMNList.ToString()));
|
||||
}
|
46
src/evo/cbtx.h
Normal file
46
src/evo/cbtx.h
Normal file
@ -0,0 +1,46 @@
|
||||
// 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_CBTX_H
|
||||
#define DASH_CBTX_H
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "consensus/validation.h"
|
||||
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
class UniValue;
|
||||
|
||||
// coinbase transaction
|
||||
class CCbTx
|
||||
{
|
||||
public:
|
||||
static const uint16_t CURRENT_VERSION = 1;
|
||||
|
||||
public:
|
||||
uint16_t nVersion{CURRENT_VERSION};
|
||||
int32_t nHeight{0};
|
||||
uint256 merkleRootMNList;
|
||||
|
||||
public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(nVersion);
|
||||
READWRITE(nHeight);
|
||||
READWRITE(merkleRootMNList);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
void ToJson(UniValue& obj) const;
|
||||
};
|
||||
|
||||
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
|
163
src/evo/simplifiedmns.cpp
Normal file
163
src/evo/simplifiedmns.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
// 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 "cbtx.h"
|
||||
|
||||
#include "validation.h"
|
||||
#include "univalue.h"
|
||||
#include "consensus/merkle.h"
|
||||
#include "chainparams.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);
|
||||
}
|
||||
|
||||
void CSimplifiedMNListDiff::ToJson(UniValue& obj) const
|
||||
{
|
||||
obj.setObject();
|
||||
|
||||
obj.push_back(Pair("baseBlockHash", baseBlockHash.ToString()));
|
||||
obj.push_back(Pair("blockHash", blockHash.ToString()));
|
||||
|
||||
UniValue deletedMNsArr(UniValue::VARR);
|
||||
for (const auto& h : deletedMNs) {
|
||||
deletedMNsArr.push_back(h.ToString());
|
||||
}
|
||||
obj.push_back(Pair("deletedMNs", deletedMNsArr));
|
||||
|
||||
UniValue mnListArr(UniValue::VARR);
|
||||
for (const auto& e : mnList) {
|
||||
UniValue eObj;
|
||||
e.ToJson(eObj);
|
||||
mnListArr.push_back(eObj);
|
||||
}
|
||||
obj.push_back(Pair("mnList", mnListArr));
|
||||
|
||||
CCbTx cbTxPayload;
|
||||
if (GetTxPayload(*cbTx, cbTxPayload)) {
|
||||
obj.push_back(Pair("merkleRootMNList", cbTxPayload.merkleRootMNList.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
bool BuildSimplifiedMNListDiff(const uint256& baseBlockHash, const uint256& blockHash, CSimplifiedMNListDiff& mnListDiffRet, std::string& errorRet)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
mnListDiffRet = CSimplifiedMNListDiff();
|
||||
|
||||
BlockMap::iterator baseBlockIt = mapBlockIndex.begin();
|
||||
if (!baseBlockHash.IsNull()) {
|
||||
baseBlockIt = mapBlockIndex.find(baseBlockHash);
|
||||
}
|
||||
auto blockIt = mapBlockIndex.find(blockHash);
|
||||
if (baseBlockIt == mapBlockIndex.end()) {
|
||||
errorRet = strprintf("block %s not found", baseBlockHash.ToString());
|
||||
return false;
|
||||
}
|
||||
if (blockIt == mapBlockIndex.end()) {
|
||||
errorRet = strprintf("block %s not found", blockHash.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chainActive.Contains(baseBlockIt->second) || !chainActive.Contains(blockIt->second)) {
|
||||
errorRet = strprintf("block %s and %s are not in the same chain", baseBlockHash.ToString(), blockHash.ToString());
|
||||
return false;
|
||||
}
|
||||
if (baseBlockIt->second->nHeight > blockIt->second->nHeight) {
|
||||
errorRet = strprintf("base block %s is higher then block %s", baseBlockHash.ToString(), blockHash.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
LOCK(deterministicMNManager->cs);
|
||||
|
||||
auto baseDmnList = deterministicMNManager->GetListForBlock(baseBlockHash);
|
||||
auto dmnList = deterministicMNManager->GetListForBlock(blockHash);
|
||||
auto dmnDiff = baseDmnList.BuildDiff(dmnList);
|
||||
|
||||
// TODO store coinbase TX in CBlockIndex
|
||||
CBlock block;
|
||||
if (!ReadBlockFromDisk(block, blockIt->second, Params().GetConsensus())) {
|
||||
errorRet = strprintf("failed to read block %s from disk", blockHash.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
mnListDiffRet.baseBlockHash = baseBlockHash;
|
||||
mnListDiffRet.blockHash = blockHash;
|
||||
mnListDiffRet.cbTx = block.vtx[0];
|
||||
|
||||
std::vector<uint256> vHashes;
|
||||
std::vector<bool> vMatch(block.vtx.size(), false);
|
||||
for (const auto& tx : block.vtx) {
|
||||
vHashes.emplace_back(tx->GetHash());
|
||||
}
|
||||
vMatch[0] = true; // only coinbase matches
|
||||
mnListDiffRet.cbTxMerkleTree = CPartialMerkleTree(vHashes, vMatch);
|
||||
mnListDiffRet.deletedMNs.assign(dmnDiff.removedMns.begin(), dmnDiff.removedMns.end());
|
||||
|
||||
for (const auto& p : dmnDiff.addedMNs) {
|
||||
mnListDiffRet.mnList.emplace_back(*p.second);
|
||||
}
|
||||
for (const auto& p : dmnDiff.updatedMNs) {
|
||||
const auto& dmn = dmnList.GetMN(p.first);
|
||||
CDeterministicMN newDmn(*dmn);
|
||||
newDmn.pdmnState = p.second;
|
||||
mnListDiffRet.mnList.emplace_back(newDmn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
111
src/evo/simplifiedmns.h
Normal file
111
src/evo/simplifiedmns.h
Normal file
@ -0,0 +1,111 @@
|
||||
// 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"
|
||||
#include "merkleblock.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;
|
||||
};
|
||||
|
||||
/// P2P messages
|
||||
|
||||
class CGetSimplifiedMNListDiff
|
||||
{
|
||||
public:
|
||||
uint256 baseBlockHash;
|
||||
uint256 blockHash;
|
||||
|
||||
public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(baseBlockHash);
|
||||
READWRITE(blockHash);
|
||||
}
|
||||
};
|
||||
|
||||
class CSimplifiedMNListDiff
|
||||
{
|
||||
public:
|
||||
uint256 baseBlockHash;
|
||||
uint256 blockHash;
|
||||
CPartialMerkleTree cbTxMerkleTree;
|
||||
CTransactionRef cbTx;
|
||||
std::vector<uint256> deletedMNs;
|
||||
std::vector<CSimplifiedMNListEntry> mnList;
|
||||
|
||||
public:
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
inline void SerializationOp(Stream& s, Operation ser_action)
|
||||
{
|
||||
READWRITE(baseBlockHash);
|
||||
READWRITE(blockHash);
|
||||
READWRITE(cbTxMerkleTree);
|
||||
READWRITE(cbTx);
|
||||
READWRITE(deletedMNs);
|
||||
READWRITE(mnList);
|
||||
}
|
||||
|
||||
public:
|
||||
void ToJson(UniValue& obj) const;
|
||||
};
|
||||
|
||||
bool BuildSimplifiedMNListDiff(const uint256& baseBlockHash, const uint256& blockHash, CSimplifiedMNListDiff& mnListDiffRet, std::string& errorRet);
|
||||
|
||||
#endif//DASH_SIMPLIFIEDMNS_H
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "specialtx.h"
|
||||
#include "deterministicmns.h"
|
||||
#include "cbtx.h"
|
||||
|
||||
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
|
||||
{
|
||||
@ -33,6 +34,8 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVali
|
||||
return CheckProUpRegTx(tx, pindexPrev, state);
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return CheckProUpRevTx(tx, pindexPrev, state);
|
||||
case TRANSACTION_COINBASE:
|
||||
return CheckCbTx(tx, pindexPrev, state);
|
||||
}
|
||||
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-tx-type");
|
||||
@ -49,6 +52,8 @@ bool ProcessSpecialTx(const CTransaction& tx, const CBlockIndex* pindex, CValida
|
||||
case TRANSACTION_PROVIDER_UPDATE_REGISTRAR:
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return true; // handled in batches per block
|
||||
case TRANSACTION_COINBASE:
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-tx-type");
|
||||
@ -65,6 +70,8 @@ bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
|
||||
case TRANSACTION_PROVIDER_UPDATE_REGISTRAR:
|
||||
case TRANSACTION_PROVIDER_UPDATE_REVOKE:
|
||||
return true; // handled in batches per block
|
||||
case TRANSACTION_COINBASE:
|
||||
return true; // nothing to do
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -83,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;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,11 @@
|
||||
#include "masternode-sync.h"
|
||||
#include "validationinterface.h"
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/cbtx.h"
|
||||
#include "evo/simplifiedmns.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
@ -126,6 +131,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
pblocktemplate->vTxSigOps.push_back(-1); // updated at end
|
||||
|
||||
LOCK2(cs_main, mempool.cs);
|
||||
|
||||
bool fDIP0003Active_context = VersionBitsState(chainActive.Tip(), chainparams.GetConsensus(), Consensus::DEPLOYMENT_DIP0003, versionbitscache) == THRESHOLD_ACTIVE;
|
||||
|
||||
CBlockIndex* pindexPrev = chainActive.Tip();
|
||||
nHeight = pindexPrev->nHeight + 1;
|
||||
|
||||
@ -166,7 +174,25 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
|
||||
// Compute regular coinbase transaction.
|
||||
coinbaseTx.vout[0].nValue = blockReward;
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
if (!fDIP0003Active_context) {
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
} else {
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << OP_RETURN;
|
||||
|
||||
coinbaseTx.nVersion = 3;
|
||||
coinbaseTx.nType = TRANSACTION_COINBASE;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Update coinbase transaction with additional info about masternode and governance payments,
|
||||
// get some info back to pass to getblocktemplate
|
||||
|
@ -42,6 +42,8 @@
|
||||
#endif // ENABLE_WALLET
|
||||
#include "privatesend-server.h"
|
||||
|
||||
#include "evo/simplifiedmns.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#if defined(NDEBUG)
|
||||
@ -2818,6 +2820,31 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
}
|
||||
|
||||
|
||||
else if (strCommand == NetMsgType::GETMNLISTDIFF) {
|
||||
CGetSimplifiedMNListDiff cmd;
|
||||
vRecv >> cmd;
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
CSimplifiedMNListDiff mnListDiff;
|
||||
std::string strError;
|
||||
if (BuildSimplifiedMNListDiff(cmd.baseBlockHash, cmd.blockHash, mnListDiff, strError)) {
|
||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::MNLISTDIFF, mnListDiff));
|
||||
} else {
|
||||
LogPrint("net", "getmnlistdiff failed for baseBlockHash=%s, blockHash=%s. error=%s\n", cmd.baseBlockHash.ToString(), cmd.blockHash.ToString(), strError);
|
||||
Misbehaving(pfrom->id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if (strCommand == NetMsgType::MNLISTDIFF) {
|
||||
// we have never requested this
|
||||
LOCK(cs_main);
|
||||
Misbehaving(pfrom->id, 100);
|
||||
LogPrint("net", "received not-requested mnlistdiff. peer=%d\n", pfrom->id);
|
||||
}
|
||||
|
||||
|
||||
else if (strCommand == NetMsgType::NOTFOUND) {
|
||||
// We do not care about the NOTFOUND message, but logging an Unknown Command
|
||||
// message would be undesirable as we transmit it ourselves.
|
||||
|
@ -18,6 +18,7 @@ enum {
|
||||
TRANSACTION_PROVIDER_UPDATE_SERVICE = 2,
|
||||
TRANSACTION_PROVIDER_UPDATE_REGISTRAR = 3,
|
||||
TRANSACTION_PROVIDER_UPDATE_REVOKE = 4,
|
||||
TRANSACTION_COINBASE = 5,
|
||||
};
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
|
@ -69,6 +69,8 @@ const char *MNGOVERNANCESYNC="govsync";
|
||||
const char *MNGOVERNANCEOBJECT="govobj";
|
||||
const char *MNGOVERNANCEOBJECTVOTE="govobjvote";
|
||||
const char *MNVERIFY="mnv";
|
||||
const char *GETMNLISTDIFF="getmnlistd";
|
||||
const char *MNLISTDIFF="mnlistdiff";
|
||||
};
|
||||
|
||||
static const char* ppszTypeName[] =
|
||||
@ -153,6 +155,8 @@ const static std::string allNetMessageTypes[] = {
|
||||
NetMsgType::MNGOVERNANCEOBJECT,
|
||||
NetMsgType::MNGOVERNANCEOBJECTVOTE,
|
||||
NetMsgType::MNVERIFY,
|
||||
NetMsgType::GETMNLISTDIFF,
|
||||
NetMsgType::MNLISTDIFF,
|
||||
};
|
||||
const static std::vector<std::string> allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes+ARRAYLEN(allNetMessageTypes));
|
||||
|
||||
|
@ -268,6 +268,8 @@ extern const char *MNGOVERNANCESYNC;
|
||||
extern const char *MNGOVERNANCEOBJECT;
|
||||
extern const char *MNGOVERNANCEOBJECTVOTE;
|
||||
extern const char *MNVERIFY;
|
||||
extern const char *GETMNLISTDIFF;
|
||||
extern const char *MNLISTDIFF;
|
||||
};
|
||||
|
||||
/* Get a vector of all valid message types (see above) */
|
||||
|
@ -23,6 +23,9 @@
|
||||
#include "utilstrencodings.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <univalue.h>
|
||||
@ -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));
|
||||
|
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -158,6 +159,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
|
||||
proTx.ToJson(proTxObj);
|
||||
entry.push_back(Pair("proUpRevTx", proTxObj));
|
||||
}
|
||||
} else if (tx.nType == TRANSACTION_COINBASE) {
|
||||
CCbTx cbTx;
|
||||
if (GetTxPayload(tx, cbTx)) {
|
||||
UniValue proTxObj;
|
||||
cbTx.ToJson(proTxObj);
|
||||
entry.push_back(Pair("cbTx", proTxObj));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hashBlock.IsNull()) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
#include "evo/simplifiedmns.h"
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
extern UniValue signrawtransaction(const JSONRPCRequest& request);
|
||||
@ -558,6 +559,60 @@ UniValue protx_list(const JSONRPCRequest& request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void protx_diff_help()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"protx diff \"baseBlock\" \"block\"\n"
|
||||
"\nCalculates a diff between two deterministic masternode lists. The result also contains proof data.\n"
|
||||
"specified, it defaults to \"wallet\". All types have the optional argument \"detailed\" which if set to\n"
|
||||
"\"true\" will result in a detailed list to be returned. If set to \"false\", only the hashes of the ProTx\n"
|
||||
"will be returned.\n"
|
||||
"\nAvailable types:\n"
|
||||
" wallet (detailed) - List only ProTx which are found in your wallet. This will also include ProTx which\n"
|
||||
" failed PoSe verfication\n"
|
||||
" valid (height) (detailed) - List only ProTx which are active/valid at the given chain height. If height is not\n"
|
||||
" specified, it defaults to the current chain-tip\n"
|
||||
" registered (height) (detaileD) - List all ProTx which are registered at the given chain height. If height is not\n"
|
||||
" specified, it defaults to the current chain-tip. This will also include ProTx\n"
|
||||
" which failed PoSe verification at that height\n"
|
||||
);
|
||||
}
|
||||
|
||||
static uint256 ParseBlock(const UniValue& v, std::string strName)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
try {
|
||||
return ParseHashV(v, strName);
|
||||
} catch (...) {
|
||||
int h = ParseInt32V(v, strName);
|
||||
if (h < 1 || h > chainActive.Height())
|
||||
throw std::runtime_error(strprintf("%s must be a block hash or chain height and not %s", strName, v.getValStr()));
|
||||
return *chainActive[h]->phashBlock;
|
||||
}
|
||||
}
|
||||
|
||||
UniValue protx_diff(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 3)
|
||||
protx_diff_help();
|
||||
|
||||
LOCK(cs_main);
|
||||
uint256 baseBlockHash = ParseBlock(request.params[1], "baseBlock");
|
||||
uint256 blockHash = ParseBlock(request.params[2], "block");
|
||||
|
||||
CSimplifiedMNListDiff mnListDiff;
|
||||
std::string strError;
|
||||
if (!BuildSimplifiedMNListDiff(baseBlockHash, blockHash, mnListDiff, strError)) {
|
||||
throw std::runtime_error(strError);
|
||||
}
|
||||
|
||||
UniValue ret;
|
||||
mnListDiff.ToJson(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
UniValue protx(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.params.empty()) {
|
||||
@ -573,6 +628,7 @@ UniValue protx(const JSONRPCRequest& request)
|
||||
" update_service - Create and send ProUpServTx to network\n"
|
||||
" update_registrar - Create and send ProUpRegTx to network\n"
|
||||
" revoke - Create and send ProUpRevTx to network\n"
|
||||
" diff - Calculate a diff and a proof between two masternode lists\n"
|
||||
);
|
||||
}
|
||||
|
||||
@ -588,6 +644,8 @@ UniValue protx(const JSONRPCRequest& request)
|
||||
return protx_update_registrar(request);
|
||||
} else if (command == "revoke") {
|
||||
return protx_revoke(request);
|
||||
} else if (command == "diff") {
|
||||
return protx_diff(request);
|
||||
} else {
|
||||
throw std::runtime_error("invalid command: " + command);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "evo/specialtx.h"
|
||||
#include "evo/providertx.h"
|
||||
#include "evo/deterministicmns.h"
|
||||
#include "evo/cbtx.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <sstream>
|
||||
@ -550,7 +551,12 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state, bool fChe
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
||||
int minCbSize = 2;
|
||||
if (tx.nType == TRANSACTION_COINBASE) {
|
||||
// With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height
|
||||
minCbSize = 1;
|
||||
}
|
||||
if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
|
||||
}
|
||||
else
|
||||
@ -576,10 +582,11 @@ bool ContextualCheckTransaction(const CTransaction& tx, CValidationState &state,
|
||||
tx.nType != TRANSACTION_PROVIDER_REGISTER &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR &&
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE) {
|
||||
tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE &&
|
||||
tx.nType != TRANSACTION_COINBASE) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
|
||||
}
|
||||
if (tx.IsCoinBase() && tx.nType != TRANSACTION_NORMAL)
|
||||
if (tx.IsCoinBase() && tx.nType != TRANSACTION_COINBASE)
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-cb-type");
|
||||
} else if (tx.nType != TRANSACTION_NORMAL) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-type");
|
||||
@ -3513,6 +3520,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
: block.GetBlockTime();
|
||||
|
||||
bool fDIP0001Active_context = nHeight >= Params().GetConsensus().DIP0001Height;
|
||||
bool fDIP0003Active_context = VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0003, versionbitscache) == THRESHOLD_ACTIVE;
|
||||
|
||||
// Size limits
|
||||
unsigned int nMaxBlockSize = MaxBlockSize(fDIP0001Active_context);
|
||||
@ -3537,7 +3545,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
return state.DoS(10, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount");
|
||||
|
||||
// Enforce rule that the coinbase starts with serialized block height
|
||||
if (nHeight >= consensusParams.BIP34Height)
|
||||
// After DIP3/DIP4 activation, we don't enforce the height in the input script anymore.
|
||||
// The CbTx special transaction payload will then contain the height, which is checked in CheckCbTx
|
||||
if (nHeight >= consensusParams.BIP34Height && !fDIP0003Active_context)
|
||||
{
|
||||
CScript expect = CScript() << nHeight;
|
||||
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
||||
@ -3546,6 +3556,12 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
|
||||
}
|
||||
}
|
||||
|
||||
if (fDIP0003Active_context) {
|
||||
if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
|
||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-type", false, "coinbase is not a CbTx");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user