From 93fb9d94af4717bc4ff98e45cf97bd45d779e9a7 Mon Sep 17 00:00:00 2001 From: timemarkovqtum Date: Wed, 20 Mar 2024 14:16:55 +0100 Subject: [PATCH] Port validation --- src/pos.cpp | 14 +-- src/pos.h | 6 +- src/txmempool.cpp | 42 +++++++++ src/validation.cpp | 216 ++++++++++++++++++++++++++++++++++++++++--- src/validation.h | 4 +- src/wallet/stake.cpp | 6 +- 6 files changed, 258 insertions(+), 30 deletions(-) diff --git a/src/pos.cpp b/src/pos.cpp index 398b1e7996..3235133347 100644 --- a/src/pos.cpp +++ b/src/pos.cpp @@ -318,10 +318,10 @@ bool CheckBlockInputPubKeyMatchesOutputPubKey(const CBlock& block, CCoinsViewCac return true; } -bool CheckRecoveredPubKeyFromBlockSignature(CBlockIndex* pindexPrev, const CBlockHeader& block, CCoinsViewCache& view, CChain& chain) { +bool CheckRecoveredPubKeyFromBlockSignature(CBlockIndex* pindexPrev, const CBlockHeader& block, CCoinsViewCache& view, Chainstate& chainstate) { Coin coinPrev; if(!view.GetCoin(block.prevoutStake, coinPrev)){ - if(!GetSpentCoinFromMainChain(pindexPrev, block.prevoutStake, &coinPrev, chain)) { + if(!GetSpentCoinFromMainChain(pindexPrev, block.prevoutStake, &coinPrev, chainstate)) { return error("CheckRecoveredPubKeyFromBlockSignature(): Could not find %s and it was not at the tip", block.prevoutStake.hash.GetHex()); } } @@ -394,13 +394,13 @@ bool CheckRecoveredPubKeyFromBlockSignature(CBlockIndex* pindexPrev, const CBloc return false; } -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, CChain& chain) +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, Chainstate& chainstate) { std::map tmp; - return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view, tmp, chain); + return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view, tmp, chainstate); } -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache, CChain& chain) +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache, Chainstate& chainstate) { uint256 hashProofOfStake, targetProofOfStake; auto it=cache.find(prevout); @@ -408,7 +408,7 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBloc //not found in cache (shouldn't happen during staking, only during verification which does not use cache) Coin coinPrev; if(!view.GetCoin(prevout, coinPrev)){ - if(!GetSpentCoinFromMainChain(pindexPrev, prevout, &coinPrev, chain)) { + if(!GetSpentCoinFromMainChain(pindexPrev, prevout, &coinPrev, chainstate)) { return error("CheckKernel(): Could not find coin and it was not at the tip"); } } @@ -434,7 +434,7 @@ bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBloc if(CheckStakeKernelHash(pindexPrev, nBits, stake.blockFromTime, stake.amount, prevout, nTimeBlock, hashProofOfStake, targetProofOfStake)){ //Cache could potentially cause false positive stakes in the event of deep reorgs, so check without cache also - return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view, chain); + return CheckKernel(pindexPrev, nBits, nTimeBlock, prevout, view, chainstate); } } return false; diff --git a/src/pos.h b/src/pos.h index 0596c24a27..a873e59b96 100644 --- a/src/pos.h +++ b/src/pos.h @@ -41,13 +41,13 @@ inline bool CheckCoinStakeTimestamp(uint32_t nTimeBlock, int nHeight, const Cons bool CheckBlockInputPubKeyMatchesOutputPubKey(const CBlock& block, CCoinsViewCache& view, bool delegateOutputExist); // Recover the pubkey and check that it matches the prevoutStake's scriptPubKey. -bool CheckRecoveredPubKeyFromBlockSignature(CBlockIndex* pindexPrev, const CBlockHeader& block, CCoinsViewCache& view, CChain& chain); +bool CheckRecoveredPubKeyFromBlockSignature(CBlockIndex* pindexPrev, const CBlockHeader& block, CCoinsViewCache& view, Chainstate& chainstate); // Wrapper around CheckStakeKernelHash() // Also checks existence of kernel input and min age // Convenient for searching a kernel -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, CChain& chain); -bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache, CChain& chain); +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, Chainstate& chainstate); +bool CheckKernel(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, CCoinsViewCache& view, const std::map& cache, Chainstate& chainstate); bool CheckKernelCache(CBlockIndex* pindexPrev, unsigned int nBits, uint32_t nTimeBlock, const COutPoint& prevout, const std::map& cache, uint256& hashProofOfStake); unsigned int GetStakeMaxCombineInputs(); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 639fbb3754..b31221fe00 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -1263,6 +1263,48 @@ std::vector CTxMemPool::GatherClusters(const std::vector inserted; + + uint256 txhash = tx.GetHash(); + for (unsigned int j = 0; j < tx.vin.size(); j++) { + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(input); + + CTxDestination dest; + if (ExtractDestination(input.prevout, prevout.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + CMempoolAddressDeltaKey key(dest.index(), uint256(addressBytes), txhash, j, 1); + CMempoolAddressDelta delta(entry.GetTime().count(), prevout.nValue * -1, input.prevout.hash, input.prevout.n); + mapAddress.insert(std::make_pair(key, delta)); + inserted.push_back(key); + } + } + + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + + CTxDestination dest; + if (ExtractDestination({tx.GetHash(), k}, out.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + CMempoolAddressDeltaKey key(dest.index(), uint256(addressBytes), txhash, k, 0); + mapAddress.insert(std::make_pair(key, CMempoolAddressDelta(entry.GetTime().count(), out.nValue))); + inserted.push_back(key); + } + } + + mapAddressInserted.insert(std::make_pair(txhash, inserted)); } bool CTxMemPool::getAddressIndex(std::vector > &addresses, std::vector > &results) diff --git a/src/validation.cpp b/src/validation.cpp index 47962b5d6e..a99ed889ba 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1803,11 +1803,11 @@ bool CheckHeaderPoS(const CBlockHeader& block, const Consensus::Params& consensu // Check the kernel hash CBlockIndex* pindexPrev = &((*mi).second); - if(pindexPrev->nHeight >= consensusParams.nEnableHeaderSignatureHeight && !CheckRecoveredPubKeyFromBlockSignature(pindexPrev, block, chainstate.CoinsTip(), chainstate.m_chain)) { + if(pindexPrev->nHeight >= consensusParams.nEnableHeaderSignatureHeight && !CheckRecoveredPubKeyFromBlockSignature(pindexPrev, block, chainstate.CoinsTip(), chainstate)) { return error("Failed signature check"); } - return CheckKernel(pindexPrev, block.nBits, block.StakeTime(), block.prevoutStake, chainstate.CoinsTip(), chainstate.m_chain); + return CheckKernel(pindexPrev, block.nBits, block.StakeTime(), block.prevoutStake, chainstate.CoinsTip(), chainstate); } bool CheckHeaderProof(const CBlockHeader& block, const Consensus::Params& consensusParams, Chainstate& chainstate){ @@ -2268,6 +2268,29 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn } } + /////////////////////////////////////////////////////////// // qtum + if (pfClean == NULL && fAddressIndex) { + + for (unsigned int k = tx.vout.size(); k-- > 0;) { + const CTxOut &out = tx.vout[k]; + + CTxDestination dest; + if (ExtractDestination({hash, k}, out.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + // undo receiving activity + addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.index(), uint256(addressBytes), pindex->nHeight, i, hash, k, false), out.nValue)); + // undo unspent index + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.index(), uint256(addressBytes), hash, k), CAddressUnspentValue())); + } + } + } + /////////////////////////////////////////////////////////// + // restore inputs if (i > 0) { // not coinbases CTxUndo &txundo = blockUndo.vtxundo[i-1]; @@ -2281,6 +2304,27 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn int res = ApplyTxInUndo(std::move(txundo.vprevout[j]), view, out); if (res == DISCONNECT_FAILED) return DISCONNECT_FAILED; fClean = fClean && res != DISCONNECT_UNCLEAN; + + if (pfClean == NULL && fAddressIndex) { + const auto &undo = txundo.vprevout[j]; + const bool isTxCoinStake = tx.IsCoinStake(); + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(input); + + CTxDestination dest; + if (ExtractDestination(input.prevout, prevout.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + // undo spending activity + addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.index(), uint256(addressBytes), pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); + // restore unspent index + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.index(), uint256(addressBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight, isTxCoinStake))); + } + } } // At this point, all of txundo.vprevout should have been moved out. } @@ -2426,15 +2470,48 @@ static SteadyClock::duration time_index{}; static SteadyClock::duration time_total{}; static int64_t num_blocks_total = 0; -bool GetSpentCoinFromBlock(const CBlockIndex* pindex, COutPoint prevout, Coin* coin) { - return {}; +/////////////////////////////////////////////////////////////////////// qtum +bool GetSpentCoinFromBlock(const CBlockIndex* pindex, COutPoint prevout, Coin* coin, Chainstate& chainstate) { + std::shared_ptr pblock = std::make_shared(); + CBlock& block = *pblock; + if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) { + return error("GetSpentCoinFromBlock(): Could not read block from disk"); + } + + for(size_t j = 1; j < block.vtx.size(); ++j) { + CTransactionRef& tx = block.vtx[j]; + for(size_t k = 0; k < tx->vin.size(); ++k) { + const COutPoint& tmpprevout = tx->vin[k].prevout; + if(tmpprevout == prevout) { + CBlockUndo undo; + if(!chainstate.m_blockman.UndoReadFromDisk(undo, *pindex)) { + return error("GetSpentCoinFromBlock(): Could not read undo block from disk"); + } + + if(undo.vtxundo.size() != block.vtx.size() - 1) { + return error("GetSpentCoinFromBlock(): undo tx size not equal to block tx size"); + } + + CTxUndo &txundo = undo.vtxundo[j-1]; // no vtxundo for coinbase + + if(txundo.vprevout.size() != tx->vin.size()) { + return error("GetSpentCoinFromBlock(): undo tx vin size not equal to block tx vin size"); + } + + *coin = txundo.vprevout[k]; + return true; + } + + } + } + return false; } -bool GetSpentCoinFromMainChain(const CBlockIndex* pforkPrev, COutPoint prevoutStake, Coin* coin, CChain& chain) { - const CBlockIndex* pforkBase = chain.FindFork(pforkPrev); +bool GetSpentCoinFromMainChain(const CBlockIndex* pforkPrev, COutPoint prevoutStake, Coin* coin, Chainstate& chainstate) { + const CBlockIndex* pforkBase = chainstate.m_chain.FindFork(pforkPrev); // If the forkbase is more than coinbaseMaturity blocks in the past, do not attempt to scan the main chain. - int nHeight = chain.Tip()->nHeight; + int nHeight = chainstate.m_chain.Tip()->nHeight; int coinbaseMaturity = Params().GetConsensus().CoinbaseMaturity(nHeight); if(nHeight - pforkBase->nHeight > coinbaseMaturity) { return error("The fork's base is behind by more than 500 blocks"); @@ -2456,9 +2533,9 @@ bool GetSpentCoinFromMainChain(const CBlockIndex* pforkPrev, COutPoint prevoutSt // Scan through blocks until we reach the forkbase to check if the prevoutStake has been spent in one of those blocks // If it not in any of those blocks, and not in the utxo set, it can't be spendable in the orphan chain. { - CBlockIndex* pindex = chain.Tip(); + CBlockIndex* pindex = chainstate.m_chain.Tip(); while(pindex && pindex != pforkBase) { - if(GetSpentCoinFromBlock(pindex, prevoutStake, coin)) { + if(GetSpentCoinFromBlock(pindex, prevoutStake, coin, chainstate)) { return true; } pindex = pindex->pprev; @@ -2676,7 +2753,56 @@ bool CheckReward(const CBlock& block, BlockValidationState& state, int nHeight, } valtype GetSenderAddress(const CTransaction& tx, const CCoinsViewCache* coinsView, const std::vector* blockTxs, Chainstate& chainstate, const CTxMemPool* mempool, int nOut = -1){ - return {}; + CScript script; + bool scriptFilled=false; //can't use script.empty() because an empty script is technically valid + + // Try get the sender script from the output script + if(nOut > -1) + scriptFilled = ExtractSenderData(tx.vout[nOut].scriptPubKey, &script, nullptr); + + // Check if the transaction has inputs + if(tx.vin.size() == 0) { + return valtype(); + } + + // Check the current (or in-progress) block for zero-confirmation change spending that won't yet be in txindex + if(!scriptFilled && blockTxs){ + for(auto btx : *blockTxs){ + if(btx->GetHash() == tx.vin[0].prevout.hash){ + script = btx->vout[tx.vin[0].prevout.n].scriptPubKey; + scriptFilled=true; + break; + } + } + } + if(!scriptFilled && coinsView){ + script = coinsView->AccessCoin(tx.vin[0].prevout).out.scriptPubKey; + scriptFilled = true; + } + if(!scriptFilled) + { + CTransactionRef txPrevout; + uint256 hashBlock; + txPrevout = node::GetTransaction(nullptr, mempool, tx.vin[0].prevout.hash, hashBlock, chainstate.m_blockman, &chainstate); + if(txPrevout != nullptr){ + script = txPrevout->vout[tx.vin[0].prevout.n].scriptPubKey; + } else { + LogPrintf("Error fetching transaction details of tx %s. This will probably cause more errors", tx.vin[0].prevout.hash.ToString()); + return valtype(); + } + } + + CTxDestination addressBit; + TxoutType txType=TxoutType::NONSTANDARD; + if(ExtractDestination(script, addressBit, &txType)){ + if ((txType == TxoutType::PUBKEY || txType == TxoutType::PUBKEYHASH) && + std::holds_alternative(addressBit)){ + PKHash senderAddress(std::get(addressBit)); + return valtype(senderAddress.begin(), senderAddress.end()); + } + } + //prevout is not a standard transaction format, so just return 0 + return valtype(); } UniValue vmLogToJSON(const ResultExecute& execRes, const CTransaction& tx, const CBlock& block, CChain& chain){ @@ -2859,7 +2985,18 @@ dev::eth::EnvInfo ByteCodeExec::BuildEVMEnvironment(){ } dev::Address ByteCodeExec::EthAddrFromScript(const CScript& script){ - return {}; + CTxDestination addressBit; + TxoutType txType=TxoutType::NONSTANDARD; + if(ExtractDestination(script, addressBit, &txType)){ + if ((txType == TxoutType::PUBKEY || txType == TxoutType::PUBKEYHASH) && + std::holds_alternative(addressBit)){ + PKHash addressKey(std::get(addressBit)); + std::vector addr(addressKey.begin(), addressKey.end()); + return dev::Address(addr); + } + } + //if not standard or not a pubkey or pubkeyhash output, then return 0 + return dev::Address(); } bool QtumTxConverter::extractionQtumTransactions(ExtractQtumTX& qtumtx){ @@ -3319,6 +3456,31 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, LogPrintf("ERROR: %s: contains a non-BIP68-final transaction\n", __func__); return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-nonfinal"); } + + ////////////////////////////////////////////////////////////////// // qtum + if (fAddressIndex) + { + for (size_t j = 0; j < tx.vin.size(); j++) { + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + + CTxDestination dest; + if (ExtractDestination(input.prevout, prevout.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.index(), uint256(addressBytes), pindex->nHeight, i, tx.GetHash(), j, true), prevout.nValue * -1)); + + // remove address from unspent index + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.index(), uint256(addressBytes), input.prevout.hash, input.prevout.n), CAddressUnspentValue())); + spentIndex.push_back(std::make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(tx.GetHash(), j, pindex->nHeight, prevout.nValue, dest.index(), uint256(addressBytes)))); + } + } + } + ////////////////////////////////////////////////////////////////// } // GetTransactionSigOpCost counts 3 types of sigops: @@ -3520,6 +3682,30 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, } ///////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////// // qtum + if (fAddressIndex) { + + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + const bool isTxCoinStake = tx.IsCoinStake(); + + CTxDestination dest; + if (ExtractDestination({tx.GetHash(), k}, out.scriptPubKey, dest)) { + valtype bytesID(std::visit(DataVisitor(), dest)); + if(bytesID.empty()) { + continue; + } + valtype addressBytes(32); + std::copy(bytesID.begin(), bytesID.end(), addressBytes.begin()); + // record receiving activity + addressIndex.push_back(std::make_pair(CAddressIndexKey(dest.index(), uint256(addressBytes), pindex->nHeight, i, tx.GetHash(), k, false), out.nValue)); + // record unspent output + addressUnspentIndex.push_back(std::make_pair(CAddressUnspentKey(dest.index(), uint256(addressBytes), tx.GetHash(), k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight, isTxCoinStake))); + } + } + } + /////////////////////////////////////////////////////////////////////////////////// + CTxUndo undoDummy; if (i > 0) { blockundo.vtxundo.emplace_back(); @@ -5765,8 +5951,6 @@ bool ChainstateManager::AcceptBlock(const std::shared_ptr& pblock, // Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW // (but if it does not build on our best tip, let the SendMessages loop relay it) - if (!IsInitialBlockDownload() && ActiveTip() == pindex->pprev) - GetMainSignals().NewPoWValidBlock(pindex, pblock); // Write block to history file if (fNewBlock) *fNewBlock = true; @@ -6425,8 +6609,10 @@ void ChainstateManager::LoadExternalBlockFile( } } - // Activate the genesis block so normal node progress can continue - if (hash == params.GetConsensus().hashGenesisBlock) { + // In Bitcoin this only needed to be done for genesis and at the end of block indexing + // But for Qtum PoS we need to sync this after every block to ensure txdb is populated for + // validating PoS proofs + { bool genesis_activation_failure = false; for (auto c : GetAll()) { BlockValidationState state; diff --git a/src/validation.h b/src/validation.h index 8ee9bc1e0c..66917cdd6d 100644 --- a/src/validation.h +++ b/src/validation.h @@ -478,9 +478,9 @@ class CVerifyDB bool CheckReward(const CBlock& block, BlockValidationState& state, int nHeight, const Consensus::Params& consensusParams, CAmount nFees, CAmount gasRefunds, CAmount nActualStakeReward, const std::vector& vouts, CAmount nValueCoinPrev, bool delegateOutputExist, CChain& chain, node::BlockManager& blockman); //////////////////////////////////////////////////////// qtum -bool GetSpentCoinFromBlock(const CBlockIndex* pindex, COutPoint prevout, Coin* coin); +bool GetSpentCoinFromBlock(const CBlockIndex* pindex, COutPoint prevout, Coin* coin, Chainstate& chainstate); -bool GetSpentCoinFromMainChain(const CBlockIndex* pforkPrev, COutPoint prevoutStake, Coin* coin, CChain& chain); +bool GetSpentCoinFromMainChain(const CBlockIndex* pforkPrev, COutPoint prevoutStake, Coin* coin, Chainstate& chainstate); unsigned int GetContractScriptFlags(int nHeight, const Consensus::Params& consensusparams); diff --git a/src/wallet/stake.cpp b/src/wallet/stake.cpp index 4e9479923c..8748c7b9af 100644 --- a/src/wallet/stake.cpp +++ b/src/wallet/stake.cpp @@ -120,7 +120,7 @@ bool CreateCoinStakeFromMine(CWallet& wallet, unsigned int nBits, const CAmount& // Search backward in time from the given txNew timestamp // Search nSearchInterval seconds back up to nMaxStakeSearchInterval COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second); - if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, wallet.chain().getCoinsTip(), cache, wallet.chain().chainman().ActiveChain())) + if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, wallet.chain().getCoinsTip(), cache, wallet.chain().chainman().ActiveChainstate())) { // Found a kernel LogPrint(BCLog::COINSTAKE, "CreateCoinStake : kernel found\n"); @@ -323,7 +323,7 @@ bool CreateCoinStakeFromDelegate(CWallet& wallet, unsigned int nBits, const CAmo boost::this_thread::interruption_point(); // Search backward in time from the given txNew timestamp // Search nSearchInterval seconds back up to nMaxStakeSearchInterval - if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, wallet.chain().getCoinsTip(), cache, wallet.chain().chainman().ActiveChain())) + if (CheckKernel(pindexPrev, nBits, nTimeBlock, prevoutStake, wallet.chain().getCoinsTip(), cache, wallet.chain().chainman().ActiveChainstate())) { // Found a kernel LogPrint(BCLog::COINSTAKE, "CreateCoinStake : kernel found\n"); @@ -331,7 +331,7 @@ bool CreateCoinStakeFromDelegate(CWallet& wallet, unsigned int nBits, const CAmo Coin coinPrev; if(!wallet.chain().getUnspentOutput(prevoutStake, coinPrev)){ - if(!GetSpentCoinFromMainChain(pindexPrev, prevoutStake, &coinPrev, wallet.chain().chainman().ActiveChain())) { + if(!GetSpentCoinFromMainChain(pindexPrev, prevoutStake, &coinPrev, wallet.chain().chainman().ActiveChainstate())) { return error("CreateCoinStake: Could not find coin and it was not at the tip"); } }