Skip to content

Commit

Permalink
fixed possible masternode payment exploit
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Duffield committed Dec 15, 2014
1 parent 8271b8f commit ee8174a
Showing 1 changed file with 63 additions and 49 deletions.
112 changes: 63 additions & 49 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,7 @@ bool CTxMemPool::acceptable(CValidationState &state, CTransaction &tx, bool fChe
return false;
}
}

// Check for conflicts with in-memory transactions
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
Expand Down Expand Up @@ -980,7 +980,7 @@ bool CTxMemPool::acceptable(CValidationState &state, CTransaction &tx, bool fChe
// only helps filling in pfMissingInputs (to determine missing vs spent).
BOOST_FOREACH(const CTxIn txin, tx.vin) {
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
if (pfMissingInputs)
*pfMissingInputs = true;
return false;
}
Expand Down Expand Up @@ -1048,7 +1048,7 @@ bool CTransaction::AcceptToMemoryPool(CValidationState &state, bool fCheckInputs

bool CTransaction::IsAcceptable(CValidationState &state, bool fCheckInputs, bool fLimitFree, bool* pfMissingInputs, bool fScriptChecks)
{
return mempool.acceptable(state, *this, fCheckInputs, fLimitFree, pfMissingInputs, fScriptChecks);
return mempool.acceptable(state, *this, fCheckInputs, fLimitFree, pfMissingInputs, fScriptChecks);
}

bool CTransaction::AcceptableInputs(CValidationState &state, bool fLimitFree)
Expand Down Expand Up @@ -1167,7 +1167,7 @@ int CMerkleTx::IsTransactionLocked() const
for (unsigned int b = 0; b < vout.size(); b++) {
for(it_ctxl it = mapTxLocks.begin(); it != mapTxLocks.end(); it++) {
for (unsigned int a = 0; a < it->second.tx.vout.size(); a++) {
if(vout[b] == it->second.tx.vout[a])
if(vout[b] == it->second.tx.vout[a])
found++;
}
if(found > 0) break;
Expand Down Expand Up @@ -1387,7 +1387,7 @@ int64 static GetBlockValue(int nBits, int nHeight, int64 nFees)
/* fixed bug caused diff to not be correctly calculated */
if(nHeight > 4500 || fTestNet) dDiff = ConvertBitsToDouble(nBits);

int64 nSubsidy = 0;
int64 nSubsidy = 0;
if(nHeight >= 5465) {
if((nHeight >= 17000 && dDiff > 75) || nHeight >= 24000) { // GPU/ASIC difficulty calc
// 2222222/(((x+2600)/9)^2)
Expand All @@ -1412,7 +1412,7 @@ int64 static GetBlockValue(int nBits, int nHeight, int64 nFees)
for(int i = 46200; i <= nHeight; i += 210240) nSubsidy -= nSubsidy/14;
} else {
// yearly decline of production by 7.1% per year, projected 21.3M coins max by year 2050.
for(int i = 210240; i <= nHeight; i += 210240) nSubsidy -= nSubsidy/14;
for(int i = 210240; i <= nHeight; i += 210240) nSubsidy -= nSubsidy/14;
}

return nSubsidy + nFees;
Expand All @@ -1424,7 +1424,7 @@ int64 GetMasternodePayment(int nHeight, int64 blockValue)

if(fTestNet) {
if(nHeight > 46000) ret += blockValue / 20; //25% - 2014-10-07
if(nHeight > 46000+((576*1)*1)) ret += blockValue / 20; //30% - 2014-10-08
if(nHeight > 46000+((576*1)*1)) ret += blockValue / 20; //30% - 2014-10-08
if(nHeight > 46000+((576*1)*2)) ret += blockValue / 20; //35% - 2014-10-09
if(nHeight > 46000+((576*1)*3)) ret += blockValue / 20; //40% - 2014-10-10
if(nHeight > 46000+((576*1)*4)) ret += blockValue / 20; //45% - 2014-10-11
Expand All @@ -1433,7 +1433,7 @@ int64 GetMasternodePayment(int nHeight, int64 blockValue)
if(nHeight > 46000+((576*1)*7)) ret += blockValue / 20; //60% - 2014-10-14
}

if(nHeight > 158000) ret += blockValue / 20; //25.0% - 2014-10-23
if(nHeight > 158000) ret += blockValue / 20; //25.0% - 2014-10-23
if(nHeight > 158000+((576*30)*1)) ret += blockValue / 20; //30.0% - 2014-11-23
if(nHeight > 158000+((576*30)*2)) ret += blockValue / 20; //35.0% - 2014-12-23
if(nHeight > 158000+((576*30)*3)) ret += blockValue / 40; //37.5% - 2015-01-23
Expand Down Expand Up @@ -1562,17 +1562,17 @@ unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBloc
double EventHorizonDeviation;
double EventHorizonDeviationFast;
double EventHorizonDeviationSlow;

if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || (uint64)BlockLastSolved->nHeight < PastBlocksMin) { return bnProofOfWorkLimit.GetCompact(); }

for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
PastBlocksMass++;

if (i == 1) { PastDifficultyAverage.SetCompact(BlockReading->nBits); }
else { PastDifficultyAverage = ((CBigNum().SetCompact(BlockReading->nBits) - PastDifficultyAveragePrev) / i) + PastDifficultyAveragePrev; }
PastDifficultyAveragePrev = PastDifficultyAverage;

PastRateActualSeconds = BlockLastSolved->GetBlockTime() - BlockReading->GetBlockTime();
PastRateTargetSeconds = TargetBlocksSpacingSeconds * PastBlocksMass;
PastRateAdjustmentRatio = double(1);
Expand All @@ -1583,24 +1583,24 @@ unsigned int static KimotoGravityWell(const CBlockIndex* pindexLast, const CBloc
EventHorizonDeviation = 1 + (0.7084 * pow((double(PastBlocksMass)/double(28.2)), -1.228));
EventHorizonDeviationFast = EventHorizonDeviation;
EventHorizonDeviationSlow = 1 / EventHorizonDeviation;

if (PastBlocksMass >= PastBlocksMin) {
if ((PastRateAdjustmentRatio <= EventHorizonDeviationSlow) || (PastRateAdjustmentRatio >= EventHorizonDeviationFast)) { assert(BlockReading); break; }
}
if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
BlockReading = BlockReading->pprev;
}

CBigNum bnNew(PastDifficultyAverage);
if (PastRateActualSeconds != 0 && PastRateTargetSeconds != 0) {
bnNew *= PastRateActualSeconds;
bnNew /= PastRateTargetSeconds;
}

if (bnNew > bnProofOfWorkLimit) {
bnNew = bnProofOfWorkLimit;
bnNew = bnProofOfWorkLimit;
}

return bnNew.GetCompact();
}

Expand All @@ -1618,10 +1618,10 @@ unsigned int static DarkGravityWave3(const CBlockIndex* pindexLast, const CBlock
CBigNum PastDifficultyAverage;
CBigNum PastDifficultyAveragePrev;

if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
return bnProofOfWorkLimit.GetCompact();
if (BlockLastSolved == NULL || BlockLastSolved->nHeight == 0 || BlockLastSolved->nHeight < PastBlocksMin) {
return bnProofOfWorkLimit.GetCompact();
}

for (unsigned int i = 1; BlockReading && BlockReading->nHeight > 0; i++) {
if (PastBlocksMax > 0 && i > PastBlocksMax) { break; }
CountBlocks++;
Expand All @@ -1636,12 +1636,12 @@ unsigned int static DarkGravityWave3(const CBlockIndex* pindexLast, const CBlock
int64 Diff = (LastBlockTime - BlockReading->GetBlockTime());
nActualTimespan += Diff;
}
LastBlockTime = BlockReading->GetBlockTime();
LastBlockTime = BlockReading->GetBlockTime();

if (BlockReading->pprev == NULL) { assert(BlockReading); break; }
BlockReading = BlockReading->pprev;
}

CBigNum bnNew(PastDifficultyAverage);

int64 nTargetTimespan = CountBlocks*nTargetSpacing;
Expand All @@ -1658,7 +1658,7 @@ unsigned int static DarkGravityWave3(const CBlockIndex* pindexLast, const CBlock
if (bnNew > bnProofOfWorkLimit){
bnNew = bnProofOfWorkLimit;
}

return bnNew.GetCompact();
}

Expand All @@ -1670,14 +1670,14 @@ unsigned int static GetNextWorkRequired_V2(const CBlockIndex* pindexLast, const
int64 PastSecondsMax = TimeDaySeconds * 7;
uint64 PastBlocksMin = PastSecondsMin / BlocksTargetSpacing;
uint64 PastBlocksMax = PastSecondsMax / BlocksTargetSpacing;

return KimotoGravityWell(pindexLast, pblock, BlocksTargetSpacing, PastBlocksMin, PastBlocksMax);
}

unsigned int static GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
int DiffMode = 1;

if (fTestNet) {
if (pindexLast->nHeight+1 >= 256) DiffMode = 3;
}
Expand Down Expand Up @@ -1821,7 +1821,7 @@ void CBlockHeader::UpdateTime(const CBlockIndex* pindexPrev)
}

uint256 CBlockHeader::GetHash() const
{
{
return HashX11(BEGIN(nVersion), END(nNonce));
}

Expand Down Expand Up @@ -2807,12 +2807,13 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
if(pindexBest->GetBlockHash() == hashPrevBlock){
int64 masternodePaymentAmount = GetMasternodePayment(pindexBest->nHeight+1, vtx[0].GetValueOut());
bool fIsInitialDownload = IsInitialBlockDownload();

// If we don't already have its previous block, skip masternode payment step
if (!fIsInitialDownload && pindexBest != NULL)
{
bool foundPaymentAmount = false;
bool foundPayee = false;
bool foundPaymentAndPayee = false;

CScript payee;
if(!masternodePayments.GetBlockPayee(pindexBest->nHeight+1, payee) || payee == CScript()){
Expand All @@ -2824,15 +2825,28 @@ bool CBlock::CheckBlock(CValidationState &state, bool fCheckPOW, bool fCheckMerk
foundPaymentAmount = true;
if(vtx[0].vout[i].scriptPubKey == payee )
foundPayee = true;
if(vtx[0].vout[i].nValue == masternodePaymentAmount && vtx[0].vout[i].scriptPubKey == payee)
foundPaymentAndPayee = true;
}

if(!foundPaymentAmount || !foundPayee) {
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);
if (GetBlockTime() < 1419207339){
if(!foundPaymentAmount || !foundPayee) {
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);

LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%"PRI64u") or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), pindexBest->nHeight+1);
if(EnforceMasternodePayments) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%"PRI64u") or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), pindexBest->nHeight+1);
if(EnforceMasternodePayments) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
}
} else {
if(!foundPaymentAndPayee) {
CTxDestination address1;
ExtractDestination(payee, address1);
CBitcoinAddress address2(address1);

LogPrintf("CheckBlock() : Couldn't find masternode payment(%d|%"PRI64u") or payee(%d|%s) nHeight %d. \n", foundPaymentAmount, masternodePaymentAmount, foundPayee, address2.ToString().c_str(), pindexBest->nHeight+1);
if(EnforceMasternodePayments) return state.DoS(100, error("CheckBlock() : Couldn't find masternode payment or payee"));
}
}
}
} else {
Expand Down Expand Up @@ -2905,7 +2919,7 @@ bool CBlock::AcceptBlock(CValidationState &state, CDiskBlockPos *dbp)
double n1 = ConvertBitsToDouble(nBits);
double n2 = ConvertBitsToDouble(nBitsNext);

if (abs(n1-n2) > n1*0.5)
if (abs(n1-n2) > n1*0.5)
return state.DoS(100, error("AcceptBlock() : incorrect proof of work (DGW pre-fork) - %f", abs(n1-n2)));
} else {
if (nBits != GetNextWorkRequired(pindexPrev, this))
Expand Down Expand Up @@ -3506,7 +3520,7 @@ bool InitBlockIndex() {
if (pindexGenesisBlock != NULL) {
// Check whether the master checkpoint key has changed and reset the sync checkpoint if needed.
if (!CheckCheckpointPubKey())
return error("LoadBlockIndex() : failed to reset checkpoint master pubkey");
return error("LoadBlockIndex() : failed to reset checkpoint master pubkey");
return true;
}

Expand All @@ -3524,7 +3538,7 @@ bool InitBlockIndex() {
// CTxOut(nValue=50.00000000, scriptPubKey=040184710fa689ad5023690c80f3a4)
// vMerkleTree: 97ddfbbae6

// Genesis block
// Genesis block
const char* pszTimestamp = "Wired 09/Jan/2014 The Grand Experiment Goes Live: Overstock.com Is Now Accepting Bitcoins";
CTransaction txNew;
txNew.vin.resize(1);
Expand Down Expand Up @@ -3926,7 +3940,7 @@ void static ProcessGetData(CNode* pfrom)
{
// Send stream from relay memory
bool pushed = false;

if(!mapDarksendBroadcastTxes.count(inv.hash))
{
LOCK(cs_mapRelay);
Expand All @@ -3942,10 +3956,10 @@ void static ProcessGetData(CNode* pfrom)
if(mapDarksendBroadcastTxes.count(inv.hash)){
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(1000);
ss <<
mapDarksendBroadcastTxes[inv.hash].tx <<
mapDarksendBroadcastTxes[inv.hash].vin <<
mapDarksendBroadcastTxes[inv.hash].vchSig <<
ss <<
mapDarksendBroadcastTxes[inv.hash].tx <<
mapDarksendBroadcastTxes[inv.hash].vin <<
mapDarksendBroadcastTxes[inv.hash].vchSig <<
mapDarksendBroadcastTxes[inv.hash].sigTime;

pfrom->PushMessage("dstx", ss);
Expand Down Expand Up @@ -4073,7 +4087,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
// Change version
pfrom->PushMessage("verack");
pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));

if (!pfrom->fInbound)
{
// Advertise our address
Expand Down Expand Up @@ -4381,7 +4395,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
return true;
}

std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast<std::string>(sigTime);
std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast<std::string>(sigTime);

std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(mn.pubkey2, vchSig, strMessage, errorMessage)){
Expand Down Expand Up @@ -4662,7 +4676,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)

else
{
//probably one the extensions
//probably one the extensions
ProcessMessageDarksend(pfrom, strCommand, vRecv);
ProcessMessageMasternode(pfrom, strCommand, vRecv);
ProcessMessageInstantX(pfrom, strCommand, vRecv);
Expand Down Expand Up @@ -5098,7 +5112,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
int payments = 1;
// Create coinbase tx
CTransaction txNew;
txNew.vin.resize(1);
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
txNew.vout[0].scriptPubKey = scriptPubKeyIn;
Expand All @@ -5116,13 +5130,13 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
bMasterNodePayment = true;
}
}

int64 nFees = 0;
{
LOCK2(cs_main, mempool.cs);
CCoinsViewCache view(*pcoinsTip, true);
CBlockIndex* pindexPrev = pindexBest;

if(bMasterNodePayment) {
bool hasPayment = true;
//spork
Expand All @@ -5131,7 +5145,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
int winningNode = GetCurrentMasterNode(1);
if(winningNode >= 0){
pblock->payee.SetDestination(darkSendMasterNodes[winningNode].pubkey.GetID());
} else {
} else {
LogPrintf("CreateNewBlock: Failed to detect masternode to pay\n");
hasPayment = false;
}
Expand Down Expand Up @@ -5357,7 +5371,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)

int64 blockValue = GetBlockValue(pindexPrev->nBits, pindexPrev->nHeight, nFees);
int64 masternodePayment = GetMasternodePayment(pindexPrev->nHeight+1, blockValue);

//create masternode payment
if(payments > 1){
pblock->vtx[0].vout[payments-1].nValue = masternodePayment;
Expand All @@ -5374,7 +5388,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
pblock->nNonce = 0;
pblock->vtx[0].vin[0].scriptSig = CScript() << OP_0 << OP_0;
pblocktemplate->vTxSigOps[0] = pblock->vtx[0].GetLegacySigOpCount();


CBlockIndex indexDummy(*pblock);
indexDummy.pprev = pindexPrev;
Expand Down

0 comments on commit ee8174a

Please sign in to comment.