From a36360b4c1b054465dc58431414f01f01a741152 Mon Sep 17 00:00:00 2001 From: furszy Date: Sat, 4 May 2019 11:10:22 +0200 Subject: [PATCH 1/4] [Net] Valid blocks from forks badly rejected due an invalid view of the available utxo set for forked chains + split height going one block further than what should be. [Net] acceptBlock, back to chain split was going one block further if prev was the previous block of the incoming block. [Net] coins cache view only has the tip view and not forks utxo chain view. Github-Pull: #880 Rebased-From: 2c76194c757ddd6a9081ee555b191c6dbb326c50 --- src/main.cpp | 73 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 08532fed7a95e..2641927294f59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4693,47 +4693,50 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // Start at the block we're adding on to CBlockIndex *prev = pindexPrev; - int readBlock = 0; vector vBlockSerials; - CBlock bl; - // Go backwards on the forked chain up to the split - do { - // Check if the forked chain is longer than the max reorg limit - if(readBlock == Params().MaxReorganizationDepth()){ - // TODO: Remove this chain from disk. - return error("%s: forked chain longer than maximum reorg limit", __func__); - } - - if(!ReadBlockFromDisk(bl, prev)) - // Previous block not on disk - return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); - // Increase amount of read blocks - readBlock++; - // Loop through every input from said block - for (const CTransaction& t : bl.vtx) { - for (const CTxIn& in: t.vin) { - // Loop through every input of the staking tx - for (const CTxIn& stakeIn : pivInputs) { - // if it's already spent - - // First regular staking check - if(hasPIVInputs) { - if (stakeIn.prevout == in.prevout) { - return state.DoS(100, error("%s: input already spent on a previous block", __func__)); - } + if (!chainActive.Contains(prev)) { + int readBlock = 0; + CBlock bl; + // Go backwards on the forked chain up to the split + do { + // Check if the forked chain is longer than the max reorg limit + if (readBlock == Params().MaxReorganizationDepth()) { + // TODO: Remove this chain from disk. + return error("%s: forked chain longer than maximum reorg limit", __func__); + } - // Second, if there is zPoS staking then store the serials for later check - if(in.scriptSig.IsZerocoinSpend()){ - vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); + if (!ReadBlockFromDisk(bl, prev)) + // Previous block not on disk + return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); + // Increase amount of read blocks + readBlock++; + // Loop through every input from said block + for (const CTransaction &t : bl.vtx) { + for (const CTxIn &in: t.vin) { + // Loop through every input of the staking tx + for (const CTxIn &stakeIn : pivInputs) { + // if it's already spent + + // First regular staking check + if (hasPIVInputs) { + if (stakeIn.prevout == in.prevout) { + return state.DoS(100, error("%s: input already spent on a previous block", + __func__)); + } + + // Second, if there is zPoS staking then store the serials for later check + if (in.scriptSig.IsZerocoinSpend()) { + vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); + } } } } } - } - prev = prev->pprev; + prev = prev->pprev; - } while (!chainActive.Contains(prev)); + } while (!chainActive.Contains(prev)); + } // Split height splitHeight = prev->nHeight; @@ -4795,9 +4798,7 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return error("%s: coin stake inputs not available on main chain, received height %d vs current %d", __func__, nHeight, chainActive.Height()); } if(coin && !coin->IsAvailable(in.prevout.n)){ - // If this is not available get the height of the spent and validate it with the forked height - // Check if this occurred before the chain split - if(!(isBlockFromFork && coin->nHeight > splitHeight)){ + if(!isBlockFromFork){ // Coins not available return error("%s: coin stake inputs already spent in main chain", __func__); } From a5c4b621240aeddeba9cc084853e2d6055789510 Mon Sep 17 00:00:00 2001 From: furszy Date: Tue, 7 May 2019 11:19:54 +0200 Subject: [PATCH 2/4] [Net] AcceptBlock, first prev block loaded from disk. Github-Pull: #880 Rebased-From: 754764be02af58b0b2059f580b40bf5f6380fa4d --- src/main.cpp | 73 +++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2641927294f59..988c39fcf060c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4693,49 +4693,52 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, // Start at the block we're adding on to CBlockIndex *prev = pindexPrev; + CBlock bl; + if (!ReadBlockFromDisk(bl, prev)) + return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); + vector vBlockSerials; - if (!chainActive.Contains(prev)) { - int readBlock = 0; - CBlock bl; - // Go backwards on the forked chain up to the split - do { - // Check if the forked chain is longer than the max reorg limit - if (readBlock == Params().MaxReorganizationDepth()) { - // TODO: Remove this chain from disk. - return error("%s: forked chain longer than maximum reorg limit", __func__); - } + int readBlock = 0; + // Go backwards on the forked chain up to the split + while (!chainActive.Contains(prev)) { + + // Increase amount of read blocks + readBlock++; + // Check if the forked chain is longer than the max reorg limit + if (readBlock == Params().MaxReorganizationDepth()) { + // TODO: Remove this chain from disk. + return error("%s: forked chain longer than maximum reorg limit", __func__); + } - if (!ReadBlockFromDisk(bl, prev)) - // Previous block not on disk - return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); - // Increase amount of read blocks - readBlock++; - // Loop through every input from said block - for (const CTransaction &t : bl.vtx) { - for (const CTxIn &in: t.vin) { - // Loop through every input of the staking tx - for (const CTxIn &stakeIn : pivInputs) { - // if it's already spent - - // First regular staking check - if (hasPIVInputs) { - if (stakeIn.prevout == in.prevout) { - return state.DoS(100, error("%s: input already spent on a previous block", - __func__)); - } - - // Second, if there is zPoS staking then store the serials for later check - if (in.scriptSig.IsZerocoinSpend()) { - vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); - } + // Loop through every input from said block + for (const CTransaction &t : bl.vtx) { + for (const CTxIn &in: t.vin) { + // Loop through every input of the staking tx + for (const CTxIn &stakeIn : pivInputs) { + // if it's already spent + + // First regular staking check + if (hasPIVInputs) { + if (stakeIn.prevout == in.prevout) { + return state.DoS(100, error("%s: input already spent on a previous block", + __func__)); + } + + // Second, if there is zPoS staking then store the serials for later check + if (in.scriptSig.IsZerocoinSpend()) { + vBlockSerials.push_back(TxInToZerocoinSpend(in).getCoinSerialNumber()); } } } } + } - prev = prev->pprev; + // Prev block + prev = prev->pprev; + if (!ReadBlockFromDisk(bl, prev)) + // Previous block not on disk + return error("%s: previous block %s not on disk", __func__, prev->GetBlockHash().GetHex()); - } while (!chainActive.Contains(prev)); } // Split height From bd4f5059ba46eeb36ba03d76eebc2a04c1a45237 Mon Sep 17 00:00:00 2001 From: Fuzzbawls Date: Tue, 7 May 2019 15:58:05 -0700 Subject: [PATCH 3/4] [Net] Add additional checkpoints This adds two additional checkpoints for known split points Github-Pull: #884 Rebased-From: af28b90a4ab119102ed995a20614025a55256526 --- src/chainparams.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 46945bbc4bdef..e9c0b06498d39 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -69,11 +69,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (908000, uint256("202708f8c289b676fceb832a079ff6b308a28608339acbf7584de533619d014d")) (1142400, uint256("98aff9d605bf123247f98b1e3a02567eb5799d208d78ec30fb89737b1c1f79c5")) (1679090, uint256("f747ce055ba1b12e1f2e842bd480bc647210799359cb2e553ab292065e3419d6")) //!< First block with a "wrapped" serial spend - (1686229, uint256("bb42bf1e886a7c23474634c90893dd3d68a6ccbfea4ac92a98da5cad0c6a6cb7")); //!< Last block in the "wrapped" serial attack range + (1686229, uint256("bb42bf1e886a7c23474634c90893dd3d68a6ccbfea4ac92a98da5cad0c6a6cb7")) //!< Last block in the "wrapped" serial attack range + (1778954, uint256("0d3241268264a2908d6babf00d9cd1ffb83d93d7bb4e428820127fe227c2029c")) //!< Network split here + (1788528, uint256("ea9243ff8fc079fdd7a04f11fac415de4d98e1bb0dc38db6f79f8f8bbfdbe496")); //!< Network split here static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1551924791, // * UNIX timestamp of last checkpoint block - 4036872, // * total number of transactions between genesis and last checkpoint + 1556529343, // * UNIX timestamp of last checkpoint block + 4271692, // * 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 }; From 85ee5f2ef573188dbdbe564c8278098ec807dcd0 Mon Sep 17 00:00:00 2001 From: Fuzzbawls Date: Tue, 7 May 2019 23:29:39 -0700 Subject: [PATCH 4/4] Fix incorrect last checkpoint timestamp Github-Pull: #887 Rebased-From: a0af2a75257a86f585580152e73de24b331c9264 --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e9c0b06498d39..7e0ce2b482a88 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -74,7 +74,7 @@ static Checkpoints::MapCheckpoints mapCheckpoints = (1788528, uint256("ea9243ff8fc079fdd7a04f11fac415de4d98e1bb0dc38db6f79f8f8bbfdbe496")); //!< Network split here static const Checkpoints::CCheckpointData data = { &mapCheckpoints, - 1556529343, // * UNIX timestamp of last checkpoint block + 1556924938, // * UNIX timestamp of last checkpoint block 4271692, // * 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