Skip to content

Commit

Permalink
Merge pull request #22 from MasterNodesPro/FakeStakeVulnerability
Browse files Browse the repository at this point in the history
Fake stake vulnerability Fix
  • Loading branch information
tvl83 authored Jan 25, 2019
2 parents a82e8b0 + cd39f76 commit 270890e
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 12 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Website: https://mnpcoin.pro

Utility: https://masternodes.pro

#### 01-24-19
- Implemented fix for "fake staking" bug

#### 01-19-19

- Implemented BIP130
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 2)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_REVISION, 2)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2019)
Expand Down
29 changes: 19 additions & 10 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,20 @@ static Checkpoints::MapCheckpoints mapCheckpoints =
( 80000, uint256("49fb6da4cbc4e834312985bfa44b08537a4c4573bbca6a37626b46e66ea246d6"))
( 90000, uint256("4035ca075e6a5759d15edd9494fd925da415baec9058dd04664b119f7a319fe9"))
( 100000, uint256("0d593545ea7f76f3012d131da70b449218b24a0eaf88db661149b08589f8b925"))
( 120000, uint256("da0954bd8915e44d2c6406bbd82a4e302b7f6620e457f73044a88897b418710e"))
( 140000, uint256("669330f0b31e937d0ce0fc18f05de4eced1da84456bd5d72e34ba6ee69ff0d25"))
( 160000, uint256("af8612d5c1c0beebd5cd168127dc6f27a025d4f9fdfedf8bca48551c144e9da1"))
( 180000, uint256("ae972cd58079c9a26d5d68b8375ab2bf3e93789bddf2c3c1e48f4bd08bdd2565"))
( 200000, uint256("b8f878e27bfee6eb63911ca0d85aa8c9c9666e4512dd8682b83d67d679f0b5c8"))
( 220000, uint256("6d55a17c276ab12b14b6b8d13fb33e733613b25c600c220a457ed6a054c137cf"))
( 240000, uint256("85469fe3a2b8130e163f1e0b1c324c405dc84f91a62d001de1cdbf465f056dcd"))
( 248000, uint256("b7934ead9db1c2444e591060d46dfcbf1330ccba04524d1b46ef164b991adc9d"))
;

static const Checkpoints::CCheckpointData data = {
&mapCheckpoints,
1539232472, // * UNIX timestamp of last checkpoint block
194131, // * total number of transactions between genesis and last checkpoint
1548362685, // * UNIX timestamp of last checkpoint block
506447, // * total number of transactions between genesis and last checkpoint
// (the tx=... number in the SetBestChain debug.log lines)
2000 // * estimated number of transactions per day after checkpoint
};
Expand Down Expand Up @@ -301,11 +309,11 @@ class CTestNetParams : public CMainParams
nBlockEnforceInvalidUTXO = 1600; //Start enforcing the invalid UTXO's

//! Modify the testnet genesis block so the timestamp is valid for a later start.
genesis.nTime = 1535229300; // GMT: 2018-08-25T20:35:00.000Z
genesis.nNonce = 83001552;
genesis.nTime = 1547942400; // GMT: 2019-01-20T00:00:00.000Z
genesis.nNonce = 83435947;

hashGenesisBlock = genesis.GetHash();
if(genesis.GetHash() != uint256("00000c8d8a5dc8021a5d70eef326b71fd05360747169cfb4bd7ce7095c812139"))
if(genesis.GetHash() != uint256("00000bcb79d73d227ed5d0daf1d9f25b64b09978a14261c6b1a6318a1d80a4ef"))
{
printf("Searching for genesis block...\n");
uint256 hashTarget = CBigNum().SetCompact(genesis.nBits).getuint256();
Expand All @@ -328,14 +336,15 @@ class CTestNetParams : public CMainParams
printf("block.GetHash = %s\n", genesis.GetHash().ToString().c_str());
printf("block.hashMerkleRoot = %s\n", genesis.hashMerkleRoot.ToString().c_str());
}
assert(hashGenesisBlock == uint256("00000c8d8a5dc8021a5d70eef326b71fd05360747169cfb4bd7ce7095c812139"));
assert(hashGenesisBlock == uint256("00000bcb79d73d227ed5d0daf1d9f25b64b09978a14261c6b1a6318a1d80a4ef"));

vFixedSeeds.clear();
vSeeds.clear();
vSeeds.push_back(CDNSSeedData("149.28.82.70", "149.28.82.70"));
vSeeds.push_back(CDNSSeedData("149.28.248.6", "149.28.248.6"));
vSeeds.push_back(CDNSSeedData("144.202.17.23", "144.202.17.23"));
vSeeds.push_back(CDNSSeedData("45.32.210.33", "45.32.210.33"));
vSeeds.push_back(CDNSSeedData("199.223.253.96", "199.223.253.96"));
vSeeds.push_back(CDNSSeedData("104.238.179.224", "104.238.179.224"));
vSeeds.push_back(CDNSSeedData("45.76.63.197", "45.76.63.197"));
vSeeds.push_back(CDNSSeedData("45.76.253.208", "45.76.253.208"));
vSeeds.push_back(CDNSSeedData("24.35.240.224", "24.35.240.224"));

base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 88); // Testnet mnpcoin addresses start with 'w'
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 112); // Testnet mnpcoin script addresses start with '7'
Expand Down
2 changes: 1 addition & 1 deletion src/config/mnpcoin-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#define CLIENT_VERSION_MINOR 2

/* Build revision */
#define CLIENT_VERSION_REVISION 1
#define CLIENT_VERSION_REVISION 2

