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 6615 : static bool HasStakeMinAgeOrDepth(int nHeight, uint32_t nTime, const CBlockIndex* pindex) 12 : { 13 6615 : const Consensus::Params& consensus = Params().GetConsensus(); 14 6615 : 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 6615 : CPivStake* CPivStake::NewPivStake(const CTxIn& txin, int nHeight, uint32_t nTime) 23 : { 24 6615 : 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 6615 : const Coin& coin = pcoinsTip->AccessCoin(txin.prevout); 31 6615 : if (!coin.IsSpent()) { 32 13130 : const CBlockIndex* pindexFrom = mapBlockIndex.at(chainActive[coin.nHeight]->GetBlockHash()); 33 : // Check that the stake has the required depth/age 34 6565 : if (!HasStakeMinAgeOrDepth(nHeight, nTime, pindexFrom)) { 35 : return nullptr; 36 : } 37 : // All good 38 6565 : return new CPivStake(coin.out, txin.prevout, pindexFrom); 39 : } 40 : 41 : // Otherwise find the previous transaction in database 42 50 : uint256 hashBlock; 43 6615 : CTransactionRef txPrev; 44 50 : 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 50 : const CBlockIndex* pindexFrom = nullptr; 49 50 : if (mapBlockIndex.count(hashBlock)) { 50 50 : CBlockIndex* pindex = mapBlockIndex.at(hashBlock); 51 100 : if (chainActive.Contains(pindex)) pindexFrom = pindex; 52 : } 53 : // Check that the input is in the active chain 54 50 : 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 50 : if (!HasStakeMinAgeOrDepth(nHeight, nTime, pindexFrom)) { 60 : return nullptr; 61 : } 62 : // All good 63 50 : return new CPivStake(txPrev->vout[txin.prevout.n], txin.prevout, pindexFrom); 64 : } 65 : 66 8471 : bool CPivStake::GetTxOutFrom(CTxOut& out) const 67 : { 68 8471 : out = outputFrom; 69 8471 : return true; 70 : } 71 : 72 1898 : CTxIn CPivStake::GetTxIn() const 73 : { 74 3796 : return CTxIn(outpointFrom.hash, outpointFrom.n); 75 : } 76 : 77 22093 : CAmount CPivStake::GetValue() const 78 : { 79 22093 : return outputFrom.nValue; 80 : } 81 : 82 20195 : CDataStream CPivStake::GetUniqueness() const 83 : { 84 : //The unique identifier for a PIV stake is the outpoint 85 20195 : CDataStream ss(SER_NETWORK, 0); 86 20195 : ss << outpointFrom.n << outpointFrom.hash; 87 20195 : return ss; 88 : } 89 : 90 : //The block that the UTXO was added to the chain 91 20472 : const CBlockIndex* CPivStake::GetIndexFrom() const 92 : { 93 : // Sanity check, pindexFrom is set on the constructor. 94 20472 : if (!pindexFrom) throw std::runtime_error("CPivStake: uninitialized pindexFrom"); 95 20472 : return pindexFrom; 96 : } 97 :