Skip to content

Commit

Permalink
Fix Spent Stake vulnerability issue
Browse files Browse the repository at this point in the history
  • Loading branch information
dsdsenen committed Jan 30, 2019
1 parent ff24280 commit dfc75ed
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 10 deletions.
2 changes: 1 addition & 1 deletion configure.ac
Expand Up @@ -3,7 +3,7 @@ AC_PREREQ([2.60])
define(_CLIENT_VERSION_MAJOR, 1)
define(_CLIENT_VERSION_MINOR, 1)
define(_CLIENT_VERSION_REVISION, 1)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_BUILD, 1)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2018)
AC_INIT([Dividendcash Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[www.dividendcash.org],[dividendcash])
Expand Down
4 changes: 2 additions & 2 deletions contrib/gitian-descriptors/gitian-linux.yml
Expand Up @@ -27,9 +27,9 @@ packages:
- "bsdmainutils"
- "ca-certificates"
- "python"
reference_datetime: "2015-06-01 00:00:00"
reference_datetime: "2019-01-31 00:00:00"
remotes:
- "url": "https://github.com/dividendcash-project/dividendcash.git"
- "url": "https://github.com/dividendcash/DividendCash.git"
"dir": "DividendCash"
files: []
script: |
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-osx.yml
Expand Up @@ -28,7 +28,7 @@ packages:
- "python-setuptools"
- "fonts-tuffy"
remotes:
- "url": "https://github.com/dividendcash-project/dividendcash.git"
- "url": "https://github.com/dividendcash/DividendCash.git"
"dir": "DividendCash"
files:
- "MacOSX10.11.sdk.tar.gz"
Expand Down
2 changes: 1 addition & 1 deletion contrib/gitian-descriptors/gitian-win.yml
Expand Up @@ -22,7 +22,7 @@ packages:
- "ca-certificates"
- "python"
remotes:
- "url": "https://github.com/dividendcash-project/dividendcash.git"
- "url": "https://github.com/dividendcash/DividendCash.git"
"dir": "DividendCash"
files: []
script: |
Expand Down
3 changes: 2 additions & 1 deletion src/chainparams.cpp
Expand Up @@ -60,7 +60,8 @@ static Checkpoints::MapCheckpoints mapCheckpoints =
(5000, uint256("483bc3771731346580f69cf8da7476b8b6c884ab14513bd66ef0ad1bd7bfd23e"))
(50000, uint256("803aab9e69e9bc0717a32f2477b17ecc6ac664cb9e6451a4f9c3f7f53194a9f2"))
(100000, uint256("95e145889cc54ef62958133b1e43fd24c3e6bbc3787f4e51141c81132e202bd8"))
(115460, uint256("687c475fa74de0e460430403825b54c9b0d8edfaa0f15fbb80819d9d834b397a"));
(115460, uint256("687c475fa74de0e460430403825b54c9b0d8edfaa0f15fbb80819d9d834b397a"))
(238676, uint256("12f41a90fce8527fbd1b3d5ca9c85f7c31c2ffeb97a2c1a0c22062a9a50c2a63"));
static const Checkpoints::CCheckpointData data = {
&mapCheckpoints,
1530489328, // * UNIX timestamp of last checkpoint block
Expand Down
2 changes: 1 addition & 1 deletion src/clientversion.h
Expand Up @@ -17,7 +17,7 @@
#define CLIENT_VERSION_MAJOR 1
#define CLIENT_VERSION_MINOR 1
#define CLIENT_VERSION_REVISION 1
#define CLIENT_VERSION_BUILD 0
#define CLIENT_VERSION_BUILD 1

//! Set to true for release, false for prerelease or test build
#define CLIENT_VERSION_IS_RELEASE true
Expand Down
75 changes: 75 additions & 0 deletions src/main.cpp
Expand Up @@ -55,6 +55,7 @@ BlockMap mapBlockIndex;
map<uint256, uint256> mapProofOfStake;
set<pair<COutPoint, unsigned int> > setStakeSeen;
map<unsigned int, unsigned int> mapHashedBlocks;
map<COutPoint, int> mapStakeSpent;
CChain chainActive;
CBlockIndex* pindexBestHeader = NULL;
int64_t nTimeBestReceived = 0;
Expand Down Expand Up @@ -2013,6 +2014,8 @@ 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
mapStakeSpent.erase(out);
}
}
}
Expand Down Expand Up @@ -2246,6 +2249,28 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (!pblocktree->WriteTxIndex(vPos))
return state.Abort("Failed to write transaction index");

// 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 @@ -3381,6 +3406,56 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,

int nHeight = pindex->nHeight;

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
6 changes: 3 additions & 3 deletions src/version.h
Expand Up @@ -12,7 +12,7 @@
* network protocol versioning
*/

static const int PROTOCOL_VERSION = 70812;
static const int PROTOCOL_VERSION = 70813;

//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
Expand All @@ -21,8 +21,8 @@ static const int INIT_PROTO_VERSION = 209;
static const int GETHEADERS_VERSION = 70077;

//! disconnect from peers older than this proto version
static const int MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT = 70811;
static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT = 70812;
static const int MIN_PEER_PROTO_VERSION_BEFORE_ENFORCEMENT = 70812;
static const int MIN_PEER_PROTO_VERSION_AFTER_ENFORCEMENT = 70813;

//! nTime field added to CAddress, starting with this version;
//! if possible, avoid requesting addresses nodes older than this
Expand Down

0 comments on commit dfc75ed

Please sign in to comment.