/* Version is release */
#define COPYRIGHT_YEAR 2019
Expand Down
77 changes: 77 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ CCriticalSection cs_main;

BlockMap mapBlockIndex;
map<uint256, uint256> mapProofOfStake;
map<COutPoint, int> mapStakeSpent;
set<pair<COutPoint, unsigned int> > setStakeSeen;
map<unsigned int, unsigned int> mapHashedBlocks;
CChain chainActive;
Expand Down Expand Up @@ -2739,6 +2740,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
if (coins->vout.size() < out.n + 1)
coins->vout.resize(out.n + 1);
coins->vout[out.n] = undo.txout;

// erase the spent input
if(IsSporkActive(SPORK_17_FAKE_STAKE_FIX) && block.GetBlockTime() >= GetSporkValue(SPORK_17_FAKE_STAKE_FIX))
mapStakeSpent.erase(out);
}
}
}
Expand Down Expand Up @@ -3310,6 +3315,27 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (!pblocktree->WriteTxIndex(vPos))
return state.Abort("Failed to write transaction index");

if(IsSporkActive(SPORK_17_FAKE_STAKE_FIX) && block.GetBlockTime() >= GetSporkValue(SPORK_17_FAKE_STAKE_FIX)){
// add new entries
for (const CTransaction tx:block.vtx) {
if (tx.IsCoinBase())
continue;
for (const CTxIn in: tx.vin) {
LogPrint("map", "mapStakeSpent: Insert %s | %u\n", in.prevout.ToString(), pindex->nHeight);
mapStakeSpent.insert(std::make_pair(in.prevout, pindex->nHeight));
}
}

// delete old entries
for (auto it = mapStakeSpent.begin(); it != mapStakeSpent.end();) {
if (it->second < pindex->nHeight - Params().MaxReorganizationDepth()) {
LogPrint("map", "mapStakeSpent: Erase %s | %u\n", it->first.ToString(), it->second);
it = mapStakeSpent.erase(it);
} else {
it++;
}
}
}
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());

Expand Down Expand Up @@ -4566,6 +4592,57 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,

int nHeight = pindex->nHeight;

if(IsSporkActive(SPORK_17_FAKE_STAKE_FIX) && block.GetBlockTime() >= GetSporkValue(SPORK_17_FAKE_STAKE_FIX)) {

if (block.IsProofOfStake()) {
LOCK(cs_main);

CCoinsViewCache coins(pcoinsTip);

if (!coins.HaveInputs(block.vtx[1])) {
// the inputs are spent at the chain tip so we should look at the recently spent outputs

for (CTxIn in : block.vtx[1].vin) {
auto it = mapStakeSpent.find(in.prevout);
if (it == mapStakeSpent.end()) {
return false;
}
if (it->second <= pindexPrev->nHeight) {
return false;
}
}
}

// if this is on a fork
if (!chainActive.Contains(pindexPrev) && pindexPrev != NULL) {
// start at the block we're adding on to
CBlockIndex *last = pindexPrev;

//while that block is not on the main chain
while (!chainActive.Contains(last) && pindexPrev != NULL) {
CBlock bl;
ReadBlockFromDisk(bl, last);
// loop through every spent input from said block
for (CTransaction t: bl.vtx) {
for (CTxIn in: t.vin) {
// loop through every spent input in the staking transaction of the new block
for (CTxIn stakeIn: block.vtx[1].vin) {
// if they spend the same input
if (stakeIn.prevout == in.prevout) {
//reject the block
return false;
}
}
}
}

// go to the parent block
last = pindexPrev->pprev;
}
}
}
}

// Write block to history file
try {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
Expand Down
1 change: 1 addition & 0 deletions src/spork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ int64_t GetSporkValue(int nSporkID)
if (nSporkID == SPORK_14_NEW_PROTOCOL_ENFORCEMENT) r = SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT;
if (nSporkID == SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2) r = SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT;
if (nSporkID == SPORK_16_ZEROCOIN_MAINTENANCE_MODE) r = SPORK_16_ZEROCOIN_MAINTENANCE_MODE_DEFAULT;
if (nSporkID == SPORK_17_FAKE_STAKE_FIX) r = SPORK_17_FAKE_STAKE_FIX_DEFAULT;

if (r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
}
Expand Down
2 changes: 2 additions & 0 deletions src/spork.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ using namespace boost;
#define SPORK_14_NEW_PROTOCOL_ENFORCEMENT 10013
#define SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2 10014
#define SPORK_16_ZEROCOIN_MAINTENANCE_MODE 10015
#define SPORK_17_FAKE_STAKE_FIX 10016

#define SPORK_2_SWIFTTX_DEFAULT 978307200 //2001-1-1
#define SPORK_3_SWIFTTX_BLOCK_FILTERING_DEFAULT 1424217600 //2015-2-18
Expand All @@ -55,6 +56,7 @@ using namespace boost;
#define SPORK_14_NEW_PROTOCOL_ENFORCEMENT_DEFAULT 4070908800 //OFF
#define SPORK_15_NEW_PROTOCOL_ENFORCEMENT_2_DEFAULT 4070908800 //OFF
#define SPORK_16_ZEROCOIN_MAINTENANCE_MODE_DEFAULT 4070908800 //OFF
#define SPORK_17_FAKE_STAKE_FIX_DEFAULT 4070908800 //OFF

class CSporkMessage;
class CSporkManager;
Expand Down

0 comments on commit 270890e

Please sign in to comment.