Line data Source code
1 : // Copyright (c) 2017-2022 The PIVX Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or https://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include "stakeinput.h" 6 : 7 : #include "chain.h" 8 : #include "txdb.h" 9 : #include "validation.h" 10 : 11 6764 : static bool HasStakeMinAgeOrDepth(int nHeight, uint32_t nTime, const CBlockIndex* pindex) 12 : { 13 6764 : const Consensus::Params& consensus = Params().GetConsensus(); 14 6764 : if (consensus.NetworkUpgradeActive(nHeight + 1, Consensus::UPGRADE_ZC_PUBLIC) && 15 5074 : !consensus.HasStakeMinAgeOrDepth(nHeight, nTime, pindex->nHeight, pindex->nTime)) { 16 0 : return error("%s : min age violation - height=%d - time=%d, nHeightBlockFrom=%d, nTimeBlockFrom=%d", 17 0 : __func__, nHeight, nTime, pindex->nHeight, pindex->nTime); 18 : } 19 : return true; 20 : } 21 : 22 6764 : CPivStake* CPivStake::NewPivStake(const CTxIn& txin, int nHeight, uint32_t nTime) 23 : { 24 6764 : if (txin.IsZerocoinSpend()) { 25 0 : error("%s: unable to initialize CPivStake from zerocoin spend", __func__); 26 0 : return nullptr; 27 : } 28 : 29 : // Look for the stake input in the coins cache first 30 6764 : const Coin& coin = pcoinsTip->AccessCoin(txin.prevout); 31 6764 : if (!coin.IsSpent()) { 32 13424 : const CBlockIndex* pindexFrom = mapBlockIndex.at(chainActive[coin.nHeight]->GetBlockHash()); 33 : // Check that the stake has the required depth/age 34 6712 : if (!HasStakeMinAgeOrDepth(nHeight, nTime, pindexFrom)) { 35 : return nullptr; 36 : } 37 : // All good 38 6712 : return new CPivStake(coin.out, txin.prevout, pindexFrom); 39 : } 40 : 41 : // Otherwise find the previous transaction in database 42 52 : uint256 hashBlock; 43 6764 : CTransactionRef txPrev; 44 52 : if (!GetTransaction(txin.prevout.hash, txPrev, hashBlock, true)) { 45 0 : error("%s : INFO: read txPrev failed, tx id prev: %s", __func__, txin.prevout.hash.GetHex()); 46 0 : return nullptr; 47 : } 48 52 : const CBlockIndex* pindexFrom = nullptr; 49 52 : if (mapBlockIndex.count(hashBlock)) { 50 52 : CBlockIndex* pindex = mapBlockIndex.at(hashBlock); 51 104 : if (chainActive.Contains(pindex)) pindexFrom = pindex; 52 : } 53 : // Check that the input is in the active chain 54 52 : if (!pindexFrom) { 55 0 : error("%s : Failed to find the block index for stake origin", __func__); 56 : return nullptr; 57 : } 58 : // Check that the stake has the required depth/age 59 52 : if (!HasStakeMinAgeOrDepth(nHeight, nTime, pindexFrom)) { 60 : return nullptr; 61 : } 62 : // All good 63 52 : return new CPivStake(txPrev->vout[txin.prevout.n], txin.prevout, pindexFrom); 64 : } 65 : 66 8639 : bool CPivStake::GetTxOutFrom(CTxOut& out) const 67 : { 68 8639 : out = outputFrom; 69 8639 : return true; 70 : } 71 : 72 1919 : CTxIn CPivStake::GetTxIn() const 73 : { 74 3838 : return CTxIn(outpointFrom.hash, outpointFrom.n); 75 : } 76 : 77 21409 : CAmount CPivStake::GetValue() const 78 : { 79 21409 : return outputFrom.nValue; 80 : } 81 : 82 19490 : CDataStream CPivStake::GetUniqueness() const 83 : { 84 : //The unique identifier for a PIV stake is the outpoint 85 19490 : CDataStream ss(SER_NETWORK, 0); 86 19490 : ss << outpointFrom.n << outpointFrom.hash; 87 19490 : return ss; 88 : } 89 : 90 : //The block that the UTXO was added to the chain 91 19734 : const CBlockIndex* CPivStake::GetIndexFrom() const 92 : { 93 : // Sanity check, pindexFrom is set on the constructor. 94 19734 : if (!pindexFrom) throw std::runtime_error("CPivStake: uninitialized pindexFrom"); 95 19734 : return pindexFrom; 96 : } 97 :