@@ -63,6 +63,7 @@ CCriticalSection cs_main;
6363
6464BlockMap mapBlockIndex;
6565map<uint256, uint256> mapProofOfStake;
66+ map<COutPoint, int > mapStakeSpent;
6667set<pair<COutPoint, unsigned int > > setStakeSeen;
6768map<unsigned int , unsigned int > mapHashedBlocks;
6869CChain chainActive;
@@ -2552,6 +2553,11 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
25522553 if (coins->vout .size () < out.n + 1 )
25532554 coins->vout .resize (out.n + 1 );
25542555 coins->vout [out.n ] = undo.txout ;
2556+
2557+ // erase the spent input
2558+ if (IsSporkActive (SPORK_17_FAKE_STAKE_FIX ) && block.GetBlockTime () >= GetSporkValue (SPORK_17_FAKE_STAKE_FIX ))
2559+ mapStakeSpent.erase (out);
2560+
25552561 }
25562562 }
25572563 }
@@ -3026,6 +3032,28 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
30263032 if (!pblocktree->WriteTxIndex (vPos))
30273033 return state.Abort (" Failed to write transaction index" );
30283034
3035+ if (IsSporkActive (SPORK_17_FAKE_STAKE_FIX ) && block.GetBlockTime () >= GetSporkValue (SPORK_17_FAKE_STAKE_FIX )){
3036+ // add new entries
3037+ for (const CTransaction tx:block.vtx ) {
3038+ if (tx.IsCoinBase ())
3039+ continue ;
3040+ for (const CTxIn in: tx.vin ) {
3041+ LogPrint (" map" , " mapStakeSpent: Insert %s | %u\n " , in.prevout .ToString (), pindex->nHeight );
3042+ mapStakeSpent.insert (std::make_pair (in.prevout , pindex->nHeight ));
3043+ }
3044+ }
3045+
3046+ // delete old entries
3047+ for (auto it = mapStakeSpent.begin (); it != mapStakeSpent.end ();) {
3048+ if (it->second < pindex->nHeight - Params ().MaxReorganizationDepth ()) {
3049+ LogPrint (" map" , " mapStakeSpent: Erase %s | %u\n " , it->first .ToString (), it->second );
3050+ it = mapStakeSpent.erase (it);
3051+ } else {
3052+ it++;
3053+ }
3054+ }
3055+ }
3056+
30293057 // add this block to the view's block chain
30303058 view.SetBestBlock (pindex->GetBlockHash ());
30313059
@@ -4192,6 +4220,57 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
41924220
41934221 int nHeight = pindex->nHeight ;
41944222
4223+ if (IsSporkActive (SPORK_17_FAKE_STAKE_FIX ) && block.GetBlockTime () >= GetSporkValue (SPORK_17_FAKE_STAKE_FIX )) {
4224+
4225+ if (block.IsProofOfStake ()) {
4226+ LOCK (cs_main);
4227+
4228+ CCoinsViewCache coins (pcoinsTip);
4229+
4230+ if (!coins.HaveInputs (block.vtx [1 ])) {
4231+ // the inputs are spent at the chain tip so we should look at the recently spent outputs
4232+
4233+ for (CTxIn in : block.vtx [1 ].vin ) {
4234+ auto it = mapStakeSpent.find (in.prevout );
4235+ if (it == mapStakeSpent.end ()) {
4236+ return false ;
4237+ }
4238+ if (it->second <= pindexPrev->nHeight ) {
4239+ return false ;
4240+ }
4241+ }
4242+ }
4243+
4244+ // if this is on a fork
4245+ if (!chainActive.Contains (pindexPrev) && pindexPrev != NULL ) {
4246+ // start at the block we're adding on to
4247+ CBlockIndex *last = pindexPrev;
4248+
4249+ // while that block is not on the main chain
4250+ while (!chainActive.Contains (last) && pindexPrev != NULL ) {
4251+ CBlock bl;
4252+ ReadBlockFromDisk (bl, last);
4253+ // loop through every spent input from said block
4254+ for (CTransaction t: bl.vtx ) {
4255+ for (CTxIn in: t.vin ) {
4256+ // loop through every spent input in the staking transaction of the new block
4257+ for (CTxIn stakeIn: block.vtx [1 ].vin ) {
4258+ // if they spend the same input
4259+ if (stakeIn.prevout == in.prevout ) {
4260+ // reject the block
4261+ return false ;
4262+ }
4263+ }
4264+ }
4265+ }
4266+
4267+ // go to the parent block
4268+ last = pindexPrev->pprev ;
4269+ }
4270+ }
4271+ }
4272+ }
4273+
41954274 // Write block to history file
41964275 try {
41974276 unsigned int nBlockSize = ::GetSerializeSize (block, SER_DISK , CLIENT_VERSION );
0 commit comments