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
13 changes: 8 additions & 5 deletions src/governance-object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,17 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast
masternode_info_t infoMn;
if(!mnodeman.GetMasternodeInfo(vinMasternode.prevout, infoMn)) {

CMasternode::CollateralStatus err = CMasternode::CheckCollateral(vinMasternode.prevout);
if (err == CMasternode::COLLATERAL_OK) {
fMissingMasternode = true;
strError = "Masternode not found: " + strOutpoint;
} else if (err == CMasternode::COLLATERAL_UTXO_NOT_FOUND) {
CMasternode::CollateralStatus err = CMasternode::CheckCollateral(vinMasternode.prevout, CPubKey());
if (err == CMasternode::COLLATERAL_UTXO_NOT_FOUND) {
strError = "Failed to find Masternode UTXO, missing masternode=" + strOutpoint + "\n";
} else if (err == CMasternode::COLLATERAL_INVALID_AMOUNT) {
strError = "Masternode UTXO should have 1000 DASH, missing masternode=" + strOutpoint + "\n";
} else if (err == CMasternode::COLLATERAL_INVALID_PUBKEY) {
fMissingMasternode = true;
strError = "Masternode not found: " + strOutpoint;
} else if (err == CMasternode::COLLATERAL_OK) {
// this should never happen with CPubKey() as a param
strError = "CheckCollateral critical failure! Masternode: " + strOutpoint;
}

return false;
Expand Down
117 changes: 45 additions & 72 deletions src/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,13 @@ arith_uint256 CMasternode::CalculateScore(const uint256& blockHash)
return UintToArith256(ss.GetHash());
}

CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint)
CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint, const CPubKey& pubkey)
{
int nHeight;
return CheckCollateral(outpoint, nHeight);
return CheckCollateral(outpoint, pubkey, nHeight);
}

CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint, int& nHeightRet)
CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outpoint, const CPubKey& pubkey, int& nHeightRet)
{
AssertLockHeld(cs_main);

Expand All @@ -120,6 +120,10 @@ CMasternode::CollateralStatus CMasternode::CheckCollateral(const COutPoint& outp
return COLLATERAL_INVALID_AMOUNT;
}

if(pubkey == CPubKey() || coin.out.scriptPubKey != GetScriptForDestination(pubkey.GetID())) {
return COLLATERAL_INVALID_PUBKEY;
}

nHeightRet = coin.nHeight;
return COLLATERAL_OK;
}
Expand All @@ -143,8 +147,8 @@ void CMasternode::Check(bool fForce)
TRY_LOCK(cs_main, lockMain);
if(!lockMain) return;

CollateralStatus err = CheckCollateral(vin.prevout);
if (err == COLLATERAL_UTXO_NOT_FOUND) {
Coin coin;
if(!GetUTXOCoin(vin.prevout, coin)) {
nActiveState = MASTERNODE_OUTPOINT_SPENT;
LogPrint("masternode", "CMasternode::Check -- Failed to find Masternode UTXO, masternode=%s\n", vin.prevout.ToStringShort());
return;
Expand Down Expand Up @@ -243,21 +247,6 @@ void CMasternode::Check(bool fForce)
}
}

bool CMasternode::IsInputAssociatedWithPubkey()
{
CScript payee;
payee = GetScriptForDestination(pubKeyCollateralAddress.GetID());

CTransaction tx;
uint256 hash;
if(GetTransaction(vin.prevout.hash, tx, Params().GetConsensus(), hash, true)) {
BOOST_FOREACH(CTxOut out, tx.vout)
if(out.nValue == 1000*COIN && out.scriptPubKey == payee) return true;
}

return false;
}

bool CMasternode::IsValidNetAddr()
{
return IsValidNetAddr(addr);
Expand Down Expand Up @@ -538,72 +527,56 @@ bool CMasternodeBroadcast::CheckOutpoint(int& nDos)
return false;
}

if (!CheckSignature(nDos)) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- CheckSignature() failed, masternode=%s\n", vin.prevout.ToStringShort());
AssertLockHeld(cs_main);

int nHeight;
CollateralStatus err = CheckCollateral(vin.prevout, pubKeyCollateralAddress, nHeight);
if (err == COLLATERAL_UTXO_NOT_FOUND) {
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Failed to find Masternode UTXO, masternode=%s\n", vin.prevout.ToStringShort());
return false;
}

