...
 
Commits (5)
......@@ -142,7 +142,9 @@ BITCOIN_CORE_H = \
masternode-sync.h \
masternodeman.h \
masternodeconfig.h \
mn-pos/blockwitness.h \
mn-pos/kernel.h \
mn-pos/prooftracker.h \
mn-pos/stakepointer.h \
mn-pos/stakeminer.h \
mn-pos/stakevalidation.h \
......@@ -206,6 +208,7 @@ libbitcoin_server_a_SOURCES = \
merkleblock.cpp \
miner.cpp \
mn-pos/kernel.cpp \
mn-pos/prooftracker.cpp \
mn-pos/stakeminer.cpp \
mn-pos/stakepointer.cpp \
mn-pos/stakevalidation.cpp \
......
This diff is collapsed.
......@@ -44,6 +44,7 @@ class CBlockIndex;
class CBlockTreeDB;
class CBloomFilter;
class CInv;
class ProofTracker;
class CScriptCheck;
class CValidationInterface;
class CValidationState;
......@@ -151,6 +152,7 @@ extern std::map<uint256, int64_t> mapRejectedBlocks;
typedef uint256 PointerHash;
extern std::map<PointerHash, uint256> mapUsedStakePointers; //pointer hash matched to blockhash that it is in
extern ProofTracker* g_proofTracker;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
......@@ -506,6 +508,7 @@ private:
MODE_VALID, //! everything ok
MODE_INVALID, //! network rule violation (DoS value may be set)
MODE_ERROR, //! run-time error
MODE_SUSPICIOUS, //! state seems wrong, but do not have all context needed to know that for sure
} mode;
int nDoS;
std::string strRejectReason;
......@@ -539,6 +542,10 @@ public:
AbortNode(msg);
return Error(msg);
}
bool Suspicious(const std::string &msg) {
mode = MODE_SUSPICIOUS;
return Error(msg);
}
bool IsValid() const {
return mode == MODE_VALID;
}
......@@ -555,6 +562,9 @@ public:
}
return false;
}
bool IsSuspicious() const {
return mode == MODE_SUSPICIOUS;
}
bool CorruptionPossible() const {
return corruptionPossible;
}
......
......@@ -1237,6 +1237,7 @@ bool CBudgetManager::SubmitProposalVote(const CBudgetVote& vote, std::string& st
mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
return true;
}
return false;
}
bool CBudgetManager::CanSubmitVotes(int blockStart, int blockEnd)
......
......@@ -9,6 +9,9 @@
#include "util.h"
#include "sync.h"
#include "addrman.h"
#include "mn-pos/blockwitness.h"
#include "mn-pos/prooftracker.h"
#include <boost/lexical_cast.hpp>
// keep track of the scanning errors I've seen
......@@ -759,6 +762,9 @@ CMasternodePing::CMasternodePing()
blockHash = uint256();
sigTime = 0;
vchSig = std::vector<unsigned char>();
vchSigPrevBlocks = std::vector<unsigned char>();
vPrevBlockHash = std::vector<uint256>();
nVersion = 2;
}
CMasternodePing::CMasternodePing(const CTxIn& newVin)
......@@ -767,6 +773,15 @@ CMasternodePing::CMasternodePing(const CTxIn& newVin)
blockHash = chainActive[chainActive.Height() - 12]->GetBlockHash();
sigTime = GetAdjustedTime();
vchSig = std::vector<unsigned char>();
vchSigPrevBlocks = std::vector<unsigned char>();
vPrevBlockHash = std::vector<uint256>();
//Add previous 10 blocks
for (unsigned int i = 0; i < 10; i ++) {
vPrevBlockHash.emplace_back(chainActive[chainActive.Height() - i]->GetBlockHash());
}
nVersion = 2;
}
......@@ -788,6 +803,17 @@ bool CMasternodePing::Sign(const CKey& keyMasternode, const CPubKey& pubKeyMaste
return false;
}
uint256 hash = Hash(vPrevBlockHash.begin(), vPrevBlockHash.end());
if(!legacySigner.SignMessage(hash.GetHex(), errorMessage, vchSigPrevBlocks, keyMasternode)) {
LogPrintf("CMasternodePing::Sign() - Error signing previous blocks: %s\n", errorMessage);
return false;
}
if(!legacySigner.VerifyMessage(pubKeyMasternode, vchSigPrevBlocks, hash.GetHex(), errorMessage)) {
LogPrintf("CMasternodePing::Sign() - Error: %s\n", errorMessage);
return false;
}
return true;
}
......@@ -802,6 +828,17 @@ bool CMasternodePing::VerifySignature(const CPubKey& pubKeyMasternode, int &nDos
nDos = 33;
return false;
}
//Also check signature of previous blockhashes
if (nVersion > 1) {
uint256 hash = Hash(vPrevBlockHash.begin(), vPrevBlockHash.end());
if (!legacySigner.VerifyMessage(pubKeyMasternode, vchSigPrevBlocks, hash.GetHex(), errorMessage)) {
LogPrintf("CMasternodePing::VerifySignature - Got bad Masternode signature for previous blocks %s Error: %s\n", vin.ToString(), errorMessage);
nDos = 33;
return false;
}
}
return true;
}
......@@ -872,6 +909,13 @@ bool CMasternodePing::CheckAndUpdate(int& nDos, bool fRequireEnabled, bool fChec
pmn->Check(true);
if(!pmn->IsEnabled()) return false;
if (this->nVersion > 1) {
for (const uint256& hashBlock : vPrevBlockHash) {
LogPrint("masternode", "%s: Adding witness for block %s from mn %s\n", __func__, hashBlock.GetHex(), vin.ToString());
g_proofTracker->AddWitness(BlockWitness(pmn->vin, hashBlock));
}
}
LogPrint("masternode", "CMasternodePing::CheckAndUpdate - Masternode ping accepted, vin: %s\n", vin.ToString());
Relay();
......
......@@ -43,6 +43,12 @@ public:
uint256 blockHash;
int64_t sigTime; //mnb message times
std::vector<unsigned char> vchSig;
//Version 2 and above
int8_t nVersion;
std::vector<uint256> vPrevBlockHash; //10 previous blocks
std::vector<unsigned char> vchSigPrevBlocks;
//removed stop
CMasternodePing();
......@@ -57,6 +63,13 @@ public:
READWRITE(blockHash);
READWRITE(sigTime);
READWRITE(vchSig);
//New versioning is set externally before serialization
if (this->nVersion >= 2) {
READWRITE(this->nVersion);
READWRITE(vPrevBlockHash);
READWRITE(vchSigPrevBlocks);
}
}
bool CheckAndUpdate(int& nDos, bool fRequireEnabled = true, bool fCheckSigTimeOnly = false) const;
......
......@@ -537,8 +537,14 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
LOCK(cs_process_message);
if (strCommand == "mnb") { //Masternode Broadcast
if (strCommand == "mnb" || strCommand == "mnb_new") { //Masternode Broadcast
CMasternodeBroadcast mnb;
if (strCommand == "mnb") {
//Set to old version for old serialization
mnb.lastPing.nVersion = 1;
} else {
mnb.lastPing.nVersion = 2;
}
vRecv >> mnb;
int nDoS = 0;
......@@ -550,8 +556,12 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
}
}
else if (strCommand == "mnp") { //Masternode Ping
else if (strCommand == "mnp" || strCommand == "mnp_new") { //Masternode Ping
CMasternodePing mnp;
if (strCommand == "mnp") {
//Set to old version for old serialization
mnp.nVersion = 1;
}
vRecv >> mnp;
LogPrint("masternode", "mnp - Masternode ping, vin: %s\n", mnp.vin.ToString());
......@@ -560,6 +570,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp));
int nDoS = 0;
LOCK(cs_main);
if(mnp.CheckAndUpdate(nDoS)) return;
if(nDoS > 0) {
......
#ifndef CROWNCOIN_BLOCKWITNESS_H
#define CROWNCOIN_BLOCKWITNESS_H
#include <primitives/transaction.h>
#include <vector>
class BlockWitness
{
public:
CTxIn m_vin;
uint256 m_hashBlock;
BlockWitness(const CTxIn& vin, const uint256& hashBlock) : m_vin(vin), m_hashBlock(hashBlock) {}
bool operator<(const BlockWitness& other) const
{
if (m_hashBlock != other.m_hashBlock)
return m_hashBlock < other.m_hashBlock;
return m_vin.prevout < other.m_vin.prevout;
}
};
#endif //CROWNCOIN_BLOCKWITNESS_H
#include "prooftracker.h"
#include "blockwitness.h"
#define REQUIRED_WITNESS_SIGS 6
#define STAKE_REPACKAGE_THRESHOLD 3
void ProofTracker::AddNewStake(const STAKEHASH& hashStake, const BLOCKHASH& hashBlock)
{
if (!m_mapStakes.count(hashStake))
m_mapStakes.emplace(std::make_pair(hashStake, std::set<BLOCKHASH>()));
m_mapStakes.at(hashStake).emplace(hashBlock);
}
void ProofTracker::AddWitness(const BlockWitness& witness)
{
if (!m_mapBlockWitness.count(witness.m_hashBlock))
m_mapBlockWitness.emplace(std::make_pair(witness.m_hashBlock, std::set<BlockWitness>()));
m_mapBlockWitness.at(witness.m_hashBlock).emplace(witness);
}
std::set<BlockWitness> ProofTracker::GetWitnesses(const uint256& hashBlock) const
{
if (m_mapBlockWitness.count(hashBlock))
return m_mapBlockWitness.at(hashBlock);
return std::set<BlockWitness>();
}
int ProofTracker::GetWitnessCount(const BLOCKHASH& hashBlock) const
{
if (!m_mapBlockWitness.count(hashBlock))
return 0;
return m_mapBlockWitness.at(hashBlock).size();
}
bool ProofTracker::HasSufficientProof(const BLOCKHASH& hashBlock) const
{
return m_mapBlockWitness.count(hashBlock) && m_mapBlockWitness.at(hashBlock).size() >= REQUIRED_WITNESS_SIGS;
}
bool ProofTracker::IsSuspicious(const STAKEHASH& hashStake, const BLOCKHASH& hashBlock)
{
if (!m_mapStakes.count(hashStake)) {
AddNewStake(hashStake, hashBlock);
return false;
}
if (m_mapStakes.at(hashStake).size() >= STAKE_REPACKAGE_THRESHOLD) {
//If there are enough masternode that has signed off on this hash then it is not suspicious
if (!m_mapBlockWitness.count(hashBlock))
return true; //suspicious because no records of mn signing this block
// Factored out for legibility...
const auto& vWitness = m_mapBlockWitness.at(hashBlock);
bool isSuspicious = vWitness.size() < REQUIRED_WITNESS_SIGS;
if (isSuspicious)
return isSuspicious;
}
//Not suspicious, but still record knowledge of this stake so potential suspicious repackaging of this stake
//can be tracked
AddNewStake(hashStake, hashBlock);
return false;
}
\ No newline at end of file
#include <map>
#include <set>
class BlockWitness;
class uint256;
typedef uint256 BLOCKHASH;
typedef uint256 STAKEHASH;
class ProofTracker
{
private:
std::map<STAKEHASH, std::set<BLOCKHASH>> m_mapStakes;
std::map<BLOCKHASH, std::set<BlockWitness>> m_mapBlockWitness;
void AddNewStake(const STAKEHASH& hashStake, const BLOCKHASH& hashBlock);
public:
std::set<BlockWitness> GetWitnesses(const uint256& hashBlock) const;
bool HasSufficientProof(const BLOCKHASH& hashBlock) const;
bool IsSuspicious(const STAKEHASH& hash, const BLOCKHASH& hashBlock);
void AddWitness(const BlockWitness& witness);
int GetWitnessCount(const BLOCKHASH& hashBlock) const;
};
\ No newline at end of file
......@@ -16,7 +16,7 @@ bool CheckBlockSignature(const CBlock& block, const CPubKey& pubkeyMasternode)
}
// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlock& block, const CBlockIndex* prevBlock, const COutPoint& outpointStakePointer)
bool CheckProofOfStake(const CBlock& block, const CBlockIndex* prevBlock, const COutPoint& outpointStakePointer, uint256& hashProofOfStake)
{
const CTransaction tx = block.vtx[1];
if (!tx.IsCoinStake())
......@@ -53,5 +53,7 @@ bool CheckProofOfStake(const CBlock& block, const CBlockIndex* prevBlock, const
LogPrintf("%s : %s\n", __func__, kernel.ToString());
hashProofOfStake = kernel.GetStakeHash();
return kernel.IsValidProof(ArithToUint256(bnTarget));
}
\ No newline at end of file
......@@ -6,10 +6,11 @@ class CPubKey;
class CBlockIndex;
class COutPoint;
class CTransaction;
class uint256;
bool CheckBlockSignature(const CBlock& block, const CPubKey& pubkeyMasternode);
// Check kernel hash target and coinstake signature
bool CheckProofOfStake(const CBlock& block, const CBlockIndex* prevBlock, const COutPoint& outpointStakePointer);
bool CheckProofOfStake(const CBlock& block, const CBlockIndex* prevBlock, const COutPoint& outpointStakePointer, uint256& hashProofOfStake);
#endif //CROWNCORE_STAKEVALIDATION_H
......@@ -9,6 +9,7 @@
#include "rpcserver.h"
#include "sync.h"
#include "util.h"
#include "mn-pos/prooftracker.h"
#include <stdint.h>
......@@ -86,6 +87,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
result.push_back(Pair("block_witnesses", (int64_t)g_proofTracker->GetWitnessCount(block.GetHash())));
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
......
......@@ -796,6 +796,7 @@ Value masternodebroadcast(const Array& params, bool fHelp)
bool fResult;
if (mnb.VerifySignature()) {
if (fSafe) {
LOCK(cs_main);
fResult = mnodeman.CheckMnbAndUpdateMasternodeList(mnb, nDos);
} else {
mnodeman.UpdateMasternodeList(mnb);
......
......@@ -9,7 +9,7 @@
/**
* network protocol versioning
*/
static const int PROTOCOL_VERSION = 71057;
static const int PROTOCOL_VERSION = 71059;
static const int PROTOCOL_POS_START = 71057;
//! initial proto version, to be increased after version/verack negotiation
......@@ -28,6 +28,9 @@ static const int MIN_BUDGET_PEER_PROTO_VERSION = PROTOCOL_POS_START;
//! minimum peer version for masternode winner broadcasts
static const int MIN_MNW_PEER_PROTO_VERSION = PROTOCOL_POS_START;
//! minimum version to get version 2 masternode ping messages
static const int MIN_MNW_PING_VERSION = 71059;
//! minimum peer version that can receive masternode payments
// V1 - Last protocol version before update
// V2 - Newest protocol version
......