Line data Source code
1 : // Copyright (c) 2017-2021 The PIVX Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include "zpiv/zpos.h" 6 : 7 : #include "validation.h" 8 : #include "zpiv/zpivmodule.h" 9 : 10 : 11 : /* 12 : * LEGACY: Kept for IBD in order to verify zerocoin stakes occurred when zPoS was active 13 : * Find the first occurrence of a certain accumulator checksum. 14 : * Return block index pointer or nullptr if not found 15 : */ 16 : 17 0 : uint32_t ParseAccChecksum(uint256 nCheckpoint, const libzerocoin::CoinDenomination denom) 18 : { 19 0 : int pos = std::distance(libzerocoin::zerocoinDenomList.begin(), 20 0 : find(libzerocoin::zerocoinDenomList.begin(), libzerocoin::zerocoinDenomList.end(), denom)); 21 0 : return (UintToArith256(nCheckpoint) >> (32*((libzerocoin::zerocoinDenomList.size() - 1) - pos))).Get32(); 22 : } 23 : 24 0 : static const CBlockIndex* FindIndexFrom(uint32_t nChecksum, libzerocoin::CoinDenomination denom, int cpHeight) 25 : { 26 : // First look in the legacy database 27 0 : Optional<int> nHeightChecksum = accumulatorCache ? accumulatorCache->Get(nChecksum, denom) : nullopt; 28 0 : if (nHeightChecksum != nullopt) { 29 0 : return mapBlockIndex.at(chainActive[*nHeightChecksum]->GetBlockHash()); 30 : } 31 : 32 : // Not found. This should never happen (during IBD we save the accumulator checksums 33 : // in the cache as they are updated, and persist the cache to DB) but better to have a fallback. 34 0 : LogPrintf("WARNING: accumulatorCache corrupt - missing (%d-%d), height=%d\n", 35 0 : nChecksum, libzerocoin::ZerocoinDenominationToInt(denom), cpHeight); 36 : 37 : // Start at the current checkpoint and go backwards 38 0 : const Consensus::Params& consensus = Params().GetConsensus(); 39 0 : int zc_activation = consensus.vUpgrades[Consensus::UPGRADE_ZC].nActivationHeight; 40 : // Height limits are ensured by the contextual checks in NewZPivStake 41 0 : assert(cpHeight <= consensus.height_last_ZC_AccumCheckpoint && cpHeight > zc_activation); 42 : 43 0 : CBlockIndex* pindex = chainActive[(cpHeight/10)*10 - 10]; 44 0 : if (!pindex) return nullptr; 45 0 : while (ParseAccChecksum(pindex->nAccumulatorCheckpoint, denom) == nChecksum && pindex->nHeight > zc_activation) { 46 : //Skip backwards in groups of 10 blocks since checkpoints only change every 10 blocks 47 0 : pindex = chainActive[pindex->nHeight - 10]; 48 : } 49 0 : if (pindex->nHeight > zc_activation) { 50 : // Found. update cache. 51 0 : CBlockIndex* pindexFrom = mapBlockIndex.at(chainActive[pindex->nHeight + 10]->GetBlockHash()); 52 0 : if (accumulatorCache) accumulatorCache->Set(nChecksum, denom, pindexFrom->nHeight); 53 0 : return pindexFrom; 54 : } 55 : return nullptr; 56 : } 57 : 58 0 : CLegacyZPivStake* CLegacyZPivStake::NewZPivStake(const CTxIn& txin, int nHeight) 59 : { 60 : // Construct the stakeinput object 61 0 : if (!txin.IsZerocoinSpend()) { 62 0 : LogPrintf("%s: unable to initialize CLegacyZPivStake from non zc-spend\n", __func__); 63 0 : return nullptr; 64 : } 65 : 66 : // Return immediately if zPOS not enforced 67 0 : const Consensus::Params& consensus = Params().GetConsensus(); 68 0 : if (!consensus.NetworkUpgradeActive(nHeight, Consensus::UPGRADE_ZC_V2) || 69 0 : nHeight >= consensus.height_last_ZC_AccumCheckpoint) { 70 0 : LogPrint(BCLog::LEGACYZC, "%s : zPIV stake block: height %d outside range\n", __func__, nHeight); 71 0 : return nullptr; 72 : } 73 : 74 : // Check spend type 75 0 : libzerocoin::CoinSpend spend = ZPIVModule::TxInToZerocoinSpend(txin); 76 0 : if (spend.getSpendType() != libzerocoin::SpendType::STAKE) { 77 0 : LogPrintf("%s : spend is using the wrong SpendType (%d)\n", __func__, (int)spend.getSpendType()); 78 0 : return nullptr; 79 : } 80 : 81 0 : uint32_t _nChecksum = spend.getAccumulatorChecksum(); 82 0 : libzerocoin::CoinDenomination _denom = spend.getDenomination(); 83 0 : const arith_uint256& nSerial = spend.getCoinSerialNumber().getuint256(); 84 0 : const uint256& _hashSerial = Hash(nSerial.begin(), nSerial.end()); 85 : 86 : // The checkpoint needs to be from 200 blocks ago 87 0 : const int cpHeight = nHeight - 1 - consensus.ZC_MinStakeDepth; 88 0 : if (ParseAccChecksum(chainActive[cpHeight]->nAccumulatorCheckpoint, _denom) != _nChecksum) { 89 0 : LogPrint(BCLog::LEGACYZC, "%s : accum. checksum at height %d is wrong.\n", __func__, nHeight); 90 : } 91 : 92 : // Find the pindex of the first block with the accumulator checksum 93 0 : const CBlockIndex* _pindexFrom = FindIndexFrom(_nChecksum, _denom, cpHeight); 94 0 : if (_pindexFrom == nullptr) { 95 0 : LogPrintf("%s : Failed to find the block index for zpiv stake origin\n", __func__); 96 : return nullptr; 97 : } 98 : 99 : // All good 100 0 : return new CLegacyZPivStake(_pindexFrom, _nChecksum, _denom, _hashSerial); 101 : } 102 : 103 0 : const CBlockIndex* CLegacyZPivStake::GetIndexFrom() const 104 : { 105 0 : return pindexFrom; 106 : } 107 : 108 0 : CAmount CLegacyZPivStake::GetValue() const 109 : { 110 0 : return denom * COIN; 111 : } 112 : 113 0 : CDataStream CLegacyZPivStake::GetUniqueness() const 114 : { 115 0 : CDataStream ss(SER_GETHASH, 0); 116 0 : ss << hashSerial; 117 0 : return ss; 118 : }