{
TRY_LOCK(cs_main, lockMain);
if(!lockMain) {
// not mnb fault, let it to be checked again later
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Failed to aquire lock, addr=%s", addr.ToString());
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
return false;
}

int nHeight;
CollateralStatus err = CheckCollateral(vin.prevout, nHeight);
if (err == COLLATERAL_UTXO_NOT_FOUND) {
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Failed to find Masternode UTXO, masternode=%s\n", vin.prevout.ToStringShort());
return false;
}
if (err == COLLATERAL_INVALID_AMOUNT) {
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should have 1000 DASH, masternode=%s\n", vin.prevout.ToStringShort());
nDos = 33;
return false;
}

if (err == COLLATERAL_INVALID_AMOUNT) {
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should have 1000 DASH, masternode=%s\n", vin.prevout.ToStringShort());
return false;
}
if(err == COLLATERAL_INVALID_PUBKEY) {
LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should match pubKeyCollateralAddress, masternode=%s\n", vin.prevout.ToStringShort());
nDos = 33;
return false;
}

if(chainActive.Height() - nHeight + 1 < Params().GetConsensus().nMasternodeMinimumConfirmations) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO must have at least %d confirmations, masternode=%s\n",
Params().GetConsensus().nMasternodeMinimumConfirmations, vin.prevout.ToStringShort());
// maybe we miss few blocks, let this mnb to be checked again later
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
return false;
}
// remember the hash of the block where masternode collateral had minimum required confirmations
nCollateralMinConfBlockHash = chainActive[nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]->GetBlockHash();
if(chainActive.Height() - nHeight + 1 < Params().GetConsensus().nMasternodeMinimumConfirmations) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO must have at least %d confirmations, masternode=%s\n",
Params().GetConsensus().nMasternodeMinimumConfirmations, vin.prevout.ToStringShort());
// UTXO is legit but has not enough confirmations.
// Maybe we miss few blocks, let this mnb be checked again later.
mnodeman.mapSeenMasternodeBroadcast.erase(GetHash());
return false;
}

LogPrint("masternode", "CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO verified\n");

// make sure the input that was signed in masternode broadcast message is related to the transaction
// that spawned the Masternode - this is expensive, so it's only done once per Masternode
if(!IsInputAssociatedWithPubkey()) {
LogPrintf("CMasternodeMan::CheckOutpoint -- Got mismatched pubKeyCollateralAddress and vin\n");
nDos = 33;
// Verify that sig time is legit, should be at least not earlier than the timestamp of the block
// at which collateral became nMasternodeMinimumConfirmations blocks deep.
// NOTE: this is not accurate because block timestamp is NOT guaranteed to be 100% correct one.
CBlockIndex* pRequiredConfIndex = chainActive[nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]; // block where tx got nMasternodeMinimumConfirmations
if(pRequiredConfIndex->GetBlockTime() > sigTime) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Masternode %s %s\n",
sigTime, Params().GetConsensus().nMasternodeMinimumConfirmations, pRequiredConfIndex->GetBlockTime(), vin.prevout.ToStringShort(), addr.ToString());
return false;
}

// verify that sig time is legit in past
// should be at least not earlier than block when 1000 DASH tx got nMasternodeMinimumConfirmations
uint256 hashBlock = uint256();
CTransaction tx2;
GetTransaction(vin.prevout.hash, tx2, Params().GetConsensus(), hashBlock, true);
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end() && (*mi).second) {
CBlockIndex* pMNIndex = (*mi).second; // block for 1000 DASH tx -> 1 confirmation
CBlockIndex* pConfIndex = chainActive[pMNIndex->nHeight + Params().GetConsensus().nMasternodeMinimumConfirmations - 1]; // block where tx got nMasternodeMinimumConfirmations
if(pConfIndex->GetBlockTime() > sigTime) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Masternode %s %s\n",
sigTime, Params().GetConsensus().nMasternodeMinimumConfirmations, pConfIndex->GetBlockTime(), vin.prevout.ToStringShort(), addr.ToString());
return false;
}
}
if (!CheckSignature(nDos)) {
LogPrintf("CMasternodeBroadcast::CheckOutpoint -- CheckSignature() failed, masternode=%s\n", vin.prevout.ToStringShort());
return false;
}

// remember the block hash when collateral for this masternode had minimum required confirmations
nCollateralMinConfBlockHash = pRequiredConfIndex->GetBlockHash();

return true;
}

Expand Down
10 changes: 4 additions & 6 deletions src/masternode.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ class CMasternode : public masternode_info_t
enum CollateralStatus {
COLLATERAL_OK,
COLLATERAL_UTXO_NOT_FOUND,
COLLATERAL_INVALID_AMOUNT
COLLATERAL_INVALID_AMOUNT,
COLLATERAL_INVALID_PUBKEY
};


Expand Down Expand Up @@ -203,8 +204,8 @@ class CMasternode : public masternode_info_t

bool UpdateFromNewBroadcast(CMasternodeBroadcast& mnb, CConnman& connman);

static CollateralStatus CheckCollateral(const COutPoint& outpoint);
static CollateralStatus CheckCollateral(const COutPoint& outpoint, int& nHeightRet);
static CollateralStatus CheckCollateral(const COutPoint& outpoint, const CPubKey& pubkey);
static CollateralStatus CheckCollateral(const COutPoint& outpoint, const CPubKey& pubkey, int& nHeightRet);
void Check(bool fForce = false);

bool IsBroadcastedWithin(int nSeconds) { return GetAdjustedTime() - sigTime < nSeconds; }
Expand Down Expand Up @@ -251,9 +252,6 @@ class CMasternode : public masternode_info_t
return false;
}

/// Is the input associated with collateral public key? (and there is 1000 DASH - checking if valid masternode)
bool IsInputAssociatedWithPubkey();

bool IsValidNetAddr();
static bool IsValidNetAddr(CService addrIn);

Expand Down