From f205314f6b09863218e6580989ba38290d55cabc Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 12 Jul 2018 15:25:48 +0800 Subject: [PATCH 001/120] change the declaration of block and block header --- src/primitives/block.cpp | 110 ++++++------ src/primitives/block.h | 349 +++++++++++++++++++++------------------ 2 files changed, 243 insertions(+), 216 deletions(-) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index e983cf0..a4c6d8b 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -1,52 +1,58 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "primitives/block.h" - -#include "hash.h" -#include "tinyformat.h" -#include "utilstrencodings.h" -//#include "crypto/common.h" - -uint256 CBlockHeader::GetHash() const -{ -// return SerializeHash(*this); - uint256 hash; - - CryptoPop(this, (unsigned char *)&hash); -// view_data_u8("PoW 3", (unsigned char *)&hash, OUTPUT_LEN); -// std::cout<<"gethex() ="< - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(this->nVersion); - nVersion = this->nVersion; - READWRITE(hashPrevBlock); - READWRITE(hashMerkleRoot); - READWRITE(hashClaimTrie); - READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); - } - - void SetNull() - { - nVersion = CBlockHeader::CURRENT_VERSION; - hashPrevBlock.SetNull(); - hashMerkleRoot.SetNull(); - hashClaimTrie.SetNull(); - nTime = 0; - nBits = 0; - nNonce.SetNull(); - } - - bool IsNull() const - { - return (nBits == 0); - } - - uint256 GetHash() const; - - int64_t GetBlockTime() const - { - return (int64_t)nTime; - } - - std::string ToString() const; -}; - - -// Popchain DevTeam -class CBlock : public CBlockHeader -{ -public: - // network and disk - std::vector vtx; - - // memory only - mutable CTxOut txoutFound; // Found payment - mutable bool fChecked; - - CBlock() - { - SetNull(); - } - - CBlock(const CBlockHeader &header) - { - SetNull(); - *((CBlockHeader*)this) = header; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(*(CBlockHeader*)this); - READWRITE(vtx); - } - - void SetNull() - { - CBlockHeader::SetNull(); - vtx.clear(); - fChecked = false; - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrevBlock; - block.hashMerkleRoot = hashMerkleRoot; - block.hashClaimTrie = hashClaimTrie; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - std::string ToString() const; -}; - -/** Describes a place in the block chain to another node such that if the - * other node doesn't have the same branch, it can find a recent common trunk. - * The further back it is, the further before the fork it may be. - */ -struct CBlockLocator -{ - std::vector vHave; - - CBlockLocator() {} - - CBlockLocator(const std::vector& vHaveIn) - { - vHave = vHaveIn; - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vHave); - } - - void SetNull() - { - vHave.clear(); - } - - bool IsNull() const - { - return vHave.empty(); - } -}; - -#endif // BITCOIN_PRIMITIVES_BLOCK_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_PRIMITIVES_BLOCK_H +#define BITCOIN_PRIMITIVES_BLOCK_H + +#include "primitives/transaction.h" +#include "serialize.h" +#include "uint256.h" + +/** Nodes collect new transactions into a block, hash them into a hash tree, + * and scan through nonce values to make the block's hash satisfy proof-of-work + * requirements. When they solve the proof-of-work, they broadcast the block + * to everyone and the block is added to the block chain. The first transaction + * in the block is a special one that creates a new coin owned by the creator + * of the block. + */ +class CBlockHeader +{ +public: + // header + static const int32_t CURRENT_VERSION=1; + int32_t nVersion; + uint256 hashPrevBlock; + /*popchain ghost*/ + uint256 hashUncles;//the hash256 of uncles or uncle block header + uint160 coinbaseAddress;//the autor address of this block header + /*popchain ghost*/ + uint256 hashMerkleRoot; + uint256 hashClaimTrie; // for claim operation + uint32_t nTime; + uint32_t nBits; + uint256 nNonce; + + CBlockHeader() + { + SetNull(); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(this->nVersion); + nVersion = this->nVersion; + READWRITE(hashPrevBlock); + /*popchain ghost*/ + READWRITE(hashUncles); + READWRITE(coinbaseAddress); + /*popchain ghost*/ + READWRITE(hashMerkleRoot); + READWRITE(hashClaimTrie); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + } + + void SetNull() + { + nVersion = CBlockHeader::CURRENT_VERSION; + hashPrevBlock.SetNull(); + hashMerkleRoot.SetNull(); + hashClaimTrie.SetNull(); + nTime = 0; + nBits = 0; + nNonce.SetNull(); + } + + bool IsNull() const + { + return (nBits == 0); + } + + uint256 GetHash() const; + + int64_t GetBlockTime() const + { + return (int64_t)nTime; + } + + std::string ToString() const; +}; + + +// Popchain DevTeam +class CBlock : public CBlockHeader +{ +public: + // network and disk + std::vector vtx; + + // memory only + mutable CTxOut txoutFound; // Found payment + mutable bool fChecked; + + /*popchain ghost*/ + std::vector vuh;//vector of uncles or uncle block header + uint256 td;//total difficulty of this block header + /*popchain ghost*/ + + CBlock() + { + SetNull(); + } + + CBlock(const CBlockHeader &header) + { + SetNull(); + *((CBlockHeader*)this) = header; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(*(CBlockHeader*)this); + READWRITE(vtx); + /*popchain ghost*/ + READWRITE(vuh); + READWRITE(td); + /*popchain ghost*/ + } + + void SetNull() + { + CBlockHeader::SetNull(); + vtx.clear(); + fChecked = false; + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrevBlock; + /*popchain ghost*/ + block.hashUncles = hashUncles; + block.coinbaseAddress = coinbaseAddress; + /*popchian ghost*/ + block.hashMerkleRoot = hashMerkleRoot; + block.hashClaimTrie = hashClaimTrie; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + std::string ToString() const; +}; + +/** Describes a place in the block chain to another node such that if the + * other node doesn't have the same branch, it can find a recent common trunk. + * The further back it is, the further before the fork it may be. + */ +struct CBlockLocator +{ + std::vector vHave; + + CBlockLocator() {} + + CBlockLocator(const std::vector& vHaveIn) + { + vHave = vHaveIn; + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(nVersion); + READWRITE(vHave); + } + + void SetNull() + { + vHave.clear(); + } + + bool IsNull() const + { + return vHave.empty(); + } +}; + +#endif // BITCOIN_PRIMITIVES_BLOCK_H From 34c33024d99cac8407423c89ba08be923afadc66 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 13 Jul 2018 09:05:01 +0800 Subject: [PATCH 002/120] change the miner to support ghost --- src/miner.cpp | 1342 +++++++++++++++++++++++++------------------------ 1 file changed, 672 insertions(+), 670 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index bb05ecd..3974a8d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1,670 +1,672 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "miner.h" - -#include "amount.h" -#include "chain.h" -#include "chainparams.h" -#include "coins.h" -#include "consensus/consensus.h" -#include "consensus/merkle.h" -#include "consensus/validation.h" -#include "hash.h" -#include "main.h" -#include "nameclaim.h" -#include "claimtrie.h" -#include "net.h" -#include "policy/policy.h" -#include "pow.h" -#include "primitives/transaction.h" -#include "script/standard.h" -#include "timedata.h" -#include "txmempool.h" -#include "util.h" -#include "utilmoneystr.h" -#include "popnode-payments.h" -#include "popnode-sync.h" -#include "validationinterface.h" -#include "arith_uint256.h" - -#include -#include -#include - -//#define KDEBUG - -using namespace std; - -////////////////////////////////////////////////////////////////////////////// -// -// PopMiner -// - -// -// Unconfirmed transactions in the memory pool often depend on other -// transactions in the memory pool. When we select transactions from the -// pool, we select by highest priority or fee rate, so we might consider -// transactions that depend on transactions that aren't yet in the block. - -uint64_t nLastBlockTx = 0; -uint64_t nLastBlockSize = 0; - -class ScoreCompare -{ -public: - ScoreCompare() {} - - bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) - { - return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than - } -}; - -int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) -{ - int64_t nOldTime = pblock->nTime; - int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - - if (nOldTime < nNewTime) - pblock->nTime = nNewTime; - - // Updating time can change work required on testnet: - if (consensusParams.fPowAllowMinDifficultyBlocks) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); - - return nNewTime - nOldTime; -} - -CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) -{ - // Create new block - unique_ptr pblocktemplate(new CBlockTemplate()); - if(!pblocktemplate.get()) - return NULL; - CBlock *pblock = &pblocktemplate->block; // pointer for convenience - - // Create coinbase tx - CMutableTransaction txNew; - txNew.vin.resize(1); - txNew.vin[0].prevout.SetNull(); - txNew.vout.resize(1); - txNew.vout[0].scriptPubKey = scriptPubKeyIn; - - // Largest block you're willing to create: - unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); - // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: - nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); - - // How much of the block should be dedicated to high-priority transactions, - // included regardless of the fees they pay - unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); - nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); - - // Minimum block size you want to create; block will be filled with free transactions - // until there are no more or the block reaches this size: - unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); - nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); - - // Collect memory pool transactions into the block - CTxMemPool::setEntries inBlock; - CTxMemPool::setEntries waitSet; - - // This vector will be sorted into a priority queue: - vector vecPriority; - TxCoinAgePriorityCompare pricomparer; - std::map waitPriMap; - typedef std::map::iterator waitPriIter; - double actualPriority = -1; - - std::priority_queue, ScoreCompare> clearedTxs; - bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); - uint64_t nBlockSize = 1000; - uint64_t nBlockTx = 0; - unsigned int nBlockSigOps = 100; - int lastFewTxs = 0; - CAmount nFees = 0; - - { - LOCK2(cs_main, mempool.cs); - CBlockIndex* pindexPrev = chainActive.Tip(); - const int nHeight = pindexPrev->nHeight + 1; - pblock->nTime = GetAdjustedTime(); - CCoinsViewCache view(pcoinsTip); - if (!pclaimTrie) - { - return NULL; - } - CClaimTrieCache trieCache(pclaimTrie); - const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); - - // Add our coinbase tx as first transaction - pblock->vtx.push_back(txNew); - pblocktemplate->vTxFees.push_back(-1); // updated at end - pblocktemplate->vTxSigOps.push_back(-1); // updated at end - pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); - // -regtest only: allow overriding block.nVersion with - // -blockversion=N to test forking scenarios - if (chainparams.MineBlocksOnDemand()) - pblock->nVersion = GetArg("-blockversion", pblock->nVersion); - - int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) - ? nMedianTimePast - : pblock->GetBlockTime(); - - bool fPriorityBlock = nBlockPrioritySize > 0; - if (fPriorityBlock) { - vecPriority.reserve(mempool.mapTx.size()); - for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); - mi != mempool.mapTx.end(); ++mi) - { - double dPriority = mi->GetPriority(nHeight); - CAmount dummy; - mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy); - vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); - } - std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); - } - - CTxMemPool::indexed_transaction_set::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin(); - CTxMemPool::txiter iter; - - while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty()) - { - bool priorityTx = false; - if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize - priorityTx = true; - iter = vecPriority.front().second; - actualPriority = vecPriority.front().first; - std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); - vecPriority.pop_back(); - } - else if (clearedTxs.empty()) { // add tx with next highest score - iter = mempool.mapTx.project<0>(mi); - mi++; - } - else { // try to add a previously postponed child tx - iter = clearedTxs.top(); - clearedTxs.pop(); - } - - if (inBlock.count(iter)) - continue; // could have been added to the priorityBlock - - const CTransaction& tx = iter->GetTx(); - - bool fOrphan = false; - BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter)) - { - if (!inBlock.count(parent)) { - fOrphan = true; - break; - } - } - if (fOrphan) { - if (priorityTx) - waitPriMap.insert(std::make_pair(iter,actualPriority)); - else - waitSet.insert(iter); - continue; - } - - unsigned int nTxSize = iter->GetTxSize(); - if (fPriorityBlock && - (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { - fPriorityBlock = false; - waitPriMap.clear(); - } - if (!priorityTx && - (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { - break; - } - if (nBlockSize + nTxSize >= nBlockMaxSize) { - if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { - break; - } - // Once we're within 1000 bytes of a full block, only look at 50 more txs - // to try to fill the remaining space. - if (nBlockSize > nBlockMaxSize - 1000) { - lastFewTxs++; - } - continue; - } - - if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) - continue; - - typedef std::vector > spentClaimsType; - spentClaimsType spentClaims; - - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - const CCoins* coins = view.AccessCoins(txin.prevout.hash); - int nTxinHeight = 0; - CScript scriptPubKey; - bool fGotCoins = false; - if (coins) - { - if (txin.prevout.n < coins->vout.size()) - { - nTxinHeight = coins->nHeight; - scriptPubKey = coins->vout[txin.prevout.n].scriptPubKey; - fGotCoins = true; - } - } - else // must be in block or else - { - BOOST_FOREACH(CTxMemPool::txiter inBlockEntry, inBlock) - { - CTransaction inBlockTx = inBlockEntry->GetTx(); - if (inBlockTx.GetHash() == txin.prevout.hash) - { - if (inBlockTx.vout.size() >= txin.prevout.n) - { - nTxinHeight = nHeight; - scriptPubKey = inBlockTx.vout[txin.prevout.n].scriptPubKey; - fGotCoins = true; - } - } - } - } - if (!fGotCoins) - { - LogPrintf("Tried to include a transaction but could not find the txout it was spending. This is bad. Please send this log file to the maintainers of this program.\n"); - throw std::runtime_error("Tried to include a transaction but could not find the txout it was spending."); - } - - std::vector > vvchParams; - int op; - - if (DecodeClaimScript(scriptPubKey, op, vvchParams)) - { - if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) - { - uint160 claimId; - if (op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2); - claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); - } - else if (op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3); - claimId = uint160(vvchParams[1]); - } - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - int throwaway; - if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) - { - std::pair entry(name, claimId); - spentClaims.push_back(entry); - } - else - { - LogPrintf("%s(): The claim was not found in the trie or queue and therefore can't be updated\n", __func__); - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - int throwaway; - if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) - { - LogPrintf("%s(): The support was not found in the trie or queue\n", __func__); - } - } - } - } - - for (unsigned int i = 0; i < tx.vout.size(); ++i) - { - const CTxOut& txout = tx.vout[i]; - - std::vector > vvchParams; - int op; - if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) - { - if (op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), ClaimIdHash(tx.GetHash(), i), txout.nValue, nHeight)) - { - LogPrintf("%s: Something went wrong inserting the name\n", __func__); - } - } - else if (op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 claimId(vvchParams[1]); - spentClaimsType::iterator itSpent; - for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) - { - if (itSpent->first == name && itSpent->second == claimId) - { - break; - } - } - if (itSpent != spentClaims.end()) - { - spentClaims.erase(itSpent); - if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), claimId, txout.nValue, nHeight)) - { - LogPrintf("%s: Something went wrong updating a claim\n", __func__); - } - } - else - { - LogPrintf("%s(): This update refers to a claim that was not found in the trie or queue, and therefore cannot be updated. The claim may have expired or it may have never existed.\n", __func__); - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 supportedClaimId(vvchParams[1]); - if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), i), txout.nValue, supportedClaimId, nHeight)) - { - LogPrintf("%s: Something went wrong inserting the claim support\n", __func__); - } - } - } - } - CValidationState state; - - unsigned int nTxSigOps = iter->GetSigOpCount(); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) { - if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2) { - break; - } - continue; - } - - CAmount nTxFees = iter->GetFee(); - // Added - pblock->vtx.push_back(tx); - pblocktemplate->vTxFees.push_back(nTxFees); - pblocktemplate->vTxSigOps.push_back(nTxSigOps); - nBlockSize += nTxSize; - ++nBlockTx; - nBlockSigOps += nTxSigOps; - nFees += nTxFees; - - if (fPrintPriority) - { - double dPriority = iter->GetPriority(nHeight); - CAmount dummy; - mempool.ApplyDeltas(tx.GetHash(), dPriority, dummy); - LogPrintf("priority %.1f fee %s txid %s\n", - dPriority , CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString()); - } - - inBlock.insert(iter); - - // Add transactions that depend on this one to the priority queue - BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) - { - if (fPriorityBlock) { - waitPriIter wpiter = waitPriMap.find(child); - if (wpiter != waitPriMap.end()) { - vecPriority.push_back(TxCoinAgePriority(wpiter->second,child)); - std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); - waitPriMap.erase(wpiter); - } - } - else { - if (waitSet.count(child)) { - clearedTxs.push(child); - waitSet.erase(child); - } - } - } - } - - // NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here - CAmount blockReward = nFees + GetMinerSubsidy(nHeight, Params().GetConsensus()); - - // Compute regular coinbase transaction. - txNew.vout[0].nValue = blockReward; - txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; - - // get some info back to pass to getblocktemplate - // Popchain DevTeam - FillBlockPayments(txNew, nHeight, blockReward, pblock->txoutFound); - - LogPrintf("CreateNewBlock -- nBlockHeight %d blockReward %lld txNew %s", - nHeight, blockReward, /*pblock->txoutPopnode.ToString(),*/ txNew.ToString()); - - nLastBlockTx = nBlockTx; - nLastBlockSize = nBlockSize; - LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); - - // Update block coinbase - pblock->vtx[0] = txNew; - pblocktemplate->vTxFees[0] = -nFees; - - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); - - // Randomise nonce - arith_uint256 nonce = UintToArith256(GetRandHash()); - // Clear the top and bottom 16 bits (for local use as thread flags and counters) - nonce <<= 32; - nonce >>= 16; - pblock->nNonce = ArithToUint256(nonce); - pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - - // claim operation - insertUndoType dummyInsertUndo; - claimQueueRowType dummyExpireUndo; - insertUndoType dummyInsertSupportUndo; - supportQueueRowType dummyExpireSupportUndo; - std::vector > dummyTakeoverHeightUndo; - trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo); - //pblock->hashClaimTrie = trieCache.getMerkleHash(); - CValidationState state; - if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { - throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); - } - } - - return pblocktemplate.release(); -} - -void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce) -{ - // Update nExtraNonce - static uint256 hashPrevBlock; - if (hashPrevBlock != pblock->hashPrevBlock) - { - nExtraNonce = 0; - hashPrevBlock = pblock->hashPrevBlock; - } - ++nExtraNonce; - unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - CMutableTransaction txCoinbase(pblock->vtx[0]); - txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; - assert(txCoinbase.vin[0].scriptSig.size() <= 100); - - pblock->vtx[0] = txCoinbase; - pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); -} - -static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) -{ - LogPrintf("%s\n", pblock->ToString()); - LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); - - // Found a solution - { - LOCK(cs_main); - if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) - { - //LogPrintf("hashPrevBlock = %s, Tip hash = %s\n", pblock->hashPrevBlock, chainActive.Tip()->GetBlockHash()); - return error("ProcessBlockFound -- generated block is stale"); - } - } - - // Inform about the new block - GetMainSignals().BlockFound(pblock->GetHash()); - - // Process this block the same as if we had received it from another node - CValidationState state; - if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) - return error("ProcessBlockFound -- ProcessNewBlock() failed, block not accepted"); - - return true; -} - -// ***TODO*** that part changed in bitcoin, we are using a mix with old one here for now -void static BitcoinMiner(const CChainParams& chainparams) -{ - LogPrintf("PopMiner -- started\n"); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - RenameThread("pop-miner"); - - unsigned int nExtraNonce = 0; - - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - try { - // Throw an error if no script was provided. This can happen - // due to some internal error but also if the keypool is empty. - // In the latter case, already the pointer is NULL. - if (!coinbaseScript || coinbaseScript->reserveScript.empty()) - throw std::runtime_error("No coinbase script available (mining requires a wallet)"); - - while (true) { - if (chainparams.MiningRequiresPeers()) { - // Busy-wait for the network to come online so we don't waste time mining - // on an obsolete chain. In regtest mode we expect to fly solo. - do { - bool fvNodesEmpty; - { - LOCK(cs_vNodes); - fvNodesEmpty = vNodes.empty(); - } - if (!fvNodesEmpty /*&& - IsInitialBlockDownload() - && popnodeSync.IsSynced()*/) - break; - MilliSleep(1000); - } while (true); - } - - - // - // Create new block - // - unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrev = chainActive.Tip(); - if(!pindexPrev) break; - - unique_ptr pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); - if (!pblocktemplate.get()) - { - LogPrintf("PopMiner -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); - return; - } - CBlock *pblock = &pblocktemplate->block; - IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); - - LogPrintf("PopMiner -- Running miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), - ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - - // - // Search - // - int64_t nStart = GetTime(); - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - while (true) - { - uint256 hash; - while (true) - { - hash = pblock->GetHash(); - if (UintToArith256(hash) <= hashTarget) - { - // Found a solution - SetThreadPriority(THREAD_PRIORITY_NORMAL); - LogPrintf("PopMiner:\n proof-of-work found\n hash: %s\n target: %s\n", hash.GetHex(), hashTarget.GetHex()); - ProcessBlockFound(pblock, chainparams); - SetThreadPriority(THREAD_PRIORITY_LOWEST); - coinbaseScript->KeepScript(); - - // In regression test mode, stop mining after a block is found. This - // allows developers to controllably generate a block on demand. - if (chainparams.MineBlocksOnDemand()) - throw boost::thread_interrupted(); - - break; - } - pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); - if ((UintToArith256(pblock->nNonce) & 0xFF) == 0) - { - //LogPrintf("PopMiner: %d nExtraNonce: %d\n", pblock->nNonce, nExtraNonce); - break; - } - } - - // Check for stop or if block needs to be rebuilt - boost::this_thread::interruption_point(); - // Regtest mode doesn't require peers - if (vNodes.empty() && chainparams.MiningRequiresPeers()) - break; - if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff) - break; - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) - break; - if (pindexPrev != chainActive.Tip()) - break; - - // Update nTime every few seconds - if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) - break; // Recreate the block if the clock has run backwards, - // so that we can use the correct time. - if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) - { - // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); - } - } - } - } - catch (const boost::thread_interrupted&) - { - LogPrintf("PopMiner -- terminated\n"); - throw; - } - catch (const std::runtime_error &e) - { - LogPrintf("PopMiner -- runtime error: %s\n", e.what()); - return; - } -} - -void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) -{ - static boost::thread_group* minerThreads = NULL; - - if (nThreads < 0) - nThreads = GetNumCores(); - - if (minerThreads != NULL) - { - minerThreads->interrupt_all(); - delete minerThreads; - minerThreads = NULL; - } - - if (nThreads == 0 || !fGenerate) - return; - - minerThreads = new boost::thread_group(); - for (int i = 0; i < nThreads; i++) - minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); -} +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "miner.h" + +#include "amount.h" +#include "chain.h" +#include "chainparams.h" +#include "coins.h" +#include "consensus/consensus.h" +#include "consensus/merkle.h" +#include "consensus/validation.h" +#include "hash.h" +#include "main.h" +#include "nameclaim.h" +#include "claimtrie.h" +#include "net.h" +#include "policy/policy.h" +#include "pow.h" +#include "primitives/transaction.h" +#include "script/standard.h" +#include "timedata.h" +#include "txmempool.h" +#include "util.h" +#include "utilmoneystr.h" +#include "popnode-payments.h" +#include "popnode-sync.h" +#include "validationinterface.h" +#include "arith_uint256.h" + +#include +#include +#include + +//#define KDEBUG + +using namespace std; + +////////////////////////////////////////////////////////////////////////////// +// +// PopMiner +// + +// +// Unconfirmed transactions in the memory pool often depend on other +// transactions in the memory pool. When we select transactions from the +// pool, we select by highest priority or fee rate, so we might consider +// transactions that depend on transactions that aren't yet in the block. + +uint64_t nLastBlockTx = 0; +uint64_t nLastBlockSize = 0; + +class ScoreCompare +{ +public: + ScoreCompare() {} + + bool operator()(const CTxMemPool::txiter a, const CTxMemPool::txiter b) + { + return CompareTxMemPoolEntryByScore()(*b,*a); // Convert to less than + } +}; + +int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) +{ + int64_t nOldTime = pblock->nTime; + int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + + if (nOldTime < nNewTime) + pblock->nTime = nNewTime; + + // Updating time can change work required on testnet: + if (consensusParams.fPowAllowMinDifficultyBlocks) + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); + + return nNewTime - nOldTime; +} + +CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& scriptPubKeyIn) +{ + // Create new block + unique_ptr pblocktemplate(new CBlockTemplate()); + if(!pblocktemplate.get()) + return NULL; + CBlock *pblock = &pblocktemplate->block; // pointer for convenience + + // Create coinbase tx + CMutableTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vout.resize(1); + txNew.vout[0].scriptPubKey = scriptPubKeyIn; + + // Largest block you're willing to create: + unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); + // Limit to between 1K and MAX_BLOCK_SIZE-1K for sanity: + nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize)); + + // How much of the block should be dedicated to high-priority transactions, + // included regardless of the fees they pay + unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); + nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize); + + // Minimum block size you want to create; block will be filled with free transactions + // until there are no more or the block reaches this size: + unsigned int nBlockMinSize = GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); + nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); + + // Collect memory pool transactions into the block + CTxMemPool::setEntries inBlock; + CTxMemPool::setEntries waitSet; + + // This vector will be sorted into a priority queue: + vector vecPriority; + TxCoinAgePriorityCompare pricomparer; + std::map waitPriMap; + typedef std::map::iterator waitPriIter; + double actualPriority = -1; + + std::priority_queue, ScoreCompare> clearedTxs; + bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); + uint64_t nBlockSize = 1000; + uint64_t nBlockTx = 0; + unsigned int nBlockSigOps = 100; + int lastFewTxs = 0; + CAmount nFees = 0; + + { + LOCK2(cs_main, mempool.cs); + CBlockIndex* pindexPrev = chainActive.Tip(); + const int nHeight = pindexPrev->nHeight + 1; + pblock->nTime = GetAdjustedTime(); + CCoinsViewCache view(pcoinsTip); + if (!pclaimTrie) + { + return NULL; + } + CClaimTrieCache trieCache(pclaimTrie); + const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); + + // Add our coinbase tx as first transaction + pblock->vtx.push_back(txNew); + pblocktemplate->vTxFees.push_back(-1); // updated at end + pblocktemplate->vTxSigOps.push_back(-1); // updated at end + pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); + // -regtest only: allow overriding block.nVersion with + // -blockversion=N to test forking scenarios + if (chainparams.MineBlocksOnDemand()) + pblock->nVersion = GetArg("-blockversion", pblock->nVersion); + + int64_t nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) + ? nMedianTimePast + : pblock->GetBlockTime(); + + bool fPriorityBlock = nBlockPrioritySize > 0; + if (fPriorityBlock) { + vecPriority.reserve(mempool.mapTx.size()); + for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin(); + mi != mempool.mapTx.end(); ++mi) + { + double dPriority = mi->GetPriority(nHeight); + CAmount dummy; + mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy); + vecPriority.push_back(TxCoinAgePriority(dPriority, mi)); + } + std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer); + } + + CTxMemPool::indexed_transaction_set::nth_index<3>::type::iterator mi = mempool.mapTx.get<3>().begin(); + CTxMemPool::txiter iter; + + while (mi != mempool.mapTx.get<3>().end() || !clearedTxs.empty()) + { + bool priorityTx = false; + if (fPriorityBlock && !vecPriority.empty()) { // add a tx from priority queue to fill the blockprioritysize + priorityTx = true; + iter = vecPriority.front().second; + actualPriority = vecPriority.front().first; + std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer); + vecPriority.pop_back(); + } + else if (clearedTxs.empty()) { // add tx with next highest score + iter = mempool.mapTx.project<0>(mi); + mi++; + } + else { // try to add a previously postponed child tx + iter = clearedTxs.top(); + clearedTxs.pop(); + } + + if (inBlock.count(iter)) + continue; // could have been added to the priorityBlock + + const CTransaction& tx = iter->GetTx(); + + bool fOrphan = false; + BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter)) + { + if (!inBlock.count(parent)) { + fOrphan = true; + break; + } + } + if (fOrphan) { + if (priorityTx) + waitPriMap.insert(std::make_pair(iter,actualPriority)); + else + waitSet.insert(iter); + continue; + } + + unsigned int nTxSize = iter->GetTxSize(); + if (fPriorityBlock && + (nBlockSize + nTxSize >= nBlockPrioritySize || !AllowFree(actualPriority))) { + fPriorityBlock = false; + waitPriMap.clear(); + } + if (!priorityTx && + (iter->GetModifiedFee() < ::minRelayTxFee.GetFee(nTxSize) && nBlockSize >= nBlockMinSize)) { + break; + } + if (nBlockSize + nTxSize >= nBlockMaxSize) { + if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) { + break; + } + // Once we're within 1000 bytes of a full block, only look at 50 more txs + // to try to fill the remaining space. + if (nBlockSize > nBlockMaxSize - 1000) { + lastFewTxs++; + } + continue; + } + + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) + continue; + + typedef std::vector > spentClaimsType; + spentClaimsType spentClaims; + + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + const CCoins* coins = view.AccessCoins(txin.prevout.hash); + int nTxinHeight = 0; + CScript scriptPubKey; + bool fGotCoins = false; + if (coins) + { + if (txin.prevout.n < coins->vout.size()) + { + nTxinHeight = coins->nHeight; + scriptPubKey = coins->vout[txin.prevout.n].scriptPubKey; + fGotCoins = true; + } + } + else // must be in block or else + { + BOOST_FOREACH(CTxMemPool::txiter inBlockEntry, inBlock) + { + CTransaction inBlockTx = inBlockEntry->GetTx(); + if (inBlockTx.GetHash() == txin.prevout.hash) + { + if (inBlockTx.vout.size() >= txin.prevout.n) + { + nTxinHeight = nHeight; + scriptPubKey = inBlockTx.vout[txin.prevout.n].scriptPubKey; + fGotCoins = true; + } + } + } + } + if (!fGotCoins) + { + LogPrintf("Tried to include a transaction but could not find the txout it was spending. This is bad. Please send this log file to the maintainers of this program.\n"); + throw std::runtime_error("Tried to include a transaction but could not find the txout it was spending."); + } + + std::vector > vvchParams; + int op; + + if (DecodeClaimScript(scriptPubKey, op, vvchParams)) + { + if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) + { + uint160 claimId; + if (op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2); + claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); + } + else if (op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3); + claimId = uint160(vvchParams[1]); + } + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + int throwaway; + if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) + { + std::pair entry(name, claimId); + spentClaims.push_back(entry); + } + else + { + LogPrintf("%s(): The claim was not found in the trie or queue and therefore can't be updated\n", __func__); + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + int throwaway; + if (!trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), nTxinHeight, throwaway)) + { + LogPrintf("%s(): The support was not found in the trie or queue\n", __func__); + } + } + } + } + + for (unsigned int i = 0; i < tx.vout.size(); ++i) + { + const CTxOut& txout = tx.vout[i]; + + std::vector > vvchParams; + int op; + if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) + { + if (op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), ClaimIdHash(tx.GetHash(), i), txout.nValue, nHeight)) + { + LogPrintf("%s: Something went wrong inserting the name\n", __func__); + } + } + else if (op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 claimId(vvchParams[1]); + spentClaimsType::iterator itSpent; + for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) + { + if (itSpent->first == name && itSpent->second == claimId) + { + break; + } + } + if (itSpent != spentClaims.end()) + { + spentClaims.erase(itSpent); + if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), i), claimId, txout.nValue, nHeight)) + { + LogPrintf("%s: Something went wrong updating a claim\n", __func__); + } + } + else + { + LogPrintf("%s(): This update refers to a claim that was not found in the trie or queue, and therefore cannot be updated. The claim may have expired or it may have never existed.\n", __func__); + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 supportedClaimId(vvchParams[1]); + if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), i), txout.nValue, supportedClaimId, nHeight)) + { + LogPrintf("%s: Something went wrong inserting the claim support\n", __func__); + } + } + } + } + CValidationState state; + + unsigned int nTxSigOps = iter->GetSigOpCount(); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) { + if (nBlockSigOps > MAX_BLOCK_SIGOPS - 2) { + break; + } + continue; + } + + CAmount nTxFees = iter->GetFee(); + // Added + pblock->vtx.push_back(tx); + pblocktemplate->vTxFees.push_back(nTxFees); + pblocktemplate->vTxSigOps.push_back(nTxSigOps); + nBlockSize += nTxSize; + ++nBlockTx; + nBlockSigOps += nTxSigOps; + nFees += nTxFees; + + if (fPrintPriority) + { + double dPriority = iter->GetPriority(nHeight); + CAmount dummy; + mempool.ApplyDeltas(tx.GetHash(), dPriority, dummy); + LogPrintf("priority %.1f fee %s txid %s\n", + dPriority , CFeeRate(iter->GetModifiedFee(), nTxSize).ToString(), tx.GetHash().ToString()); + } + + inBlock.insert(iter); + + // Add transactions that depend on this one to the priority queue + BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter)) + { + if (fPriorityBlock) { + waitPriIter wpiter = waitPriMap.find(child); + if (wpiter != waitPriMap.end()) { + vecPriority.push_back(TxCoinAgePriority(wpiter->second,child)); + std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer); + waitPriMap.erase(wpiter); + } + } + else { + if (waitSet.count(child)) { + clearedTxs.push(child); + waitSet.erase(child); + } + } + } + } + + // NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here + CAmount blockReward = nFees + GetMinerSubsidy(nHeight, Params().GetConsensus()); + + // Compute regular coinbase transaction. + txNew.vout[0].nValue = blockReward; + txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; + + // get some info back to pass to getblocktemplate + // Popchain DevTeam + FillBlockPayments(txNew, nHeight, blockReward, pblock->txoutFound); + + LogPrintf("CreateNewBlock -- nBlockHeight %d blockReward %lld txNew %s", + nHeight, blockReward, /*pblock->txoutPopnode.ToString(),*/ txNew.ToString()); + + nLastBlockTx = nBlockTx; + nLastBlockSize = nBlockSize; + LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); + + // Update block coinbase + pblock->vtx[0] = txNew; + pblocktemplate->vTxFees[0] = -nFees; + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); + + // Randomise nonce + arith_uint256 nonce = UintToArith256(GetRandHash()); + // Clear the top and bottom 16 bits (for local use as thread flags and counters) + nonce <<= 32; + nonce >>= 16; + pblock->nNonce = ArithToUint256(nonce); + pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); + + // claim operation + insertUndoType dummyInsertUndo; + claimQueueRowType dummyExpireUndo; + insertUndoType dummyInsertSupportUndo; + supportQueueRowType dummyExpireSupportUndo; + std::vector > dummyTakeoverHeightUndo; + trieCache.incrementBlock(dummyInsertUndo, dummyExpireUndo, dummyInsertSupportUndo, dummyExpireSupportUndo, dummyTakeoverHeightUndo); + //pblock->hashClaimTrie = trieCache.getMerkleHash(); + CValidationState state; + if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { + throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); + } + } + + return pblocktemplate.release(); +} + +void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce) +{ + // Update nExtraNonce + static uint256 hashPrevBlock; + if (hashPrevBlock != pblock->hashPrevBlock) + { + nExtraNonce = 0; + hashPrevBlock = pblock->hashPrevBlock; + } + ++nExtraNonce; + unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + CMutableTransaction txCoinbase(pblock->vtx[0]); + txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; + assert(txCoinbase.vin[0].scriptSig.size() <= 100); + + pblock->vtx[0] = txCoinbase; + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); +} + +static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) +{ + LogPrintf("%s\n", pblock->ToString()); + LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue)); + + // Found a solution + { + LOCK(cs_main); + if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) + { + //LogPrintf("hashPrevBlock = %s, Tip hash = %s\n", pblock->hashPrevBlock, chainActive.Tip()->GetBlockHash()); + return error("ProcessBlockFound -- generated block is stale"); + } + } + + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); + + // Process this block the same as if we had received it from another node + CValidationState state; + if (!ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL)) + return error("ProcessBlockFound -- ProcessNewBlock() failed, block not accepted"); + + return true; +} + +// ***TODO*** that part changed in bitcoin, we are using a mix with old one here for now +void static BitcoinMiner(const CChainParams& chainparams) +{ + LogPrintf("PopMiner -- started\n"); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + RenameThread("pop-miner"); + + unsigned int nExtraNonce = 0; + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + try { + // Throw an error if no script was provided. This can happen + // due to some internal error but also if the keypool is empty. + // In the latter case, already the pointer is NULL. + if (!coinbaseScript || coinbaseScript->reserveScript.empty()) + throw std::runtime_error("No coinbase script available (mining requires a wallet)"); + + while (true) { + if (chainparams.MiningRequiresPeers()) { + // Busy-wait for the network to come online so we don't waste time mining + // on an obsolete chain. In regtest mode we expect to fly solo. + do { + bool fvNodesEmpty; + { + LOCK(cs_vNodes); + fvNodesEmpty = vNodes.empty(); + } + if (!fvNodesEmpty /*&& + IsInitialBlockDownload() + && popnodeSync.IsSynced()*/) + break; + MilliSleep(1000); + } while (true); + } + + + // + // Create new block + // + unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrev = chainActive.Tip(); + if(!pindexPrev) break; + + unique_ptr pblocktemplate(CreateNewBlock(chainparams, coinbaseScript->reserveScript)); + if (!pblocktemplate.get()) + { + LogPrintf("PopMiner -- Keypool ran out, please call keypoolrefill before restarting the mining thread\n"); + return; + } + CBlock *pblock = &pblocktemplate->block; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce); + + LogPrintf("PopMiner -- Running miner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), + ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); + + // + // Search + // + int64_t nStart = GetTime(); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + while (true) + { + uint256 hash; + while (true) + { + hash = pblock->GetHash(); + if (UintToArith256(hash) <= hashTarget) + { + // Found a solution + SetThreadPriority(THREAD_PRIORITY_NORMAL); + LogPrintf("PopMiner:\n proof-of-work found\n hash: %s\n target: %s\n", hash.GetHex(), hashTarget.GetHex()); + ProcessBlockFound(pblock, chainparams); + SetThreadPriority(THREAD_PRIORITY_LOWEST); + coinbaseScript->KeepScript(); + + // In regression test mode, stop mining after a block is found. This + // allows developers to controllably generate a block on demand. + if (chainparams.MineBlocksOnDemand()) + throw boost::thread_interrupted(); + + break; + } + pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); + /*popchain ghost*/ + //change parameter 0xFF to 0xffff to support the ghost protol + if ((UintToArith256(pblock->nNonce) & 0xffff) == 0) + { + //LogPrintf("PopMiner: %d nExtraNonce: %d\n", pblock->nNonce, nExtraNonce); + break; + } + } + + // Check for stop or if block needs to be rebuilt + boost::this_thread::interruption_point(); + // Regtest mode doesn't require peers + if (vNodes.empty() && chainparams.MiningRequiresPeers()) + break; + if ((UintToArith256(pblock->nNonce) & 0xffff) == 0xffff) + break; + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) + break; + if (pindexPrev != chainActive.Tip()) + break; + + // Update nTime every few seconds + if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0) + break; // Recreate the block if the clock has run backwards, + // so that we can use the correct time. + if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) + { + // Changing pblock->nTime can change work required on testnet: + hashTarget.SetCompact(pblock->nBits); + } + } + } + } + catch (const boost::thread_interrupted&) + { + LogPrintf("PopMiner -- terminated\n"); + throw; + } + catch (const std::runtime_error &e) + { + LogPrintf("PopMiner -- runtime error: %s\n", e.what()); + return; + } +} + +void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams) +{ + static boost::thread_group* minerThreads = NULL; + + if (nThreads < 0) + nThreads = GetNumCores(); + + if (minerThreads != NULL) + { + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; + } + + if (nThreads == 0 || !fGenerate) + return; + + minerThreads = new boost::thread_group(); + for (int i = 0; i < nThreads; i++) + minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams))); +} From 1bc4930dea455f3b3d2c36fe9310358374243215 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 14 Jul 2018 15:30:43 +0800 Subject: [PATCH 003/120] change block index and disk block index struction --- src/chain.h | 858 +++++++++++++++++++++++++++------------------------- 1 file changed, 443 insertions(+), 415 deletions(-) diff --git a/src/chain.h b/src/chain.h index 83f1612..263b80f 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,415 +1,443 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#ifndef BITCOIN_CHAIN_H -#define BITCOIN_CHAIN_H - -#include "arith_uint256.h" -#include "primitives/block.h" -#include "pow.h" -#include "tinyformat.h" -#include "uint256.h" - -#include - -struct CDiskBlockPos -{ - int nFile; - unsigned int nPos; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(nFile)); - READWRITE(VARINT(nPos)); - } - - CDiskBlockPos() { - SetNull(); - } - - CDiskBlockPos(int nFileIn, unsigned int nPosIn) { - nFile = nFileIn; - nPos = nPosIn; - } - - friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { - return (a.nFile == b.nFile && a.nPos == b.nPos); - } - - friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { - return !(a == b); - } - - void SetNull() { nFile = -1; nPos = 0; } - bool IsNull() const { return (nFile == -1); } - - std::string ToString() const - { - return strprintf("CBlockDiskPos(nFile=%i, nPos=%i)", nFile, nPos); - } - -}; - -enum BlockStatus { - //! Unused. - BLOCK_VALID_UNKNOWN = 0, - - //! Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future - BLOCK_VALID_HEADER = 1, - - //! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents - //! are also at least TREE. - BLOCK_VALID_TREE = 2, - - /** - * Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, - * sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all - * parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set. - */ - BLOCK_VALID_TRANSACTIONS = 3, - - //! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30. - //! Implies all parents are also at least CHAIN. - BLOCK_VALID_CHAIN = 4, - - //! Scripts & signatures ok. Implies all parents are also at least SCRIPTS. - BLOCK_VALID_SCRIPTS = 5, - - //! All validity bits. - BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | - BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, - - BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat - BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat - BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO, - - BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed - BLOCK_FAILED_CHILD = 64, //! descends from failed block - BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, -}; - -/** The block chain is a tree shaped structure starting with the - * genesis block at the root, with each block potentially having multiple - * candidates to be the next block. A blockindex may have multiple pprev pointing - * to it, but at most one of them can be part of the currently active branch. - */ -class CBlockIndex -{ -public: - //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex - const uint256* phashBlock; - - //! pointer to the index of the predecessor of this block - CBlockIndex* pprev; - - //! pointer to the index of some further predecessor of this block - CBlockIndex* pskip; - - //! height of the entry in the chain. The genesis block has height 0 - int nHeight; - - //! Which # file this block is stored in (blk?????.dat) - int nFile; - - //! Byte offset within blk?????.dat where this block's data is stored - unsigned int nDataPos; - - //! Byte offset within rev?????.dat where this block's undo data is stored - unsigned int nUndoPos; - - //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block - arith_uint256 nChainWork; - - //! Number of transactions in this block. - //! Note: in a potential headers-first mode, this number cannot be relied upon - unsigned int nTx; - - //! (memory only) Number of transactions in the chain up to and including this block. - //! This value will be non-zero only if and only if transactions for this block and all its parents are available. - //! Change to 64-bit type when necessary; won't happen before 2030 - unsigned int nChainTx; - - //! Verification status of this block. See enum BlockStatus - unsigned int nStatus; - - //! block header - int nVersion; - uint256 hashMerkleRoot; - uint256 hashClaimTrie; - unsigned int nTime; - unsigned int nBits; - uint256 nNonce; - - //! (memory only) Sequential id assigned to distinguish order in which blocks are received. - uint32_t nSequenceId; - - void SetNull() - { - phashBlock = NULL; - pprev = NULL; - pskip = NULL; - nHeight = 0; - nFile = 0; - nDataPos = 0; - nUndoPos = 0; - nChainWork = arith_uint256(); - nTx = 0; - nChainTx = 0; - nStatus = 0; - nSequenceId = 0; - - nVersion = 0; - hashMerkleRoot = uint256(); - hashClaimTrie = uint256(); - nTime = 0; - nBits = 0; - nNonce = uint256(); - } - - CBlockIndex() - { - SetNull(); - } - - CBlockIndex(const CBlockHeader& block) - { - SetNull(); - - nVersion = block.nVersion; - hashMerkleRoot = block.hashMerkleRoot; - hashClaimTrie = block.hashClaimTrie; - nTime = block.nTime; - nBits = block.nBits; - nNonce = block.nNonce; - } - - CDiskBlockPos GetBlockPos() const { - CDiskBlockPos ret; - if (nStatus & BLOCK_HAVE_DATA) { - ret.nFile = nFile; - ret.nPos = nDataPos; - } - return ret; - } - - CDiskBlockPos GetUndoPos() const { - CDiskBlockPos ret; - if (nStatus & BLOCK_HAVE_UNDO) { - ret.nFile = nFile; - ret.nPos = nUndoPos; - } - return ret; - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - if (pprev) - block.hashPrevBlock = pprev->GetBlockHash(); - block.hashMerkleRoot = hashMerkleRoot; - block.hashClaimTrie = hashClaimTrie; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - uint256 GetBlockHash() const - { - return *phashBlock; - } - - int64_t GetBlockTime() const - { - return (int64_t)nTime; - } - - enum { nMedianTimeSpan=11 }; - - int64_t GetMedianTimePast() const - { - int64_t pmedian[nMedianTimeSpan]; - int64_t* pbegin = &pmedian[nMedianTimeSpan]; - int64_t* pend = &pmedian[nMedianTimeSpan]; - - const CBlockIndex* pindex = this; - for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) - *(--pbegin) = pindex->GetBlockTime(); - - std::sort(pbegin, pend); - return pbegin[(pend - pbegin)/2]; - } - - std::string ToString() const - { - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, claimtrie=%s, hashBlock=%s)", - pprev, nHeight, - hashMerkleRoot.ToString(), - hashClaimTrie.ToString(), - GetBlockHash().ToString()); - } - - //! Check whether this block index entry is valid up to the passed validity level. - bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const - { - assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. - if (nStatus & BLOCK_FAILED_MASK) - return false; - return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); - } - - //! Raise the validity level of this block index entry. - //! Returns true if the validity was changed. - bool RaiseValidity(enum BlockStatus nUpTo) - { - assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. - if (nStatus & BLOCK_FAILED_MASK) - return false; - if ((nStatus & BLOCK_VALID_MASK) < nUpTo) { - nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo; - return true; - } - return false; - } - - //! Build the skiplist pointer for this entry. - void BuildSkip(); - - //! Efficiently find an ancestor of this block. - CBlockIndex* GetAncestor(int height); - const CBlockIndex* GetAncestor(int height) const; -}; - -/** Used to marshal pointers into hashes for db storage. */ -class CDiskBlockIndex : public CBlockIndex -{ -public: - uint256 hash; - uint256 hashPrev; - - CDiskBlockIndex() { - hash = uint256(); - hashPrev = uint256(); - } - - explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) { - hash = (hash == uint256() ? pindex->GetBlockHash() : hash); - hashPrev = (pprev ? pprev->GetBlockHash() : uint256()); - } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(VARINT(nVersion)); - - READWRITE(VARINT(nHeight)); - READWRITE(VARINT(nStatus)); - READWRITE(VARINT(nTx)); - if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) - READWRITE(VARINT(nFile)); - if (nStatus & BLOCK_HAVE_DATA) - READWRITE(VARINT(nDataPos)); - if (nStatus & BLOCK_HAVE_UNDO) - READWRITE(VARINT(nUndoPos)); - - // block hash - READWRITE(hash); - // block header - READWRITE(this->nVersion); - READWRITE(hashPrev); - READWRITE(hashMerkleRoot); - READWRITE(hashClaimTrie); - READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); - } - - uint256 GetBlockHash() const - { - if(hash != uint256()) return hash; - // should never really get here, keeping this as a fallback - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrev; - block.hashMerkleRoot = hashMerkleRoot; - block.hashClaimTrie = hashClaimTrie; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block.GetHash(); - } - - - std::string ToString() const - { - std::string str = "CDiskBlockIndex("; - str += CBlockIndex::ToString(); - str += strprintf("\n hashBlock=%s, hashPrev=%s)", - GetBlockHash().ToString(), - hashPrev.ToString()); - return str; - } -}; - -/** An in-memory indexed chain of blocks. */ -class CChain { -private: - std::vector vChain; - -public: - /** Returns the index entry for the genesis block of this chain, or NULL if none. */ - CBlockIndex *Genesis() const { - return vChain.size() > 0 ? vChain[0] : NULL; - } - - /** Returns the index entry for the tip of this chain, or NULL if none. */ - CBlockIndex *Tip() const { - return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; - } - - /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ - CBlockIndex *operator[](int nHeight) const { - if (nHeight < 0 || nHeight >= (int)vChain.size()) - return NULL; - return vChain[nHeight]; - } - - /** Compare two chains efficiently. */ - friend bool operator==(const CChain &a, const CChain &b) { - return a.vChain.size() == b.vChain.size() && - a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; - } - - /** Efficiently check whether a block is present in this chain. */ - bool Contains(const CBlockIndex *pindex) const { - return (*this)[pindex->nHeight] == pindex; - } - - /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ - CBlockIndex *Next(const CBlockIndex *pindex) const { - if (Contains(pindex)) - return (*this)[pindex->nHeight + 1]; - else - return NULL; - } - - /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ - int Height() const { - return vChain.size() - 1; - } - - /** Set/initialize a chain with a given tip. */ - void SetTip(CBlockIndex *pindex); - - /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ - CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; - - /** Find the last common block between this chain and a block index entry. */ - const CBlockIndex *FindFork(const CBlockIndex *pindex) const; -}; - -#endif // BITCOIN_CHAIN_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_CHAIN_H +#define BITCOIN_CHAIN_H + +#include "arith_uint256.h" +#include "primitives/block.h" +#include "pow.h" +#include "tinyformat.h" +#include "uint256.h" + +#include + +struct CDiskBlockPos +{ + int nFile; + unsigned int nPos; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nFile)); + READWRITE(VARINT(nPos)); + } + + CDiskBlockPos() { + SetNull(); + } + + CDiskBlockPos(int nFileIn, unsigned int nPosIn) { + nFile = nFileIn; + nPos = nPosIn; + } + + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return (a.nFile == b.nFile && a.nPos == b.nPos); + } + + friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return !(a == b); + } + + void SetNull() { nFile = -1; nPos = 0; } + bool IsNull() const { return (nFile == -1); } + + std::string ToString() const + { + return strprintf("CBlockDiskPos(nFile=%i, nPos=%i)", nFile, nPos); + } + +}; + +enum BlockStatus { + //! Unused. + BLOCK_VALID_UNKNOWN = 0, + + //! Parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future + BLOCK_VALID_HEADER = 1, + + //! All parent headers found, difficulty matches, timestamp >= median previous, checkpoint. Implies all parents + //! are also at least TREE. + BLOCK_VALID_TREE = 2, + + /** + * Only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, + * sigops, size, merkle root. Implies all parents are at least TREE but not necessarily TRANSACTIONS. When all + * parent blocks also have TRANSACTIONS, CBlockIndex::nChainTx will be set. + */ + BLOCK_VALID_TRANSACTIONS = 3, + + //! Outputs do not overspend inputs, no double spends, coinbase output ok, no immature coinbase spends, BIP30. + //! Implies all parents are also at least CHAIN. + BLOCK_VALID_CHAIN = 4, + + //! Scripts & signatures ok. Implies all parents are also at least SCRIPTS. + BLOCK_VALID_SCRIPTS = 5, + + //! All validity bits. + BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | + BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, + + BLOCK_HAVE_DATA = 8, //! full block available in blk*.dat + BLOCK_HAVE_UNDO = 16, //! undo data available in rev*.dat + BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO, + + BLOCK_FAILED_VALID = 32, //! stage after last reached validness failed + BLOCK_FAILED_CHILD = 64, //! descends from failed block + BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, +}; + +/** The block chain is a tree shaped structure starting with the + * genesis block at the root, with each block potentially having multiple + * candidates to be the next block. A blockindex may have multiple pprev pointing + * to it, but at most one of them can be part of the currently active branch. + */ +class CBlockIndex +{ +public: + //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex + const uint256* phashBlock; + + //! pointer to the index of the predecessor of this block + CBlockIndex* pprev; + + //! pointer to the index of some further predecessor of this block + CBlockIndex* pskip; + + //! height of the entry in the chain. The genesis block has height 0 + int nHeight; + + //! Which # file this block is stored in (blk?????.dat) + int nFile; + + //! Byte offset within blk?????.dat where this block's data is stored + unsigned int nDataPos; + + //! Byte offset within rev?????.dat where this block's undo data is stored + unsigned int nUndoPos; + + //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block + arith_uint256 nChainWork; + + //! Number of transactions in this block. + //! Note: in a potential headers-first mode, this number cannot be relied upon + unsigned int nTx; + + //! (memory only) Number of transactions in the chain up to and including this block. + //! This value will be non-zero only if and only if transactions for this block and all its parents are available. + //! Change to 64-bit type when necessary; won't happen before 2030 + unsigned int nChainTx; + + //! Verification status of this block. See enum BlockStatus + unsigned int nStatus; + + //! block header + int nVersion; + /*popchain ghost*/ + uint256 hashUncles;//the hash256 of uncles or uncle block header + uint160 coinbaseAddress;//the autor address of this block header + /*popchain ghost*/ + uint256 hashMerkleRoot; + uint256 hashClaimTrie; + unsigned int nTime; + unsigned int nBits; + uint256 nNonce; + + //! (memory only) Sequential id assigned to distinguish order in which blocks are received. + uint32_t nSequenceId; + + void SetNull() + { + phashBlock = NULL; + pprev = NULL; + pskip = NULL; + nHeight = 0; + nFile = 0; + nDataPos = 0; + nUndoPos = 0; + nChainWork = arith_uint256(); + nTx = 0; + nChainTx = 0; + nStatus = 0; + nSequenceId = 0; + + nVersion = 0; + /*popchain ghost*/ + hashUncles = uint256(); + coinbaseAddress = uint160(); + /*popchain ghost*/ + hashMerkleRoot = uint256(); + hashClaimTrie = uint256(); + nTime = 0; + nBits = 0; + nNonce = uint256(); + } + + CBlockIndex() + { + SetNull(); + } + + CBlockIndex(const CBlockHeader& block) + { + SetNull(); + + nVersion = block.nVersion; + /*popchain ghost*/ + hashUncles = block.hashUncles; + coinbaseAddress = block.coinbaseAddress; + /*popchain ghost*/ + hashMerkleRoot = block.hashMerkleRoot; + hashClaimTrie = block.hashClaimTrie; + nTime = block.nTime; + nBits = block.nBits; + nNonce = block.nNonce; + } + + CDiskBlockPos GetBlockPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_DATA) { + ret.nFile = nFile; + ret.nPos = nDataPos; + } + return ret; + } + + CDiskBlockPos GetUndoPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_UNDO) { + ret.nFile = nFile; + ret.nPos = nUndoPos; + } + return ret; + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + if (pprev) + block.hashPrevBlock = pprev->GetBlockHash(); + /*popchain ghost*/ + block.hashUncles = hashUncles; + block.coinbaseAddress = coinbaseAddress; + /*popchain ghost*/ + block.hashMerkleRoot = hashMerkleRoot; + block.hashClaimTrie = hashClaimTrie; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 GetBlockHash() const + { + return *phashBlock; + } + + int64_t GetBlockTime() const + { + return (int64_t)nTime; + } + + enum { nMedianTimeSpan=11 }; + + int64_t GetMedianTimePast() const + { + int64_t pmedian[nMedianTimeSpan]; + int64_t* pbegin = &pmedian[nMedianTimeSpan]; + int64_t* pend = &pmedian[nMedianTimeSpan]; + + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) + *(--pbegin) = pindex->GetBlockTime(); + + std::sort(pbegin, pend); + return pbegin[(pend - pbegin)/2]; + } + + std::string ToString() const + { + /*popchain ghost*/ + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, merkle=%s, claimtrie=%s, hashBlock=%s)", + pprev, nHeight, + hashUncles.ToString(), + coinbaseAddress.ToString(), + hashMerkleRoot.ToString(), + hashClaimTrie.ToString(), + GetBlockHash().ToString()); + /*popchain ghost*/ + } + + //! Check whether this block index entry is valid up to the passed validity level. + bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); + } + + //! Raise the validity level of this block index entry. + //! Returns true if the validity was changed. + bool RaiseValidity(enum BlockStatus nUpTo) + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + if ((nStatus & BLOCK_VALID_MASK) < nUpTo) { + nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo; + return true; + } + return false; + } + + //! Build the skiplist pointer for this entry. + void BuildSkip(); + + //! Efficiently find an ancestor of this block. + CBlockIndex* GetAncestor(int height); + const CBlockIndex* GetAncestor(int height) const; +}; + +/** Used to marshal pointers into hashes for db storage. */ +class CDiskBlockIndex : public CBlockIndex +{ +public: + uint256 hash; + uint256 hashPrev; + + CDiskBlockIndex() { + hash = uint256(); + hashPrev = uint256(); + } + + explicit CDiskBlockIndex(const CBlockIndex* pindex) : CBlockIndex(*pindex) { + hash = (hash == uint256() ? pindex->GetBlockHash() : hash); + hashPrev = (pprev ? pprev->GetBlockHash() : uint256()); + } + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(VARINT(nVersion)); + + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nStatus)); + READWRITE(VARINT(nTx)); + if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) + READWRITE(VARINT(nFile)); + if (nStatus & BLOCK_HAVE_DATA) + READWRITE(VARINT(nDataPos)); + if (nStatus & BLOCK_HAVE_UNDO) + READWRITE(VARINT(nUndoPos)); + + // block hash + READWRITE(hash); + // block header + READWRITE(this->nVersion); + READWRITE(hashPrev); + /*popchain ghost*/ + READWRITE(hashUncles); + READWRITE(coinbaseAddress); + /*popchain ghost*/ + READWRITE(hashMerkleRoot); + READWRITE(hashClaimTrie); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + } + + uint256 GetBlockHash() const + { + if(hash != uint256()) return hash; + // should never really get here, keeping this as a fallback + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrev; + /*popchain ghost*/ + block.hashUncles = hashUncles; + block.coinbaseAddress = coinbaseAddress; + /*popchain ghost*/ + block.hashMerkleRoot = hashMerkleRoot; + block.hashClaimTrie = hashClaimTrie; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block.GetHash(); + } + + + std::string ToString() const + { + std::string str = "CDiskBlockIndex("; + str += CBlockIndex::ToString(); + str += strprintf("\n hashBlock=%s, hashPrev=%s)", + GetBlockHash().ToString(), + hashPrev.ToString()); + return str; + } +}; + +/** An in-memory indexed chain of blocks. */ +class CChain { +private: + std::vector vChain; + +public: + /** Returns the index entry for the genesis block of this chain, or NULL if none. */ + CBlockIndex *Genesis() const { + return vChain.size() > 0 ? vChain[0] : NULL; + } + + /** Returns the index entry for the tip of this chain, or NULL if none. */ + CBlockIndex *Tip() const { + return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; + } + + /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ + CBlockIndex *operator[](int nHeight) const { + if (nHeight < 0 || nHeight >= (int)vChain.size()) + return NULL; + return vChain[nHeight]; + } + + /** Compare two chains efficiently. */ + friend bool operator==(const CChain &a, const CChain &b) { + return a.vChain.size() == b.vChain.size() && + a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; + } + + /** Efficiently check whether a block is present in this chain. */ + bool Contains(const CBlockIndex *pindex) const { + return (*this)[pindex->nHeight] == pindex; + } + + /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ + CBlockIndex *Next(const CBlockIndex *pindex) const { + if (Contains(pindex)) + return (*this)[pindex->nHeight + 1]; + else + return NULL; + } + + /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ + int Height() const { + return vChain.size() - 1; + } + + /** Set/initialize a chain with a given tip. */ + void SetTip(CBlockIndex *pindex); + + /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ + CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; + + /** Find the last common block between this chain and a block index entry. */ + const CBlockIndex *FindFork(const CBlockIndex *pindex) const; +}; + +#endif // BITCOIN_CHAIN_H From 2fb906ddfd7c30bd25cf542240c6a8bacc4aa20b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 23 Jul 2018 20:10:51 +0800 Subject: [PATCH 004/120] add the block height to block header --- src/chain.h | 11 +++++++++-- src/primitives/block.cpp | 6 ++++-- src/primitives/block.h | 8 ++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/chain.h b/src/chain.h index 263b80f..798a40e 100644 --- a/src/chain.h +++ b/src/chain.h @@ -138,6 +138,7 @@ class CBlockIndex /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 coinbaseAddress;//the autor address of this block header + unsigned int number;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; @@ -167,6 +168,7 @@ class CBlockIndex /*popchain ghost*/ hashUncles = uint256(); coinbaseAddress = uint160(); + number = 0; /*popchain ghost*/ hashMerkleRoot = uint256(); hashClaimTrie = uint256(); @@ -188,6 +190,7 @@ class CBlockIndex /*popchain ghost*/ hashUncles = block.hashUncles; coinbaseAddress = block.coinbaseAddress; + number = block.number; /*popchain ghost*/ hashMerkleRoot = block.hashMerkleRoot; hashClaimTrie = block.hashClaimTrie; @@ -223,6 +226,7 @@ class CBlockIndex /*popchain ghost*/ block.hashUncles = hashUncles; block.coinbaseAddress = coinbaseAddress; + block.number = number; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; @@ -261,10 +265,11 @@ class CBlockIndex std::string ToString() const { /*popchain ghost*/ - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, merkle=%s, claimtrie=%s, hashBlock=%s)", + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, number=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", pprev, nHeight, hashUncles.ToString(), coinbaseAddress.ToString(), + number, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), GetBlockHash().ToString()); @@ -343,7 +348,8 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(hashPrev); /*popchain ghost*/ READWRITE(hashUncles); - READWRITE(coinbaseAddress); + READWRITE(coinbaseAddress); + READWRITE(number); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); @@ -362,6 +368,7 @@ class CDiskBlockIndex : public CBlockIndex /*popchain ghost*/ block.hashUncles = hashUncles; block.coinbaseAddress = coinbaseAddress; + block.number = number; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index a4c6d8b..87e37d2 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -23,12 +23,13 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, coinbaseAddress=%s, number=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(), coinbaseAddress.ToString(),/*change by base58 ?*/ + number, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, nBits, nNonce.ToString()); @@ -39,12 +40,13 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, coinbaseAddress=%s, number=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(),/*popchain ghost*/ coinbaseAddress.ToString(),/*popchain ghost*/ + number,/*popchain ghost*/ hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, nBits, nNonce.ToString(), diff --git a/src/primitives/block.h b/src/primitives/block.h index 4710697..61e8f99 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -24,6 +24,7 @@ class CBlockHeader /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 coinbaseAddress;//the autor address of this block header + uint32_t number;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; // for claim operation @@ -46,6 +47,7 @@ class CBlockHeader /*popchain ghost*/ READWRITE(hashUncles); READWRITE(coinbaseAddress); + READWRITE(number); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); @@ -58,6 +60,11 @@ class CBlockHeader { nVersion = CBlockHeader::CURRENT_VERSION; hashPrevBlock.SetNull(); + /*popchain ghost*/ + hashUncles.SetNull(); + coinbaseAddress.SetNull(); + number=0; + /*popchain ghost*/ hashMerkleRoot.SetNull(); hashClaimTrie.SetNull(); nTime = 0; @@ -135,6 +142,7 @@ class CBlock : public CBlockHeader /*popchain ghost*/ block.hashUncles = hashUncles; block.coinbaseAddress = coinbaseAddress; + block.number = number; /*popchian ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; From 0a2b5c2eb5ce2c9c91eac10e50879c9a985eb0fc Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 24 Jul 2018 10:26:50 +0800 Subject: [PATCH 005/120] add the total difficult data save --- src/txdb.cpp | 716 ++++++++++++++++++++++++++------------------------- src/txdb.h | 170 ++++++------ 2 files changed, 454 insertions(+), 432 deletions(-) diff --git a/src/txdb.cpp b/src/txdb.cpp index 7e7ae5e..60cf89e 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -1,349 +1,367 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "txdb.h" - -#include "chain.h" -#include "chainparams.h" -#include "hash.h" -#include "main.h" -#include "pow.h" -#include "uint256.h" - -#include - -#include - -using namespace std; - -static const char DB_COINS = 'c'; -static const char DB_BLOCK_FILES = 'f'; -static const char DB_TXINDEX = 't'; -static const char DB_ADDRESSINDEX = 'a'; -static const char DB_ADDRESSUNSPENTINDEX = 'u'; -static const char DB_TIMESTAMPINDEX = 's'; -static const char DB_SPENTINDEX = 'p'; -static const char DB_BLOCK_INDEX = 'b'; - -static const char DB_BEST_BLOCK = 'B'; -static const char DB_FLAG = 'F'; -static const char DB_REINDEX_FLAG = 'R'; -static const char DB_LAST_BLOCK = 'l'; - - -CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true) -{ -} - -bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { - return db.Read(make_pair(DB_COINS, txid), coins); -} - -bool CCoinsViewDB::HaveCoins(const uint256 &txid) const { - return db.Exists(make_pair(DB_COINS, txid)); -} - -uint256 CCoinsViewDB::GetBestBlock() const { - uint256 hashBestChain; - if (!db.Read(DB_BEST_BLOCK, hashBestChain)) - return uint256(); - return hashBestChain; -} - -bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { - CDBBatch batch(&db.GetObfuscateKey()); - size_t count = 0; - size_t changed = 0; - for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { - if (it->second.flags & CCoinsCacheEntry::DIRTY) { - if (it->second.coins.IsPruned()) - batch.Erase(make_pair(DB_COINS, it->first)); - else - batch.Write(make_pair(DB_COINS, it->first), it->second.coins); - changed++; - } - count++; - CCoinsMap::iterator itOld = it++; - mapCoins.erase(itOld); - } - if (!hashBlock.IsNull()) - batch.Write(DB_BEST_BLOCK, hashBlock); - - LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); - return db.WriteBatch(batch); -} - -CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { -} - -bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { - return Read(make_pair(DB_BLOCK_FILES, nFile), info); -} - -bool CBlockTreeDB::WriteReindexing(bool fReindexing) { - if (fReindexing) - return Write(DB_REINDEX_FLAG, '1'); - else - return Erase(DB_REINDEX_FLAG); -} - -bool CBlockTreeDB::ReadReindexing(bool &fReindexing) { - fReindexing = Exists(DB_REINDEX_FLAG); - return true; -} - -bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { - return Read(DB_LAST_BLOCK, nFile); -} - -bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { - /* It seems that there are no "const iterators" for LevelDB. Since we - only need read operations on it, use a const-cast to get around - that restriction. */ - boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); - pcursor->Seek(DB_COINS); - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - stats.hashBlock = GetBestBlock(); - ss << stats.hashBlock; - CAmount nTotalAmount = 0; - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - CCoins coins; - if (pcursor->GetKey(key) && key.first == DB_COINS) { - if (pcursor->GetValue(coins)) { - stats.nTransactions++; - for (unsigned int i=0; iGetValueSize(); - ss << VARINT(0); - } else { - return error("CCoinsViewDB::GetStats() : unable to read value"); - } - } else { - break; - } - pcursor->Next(); - } - { - LOCK(cs_main); - stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; - } - stats.hashSerialized = ss.GetHash(); - stats.nTotalAmount = nTotalAmount; - return true; -} - -bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { - batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second); - } - batch.Write(DB_LAST_BLOCK, nLastFile); - for (std::vector::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) { - batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it)); - } - return WriteBatch(batch, true); -} - -bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { - return Read(make_pair(DB_TXINDEX, txid), pos); -} - -bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) - batch.Write(make_pair(DB_TXINDEX, it->first), it->second); - return WriteBatch(batch); -} - -bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) { - return Read(make_pair(DB_SPENTINDEX, key), value); -} - -bool CBlockTreeDB::UpdateSpentIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { - if (it->second.IsNull()) { - batch.Erase(make_pair(DB_SPENTINDEX, it->first)); - } else { - batch.Write(make_pair(DB_SPENTINDEX, it->first), it->second); - } - } - return WriteBatch(batch); -} - -bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { - if (it->second.IsNull()) { - batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first)); - } else { - batch.Write(make_pair(DB_ADDRESSUNSPENTINDEX, it->first), it->second); - } - } - return WriteBatch(batch); -} - -bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type, - std::vector > &unspentOutputs) { - - boost::scoped_ptr pcursor(NewIterator()); - - pcursor->Seek(make_pair(DB_ADDRESSUNSPENTINDEX, CAddressIndexIteratorKey(type, addressHash))); - - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - if (pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.hashBytes == addressHash) { - CAddressUnspentValue nValue; - if (pcursor->GetValue(nValue)) { - unspentOutputs.push_back(make_pair(key.second, nValue)); - pcursor->Next(); - } else { - return error("failed to get address unspent value"); - } - } else { - break; - } - } - - return true; -} - -bool CBlockTreeDB::WriteAddressIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) - batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second); - return WriteBatch(batch); -} - -bool CBlockTreeDB::EraseAddressIndex(const std::vector >&vect) { - CDBBatch batch(&GetObfuscateKey()); - for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) - batch.Erase(make_pair(DB_ADDRESSINDEX, it->first)); - return WriteBatch(batch); -} - -bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, - std::vector > &addressIndex, - int start, int end) { - - boost::scoped_ptr pcursor(NewIterator()); - - if (start > 0 && end > 0) { - pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorHeightKey(type, addressHash, start))); - } else { - pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash))); - } - - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash) { - if (end > 0 && key.second.blockHeight > end) { - break; - } - CAmount nValue; - if (pcursor->GetValue(nValue)) { - addressIndex.push_back(make_pair(key.second, nValue)); - pcursor->Next(); - } else { - return error("failed to get address index value"); - } - } else { - break; - } - } - - return true; -} - -bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) { - CDBBatch batch(&GetObfuscateKey()); - batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0); - return WriteBatch(batch); -} - -bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) { - - boost::scoped_ptr pcursor(NewIterator()); - - pcursor->Seek(make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low))); - - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp <= high) { - hashes.push_back(key.second.blockHash); - pcursor->Next(); - } else { - break; - } - } - - return true; -} - -bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { - return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); -} - -bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { - char ch; - if (!Read(std::make_pair(DB_FLAG, name), ch)) - return false; - fValue = ch == '1'; - return true; -} - -bool CBlockTreeDB::LoadBlockIndexGuts() -{ - boost::scoped_ptr pcursor(NewIterator()); - - pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); - - // Load mapBlockIndex - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - std::pair key; - if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) { - CDiskBlockIndex diskindex; - if (pcursor->GetValue(diskindex)) { - // Construct block index object - CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); - pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); - pindexNew->nHeight = diskindex.nHeight; - pindexNew->nFile = diskindex.nFile; - pindexNew->nDataPos = diskindex.nDataPos; - pindexNew->nUndoPos = diskindex.nUndoPos; - pindexNew->nVersion = diskindex.nVersion; - pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; - pindexNew->hashClaimTrie = diskindex.hashClaimTrie; - pindexNew->nTime = diskindex.nTime; - pindexNew->nBits = diskindex.nBits; - pindexNew->nNonce = diskindex.nNonce; - pindexNew->nStatus = diskindex.nStatus; - pindexNew->nTx = diskindex.nTx; - - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) - return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); - - pcursor->Next(); - } else { - return error("LoadBlockIndex() : failed to read value"); - } - } else { - break; - } - } - - return true; -} +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "txdb.h" + +#include "chain.h" +#include "chainparams.h" +#include "hash.h" +#include "main.h" +#include "pow.h" +#include "uint256.h" + +#include + +#include + +using namespace std; + +static const char DB_COINS = 'c'; +static const char DB_BLOCK_FILES = 'f'; +static const char DB_TXINDEX = 't'; +static const char DB_ADDRESSINDEX = 'a'; +static const char DB_ADDRESSUNSPENTINDEX = 'u'; +static const char DB_TIMESTAMPINDEX = 's'; +static const char DB_SPENTINDEX = 'p'; +static const char DB_BLOCK_INDEX = 'b'; + +static const char DB_BEST_BLOCK = 'B'; +static const char DB_FLAG = 'F'; +static const char DB_REINDEX_FLAG = 'R'; +static const char DB_LAST_BLOCK = 'l'; + +/*popchain ghost*/ +static const char DB_TOTALDIFFICULT = 'd'; +/*popchain ghost*/ + +CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true) +{ +} + +bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { + return db.Read(make_pair(DB_COINS, txid), coins); +} + +bool CCoinsViewDB::HaveCoins(const uint256 &txid) const { + return db.Exists(make_pair(DB_COINS, txid)); +} + +uint256 CCoinsViewDB::GetBestBlock() const { + uint256 hashBestChain; + if (!db.Read(DB_BEST_BLOCK, hashBestChain)) + return uint256(); + return hashBestChain; +} + +bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { + CDBBatch batch(&db.GetObfuscateKey()); + size_t count = 0; + size_t changed = 0; + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { + if (it->second.flags & CCoinsCacheEntry::DIRTY) { + if (it->second.coins.IsPruned()) + batch.Erase(make_pair(DB_COINS, it->first)); + else + batch.Write(make_pair(DB_COINS, it->first), it->second.coins); + changed++; + } + count++; + CCoinsMap::iterator itOld = it++; + mapCoins.erase(itOld); + } + if (!hashBlock.IsNull()) + batch.Write(DB_BEST_BLOCK, hashBlock); + + LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); + return db.WriteBatch(batch); +} + +CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) { +} + +bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) { + return Read(make_pair(DB_BLOCK_FILES, nFile), info); +} + +bool CBlockTreeDB::WriteReindexing(bool fReindexing) { + if (fReindexing) + return Write(DB_REINDEX_FLAG, '1'); + else + return Erase(DB_REINDEX_FLAG); +} + +bool CBlockTreeDB::ReadReindexing(bool &fReindexing) { + fReindexing = Exists(DB_REINDEX_FLAG); + return true; +} + +bool CBlockTreeDB::ReadLastBlockFile(int &nFile) { + return Read(DB_LAST_BLOCK, nFile); +} + +bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { + /* It seems that there are no "const iterators" for LevelDB. Since we + only need read operations on it, use a const-cast to get around + that restriction. */ + boost::scoped_ptr pcursor(const_cast(&db)->NewIterator()); + pcursor->Seek(DB_COINS); + + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + stats.hashBlock = GetBestBlock(); + ss << stats.hashBlock; + CAmount nTotalAmount = 0; + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + CCoins coins; + if (pcursor->GetKey(key) && key.first == DB_COINS) { + if (pcursor->GetValue(coins)) { + stats.nTransactions++; + for (unsigned int i=0; iGetValueSize(); + ss << VARINT(0); + } else { + return error("CCoinsViewDB::GetStats() : unable to read value"); + } + } else { + break; + } + pcursor->Next(); + } + { + LOCK(cs_main); + stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; + } + stats.hashSerialized = ss.GetHash(); + stats.nTotalAmount = nTotalAmount; + return true; +} + +bool CBlockTreeDB::WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) { + batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second); + } + batch.Write(DB_LAST_BLOCK, nLastFile); + for (std::vector::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) { + batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it)); + } + return WriteBatch(batch, true); +} + +bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) { + return Read(make_pair(DB_TXINDEX, txid), pos); +} + +bool CBlockTreeDB::WriteTxIndex(const std::vector >&vect) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Write(make_pair(DB_TXINDEX, it->first), it->second); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) { + return Read(make_pair(DB_SPENTINDEX, key), value); +} + +bool CBlockTreeDB::UpdateSpentIndex(const std::vector >&vect) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { + if (it->second.IsNull()) { + batch.Erase(make_pair(DB_SPENTINDEX, it->first)); + } else { + batch.Write(make_pair(DB_SPENTINDEX, it->first), it->second); + } + } + return WriteBatch(batch); +} + +bool CBlockTreeDB::UpdateAddressUnspentIndex(const std::vector >&vect) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) { + if (it->second.IsNull()) { + batch.Erase(make_pair(DB_ADDRESSUNSPENTINDEX, it->first)); + } else { + batch.Write(make_pair(DB_ADDRESSUNSPENTINDEX, it->first), it->second); + } + } + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadAddressUnspentIndex(uint160 addressHash, int type, + std::vector > &unspentOutputs) { + + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_ADDRESSUNSPENTINDEX, CAddressIndexIteratorKey(type, addressHash))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_ADDRESSUNSPENTINDEX && key.second.hashBytes == addressHash) { + CAddressUnspentValue nValue; + if (pcursor->GetValue(nValue)) { + unspentOutputs.push_back(make_pair(key.second, nValue)); + pcursor->Next(); + } else { + return error("failed to get address unspent value"); + } + } else { + break; + } + } + + return true; +} + +bool CBlockTreeDB::WriteAddressIndex(const std::vector >&vect) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Write(make_pair(DB_ADDRESSINDEX, it->first), it->second); + return WriteBatch(batch); +} + +bool CBlockTreeDB::EraseAddressIndex(const std::vector >&vect) { + CDBBatch batch(&GetObfuscateKey()); + for (std::vector >::const_iterator it=vect.begin(); it!=vect.end(); it++) + batch.Erase(make_pair(DB_ADDRESSINDEX, it->first)); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start, int end) { + + boost::scoped_ptr pcursor(NewIterator()); + + if (start > 0 && end > 0) { + pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorHeightKey(type, addressHash, start))); + } else { + pcursor->Seek(make_pair(DB_ADDRESSINDEX, CAddressIndexIteratorKey(type, addressHash))); + } + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_ADDRESSINDEX && key.second.hashBytes == addressHash) { + if (end > 0 && key.second.blockHeight > end) { + break; + } + CAmount nValue; + if (pcursor->GetValue(nValue)) { + addressIndex.push_back(make_pair(key.second, nValue)); + pcursor->Next(); + } else { + return error("failed to get address index value"); + } + } else { + break; + } + } + + return true; +} + +bool CBlockTreeDB::WriteTimestampIndex(const CTimestampIndexKey ×tampIndex) { + CDBBatch batch(&GetObfuscateKey()); + batch.Write(make_pair(DB_TIMESTAMPINDEX, timestampIndex), 0); + return WriteBatch(batch); +} + +bool CBlockTreeDB::ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) { + + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_TIMESTAMPINDEX, CTimestampIndexIteratorKey(low))); + + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_TIMESTAMPINDEX && key.second.timestamp <= high) { + hashes.push_back(key.second.blockHash); + pcursor->Next(); + } else { + break; + } + } + + return true; +} + +bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) { + return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0'); +} + +bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) { + char ch; + if (!Read(std::make_pair(DB_FLAG, name), ch)) + return false; + fValue = ch == '1'; + return true; +} + +bool CBlockTreeDB::LoadBlockIndexGuts() +{ + boost::scoped_ptr pcursor(NewIterator()); + + pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); + + // Load mapBlockIndex + while (pcursor->Valid()) { + boost::this_thread::interruption_point(); + std::pair key; + if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) { + CDiskBlockIndex diskindex; + if (pcursor->GetValue(diskindex)) { + // Construct block index object + CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash()); + pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); + pindexNew->nHeight = diskindex.nHeight; + pindexNew->nFile = diskindex.nFile; + pindexNew->nDataPos = diskindex.nDataPos; + pindexNew->nUndoPos = diskindex.nUndoPos; + pindexNew->nVersion = diskindex.nVersion; + pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; + pindexNew->hashClaimTrie = diskindex.hashClaimTrie; + pindexNew->nTime = diskindex.nTime; + pindexNew->nBits = diskindex.nBits; + pindexNew->nNonce = diskindex.nNonce; + pindexNew->nStatus = diskindex.nStatus; + pindexNew->nTx = diskindex.nTx; + + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) + return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); + + pcursor->Next(); + } else { + return error("LoadBlockIndex() : failed to read value"); + } + } else { + break; + } + } + + return true; +} + + +bool CBlockTreeDB::WriteTd(const uint256 &hash, uint256 td) +{ + return Write(std::make_pair(DB_TOTALDIFFICULT, hash), td); + +} +bool CBlockTreeDB::ReadTd(const uint256 &hash, uint256 &td) +{ + if (!Read(std::make_pair(DB_TOTALDIFFICULT, hash), td)) + return false; + return true; +} + + diff --git a/src/txdb.h b/src/txdb.h index 12388ab..2dbd7d6 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -1,83 +1,87 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#ifndef BITCOIN_TXDB_H -#define BITCOIN_TXDB_H - -#include "coins.h" -#include "dbwrapper.h" - -#include -#include -#include -#include - -class CBlockFileInfo; -class CBlockIndex; -struct CDiskTxPos; -struct CAddressUnspentKey; -struct CAddressUnspentValue; -struct CAddressIndexKey; -struct CAddressIndexIteratorKey; -struct CAddressIndexIteratorHeightKey; -struct CTimestampIndexKey; -struct CTimestampIndexIteratorKey; -struct CSpentIndexKey; -struct CSpentIndexValue; -class uint256; - -//! -dbcache default (MiB) -static const int64_t nDefaultDbCache = 100; -//! max. -dbcache in (MiB) -static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; -//! min. -dbcache in (MiB) -static const int64_t nMinDbCache = 4; - -/** CCoinsView backed by the coin database (chainstate/) */ -class CCoinsViewDB : public CCoinsView -{ -protected: - CDBWrapper db; -public: - CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - - bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool HaveCoins(const uint256 &txid) const; - uint256 GetBestBlock() const; - bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); - bool GetStats(CCoinsStats &stats) const; -}; - -/** Access to the block database (blocks/index/) */ -class CBlockTreeDB : public CDBWrapper -{ -public: - CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); -private: - CBlockTreeDB(const CBlockTreeDB&); - void operator=(const CBlockTreeDB&); -public: - bool WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo); - bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo); - bool ReadLastBlockFile(int &nFile); - bool WriteReindexing(bool fReindex); - bool ReadReindexing(bool &fReindex); - bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); - bool WriteTxIndex(const std::vector > &list); - bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); - bool UpdateSpentIndex(const std::vector >&vect); - bool UpdateAddressUnspentIndex(const std::vector >&vect); - bool ReadAddressUnspentIndex(uint160 addressHash, int type, - std::vector > &vect); - bool WriteAddressIndex(const std::vector > &vect); - bool EraseAddressIndex(const std::vector > &vect); - bool ReadAddressIndex(uint160 addressHash, int type, - std::vector > &addressIndex, - int start = 0, int end = 0); - bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); - bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &vect); - bool WriteFlag(const std::string &name, bool fValue); - bool ReadFlag(const std::string &name, bool &fValue); - bool LoadBlockIndexGuts(); -}; - -#endif // BITCOIN_TXDB_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_TXDB_H +#define BITCOIN_TXDB_H + +#include "coins.h" +#include "dbwrapper.h" + +#include +#include +#include +#include + +class CBlockFileInfo; +class CBlockIndex; +struct CDiskTxPos; +struct CAddressUnspentKey; +struct CAddressUnspentValue; +struct CAddressIndexKey; +struct CAddressIndexIteratorKey; +struct CAddressIndexIteratorHeightKey; +struct CTimestampIndexKey; +struct CTimestampIndexIteratorKey; +struct CSpentIndexKey; +struct CSpentIndexValue; +class uint256; + +//! -dbcache default (MiB) +static const int64_t nDefaultDbCache = 100; +//! max. -dbcache in (MiB) +static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024; +//! min. -dbcache in (MiB) +static const int64_t nMinDbCache = 4; + +/** CCoinsView backed by the coin database (chainstate/) */ +class CCoinsViewDB : public CCoinsView +{ +protected: + CDBWrapper db; +public: + CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); + + bool GetCoins(const uint256 &txid, CCoins &coins) const; + bool HaveCoins(const uint256 &txid) const; + uint256 GetBestBlock() const; + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); + bool GetStats(CCoinsStats &stats) const; +}; + +/** Access to the block database (blocks/index/) */ +class CBlockTreeDB : public CDBWrapper +{ +public: + CBlockTreeDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); +private: + CBlockTreeDB(const CBlockTreeDB&); + void operator=(const CBlockTreeDB&); +public: + bool WriteBatchSync(const std::vector >& fileInfo, int nLastFile, const std::vector& blockinfo); + bool ReadBlockFileInfo(int nFile, CBlockFileInfo &fileinfo); + bool ReadLastBlockFile(int &nFile); + bool WriteReindexing(bool fReindex); + bool ReadReindexing(bool &fReindex); + bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos); + bool WriteTxIndex(const std::vector > &list); + bool ReadSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); + bool UpdateSpentIndex(const std::vector >&vect); + bool UpdateAddressUnspentIndex(const std::vector >&vect); + bool ReadAddressUnspentIndex(uint160 addressHash, int type, + std::vector > &vect); + bool WriteAddressIndex(const std::vector > &vect); + bool EraseAddressIndex(const std::vector > &vect); + bool ReadAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start = 0, int end = 0); + bool WriteTimestampIndex(const CTimestampIndexKey ×tampIndex); + bool ReadTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &vect); + bool WriteFlag(const std::string &name, bool fValue); + bool ReadFlag(const std::string &name, bool &fValue); + bool LoadBlockIndexGuts(); + /*popchain ghost*/ + bool WriteTd(const uint256 &hash, uint256 td); + bool ReadTd(const uint256 &hash, uint256 &td) ; + /*popchain ghost*/ +}; + +#endif // BITCOIN_TXDB_H From fafe0f66987b692a333bfdaee03c8cb2b8fec5c4 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 25 Jul 2018 20:05:53 +0800 Subject: [PATCH 006/120] add the work of accept uncles block headers --- src/main.cpp | 14097 +++++++++++++++++++++++++------------------------ 1 file changed, 7070 insertions(+), 7027 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0414fe8..2e0cfd1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7027 +1,7070 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "main.h" - -#include "nameclaim.h" -#include "addrman.h" -#include "alert.h" -#include "arith_uint256.h" -#include "chainparams.h" -#include "checkpoints.h" -#include "checkqueue.h" -#include "consensus/consensus.h" -#include "consensus/merkle.h" -#include "consensus/validation.h" -#include "hash.h" -#include "init.h" -#include "merkleblock.h" -#include "net.h" -#include "policy/policy.h" -#include "pow.h" -#include "primitives/block.h" -#include "primitives/transaction.h" -#include "script/script.h" -#include "script/sigcache.h" -#include "script/standard.h" -#include "tinyformat.h" -#include "txdb.h" -#include "txmempool.h" -#include "ui_interface.h" -#include "undo.h" -#include "util.h" -#include "spork.h" -#include "utilmoneystr.h" -#include "utilstrencodings.h" -#include "validationinterface.h" -#include "versionbits.h" - -#include "darksend.h" -#include "instantx.h" -#include "popnode-payments.h" -#include "popnode-sync.h" -#include "popnodeman.h" - -#include - -#include -#include -#include -#include -#include -#include - -using namespace std; - -#if defined(NDEBUG) -# error "Pop Core cannot be compiled without assertions." -#endif - -/** - * Global state - */ - -CCriticalSection cs_main; - -BlockMap mapBlockIndex; -CChain chainActive; -CBlockIndex *pindexBestHeader = NULL; -int64_t nTimeBestReceived = 0; -CWaitableCriticalSection csBestBlock; -CConditionVariable cvBlockChange; -int nScriptCheckThreads = 0; -bool fImporting = false; -bool fReindex = false; -bool fTxIndex = true; -bool fAddressIndex = false; -bool fTimestampIndex = false; -bool fSpentIndex = false; -bool fHavePruned = false; -bool fPruneMode = false; -bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG; -bool fRequireStandard = true; -unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; -bool fCheckBlockIndex = false; -bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; -size_t nCoinCacheUsage = 5000 * 300; -uint64_t nPruneTarget = 0; -bool fAlerts = DEFAULT_ALERTS; -bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; - -/** Fees smaller than this (in duffs) are considered zero fee (for relaying, mining and transaction creation) */ -CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); - -CTxMemPool mempool(::minRelayTxFee); - -struct COrphanTx { - CTransaction tx; - NodeId fromPeer; -}; -map mapOrphanTransactions GUARDED_BY(cs_main);; -map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; -map mapRejectedBlocks GUARDED_BY(cs_main); -void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - -/** - * Returns true if there are nRequired or more blocks of minVersion or above - * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. - */ -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); -static void CheckBlockIndex(const Consensus::Params& consensusParams); - -/** Constant stuff for coinbase transactions we create: */ -CScript COINBASE_FLAGS; - -const string strMessageMagic = "Pop Signed Message:\n"; - -// Internal stuff -namespace { - - struct CBlockIndexWorkComparator - { - bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { - // First sort by most total work, ... - if (pa->nChainWork > pb->nChainWork) return false; - if (pa->nChainWork < pb->nChainWork) return true; - - // ... then by earliest time received, ... - if (pa->nSequenceId < pb->nSequenceId) return false; - if (pa->nSequenceId > pb->nSequenceId) return true; - - // Use pointer address as tie breaker (should only happen with blocks - // loaded from disk, as those all have id 0). - if (pa < pb) return false; - if (pa > pb) return true; - - // Identical blocks. - return false; - } - }; - - CBlockIndex *pindexBestInvalid; - - /** - * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and - * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be - * missing the data for the block. - */ - set setBlockIndexCandidates; - /** Number of nodes with fSyncStarted. */ - int nSyncStarted = 0; - /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. - * Pruned nodes may have entries where B is missing data. - */ - multimap mapBlocksUnlinked; - - CCriticalSection cs_LastBlockFile; - std::vector vinfoBlockFile; - int nLastBlockFile = 0; - /** Global flag to indicate we should check to see if there are - * block/undo files that should be deleted. Set on startup - * or if we allocate more file space when we're in prune mode - */ - bool fCheckForPruning = false; - - /** - * Every received block is assigned a unique and increasing identifier, so we - * know which one to give priority in case of a fork. - */ - CCriticalSection cs_nBlockSequenceId; - /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ - uint32_t nBlockSequenceId = 1; - - /** - * Sources of received blocks, saved to be able to send them reject - * messages or ban them when processing happens afterwards. Protected by - * cs_main. - */ - map mapBlockSource; - - /** - * Filter for transactions that were recently rejected by - * AcceptToMemoryPool. These are not rerequested until the chain tip - * changes, at which point the entire filter is reset. Protected by - * cs_main. - * - * Without this filter we'd be re-requesting txs from each of our peers, - * increasing bandwidth consumption considerably. For instance, with 100 - * peers, half of which relay a tx we don't accept, that might be a 50x - * bandwidth increase. A flooding attacker attempting to roll-over the - * filter using minimum-sized, 60byte, transactions might manage to send - * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a - * two minute window to send invs to us. - * - * Decreasing the false positive rate is fairly cheap, so we pick one in a - * million to make it highly unlikely for users to have issues with this - * filter. - * - * Memory used: 1.7MB - */ - boost::scoped_ptr recentRejects; - uint256 hashRecentRejectsChainTip; - - /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ - struct QueuedBlock { - uint256 hash; - CBlockIndex* pindex; //!< Optional. - bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. - }; - map::iterator> > mapBlocksInFlight; - - /** Number of preferable block download peers. */ - int nPreferredDownload = 0; - - /** Dirty block index entries. */ - set setDirtyBlockIndex; - - /** Dirty block file entries. */ - set setDirtyFileInfo; - - /** Number of peers from which we're downloading blocks. */ - int nPeersWithValidatedDownloads = 0; -} // anon namespace - -////////////////////////////////////////////////////////////////////////////// -// -// Registration of network node signals. -// - -namespace { - -struct CBlockReject { - unsigned char chRejectCode; - string strRejectReason; - uint256 hashBlock; -}; - -/** - * Maintain validation-specific state about nodes, protected by cs_main, instead - * by CNode's own locks. This simplifies asynchronous operation, where - * processing of incoming data is done after the ProcessMessage call returns, - * and we're no longer holding the node's locks. - */ -struct CNodeState { - //! The peer's address - CService address; - //! Whether we have a fully established connection. - bool fCurrentlyConnected; - //! Accumulated misbehaviour score for this peer. - int nMisbehavior; - //! Whether this peer should be disconnected and banned (unless whitelisted). - bool fShouldBan; - //! String name of this peer (debugging/logging purposes). - std::string name; - //! List of asynchronously-determined block rejections to notify this peer about. - std::vector rejects; - //! The best known block we know this peer has announced. - CBlockIndex *pindexBestKnownBlock; - //! The hash of the last unknown block this peer has announced. - uint256 hashLastUnknownBlock; - //! The last full block we both have. - CBlockIndex *pindexLastCommonBlock; - //! The best header we have sent our peer. - CBlockIndex *pindexBestHeaderSent; - //! Whether we've started headers synchronization with this peer. - bool fSyncStarted; - //! Since when we're stalling block download progress (in microseconds), or 0. - int64_t nStallingSince; - list vBlocksInFlight; - //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty. - int64_t nDownloadingSince; - int nBlocksInFlight; - int nBlocksInFlightValidHeaders; - //! Whether we consider this a preferred download peer. - bool fPreferredDownload; - //! Whether this peer wants invs or headers (when possible) for block announcements. - bool fPreferHeaders; - - CNodeState() { - fCurrentlyConnected = false; - nMisbehavior = 0; - fShouldBan = false; - pindexBestKnownBlock = NULL; - hashLastUnknownBlock.SetNull(); - pindexLastCommonBlock = NULL; - pindexBestHeaderSent = NULL; - fSyncStarted = false; - nStallingSince = 0; - nDownloadingSince = 0; - nBlocksInFlight = 0; - nBlocksInFlightValidHeaders = 0; - fPreferredDownload = false; - fPreferHeaders = false; - } -}; - -/** Map maintaining per-node state. Requires cs_main. */ -map mapNodeState; - -// Requires cs_main. -CNodeState *State(NodeId pnode) { - map::iterator it = mapNodeState.find(pnode); - if (it == mapNodeState.end()) - return NULL; - return &it->second; -} - -int GetHeight() -{ - LOCK(cs_main); - return chainActive.Height(); -} - -void UpdatePreferredDownload(CNode* node, CNodeState* state) -{ - nPreferredDownload -= state->fPreferredDownload; - - // Whether this node should be marked as a preferred download node. - state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; - - nPreferredDownload += state->fPreferredDownload; -} - -void InitializeNode(NodeId nodeid, const CNode *pnode) { - LOCK(cs_main); - CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; - state.name = pnode->addrName; - state.address = pnode->addr; -} - -void FinalizeNode(NodeId nodeid) { - LOCK(cs_main); - CNodeState *state = State(nodeid); - - if (state->fSyncStarted) - nSyncStarted--; - - if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { - AddressCurrentlyConnected(state->address); - } - - BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { - mapBlocksInFlight.erase(entry.hash); - } - EraseOrphansFor(nodeid); - nPreferredDownload -= state->fPreferredDownload; - nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); - assert(nPeersWithValidatedDownloads >= 0); - - mapNodeState.erase(nodeid); - - if (mapNodeState.empty()) { - // Do a consistency check after the last peer is removed. - assert(mapBlocksInFlight.empty()); - assert(nPreferredDownload == 0); - assert(nPeersWithValidatedDownloads == 0); - } -} - -// Requires cs_main. -// Returns a bool indicating whether we requested this block. -bool MarkBlockAsReceived(const uint256& hash) { - map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); - if (itInFlight != mapBlocksInFlight.end()) { - CNodeState *state = State(itInFlight->second.first); - state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; - if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { - // Last validated block on the queue was received. - nPeersWithValidatedDownloads--; - } - if (state->vBlocksInFlight.begin() == itInFlight->second.second) { - // First block on the queue was received, update the start download time for the next one - state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); - } - state->vBlocksInFlight.erase(itInFlight->second.second); - state->nBlocksInFlight--; - state->nStallingSince = 0; - mapBlocksInFlight.erase(itInFlight); - return true; - } - return false; -} - -// Requires cs_main. -void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - // Make sure it's not listed somewhere already. - MarkBlockAsReceived(hash); - - QueuedBlock newentry = {hash, pindex, pindex != NULL}; - list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); - state->nBlocksInFlight++; - state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; - if (state->nBlocksInFlight == 1) { - // We're starting a block download (batch) from this peer. - state->nDownloadingSince = GetTimeMicros(); - } - if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) { - nPeersWithValidatedDownloads++; - } - mapBlocksInFlight[hash] = std::make_pair(nodeid, it); -} - -/** Check whether the last unknown block a peer advertised is not yet known. */ -void ProcessBlockAvailability(NodeId nodeid) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - if (!state->hashLastUnknownBlock.IsNull()) { - BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); - if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { - if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) - state->pindexBestKnownBlock = itOld->second; - state->hashLastUnknownBlock.SetNull(); - } - } -} - -/** Update tracking information about which blocks a peer is assumed to have. */ -void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { - CNodeState *state = State(nodeid); - assert(state != NULL); - - ProcessBlockAvailability(nodeid); - - BlockMap::iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { - // An actually better block was announced. - if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) - state->pindexBestKnownBlock = it->second; - } else { - // An unknown block was announced; just assume that the latest one is the best one. - state->hashLastUnknownBlock = hash; - } -} - -// Requires cs_main -bool CanDirectFetch(const Consensus::Params &consensusParams) -{ - return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; -} - -// Requires cs_main -bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex) -{ - if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) - return true; - if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) - return true; - return false; -} - -/** Find the last common ancestor two blocks have. - * Both pa and pb must be non-NULL. */ -CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { - if (pa->nHeight > pb->nHeight) { - pa = pa->GetAncestor(pb->nHeight); - } else if (pb->nHeight > pa->nHeight) { - pb = pb->GetAncestor(pa->nHeight); - } - - while (pa != pb && pa && pb) { - pa = pa->pprev; - pb = pb->pprev; - } - - // Eventually all chain branches meet at the genesis block. - assert(pa == pb); - return pa; -} - -/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has - * at most count entries. */ -void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller) { - if (count == 0) - return; - - vBlocks.reserve(vBlocks.size() + count); - CNodeState *state = State(nodeid); - assert(state != NULL); - - // Make sure pindexBestKnownBlock is up to date, we'll need it. - ProcessBlockAvailability(nodeid); - - if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { - // This peer has nothing interesting. - return; - } - - if (state->pindexLastCommonBlock == NULL) { - // Bootstrap quickly by guessing a parent of our best tip is the forking point. - // Guessing wrong in either direction is not a problem. - state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; - } - - // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor - // of its current tip anymore. Go back enough to fix that. - state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); - if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) - return; - - std::vector vToFetch; - CBlockIndex *pindexWalk = state->pindexLastCommonBlock; - // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last - // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to - // download that next block if the window were 1 larger. - int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW; - int nMaxHeight = std::min(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1); - NodeId waitingfor = -1; - while (pindexWalk->nHeight < nMaxHeight) { - // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards - // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive - // as iterating over ~100 CBlockIndex* entries anyway. - int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max(count - vBlocks.size(), 128)); - vToFetch.resize(nToFetch); - pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch); - vToFetch[nToFetch - 1] = pindexWalk; - for (unsigned int i = nToFetch - 1; i > 0; i--) { - vToFetch[i - 1] = vToFetch[i]->pprev; - } - - // Iterate over those blocks in vToFetch (in forward direction), adding the ones that - // are not yet downloaded and not in flight to vBlocks. In the mean time, update - // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's - // already part of our chain (and therefore don't need it even if pruned). - BOOST_FOREACH(CBlockIndex* pindex, vToFetch) { - if (!pindex->IsValid(BLOCK_VALID_TREE)) { - // We consider the chain that this peer is on invalid. - return; - } - if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { - if (pindex->nChainTx) - state->pindexLastCommonBlock = pindex; - } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { - // The block is not already downloaded, and not yet in flight. - if (pindex->nHeight > nWindowEnd) { - // We reached the end of the window. - if (vBlocks.size() == 0 && waitingfor != nodeid) { - // We aren't able to fetch anything, but we would be if the download window was one larger. - nodeStaller = waitingfor; - } - return; - } - vBlocks.push_back(pindex); - if (vBlocks.size() == count) { - return; - } - } else if (waitingfor == -1) { - // This is the first already-in-flight block. - waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first; - } - } - } -} - -} // anon namespace - -bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { - LOCK(cs_main); - CNodeState *state = State(nodeid); - if (state == NULL) - return false; - stats.nMisbehavior = state->nMisbehavior; - stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; - stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; - BOOST_FOREACH(const QueuedBlock& queue, state->vBlocksInFlight) { - if (queue.pindex) - stats.vHeightInFlight.push_back(queue.pindex->nHeight); - } - return true; -} - -void RegisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.GetHeight.connect(&GetHeight); - nodeSignals.ProcessMessages.connect(&ProcessMessages); - nodeSignals.SendMessages.connect(&SendMessages); - nodeSignals.InitializeNode.connect(&InitializeNode); - nodeSignals.FinalizeNode.connect(&FinalizeNode); -} - -void UnregisterNodeSignals(CNodeSignals& nodeSignals) -{ - nodeSignals.GetHeight.disconnect(&GetHeight); - nodeSignals.ProcessMessages.disconnect(&ProcessMessages); - nodeSignals.SendMessages.disconnect(&SendMessages); - nodeSignals.InitializeNode.disconnect(&InitializeNode); - nodeSignals.FinalizeNode.disconnect(&FinalizeNode); -} - -CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) -{ - // Find the first block the caller has in the main chain - BOOST_FOREACH(const uint256& hash, locator.vHave) { - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*mi).second; - if (chain.Contains(pindex)) - return pindex; - } - } - return chain.Genesis(); -} - -CCoinsViewCache *pcoinsTip = NULL; -CClaimTrie *pclaimTrie = NULL; // claim operation -CBlockTreeDB *pblocktree = NULL; - -////////////////////////////////////////////////////////////////////////////// -// -// mapOrphanTransactions -// - -bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - uint256 hash = tx.GetHash(); - if (mapOrphanTransactions.count(hash)) - return false; - - // Ignore big transactions, to avoid a - // send-big-orphans memory exhaustion attack. If a peer has a legitimate - // large transaction with a missing parent then we assume - // it will rebroadcast it later, after the parent transaction(s) - // have been mined or received. - // 10,000 orphans, each of which is at most 5,000 bytes big is - // at most 500 megabytes of orphans: - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz > 5000) - { - LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); - return false; - } - - mapOrphanTransactions[hash].tx = tx; - mapOrphanTransactions[hash].fromPeer = peer; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); - - LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), - mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); - return true; -} - -void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - map::iterator it = mapOrphanTransactions.find(hash); - if (it == mapOrphanTransactions.end()) - return; - BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) - { - map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); - if (itPrev == mapOrphanTransactionsByPrev.end()) - continue; - itPrev->second.erase(hash); - if (itPrev->second.empty()) - mapOrphanTransactionsByPrev.erase(itPrev); - } - mapOrphanTransactions.erase(it); -} - -void EraseOrphansFor(NodeId peer) -{ - int nErased = 0; - map::iterator iter = mapOrphanTransactions.begin(); - while (iter != mapOrphanTransactions.end()) - { - map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid - if (maybeErase->second.fromPeer == peer) - { - EraseOrphanTx(maybeErase->second.tx.GetHash()); - ++nErased; - } - } - if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); -} - - -unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - unsigned int nEvicted = 0; - while (mapOrphanTransactions.size() > nMaxOrphans) - { - // Evict a random orphan: - uint256 randomhash = GetRandHash(); - map::iterator it = mapOrphanTransactions.lower_bound(randomhash); - if (it == mapOrphanTransactions.end()) - it = mapOrphanTransactions.begin(); - EraseOrphanTx(it->first); - ++nEvicted; - } - return nEvicted; -} - -bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) -{ - if (tx.nLockTime == 0) - return true; - if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) - return true; - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) - return false; - } - return true; -} - -bool CheckFinalTx(const CTransaction &tx, int flags) -{ - AssertLockHeld(cs_main); - - // By convention a negative value for flags indicates that the - // current network-enforced consensus rules should be used. In - // a future soft-fork scenario that would mean checking which - // rules would be enforced for the next block and setting the - // appropriate flags. At the present time no soft-forks are - // scheduled, so no flags are set. - flags = std::max(flags, 0); - - // CheckFinalTx() uses chainActive.Height()+1 to evaluate - // nLockTime because when IsFinalTx() is called within - // CBlock::AcceptBlock(), the height of the block *being* - // evaluated is what is used. Thus if we want to know if a - // transaction can be part of the *next* block, we need to call - // IsFinalTx() with one more than chainActive.Height(). - const int nBlockHeight = chainActive.Height() + 1; - - // BIP113 will require that time-locked transactions have nLockTime set to - // less than the median time of the previous block they're contained in. - // When the next block is created its previous block will be the current - // chain tip, so we use that to calculate the median time passed to - // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. - const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) - ? chainActive.Tip()->GetMedianTimePast() - : GetAdjustedTime(); - - return IsFinalTx(tx, nBlockHeight, nBlockTime); -} - -/** - * Calculates the block height and previous block's median time past at - * which the transaction will be considered final in the context of BIP 68. - * Also removes from the vector of input heights any entries which did not - * correspond to sequence locked inputs as they do not affect the calculation. - */ -static std::pair CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) -{ - assert(prevHeights->size() == tx.vin.size()); - - // Will be set to the equivalent height- and time-based nLockTime - // values that would be necessary to satisfy all relative lock- - // time constraints given our view of block chain history. - // The semantics of nLockTime are the last invalid height/time, so - // use -1 to have the effect of any height or time being valid. - int nMinHeight = -1; - int64_t nMinTime = -1; - - // tx.nVersion is signed integer so requires cast to unsigned otherwise - // we would be doing a signed comparison and half the range of nVersion - // wouldn't support BIP 68. - bool fEnforceBIP68 = static_cast(tx.nVersion) >= 2 - && flags & LOCKTIME_VERIFY_SEQUENCE; - - // Do not enforce sequence numbers as a relative lock time - // unless we have been instructed to - if (!fEnforceBIP68) { - return std::make_pair(nMinHeight, nMinTime); - } - - for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { - const CTxIn& txin = tx.vin[txinIndex]; - - // Sequence numbers with the most significant bit set are not - // treated as relative lock-times, nor are they given any - // consensus-enforced meaning at this point. - if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { - // The height of this input is not relevant for sequence locks - (*prevHeights)[txinIndex] = 0; - continue; - } - - int nCoinHeight = (*prevHeights)[txinIndex]; - - if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) { - int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast(); - // NOTE: Subtract 1 to maintain nLockTime semantics - // BIP 68 relative lock times have the semantics of calculating - // the first block or time at which the transaction would be - // valid. When calculating the effective block time or height - // for the entire transaction, we switch to using the - // semantics of nLockTime which is the last invalid block - // time or height. Thus we subtract 1 from the calculated - // time or height. - - // Time-based relative lock-times are measured from the - // smallest allowed timestamp of the block containing the - // txout being spent, which is the median time past of the - // block prior. - nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1); - } else { - nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1); - } - } - - return std::make_pair(nMinHeight, nMinTime); -} - -static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair lockPair) -{ - assert(block.pprev); - int64_t nBlockTime = block.pprev->GetMedianTimePast(); - if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime) - return false; - - return true; -} - -bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) -{ - return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); -} - -bool TestLockPointValidity(const LockPoints* lp) -{ - AssertLockHeld(cs_main); - assert(lp); - // If there are relative lock times then the maxInputBlock will be set - // If there are no relative lock times, the LockPoints don't depend on the chain - if (lp->maxInputBlock) { - // Check whether chainActive is an extension of the block at which the LockPoints - // calculation was valid. If not LockPoints are no longer valid - if (!chainActive.Contains(lp->maxInputBlock)) { - return false; - } - } - - // LockPoints still valid - return true; -} - -bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) -{ - AssertLockHeld(cs_main); - AssertLockHeld(mempool.cs); - - CBlockIndex* tip = chainActive.Tip(); - CBlockIndex index; - index.pprev = tip; - // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate - // height based locks because when SequenceLocks() is called within - // ConnectBlock(), the height of the block *being* - // evaluated is what is used. - // Thus if we want to know if a transaction can be part of the - // *next* block, we need to use one more than chainActive.Height() - index.nHeight = tip->nHeight + 1; - - std::pair lockPair; - if (useExistingLockPoints) { - assert(lp); - lockPair.first = lp->height; - lockPair.second = lp->time; - } - else { - // pcoinsTip contains the UTXO set for chainActive.Tip() - CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); - std::vector prevheights; - prevheights.resize(tx.vin.size()); - for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { - const CTxIn& txin = tx.vin[txinIndex]; - CCoins coins; - if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) { - return error("%s: Missing input", __func__); - } - if (coins.nHeight == MEMPOOL_HEIGHT) { - // Assume all mempool transaction confirm in the next block - prevheights[txinIndex] = tip->nHeight + 1; - } else { - prevheights[txinIndex] = coins.nHeight; - } - } - lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); - if (lp) { - lp->height = lockPair.first; - lp->time = lockPair.second; - // Also store the hash of the block with the highest height of - // all the blocks which have sequence locked prevouts. - // This hash needs to still be on the chain - // for these LockPoint calculations to be valid - // Note: It is impossible to correctly calculate a maxInputBlock - // if any of the sequence locked inputs depend on unconfirmed txs, - // except in the special case where the relative lock time/height - // is 0, which is equivalent to no sequence lock. Since we assume - // input height of tip+1 for mempool txs and test the resulting - // lockPair from CalculateSequenceLocks against tip+1. We know - // EvaluateSequenceLocks will fail if there was a non-zero sequence - // lock on a mempool input, so we can use the return value of - // CheckSequenceLocks to indicate the LockPoints validity - int maxInputHeight = 0; - BOOST_FOREACH(int height, prevheights) { - // Can ignore mempool inputs since we'll fail if they had non-zero locks - if (height != tip->nHeight+1) { - maxInputHeight = std::max(maxInputHeight, height); - } - } - lp->maxInputBlock = tip->GetAncestor(maxInputHeight); - } - } - return EvaluateSequenceLocks(index, lockPair); -} - - -unsigned int GetLegacySigOpCount(const CTransaction& tx) -{ - unsigned int nSigOps = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - nSigOps += txin.scriptSig.GetSigOpCount(false); - } - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - nSigOps += txout.scriptPubKey.GetSigOpCount(false); - } - return nSigOps; -} - -unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) -{ - if (tx.IsCoinBase()) - return 0; - - unsigned int nSigOps = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); - if (prevout.scriptPubKey.IsPayToScriptHash()) - nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); - } - return nSigOps; -} - -int GetUTXOHeight(const COutPoint& outpoint) -{ - LOCK(cs_main); - CCoins coins; - if(!pcoinsTip->GetCoins(outpoint.hash, coins) || - (unsigned int)outpoint.n>=coins.vout.size() || - coins.vout[outpoint.n].IsNull()) { - return -1; - } - return coins.nHeight; -} - -int GetInputAge(const CTxIn &txin) -{ - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - { - LOCK(mempool.cs); - CCoinsViewMemPool viewMempool(pcoinsTip, mempool); - view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - - const CCoins* coins = view.AccessCoins(txin.prevout.hash); - - if (coins) { - if(coins->nHeight < 0) return 0; - return chainActive.Height() - coins->nHeight + 1; - } else { - return -1; - } - } -} - -int GetInputAgeIX(const uint256 &nTXHash, const CTxIn &txin) -{ - int nResult = GetInputAge(txin); - if(nResult < 0) return -1; - - if (nResult < 6 && instantsend.IsLockedInstantSendTransaction(nTXHash)) - return nInstantSendDepth + nResult; - - return nResult; -} - -int GetIXConfirmations(const uint256 &nTXHash) -{ - if (instantsend.IsLockedInstantSendTransaction(nTXHash)) - return nInstantSendDepth; - - return 0; -} - - -bool CheckTransaction(const CTransaction& tx, CValidationState &state) -{ - // Basic checks that don't depend on any context - if (tx.vin.empty()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); - if (tx.vout.empty()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); - // Size limits - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); - - // Check for negative or overflow output values - CAmount nValueOut = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - if (txout.nValue < 0) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); - if (txout.nValue > MAX_MONEY) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge"); - nValueOut += txout.nValue; - if (!MoneyRange(nValueOut)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); - } - - // Check for duplicate inputs - set vInOutPoints; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); - vInOutPoints.insert(txin.prevout); - } - - if (tx.IsCoinBase()) - { - if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) - return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); - } - else - { - BOOST_FOREACH(const CTxIn& txin, tx.vin) - if (txin.prevout.IsNull()) - return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); - } - - return true; -} - -void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) { - int expired = pool.Expire(GetTime() - age); - if (expired != 0) - LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); - - std::vector vNoSpendsRemaining; - pool.TrimToSize(limit, &vNoSpendsRemaining); - BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) - pcoinsTip->Uncache(removed); -} - -/** Convert CValidationState to a human-readable message for logging */ -std::string FormatStateMessage(const CValidationState &state) -{ - return strprintf("%s%s (code %i)", - state.GetRejectReason(), - state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), - state.GetRejectCode()); -} - -bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, - std::vector& vHashTxnToUncache, bool fDryRun) -{ - AssertLockHeld(cs_main); - if (pfMissingInputs) - *pfMissingInputs = false; - - if (!CheckTransaction(tx, state)) - return false; - - // Coinbase is only valid in a block, not as a loose transaction - if (tx.IsCoinBase()) - return state.DoS(100, false, REJECT_INVALID, "coinbase"); - - // Rather not work on nonstandard transactions (unless -testnet/-regtest) - string reason; - if (fRequireStandard && !IsStandardTx(tx, reason)) - return state.DoS(0, false, REJECT_NONSTANDARD, reason); - - // Don't relay version 2 transactions until CSV is active, and we can be - // sure that such transactions will be mined (unless we're on - // -testnet/-regtest). - const CChainParams& chainparams = Params(); - if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { - return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); - } - - // Only accept nLockTime-using transactions that can be mined in the next - // block; we don't want our mempool filled up with transactions that can't - // be mined yet. - if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) - return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); - - // is it already in the memory pool? - uint256 hash = tx.GetHash(); - if (pool.exists(hash)) - return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); - - // If this is a Transaction Lock Request check to see if it's valid - if(instantsend.HasTxLockRequest(hash) && !CTxLockRequest(tx).IsValid()) - return state.DoS(10, error("AcceptToMemoryPool : CTxLockRequest %s is invalid", hash.ToString()), - REJECT_INVALID, "bad-txlockrequest"); - - // Check for conflicts with a completed Transaction Lock - BOOST_FOREACH(const CTxIn &txin, tx.vin) - { - uint256 hashLocked; - if(instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hash != hashLocked) - return state.DoS(10, error("AcceptToMemoryPool : Transaction %s conflicts with completed Transaction Lock %s", - hash.ToString(), hashLocked.ToString()), - REJECT_INVALID, "tx-txlock-conflict"); - } - - // Check for conflicts with in-memory transactions - set setConflicts; - { - LOCK(pool.cs); // protect pool.mapNextTx - BOOST_FOREACH(const CTxIn &txin, tx.vin) - { - if (pool.mapNextTx.count(txin.prevout)) - { - const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; - if (!setConflicts.count(ptxConflicting->GetHash())) - { - // InstantSend txes are not replacable - if(instantsend.HasTxLockRequest(ptxConflicting->GetHash())) { - // this tx conflicts with a Transaction Lock Request candidate - return state.DoS(0, error("AcceptToMemoryPool : Transaction %s conflicts with Transaction Lock Request %s", - hash.ToString(), ptxConflicting->GetHash().ToString()), - REJECT_INVALID, "tx-txlockreq-mempool-conflict"); - } else if (instantsend.HasTxLockRequest(hash)) { - // this tx is a tx lock request and it conflicts with a normal tx - return state.DoS(0, error("AcceptToMemoryPool : Transaction Lock Request %s conflicts with transaction %s", - hash.ToString(), ptxConflicting->GetHash().ToString()), - REJECT_INVALID, "txlockreq-tx-mempool-conflict"); - } - // Allow opt-out of transaction replacement by setting - // nSequence >= maxint-1 on all inputs. - // - // maxint-1 is picked to still allow use of nLockTime by - // non-replacable transactions. All inputs rather than just one - // is for the sake of multi-party protocols, where we don't - // want a single party to be able to disable replacement. - // - // The opt-out ignores descendants as anyone relying on - // first-seen mempool behavior should be checking all - // unconfirmed ancestors anyway; doing otherwise is hopelessly - // insecure. - bool fReplacementOptOut = true; - if (fEnableReplacement) - { - BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin) - { - if (txin.nSequence < std::numeric_limits::max()-1) - { - fReplacementOptOut = false; - break; - } - } - } - if (fReplacementOptOut) - return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); - - setConflicts.insert(ptxConflicting->GetHash()); - } - } - } - } - - { - CCoinsView dummy; - CCoinsViewCache view(&dummy); - - CAmount nValueIn = 0; - LockPoints lp; - { - LOCK(pool.cs); - CCoinsViewMemPool viewMemPool(pcoinsTip, pool); - view.SetBackend(viewMemPool); - - // do we already have it? - bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(hash); - if (view.HaveCoins(hash)) { - if (!fHadTxInCache) - vHashTxnToUncache.push_back(hash); - return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known"); - } - - // do all inputs exist? - // Note that this does not check for the presence of actual outputs (see the next check for that), - // and only helps with filling in pfMissingInputs (to determine missing vs spent). - BOOST_FOREACH(const CTxIn txin, tx.vin) { - if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) - vHashTxnToUncache.push_back(txin.prevout.hash); - if (!view.HaveCoins(txin.prevout.hash)) { - if (pfMissingInputs) - *pfMissingInputs = true; - return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() - } - } - - // are the actual inputs available? - if (!view.HaveInputs(tx)) - return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent"); - - // Bring the best block into scope - view.GetBestBlock(); - - nValueIn = view.GetValueIn(tx); - - // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool - view.SetBackend(dummy); - - // Only accept BIP68 sequence locked transactions that can be mined in the next - // block; we don't want our mempool filled up with transactions that can't - // be mined yet. - // Must keep pool.cs for this unless we change CheckSequenceLocks to take a - // CoinsViewCache instead of create its own - if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) - return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); - } - - // Check for non-standard pay-to-script-hash in inputs - if (fRequireStandard && !AreInputsStandard(tx, view)) - return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); - - unsigned int nSigOps = GetLegacySigOpCount(tx); - nSigOps += GetP2SHSigOpCount(tx, view); - - CAmount nValueOut = tx.GetValueOut(); - CAmount nFees = nValueIn-nValueOut; - // nModifiedFees includes any fee deltas from PrioritiseTransaction - if(nFees<=0) - { - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient nFees"); - } - CAmount nModifiedFees = nFees; - double nPriorityDummy = 0; - pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees); - - CAmount inChainInputValue; - double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); - - // Keep track of transactions that spend a coinbase, which we re-scan - // during reorgs to ensure COINBASE_MATURITY is still met. - bool fSpendsCoinbase = false; - BOOST_FOREACH(const CTxIn &txin, tx.vin) { - const CCoins *coins = view.AccessCoins(txin.prevout.hash); - if (coins->IsCoinBase()) { - fSpendsCoinbase = true; - break; - } - } - - CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); - unsigned int nSize = entry.GetTxSize(); - - // Check that the transaction doesn't have an excessive number of - // sigops, making it impossible to mine. Since the coinbase transaction - // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than - // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than - // merely non-standard transaction. - if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp)) - return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, - strprintf("%d", nSigOps)); - - CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); - if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee)); - } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { - // Require that free transactions have sufficient priority to be mined in the next block. - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); - } - - // Continuously rate-limit free (really, very-low-fee) transactions - // This mitigates 'penny-flooding' -- sending thousands of free transactions just to - // be annoying or make others' transactions take longer to confirm. - if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) - { - static CCriticalSection csFreeLimiter; - static double dFreeCount; - static int64_t nLastTime; - int64_t nNow = GetTime(); - - LOCK(csFreeLimiter); - - // Use an exponentially decaying ~10-minute window: - dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); - nLastTime = nNow; - // -limitfreerelay unit is thousand-bytes-per-minute - // At default rate it would take over a month to fill 1GB - if (dFreeCount >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction"); - LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); - dFreeCount += nSize; - } - - if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) - return state.Invalid(false, - REJECT_HIGHFEE, "absurdly-high-fee", - strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); - - // Calculate in-mempool ancestors, up to a limit. - CTxMemPool::setEntries setAncestors; - size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); - size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; - size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); - size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; - std::string errString; - if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { - return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString); - } - - // A transaction that spends outputs that would be replaced by it is invalid. Now - // that we have the set of all ancestors we can detect this - // pathological case by making sure setConflicts and setAncestors don't - // intersect. - BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) - { - const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); - if (setConflicts.count(hashAncestor)) - { - return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s", - hash.ToString(), - hashAncestor.ToString()), - REJECT_INVALID, "bad-txns-spends-conflicting-tx"); - } - } - - // Check if it's economically rational to mine this transaction rather - // than the ones it replaces. - CAmount nConflictingFees = 0; - size_t nConflictingSize = 0; - uint64_t nConflictingCount = 0; - CTxMemPool::setEntries allConflicting; - - // If we don't hold the lock allConflicting might be incomplete; the - // subsequent RemoveStaged() and addUnchecked() calls don't guarantee - // mempool consistency for us. - LOCK(pool.cs); - if (setConflicts.size()) - { - CFeeRate newFeeRate(nModifiedFees, nSize); - set setConflictsParents; - const int maxDescendantsToVisit = 100; - CTxMemPool::setEntries setIterConflicting; - BOOST_FOREACH(const uint256 &hashConflicting, setConflicts) - { - CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting); - if (mi == pool.mapTx.end()) - continue; - - // Save these to avoid repeated lookups - setIterConflicting.insert(mi); - - // If this entry is "dirty", then we don't have descendant - // state for this transaction, which means we probably have - // lots of in-mempool descendants. - // Don't allow replacements of dirty transactions, to ensure - // that we don't spend too much time walking descendants. - // This should be rare. - if (mi->IsDirty()) { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants", - hash.ToString(), - mi->GetTx().GetHash().ToString()), - REJECT_NONSTANDARD, "too many potential replacements"); - } - - // Don't allow the replacement to reduce the feerate of the - // mempool. - // - // We usually don't want to accept replacements with lower - // feerates than what they replaced as that would lower the - // feerate of the next block. Requiring that the feerate always - // be increased is also an easy-to-reason about way to prevent - // DoS attacks via replacements. - // - // The mining code doesn't (currently) take children into - // account (CPFP) so we only consider the feerates of - // transactions being directly replaced, not their indirect - // descendants. While that does mean high feerate children are - // ignored when deciding whether or not to replace, we do - // require the replacement to pay more overall fees too, - // mitigating most cases. - CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); - if (newFeeRate <= oldFeeRate) - { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s", - hash.ToString(), - newFeeRate.ToString(), - oldFeeRate.ToString()), - REJECT_INSUFFICIENTFEE, "insufficient fee"); - } - - BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin) - { - setConflictsParents.insert(txin.prevout.hash); - } - - nConflictingCount += mi->GetCountWithDescendants(); - } - // This potentially overestimates the number of actual descendants - // but we just want to be conservative to avoid doing too much - // work. - if (nConflictingCount <= maxDescendantsToVisit) { - // If not too many to replace, then calculate the set of - // transactions that would have to be evicted - BOOST_FOREACH(CTxMemPool::txiter it, setIterConflicting) { - pool.CalculateDescendants(it, allConflicting); - } - BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) { - nConflictingFees += it->GetModifiedFee(); - nConflictingSize += it->GetTxSize(); - } - } else { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n", - hash.ToString(), - nConflictingCount, - maxDescendantsToVisit), - REJECT_NONSTANDARD, "too many potential replacements"); - } - - for (unsigned int j = 0; j < tx.vin.size(); j++) - { - // We don't want to accept replacements that require low - // feerate junk to be mined first. Ideally we'd keep track of - // the ancestor feerates and make the decision based on that, - // but for now requiring all new inputs to be confirmed works. - if (!setConflictsParents.count(tx.vin[j].prevout.hash)) - { - // Rather than check the UTXO set - potentially expensive - - // it's cheaper to just check if the new input refers to a - // tx that's in the mempool. - if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) - return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d", - hash.ToString(), j), - REJECT_NONSTANDARD, "replacement-adds-unconfirmed"); - } - } - - // The replacement must pay greater fees than the transactions it - // replaces - if we did the bandwidth used by those conflicting - // transactions would not be paid for. - if (nModifiedFees < nConflictingFees) - { - return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s", - hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)), - REJECT_INSUFFICIENTFEE, "insufficient fee"); - } - - // Finally in addition to paying more fees than the conflicts the - // new transaction must pay for its own bandwidth. - CAmount nDeltaFees = nModifiedFees - nConflictingFees; - if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) - { - return state.DoS(0, - error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s", - hash.ToString(), - FormatMoney(nDeltaFees), - FormatMoney(::minRelayTxFee.GetFee(nSize))), - REJECT_INSUFFICIENTFEE, "insufficient fee"); - } - } - - // If we aren't going to actually accept it but just were verifying it, we are fine already - if(fDryRun) return true; - - // Check against previous transactions - // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) - return false; - - // Check again against just the consensus-critical mandatory script - // verification flags, in case of bugs in the standard flags that cause - // transactions to pass as valid when they're actually invalid. For - // instance the STRICTENC flag was incorrectly allowing certain - // CHECKSIG NOT scripts to pass, even though they were invalid. - // - // There is a similar check in CreateNewBlock() to prevent creating - // invalid blocks, however allowing such transactions into the mempool - // can be exploited as a DoS attack. - if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) - { - return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", - __func__, hash.ToString(), FormatStateMessage(state)); - } - - // Remove conflicting transactions from the mempool - BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting) - { - LogPrint("mempool", "replacing tx %s with %s for %s PCH additional fees, %d delta bytes\n", - it->GetTx().GetHash().ToString(), - hash.ToString(), - FormatMoney(nModifiedFees - nConflictingFees), - (int)nSize - (int)nConflictingSize); - } - pool.RemoveStaged(allConflicting); - - // Store transaction in memory - pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); - - // Add memory address index - if (fAddressIndex) { - pool.addAddressIndex(entry, view); - } - - // Add memory spent index - if (fSpentIndex) { - pool.addSpentIndex(entry, view); - } - - // trim mempool and check if tx was trimmed - if (!fOverrideMempoolLimit) { - LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); - if (!pool.exists(hash)) - return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full"); - } - } - - if(!fDryRun) SyncWithWallets(tx, NULL); - - return true; -} - -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, bool fDryRun) -{ - std::vector vHashTxToUncache; - bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, fRejectAbsurdFee, vHashTxToUncache, fDryRun); - if (!res || fDryRun) { - if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx.GetHash().ToString(), state.GetRejectReason()); - BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) - pcoinsTip->Uncache(hashTx); - } - return res; -} - -bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) -{ - if (!fTimestampIndex) - return error("Timestamp index not enabled"); - - if (!pblocktree->ReadTimestampIndex(high, low, hashes)) - return error("Unable to get hashes for timestamps"); - - return true; -} - -bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) -{ - if (!fSpentIndex) - return false; - - if (mempool.getSpentIndex(key, value)) - return true; - - if (!pblocktree->ReadSpentIndex(key, value)) - return false; - - return true; -} - -bool GetAddressIndex(uint160 addressHash, int type, - std::vector > &addressIndex, int start, int end) -{ - if (!fAddressIndex) - { - return error("address index not enabled"); - } - if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end)) - { - return error("unable to get txids for address"); - } - - return true; -} - -bool GetAddressUnspent(uint160 addressHash, int type, - std::vector > &unspentOutputs) -{ - if (!fAddressIndex) - return error("address index not enabled"); - - if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs)) - return error("unable to get txids for address"); - - return true; -} - -/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ -bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) -{ - CBlockIndex *pindexSlow = NULL; - - LOCK(cs_main); - - if (mempool.lookup(hash, txOut)) - { - return true; - } - - if (fTxIndex) { - CDiskTxPos postx; - if (pblocktree->ReadTxIndex(hash, postx)) { - CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); - if (file.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - CBlockHeader header; - try { - file >> header; - fseek(file.Get(), postx.nTxOffset, SEEK_CUR); - file >> txOut; - } catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - hashBlock = header.GetHash(); - if (txOut.GetHash() != hash) - return error("%s: txid mismatch", __func__); - return true; - } - } - - if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it - int nHeight = -1; - { - CCoinsViewCache &view = *pcoinsTip; - const CCoins* coins = view.AccessCoins(hash); - if (coins) - nHeight = coins->nHeight; - } - if (nHeight > 0) - pindexSlow = chainActive[nHeight]; - } - - if (pindexSlow) { - CBlock block; - if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - if (tx.GetHash() == hash) { - txOut = tx; - hashBlock = pindexSlow->GetBlockHash(); - return true; - } - } - } - } - - return false; -} - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// CBlock and CBlockIndex -// - -bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) -{ - // Open history file to append - CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("WriteBlockToDisk: OpenBlockFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(block); - fileout << FLATDATA(messageStart) << nSize; - - // Write block - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("WriteBlockToDisk: ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << block; - - return true; -} - -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) -{ - block.SetNull(); - - // Open history file to read - CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); - - // Read block - try { - filein >> block; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); - } - - // Check the header - -//arith_uint256 k = UintToArith256(block.GetHash()); -//LogPrintf("\t\t\tblock = %s\n\t\t\thash = %s\n\t\t\tarith hash = %s\n", block.ToString().c_str(), block.GetHash().ToString().c_str(), k.ToString().c_str()); - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); - - return true; -} - -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) -{ - if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) - return false; - if (block.GetHash() != pindex->GetBlockHash()) - return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", - pindex->ToString(), pindex->GetBlockPos().ToString()); - return true; -} - -CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) -{ - // genesis - if (!height) - { - return cp.genesisReward; - } - // first block - else if (height == 1) - { - return cp.premine; - } - // the others - else - { - const int intval = cp.nSubsidyHalvingInterval; - - // first 4 years - if (height < intval) - { - return cp.minerReward4; - } - // from the 5th year on - else - { - int halvings = (height - intval) / intval; - // force subsidy to 0 when right shift 64 bit is undifined - if (halvings > 63) - { - return 0; - } - CAmount subsidy(cp.minerReward5); - subsidy >>= halvings; - return subsidy; - } - } -} - -CAmount GetFoundersReward(const int height, const Consensus::Params &cp) -{ - const int beg = cp.nSuperblockStartBlock; - const int end = cp.endOfFoundersReward(); - if (height >= beg && height < end) // before super block starting - { - return cp.foundersReward; - } - return 0; -} - -// return all subsidy -CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp) -{ - return GetMinerSubsidy(height, cp) + - GetFoundersReward(height, cp); -} - -bool IsInitialBlockDownload() -{ - static bool lockIBDState = false; - if (lockIBDState) - return false; - if (fImporting || fReindex) - return true; - LOCK(cs_main); - const CChainParams& chainParams = Params(); - if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) - return true; - bool state = - (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - chainParams.MaxTipAge()); - if (!state) - lockIBDState = true; - return state; -} - -bool fLargeWorkForkFound = false; -bool fLargeWorkInvalidChainFound = false; -CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; - -void CheckForkWarningConditions() -{ - AssertLockHeld(cs_main); - // Before we get past initial download, we cannot reliably alert about forks - // (we assume we don't get stuck on a fork before the last checkpoint) - if (IsInitialBlockDownload()) - return; - - // If our best fork is no longer within 72 blocks (+/- 3 hours if no one mines it) - // of our head, drop it - if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) - pindexBestForkTip = NULL; - - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) - { - if (!fLargeWorkForkFound && pindexBestForkBase) - { - if(pindexBestForkBase->phashBlock){ - std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); - CAlert::Notify(warning, true); - } - } - if (pindexBestForkTip && pindexBestForkBase) - { - if(pindexBestForkBase->phashBlock){ - LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, - pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), - pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); - fLargeWorkForkFound = true; - } - } - else - { - if(pindexBestInvalid->nHeight > chainActive.Height() + 6) - LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); - else - LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); - fLargeWorkInvalidChainFound = true; - } - } - else - { - fLargeWorkForkFound = false; - fLargeWorkInvalidChainFound = false; - } -} - -void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) -{ - AssertLockHeld(cs_main); - // If we are on a fork that is sufficiently large, set a warning flag - CBlockIndex* pfork = pindexNewForkTip; - CBlockIndex* plonger = chainActive.Tip(); - while (pfork && pfork != plonger) - { - while (plonger && plonger->nHeight > pfork->nHeight) - plonger = plonger->pprev; - if (pfork == plonger) - break; - pfork = pfork->pprev; - } - - // We define a condition where we should warn the user about as a fork of at least 7 blocks - // with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours - // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) - // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network - // hash rate operating on the fork. - // We define it this way because it allows us to only store the highest fork tip (+ base) which meets - // the 7-block condition and from this always have the most-likely-to-cause-warning fork - if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && - chainActive.Height() - pindexNewForkTip->nHeight < 72) - { - pindexBestForkTip = pindexNewForkTip; - pindexBestForkBase = pfork; - } - - CheckForkWarningConditions(); -} - -// Requires cs_main. -void Misbehaving(NodeId pnode, int howmuch) -{ - if (howmuch == 0) - return; - - CNodeState *state = State(pnode); - if (state == NULL) - return; - - state->nMisbehavior += howmuch; - int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); - if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) - { - LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); - state->fShouldBan = true; - } else - LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); -} - -void static InvalidChainFound(CBlockIndex* pindexNew) -{ - if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) - pindexBestInvalid = pindexNew; - - LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, - pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, - log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", - pindexNew->GetBlockTime())); - CBlockIndex *tip = chainActive.Tip(); - assert (tip); - LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, - tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); - CheckForkWarningConditions(); -} - -void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { - int nDoS = 0; - if (state.IsInvalid(nDoS)) { - std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); - if (it != mapBlockSource.end() && State(it->second)) { - assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; - State(it->second)->rejects.push_back(reject); - if (nDoS > 0) - Misbehaving(it->second, nDoS); - } - } - if (!state.CorruptionPossible()) { - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); - setBlockIndexCandidates.erase(pindex); - InvalidChainFound(pindex); - } -} - -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) -{ - // mark inputs spent - if (!tx.IsCoinBase()) { - txundo.vprevout.reserve(tx.vin.size()); - BOOST_FOREACH(const CTxIn &txin, tx.vin) { - CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); - unsigned nPos = txin.prevout.n; - - if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull()) - assert(false); - // mark an outpoint spent, and construct undo information - txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); - coins->Spend(nPos); - if (coins->vout.size() == 0) { - CTxInUndo& undo = txundo.vprevout.back(); - undo.nHeight = coins->nHeight; - undo.fCoinBase = coins->fCoinBase; - undo.nVersion = coins->nVersion; - } - } - // add outputs - inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight); - } - else { - // add outputs for coinbase tx - // In this case call the full ModifyCoins which will do a database - // lookup to be sure the coins do not already exist otherwise we do not - // know whether to mark them fresh or not. We want the duplicate coinbases - // before BIP30 to still be properly overwritten. - inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); - } -} - -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) -{ - CTxUndo txundo; - UpdateCoins(tx, state, inputs, txundo, nHeight); -} - -bool CScriptCheck::operator()() { - const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) { - return false; - } - return true; -} - -int GetSpendHeight(const CCoinsViewCache& inputs) -{ - LOCK(cs_main); - CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; - return pindexPrev->nHeight + 1; -} - -namespace Consensus { -bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight) -{ - // This doesn't trigger the DoS code on purpose; if it did, it would make it easier - // for an attacker to attempt to split the network. - if (!inputs.HaveInputs(tx)) - return state.Invalid(false, 0, "", "Inputs unavailable"); - - CAmount nValueIn = 0; - CAmount nFees = 0; - for (unsigned int i = 0; i < tx.vin.size(); i++) - { - const COutPoint &prevout = tx.vin[i].prevout; - const CCoins *coins = inputs.AccessCoins(prevout.hash); - assert(coins); - - // If prev is coinbase, check that it's matured - if (coins->IsCoinBase()) { - if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) - return state.Invalid(false, - REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", - strprintf("tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight)); - } - - // Check for negative or overflow input values - nValueIn += coins->vout[prevout.n].nValue; - if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); - - } - - if (nValueIn < tx.GetValueOut()) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, - strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()))); - - // Tally transaction fees - CAmount nTxFee = nValueIn - tx.GetValueOut(); - if (nTxFee < 0) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); - nFees += nTxFee; - if (!MoneyRange(nFees)) - return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); - return true; -} -}// namespace Consensus - -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector *pvChecks) -{ - if (!tx.IsCoinBase()) - { - if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs))) - return false; - - if (pvChecks) - pvChecks->reserve(tx.vin.size()); - - // The first loop above does all the inexpensive checks. - // Only if ALL inputs pass do we perform expensive ECDSA signature checks. - // Helps prevent CPU exhaustion attacks. - - // Skip ECDSA signature verification when connecting blocks - // before the last block chain checkpoint. This is safe because block merkle hashes are - // still computed and checked, and any change will be caught at the next checkpoint. - if (fScriptChecks) { - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const COutPoint &prevout = tx.vin[i].prevout; - const CCoins* coins = inputs.AccessCoins(prevout.hash); - assert(coins); - - // Verify signature - CScriptCheck check(*coins, tx, i, flags, cacheStore); - if (pvChecks) { - pvChecks->push_back(CScriptCheck()); - check.swap(pvChecks->back()); - } else if (!check()) { - if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { - // Check whether the failure was caused by a - // non-mandatory script verification check, such as - // non-standard DER encodings or non-null dummy - // arguments; if so, don't trigger DoS protection to - // avoid splitting the network between upgraded and - // non-upgraded nodes. - CScriptCheck check2(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); - if (check2()) - return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); - } - // Failures of other flags indicate a transaction that is - // invalid in new blocks, e.g. a invalid P2SH. We DoS ban - // such nodes as they are not following the protocol. That - // said during an upgrade careful thought should be taken - // as to the correct behavior - we may want to continue - // peering with non-upgraded nodes even after a soft-fork - // super-majority vote has passed. - return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); - } - } - } - } - - return true; -} - -namespace { - -bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) -{ - // Open history file to append - CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("%s: OpenUndoFile failed", __func__); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(blockundo); - fileout << FLATDATA(messageStart) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("%s: ftell failed", __func__); - pos.nPos = (unsigned int)fileOutPos; - fileout << blockundo; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - fileout << hasher.GetHash(); - - return true; -} - -bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) -{ - // Open history file to read - CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - - // Read block - uint256 hashChecksum; - try { - filein >> blockundo; - filein >> hashChecksum; - } - catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << blockundo; - if (hashChecksum != hasher.GetHash()) - return error("%s: Checksum mismatch", __func__); - - return true; -} - -/** Abort with a message */ -bool AbortNode(const std::string& strMessage, const std::string& userMessage="") -{ - strMiscWarning = strMessage; - LogPrintf("*** %s\n", strMessage); - uiInterface.ThreadSafeMessageBox( - userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, - "", CClientUIInterface::MSG_ERROR); - StartShutdown(); - return false; -} - -bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="") -{ - AbortNode(strMessage, userMessage); - return state.Error(strMessage); -} - -} // anon namespace - -/** - * Apply the undo operation of a CTxInUndo to the given chain state. - * @param undo The undo object. - * @param view The coins view to which to apply the changes. - * @param trieCache - * @param out The out point that corresponds to the tx input. - * @return True on success. - */ -static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, CClaimTrieCache& trieCache, const COutPoint& out) -{ - bool fClean = true; - - CCoinsModifier coins = view.ModifyCoins(out.hash); - if (undo.nHeight != 0) { - // undo data contains height: this is the last output of the prevout tx being spent - if (!coins->IsPruned()) - fClean = fClean && error("%s: undo data overwriting existing transaction", __func__); - coins->Clear(); - coins->fCoinBase = undo.fCoinBase; - coins->nHeight = undo.nHeight; - coins->nVersion = undo.nVersion; - } else { - if (coins->IsPruned()) - fClean = fClean && error("%s: undo data adding output to missing transaction", __func__); - } - if (coins->IsAvailable(out.n)) - fClean = fClean && error("%s: undo data overwriting existing output", __func__); - if (coins->vout.size() < out.n+1) - coins->vout.resize(out.n+1); - - //restore claim if applicable - int op; - std::vector > vvchParams; - if(undo.fIsClaim && DecodeClaimScript(undo.txout.scriptPubKey,op,vvchParams)) - { - if(op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) - { - uint160 claimId; - if(op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2 ); - claimId = ClaimIdHash(out.hash,out.n); - } - else if( op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3 ); - claimId = uint160(vvchParams[1]); - } - std::string name(vvchParams[0].begin(),vvchParams[0].end()); - int nValidHeight = undo.nClaimValidHeight; - if(nValidHeight > 0 && nValidHeight >= coins->nHeight) - { - LogPrintf("%s: (txid: %s, nOut: %d) Restoring %s to the claim trie due to a block being disconnected\n", __func__, out.hash.ToString(), out.n, name.c_str()); - if ( !trieCache.undoSpendClaim(name, COutPoint(out.hash, out.n), claimId, undo.txout.nValue, coins->nHeight, nValidHeight)) - LogPrintf("%s: Something went wrong inserting the claim\n", __func__); - else - { - LogPrintf("%s: (txid: %s, nOut: %d) Not restoring %s to the claim trie because it expired before it was spent\n", __func__, out.hash.ToString(), out.n, name.c_str()); - } - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 supportedClaimId(vvchParams[1]); - int nValidHeight = undo.nClaimValidHeight; - if (nValidHeight > 0 && nValidHeight >= coins->nHeight) - { - LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s in claimid %s due to a block being disconnected\n", __func__, out.hash.ToString(), out.n, name, supportedClaimId.ToString()); - if (!trieCache.undoSpendSupport(name, COutPoint(out.hash, out.n), supportedClaimId, undo.txout.nValue, coins->nHeight, nValidHeight)) - LogPrintf("%s: Something went wrong inserting support for the claim\n", __func__); - } - else - { - LogPrintf("%s: (txid: %s, nOut: %d) Not restoring support for %s in claimid %s because the support expired before it was spent\n", __func__, out.hash.ToString(), out.n, name, supportedClaimId.ToString()); - } - } - } - - coins->vout[out.n] = undo.txout; - - return fClean; -} - -bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, CClaimTrieCache& trieCache, bool* pfClean) -{ - assert(pindex->GetBlockHash() == view.GetBestBlock()); - //assert(pindex->GetBlockHash() == trieCache.getBestBlock()); - - if (pfClean) - *pfClean = false; - - bool fClean = true; - - CBlockUndo blockUndo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (pos.IsNull()) - return error("DisconnectBlock(): no undo data available"); - if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) - return error("DisconnectBlock(): failure reading undo data"); - - if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) - return error("DisconnectBlock(): block and undo data inconsistent"); - - std::vector > addressIndex; - std::vector > addressUnspentIndex; - std::vector > spentIndex; - - assert(trieCache.decrementBlock(blockUndo.insertUndo, blockUndo.expireUndo, blockUndo.insertSupportUndo, blockUndo.expireSupportUndo, blockUndo.takeoverHeightUndo)); - - // undo transactions in reverse order - for (int i = block.vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = block.vtx[i]; - uint256 hash = tx.GetHash(); - - if (fAddressIndex) { - - for (unsigned int k = tx.vout.size(); k-- > 0;) { - const CTxOut &out = tx.vout[k]; - uint160 hashBytes; - int addressType; - - if(DecodeAddressHash(out.scriptPubKey, hashBytes, addressType)) - { - // undo receiving activity - addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, hash, k, false), out.nValue)); - - // undo unspent index - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, hash, k), CAddressUnspentValue())); - } - } - - } - - // Check that all outputs are available and match the outputs in the block itself - // exactly. - { - CCoinsModifier outs = view.ModifyCoins(hash); - outs->ClearUnspendable(); - - CCoins outsBlock(tx, pindex->nHeight); - // The CCoins serialization does not serialize negative numbers. - // No network rules currently depend on the version here, so an inconsistency is harmless - // but it must be corrected before txout nversion ever influences a network rule. -if (outs->nVersion != outsBlock.nVersion) -{ -LogPrintf("main.cpp:2365, outs->nVersion(%d) != outsBlock.nVer(%d), ", outs->nVersion, outsBlock.nVersion); -outs->nVersion = outsBlock.nVersion; -} - if (outsBlock.nVersion < 0) - outs->nVersion = outsBlock.nVersion; - if (*outs != outsBlock) - fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); - - // remove any claims - for (unsigned int i = 0; i < tx.vout.size(); ++i) - { - const CTxOut& txout = tx.vout[i]; - - int op; - std::vector > vvchParams; - if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) - { - if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) - { - uint160 claimId; - if (op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2); - claimId = ClaimIdHash(hash, i); - } - else if (op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3); - claimId = uint160(vvchParams[1]); - } - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - LogPrintf("%s: (txid: %s, nOut: %d) Trying to remove %s from the claim trie due to its block being disconnected\n", __func__, hash.ToString(), i, name.c_str()); - if (!trieCache.undoAddClaim(name, COutPoint(hash, i), pindex->nHeight)) - { - LogPrintf("%s: Could not find the claim in the trie or the cache\n", __func__); - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 supportedClaimId(vvchParams[1]); - LogPrintf("%s: (txid: %s, nOut: %d) Removing support for claim id %s on %s due to its block being disconnected\n", __func__, hash.ToString(), i, supportedClaimId.ToString(), name.c_str()); - if (!trieCache.undoAddSupport(name, COutPoint(hash, i), pindex->nHeight)) - LogPrintf("%s: Something went wrong removing support for name %s in hash %s\n", __func__, name.c_str(), hash.ToString()); - } - } - } - - // remove outputs - outs->Clear(); - } - - // restore inputs - if (i > 0) { // not coinbases - const CTxUndo &txundo = blockUndo.vtxundo[i-1]; - if (txundo.vprevout.size() != tx.vin.size()) - return error("DisconnectBlock(): transaction and undo data inconsistent"); - for (unsigned int j = tx.vin.size(); j-- > 0;) { - const COutPoint &out = tx.vin[j].prevout; - const CTxInUndo &undo = txundo.vprevout[j]; - if (!ApplyTxInUndo(undo, view, trieCache, out)) - fClean = false; - - const CTxIn input = tx.vin[j]; - - if (fSpentIndex) { - // undo and delete the spent index - spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue())); - } - - if (fAddressIndex) { - const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); - uint160 hashBytes; - int addressType; - - if(DecodeAddressHash(prevout.scriptPubKey, hashBytes, addressType)) - { - // undo spending activity - addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); - - // restore unspent index - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); - } - } - - } - } - } - - - // move best block pointer to prevout block - view.SetBestBlock(pindex->pprev->GetBlockHash()); - assert(trieCache.finalizeDecrement()); - //trieCache.setBestBlock(pindex->pprev->GetBlockHash()); - //assert(trieCache.getMerkleHash() == pindex->pprev->hashClaimTrie); - - if (pfClean) { - *pfClean = fClean; - return true; - } - - if (fAddressIndex) { - if (!pblocktree->EraseAddressIndex(addressIndex)) { - return AbortNode(state, "Failed to delete address index"); - } - if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { - return AbortNode(state, "Failed to write address unspent index"); - } - } - - return fClean; -} - -void static FlushBlockFile(bool fFinalize = false) -{ - LOCK(cs_LastBlockFile); - - CDiskBlockPos posOld(nLastBlockFile, 0); - - FILE *fileOld = OpenBlockFile(posOld); - if (fileOld) { - if (fFinalize) - TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); - FileCommit(fileOld); - fclose(fileOld); - } - - fileOld = OpenUndoFile(posOld); - if (fileOld) { - if (fFinalize) - TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); - FileCommit(fileOld); - fclose(fileOld); - } -} - -bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); - -static CCheckQueue scriptcheckqueue(128); - -void ThreadScriptCheck() { - RenameThread("pop-scriptch"); - scriptcheckqueue.Thread(); -} - -// -// Called periodically asynchronously; alerts if it smells like -// we're being fed a bad chain (blocks being generated much -// too slowly or too quickly). -// -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, - int64_t nPowTargetSpacing) -{ - if (bestHeader == NULL || initialDownloadCheck()) return; - - static int64_t lastAlertTime = 0; - int64_t now = GetAdjustedTime(); - if (lastAlertTime > now-60*60*24) return; // Alert at most once per day - - const int SPAN_HOURS=1; // was 4h in bitcoin but we have 4x faster blocks - const int SPAN_SECONDS=SPAN_HOURS*60*60; - int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; - - boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); - - std::string strWarning; - int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; - - LOCK(cs); - const CBlockIndex* i = bestHeader; - int nBlocks = 0; - while (i->GetBlockTime() >= startTime) { - ++nBlocks; - i = i->pprev; - if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed - } - - // How likely is it to find that many by chance? - double p = boost::math::pdf(poisson, nBlocks); - - LogPrint("partitioncheck", "%s: Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); - LogPrint("partitioncheck", "%s: likelihood: %g\n", __func__, p); - - // Aim for one false-positive about every fifty years of normal running: - const int FIFTY_YEARS = 50*365*24*60*60; - double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); - - if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) - { - // Many fewer blocks than expected: alert! - strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"), - nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); - } - else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED) - { - // Many more blocks than expected: alert! - strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"), - nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); - } - if (!strWarning.empty()) - { - strMiscWarning = strWarning; - CAlert::Notify(strWarning, true); - lastAlertTime = now; - } -} - -// Protected by cs_main -static VersionBitsCache versionbitscache; - -int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) -{ - LOCK(cs_main); - int32_t nVersion = VERSIONBITS_TOP_BITS; - - for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { - ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache); - if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { - nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); - } - } - - return nVersion; -} - -bool GetBlockHash(uint256& hashRet, int nBlockHeight) -{ - LOCK(cs_main); - if(chainActive.Tip() == NULL) return false; - if(nBlockHeight < -1 || nBlockHeight > chainActive.Height()) return false; - if(nBlockHeight == -1) nBlockHeight = chainActive.Height(); - hashRet = chainActive[nBlockHeight]->GetBlockHash(); - return true; -} - -/** - * Threshold condition checker that triggers when unknown versionbits are seen on the network. - */ -class WarningBitsConditionChecker : public AbstractThresholdConditionChecker -{ -private: - int bit; - -public: - WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} - - int64_t BeginTime(const Consensus::Params& params) const { return 0; } - int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits::max(); } - int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } - int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } - - bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const - { - return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && - ((pindex->nVersion >> bit) & 1) != 0 && - ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; - } -}; - -// Protected by cs_main -static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; - -static int64_t nTimeCheck = 0; -static int64_t nTimeForks = 0; -static int64_t nTimeVerify = 0; -static int64_t nTimeConnect = 0; -static int64_t nTimeIndex = 0; -static int64_t nTimeCallbacks = 0; -static int64_t nTimeTotal = 0; - -// added trieCache arg -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, CClaimTrieCache& trieCache, bool fJustCheck) -{ - const CChainParams& chainparams = Params(); - AssertLockHeld(cs_main); - - int64_t nTimeStart = GetTimeMicros(); - - // Check it again in case a previous version let a bad block in - if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) - return false; - - // verify that the view's current state corresponds to the previous block - uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); - assert(hashPrevBlock == view.GetBestBlock()); - - // also verify that the trie cache's current state corresponds to the previous block - //assert(hashPrevBlock == trieCache.getBestBlock()); - - // Special case for the genesis block, skipping connection of its transactions - // (its coinbase is unspendable) - if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { - if (!fJustCheck) - { - view.SetBestBlock(pindex->GetBlockHash()); - trieCache.setBestBlock(pindex->GetBlockHash()); - } - return true; - } - - bool fScriptChecks = true; - if (fCheckpointsEnabled) { - CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); - if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { - // This block is an ancestor of a checkpoint: disable script checks - fScriptChecks = false; - } - } - - int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; - LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); - - // Do not allow blocks that contain transactions which 'overwrite' older transactions, - // unless those are already completely spent. - // If such overwrites are allowed, coinbases and transactions depending upon those - // can be duplicated to remove the ability to spend the first instance -- even after - // being sent to another address. - // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. - // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool - // already refuses previously-known transaction ids entirely. - // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC. - // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the - // two in the chain that violate it. This prevents exploiting the issue against nodes during their - // initial block download. - bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash. - !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || - (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); - - // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting - // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the - // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first - // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further - // duplicate transactions descending from the known pairs either. - // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check. - CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); - //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. - fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); - - if (fEnforceBIP30) { - BOOST_FOREACH(const CTransaction& tx, block.vtx) { - const CCoins* coins = view.AccessCoins(tx.GetHash()); - if (coins && !coins->IsPruned()) - return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), - REJECT_INVALID, "bad-txns-BIP30"); - } - } - - // BIP16 didn't become active until Apr 1 2012 - int64_t nBIP16SwitchTime = 1333238400; - bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime); - - unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; - - // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, - // when 75% of the network has upgraded: - if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { - flags |= SCRIPT_VERIFY_DERSIG; - } - - // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 - // blocks, when 75% of the network has upgraded: - if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { - flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; - } - - // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. - int nLockTimeFlags = 0; - if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { - flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; - nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; - } - - int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; - LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001); - - CBlockUndo blockundo; - - CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); - - std::vector prevheights; - CAmount nFees = 0; - int nInputs = 0; - unsigned int nSigOps = 0; - CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); - std::vector > vPos; - vPos.reserve(block.vtx.size()); - blockundo.vtxundo.reserve(block.vtx.size() - 1); - std::vector > addressIndex; - std::vector > addressUnspentIndex; - std::vector > spentIndex; - - for (unsigned int i = 0; i < block.vtx.size(); i++) - { - const CTransaction &tx = block.vtx[i]; - const uint256 txhash = tx.GetHash(); - - nInputs += tx.vin.size(); - nSigOps += GetLegacySigOpCount(tx); - if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("ConnectBlock(): too many sigops"), - REJECT_INVALID, "bad-blk-sigops"); - std::map mClaimUndoHeights; // claim - - if (!tx.IsCoinBase()) - { - if (!view.HaveInputs(tx)) - return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), - REJECT_INVALID, "bad-txns-inputs-missingorspent"); - - // Check that transaction is BIP68 final - // BIP68 lock checks (as opposed to nLockTime checks) must - // be in ConnectBlock because they require the UTXO set - prevheights.resize(tx.vin.size()); - for (size_t j = 0; j < tx.vin.size(); j++) { - prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight; - } - - if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { - return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), - REJECT_INVALID, "bad-txns-nonfinal"); - } - - if (fAddressIndex || fSpentIndex) - { - for (size_t j = 0; j < tx.vin.size(); j++) { - - const CTxIn input = tx.vin[j]; - const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); - uint160 hashBytes; - int addressType; - if(DecodeAddressHash(prevout.scriptPubKey, hashBytes, addressType)) - { - if (fAddressIndex && addressType > 0) { - // record spending activity - addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); - - // remove address from unspent index - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); - } - } - if (fSpentIndex) { - // add the spent index to determine the txid and input that spent an output - // and to find the amount and address from an input - spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); - } - } - - } - - if (fStrictPayToScriptHash) - { - // Add in sigops done by pay-to-script-hash inputs; - // this is to prevent a "rogue miner" from creating - // an incredibly-expensive-to-validate block. - nSigOps += GetP2SHSigOpCount(tx, view); - if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("ConnectBlock(): too many sigops"), - REJECT_INVALID, "bad-blk-sigops"); - } - - nFees += view.GetValueIn(tx)-tx.GetValueOut(); - - std::vector vChecks; - bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ - if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) - return error("ConnectBlock(): CheckInputs on %s failed with %s", - tx.GetHash().ToString(), FormatStateMessage(state)); - control.Add(vChecks); - - // To handle claim updates, stick all claims found in the inputs into a map of - // name: (txhash, nOut). When running through the outputs, if any claim's - // name is found in the map, send the name's txhash and nOut to the trie cache, - // and then remove the name: (txhash, nOut) mapping from the map. - // If there are two or more claims in the inputs with the same name, only - // use the first. - - typedef std::vector > spentClaimsType; - spentClaimsType spentClaims; - - for (unsigned int m = 0; m < tx.vin.size(); ++m) - { - const CTxIn& txin = tx.vin[m]; - const CCoins* coins = view.AccessCoins(txin.prevout.hash); - assert(coins); - - int op; - std::vector > vvchParams; - if (DecodeClaimScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams)) - { - if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) - { - uint160 claimId; - if (op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2); - claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); - } - else if (op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3); - claimId = uint160(vvchParams[1]); - } - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - int nValidAtHeight; - LogPrintf("%s: Removing %s from the claim trie. Tx: %s, nOut: %d\n", __func__, name, txin.prevout.hash.GetHex(), txin.prevout.n); - if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) - { - mClaimUndoHeights[m] = nValidAtHeight; - std::pair entry(name, claimId); - spentClaims.push_back(entry); - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 supportedClaimId(vvchParams[1]); - int nValidAtHeight; - LogPrintf("%s: Removing support for %s in %s. Tx: %s, nOut: %d, removed txid: %s\n", __func__, supportedClaimId.ToString(), name, txin.prevout.hash.ToString(), txin.prevout.n,tx.GetHash().ToString()); - if (trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) - { - mClaimUndoHeights[m] = nValidAtHeight; - } - } - } - } - - for(unsigned int l =0 ; l< tx.vout.size();++l) - { - const CTxOut& txout = tx.vout[l]; - int op; - std::vector > vvchParams; - if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) - { - if (op == OP_CLAIM_NAME) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - LogPrintf("%s: Inserting %s into the claim trie. Tx: %s, nOut: %d\n", __func__, name, tx.GetHash().GetHex(), l); - if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), l), ClaimIdHash(tx.GetHash(), l), txout.nValue, pindex->nHeight)) - { - LogPrintf("%s: Something went wrong inserting the claim\n", __func__); - } - } - else if (op == OP_UPDATE_CLAIM) - { - assert(vvchParams.size() == 3); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 claimId(vvchParams[1]); - LogPrintf("%s: Got a claim update. Name: %s, claimId: %s, new txid: %s, nOut: %d\n", __func__, name, claimId.GetHex(), tx.GetHash().GetHex(), l); - spentClaimsType::iterator itSpent; - for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) - { - if (itSpent->first == name && itSpent->second == claimId) - { - break; - } - } - if (itSpent != spentClaims.end()) - { - spentClaims.erase(itSpent); - if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), l), claimId, txout.nValue, pindex->nHeight)) - { - LogPrintf("%s: Something went wrong updating the claim\n", __func__); - } - } - } - else if (op == OP_SUPPORT_CLAIM) - { - assert(vvchParams.size() == 2); - std::string name(vvchParams[0].begin(), vvchParams[0].end()); - uint160 supportedClaimId(vvchParams[1]); - if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), l), txout.nValue, supportedClaimId, pindex->nHeight)) - { - LogPrintf("%s: Something went wrong inserting the support\n", __func__); - } - } - } - } - } - - if (fAddressIndex) { - for (unsigned int k = 0; k < tx.vout.size(); k++) { - const CTxOut &out = tx.vout[k]; - uint160 hashBytes; - int addressType; - if(DecodeAddressHash(out.scriptPubKey, hashBytes, addressType)) - { - // record receiving activity - addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, k, false), out.nValue)); - - // record unspent output - addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); - } - } - } - - CTxUndo undoDummy; - if (i > 0) { - blockundo.vtxundo.push_back(CTxUndo()); - } - UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); - if (i > 0 && !mClaimUndoHeights.empty()) - { - std::vector& txinUndos = blockundo.vtxundo.back().vprevout; - for (std::map::iterator itHeight = mClaimUndoHeights.begin(); itHeight != mClaimUndoHeights.end(); ++itHeight) - { - txinUndos[itHeight->first].nClaimValidHeight = itHeight->second; - txinUndos[itHeight->first].fIsClaim = true; - } - } - // The CTxUndo vector contains the heights at which claims should be put into the trie. - // This is necessary because some claims are inserted immediately into the trie, and - // others are inserted after a delay, depending on the state of the claim trie at the time - // that the claim was originally inserted into the blockchain. That state will not be - // available when and if this block is disconnected. - // It also contains whether or not any given txin represents a claim that should - // be put back into the trie. If we didn't find a claim or support in the trie - // or cache when trying to spend it, we shouldn't try to put a claim or support back - // in. Some OP_UPDATE_CLAIM's, for example, may be invalid, and so may never have been - // inserted into the trie in the first place. - - vPos.push_back(std::make_pair(tx.GetHash(), pos)); - pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); - } - - assert(trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo, blockundo.takeoverHeightUndo)); - - /*if (trieCache.getMerkleHash() != block.hashClaimTrie) - { - return state.DoS(100,error("ConnectBlock() : the merkle root of the claim trie does not match " - "(actual=%s vs block=%s)", trieCache.getMerkleHash().GetHex(), - block.hashClaimTrie.GetHex()), REJECT_INVALID, "bad-claim-merkle-hash"); - }*/ - - int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; - LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); - - // It's possible that we simply don't have enough data and this could fail - // (i.e. block itself could be a correct one and we need to store it), - // that's why this is in ConnectBlock. Could be the other way around however - - // the peer who sent us this block is missing some data and wasn't able - // to recognize that block is actually invalid. - // TODO: resync data (both ways?) and try to reprocess this block later. - CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); - std::string strError = ""; - if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) { - return state.DoS(0, error("ConnectBlock(PCH): %s", strError), REJECT_INVALID, "bad-cb-amount"); - } - - if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, blockReward)) { - mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); - return state.DoS(0, error("ConnectBlock(PCH): couldn't find popnode or superblock payments"), - REJECT_INVALID, "bad-cb-payee"); - } - // END PCH - - if (!control.Wait()) - return state.DoS(100, false); - int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; - LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); - - if (fJustCheck) - return true; - - // Write undo information to disk - if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) - { - if (pindex->GetUndoPos().IsNull()) { - CDiskBlockPos pos; - if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) - return error("ConnectBlock(): FindUndoPos failed"); - if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) - return AbortNode(state, "Failed to write undo data"); - - // update nUndoPos in block index - pindex->nUndoPos = pos.nPos; - pindex->nStatus |= BLOCK_HAVE_UNDO; - } - - pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); - setDirtyBlockIndex.insert(pindex); - } - - if (fTxIndex) - if (!pblocktree->WriteTxIndex(vPos)) - return AbortNode(state, "Failed to write transaction index"); - - if (fAddressIndex) { - if (!pblocktree->WriteAddressIndex(addressIndex)) { - return AbortNode(state, "Failed to write address index"); - } - - if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { - return AbortNode(state, "Failed to write address unspent index"); - } - } - - if (fSpentIndex) - if (!pblocktree->UpdateSpentIndex(spentIndex)) - return AbortNode(state, "Failed to write transaction index"); - - if (fTimestampIndex) - if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(pindex->nTime, pindex->GetBlockHash()))) - return AbortNode(state, "Failed to write timestamp index"); - - // add this block to the view's block chain - view.SetBestBlock(pindex->GetBlockHash()); - trieCache.setBestBlock(pindex->GetBlockHash()); - - int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; - LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); - - // Watch for changes to the previous coinbase transaction. - static uint256 hashPrevBestCoinBase; - GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = block.vtx[0].GetHash(); - - int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; - LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); - - return true; -} - -enum FlushStateMode { - FLUSH_STATE_NONE, - FLUSH_STATE_IF_NEEDED, - FLUSH_STATE_PERIODIC, - FLUSH_STATE_ALWAYS -}; - -/** - * Update the on-disk chain state. - * The caches and indexes are flushed depending on the mode we're called with - * if they're too large, if it's been a while since the last write, - * or always and in all cases if we're in prune mode and are deleting files. - */ -bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { - const CChainParams& chainparams = Params(); - LOCK2(cs_main, cs_LastBlockFile); - static int64_t nLastWrite = 0; - static int64_t nLastFlush = 0; - static int64_t nLastSetChain = 0; - std::set setFilesToPrune; - bool fFlushForPrune = false; - try { - if (fPruneMode && fCheckForPruning && !fReindex) { - FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); - fCheckForPruning = false; - if (!setFilesToPrune.empty()) { - fFlushForPrune = true; - if (!fHavePruned) { - pblocktree->WriteFlag("prunedblockfiles", true); - fHavePruned = true; - } - } - } - int64_t nNow = GetTimeMicros(); - // Avoid writing/flushing immediately after startup. - if (nLastWrite == 0) { - nLastWrite = nNow; - } - if (nLastFlush == 0) { - nLastFlush = nNow; - } - if (nLastSetChain == 0) { - nLastSetChain = nNow; - } - size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); - // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). - bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; - // The cache is over the limit, we have to write now. - bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; - // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. - bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; - // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. - bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; - // Combine all conditions that result in a full cache flush. - bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; - // Write blocks and block index to disk. - if (fDoFullFlush || fPeriodicWrite) { - // Depend on nMinDiskSpace to ensure we can write block index - if (!CheckDiskSpace(0)) - return state.Error("out of disk space"); - // First make sure all block and undo data is flushed to disk. - FlushBlockFile(); - // Then update all block file information (which may refer to block and undo files). - { - std::vector > vFiles; - vFiles.reserve(setDirtyFileInfo.size()); - for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { - vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); - setDirtyFileInfo.erase(it++); - } - std::vector vBlocks; - vBlocks.reserve(setDirtyBlockIndex.size()); - for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { - vBlocks.push_back(*it); - setDirtyBlockIndex.erase(it++); - } - if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { - return AbortNode(state, "Files to write to block index database"); - } - } - // Finally remove any pruned files - if (fFlushForPrune) - UnlinkPrunedFiles(setFilesToPrune); - nLastWrite = nNow; - } - // Flush best chain related state. This can only be done if the blocks / block index write was also done. - if (fDoFullFlush) { - // Typical CCoins structures on disk are around 128 bytes in size. - // Pushing a new one to the database can cause it to be written - // twice (once in the log, and once in the tables). This is already - // an overestimation, as most will delete an existing entry or - // overwrite one. Still, use a conservative safety factor of 2. - if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) - return state.Error("out of disk space"); - if(!pclaimTrie->WriteToDisk()) - return AbortNode("Failed to write to claim trie database"); - // Flush the chainstate (which may refer to block index entries). - if (!pcoinsTip->Flush()) - return AbortNode(state, "Failed to write to coin database"); - nLastFlush = nNow; - } - if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { - // Update best block in wallet (so we can detect restored wallets). - GetMainSignals().SetBestChain(chainActive.GetLocator()); - nLastSetChain = nNow; - } - } catch (const std::runtime_error& e) { - return AbortNode(state, std::string("System error while flushing: ") + e.what()); - } - return true; -} - -void FlushStateToDisk() { - CValidationState state; - FlushStateToDisk(state, FLUSH_STATE_ALWAYS); -} - -void PruneAndFlush() { - CValidationState state; - fCheckForPruning = true; - FlushStateToDisk(state, FLUSH_STATE_NONE); -} - -/** Update chainActive and related internal data structures. */ -void static UpdateTip(CBlockIndex *pindexNew) { - const CChainParams& chainParams = Params(); - chainActive.SetTip(pindexNew); - - // New best block - nTimeBestReceived = GetTime(); - mempool.AddTransactionsUpdated(1); - - LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); - - cvBlockChange.notify_all(); - - // Check the version of the last 100 blocks to see if we need to upgrade: - static bool fWarned = false; - if (!IsInitialBlockDownload()) - { - int nUpgraded = 0; - const CBlockIndex* pindex = chainActive.Tip(); - for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { - WarningBitsConditionChecker checker(bit); - ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); - if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { - if (state == THRESHOLD_ACTIVE) { - strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); - if (!fWarned) { - CAlert::Notify(strMiscWarning, true); - fWarned = true; - } - } else { - LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit); - } - } - } - for (int i = 0; i < 100 && pindex != NULL; i++) - { - int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); - if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) - ++nUpgraded; - pindex = pindex->pprev; - } - if (nUpgraded > 0) - LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded); - if (nUpgraded > 100/2) - { - // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); - if (!fWarned) { - CAlert::Notify(strMiscWarning, true); - fWarned = true; - } - } - } -} - -/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */ -bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams) -{ - CBlockIndex *pindexDelete = chainActive.Tip(); - assert(pindexDelete); - // Read block from disk. - CBlock block; - if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) - return AbortNode(state, "Failed to read block"); - // Apply the block atomically to the chain state. - int64_t nStart = GetTimeMicros(); - { - CCoinsViewCache view(pcoinsTip); - CClaimTrieCache trieCache(pclaimTrie); - if (!DisconnectBlock(block, state, pindexDelete, view, trieCache)) - return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); - assert(view.Flush()); - assert(trieCache.flush()); - //assert(pindexDelete->pprev->hashClaimTrie == trieCache.getMerkleHash()); - } - LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); - // Write the chain state to disk, if necessary. - if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) - return false; - // Resurrect mempool transactions from the disconnected block. - std::vector vHashUpdate; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - // ignore validation errors in resurrected transactions - list removed; - CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { - mempool.remove(tx, removed, true); - } else if (mempool.exists(tx.GetHash())) { - vHashUpdate.push_back(tx.GetHash()); - } - } - // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have - // no in-mempool children, which is generally not true when adding - // previously-confirmed transactions back to the mempool. - // UpdateTransactionsFromBlock finds descendants of any transactions in this - // block that were added back and cleans up the mempool state. - mempool.UpdateTransactionsFromBlock(vHashUpdate); - // Update chainActive and related variables. - UpdateTip(pindexDelete->pprev); - // Let wallets know transactions went from 1-confirmed to - // 0-confirmed or conflicted: - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - SyncWithWallets(tx, NULL); - } - return true; -} - -static int64_t nTimeReadFromDisk = 0; -static int64_t nTimeConnectTotal = 0; -static int64_t nTimeFlush = 0; -static int64_t nTimeChainState = 0; -static int64_t nTimePostConnect = 0; - -/** - * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock - * corresponding to pindexNew, to bypass loading it again from disk. - */ -bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock) -{ - assert(pindexNew->pprev == chainActive.Tip()); - // Read block from disk. - int64_t nTime1 = GetTimeMicros(); - CBlock block; - if (!pblock) { - if (!ReadBlockFromDisk(block, pindexNew, chainparams.GetConsensus())) - return AbortNode(state, "Failed to read block"); - pblock = █ - } - // Apply the block atomically to the chain state. - int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; - int64_t nTime3; - LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); - { - CCoinsViewCache view(pcoinsTip); - CClaimTrieCache trieCache(pclaimTrie); - bool rv = ConnectBlock(*pblock, state, pindexNew, view, trieCache); - GetMainSignals().BlockChecked(*pblock, state); - if (!rv) { - if (state.IsInvalid()) - InvalidBlockFound(pindexNew, state); - return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); - } - mapBlockSource.erase(pindexNew->GetBlockHash()); - nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; - LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001); - assert(view.Flush()); - assert(trieCache.flush()); - } - int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; - LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001); - // Write the chain state to disk, if necessary. - if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) - return false; - int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; - LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); - // Remove conflicting transactions from the mempool. - list txConflicted; - mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); - // Update chainActive & related variables. - UpdateTip(pindexNew); - // Tell wallet about transactions that went from mempool - // to conflicted: - BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, NULL); - } - // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pblock); - } - - int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; - LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); - LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); - return true; -} - -bool DisconnectBlocks(int blocks) -{ - LOCK(cs_main); - - CValidationState state; - const CChainParams& chainparams = Params(); - - LogPrintf("DisconnectBlocks -- Got command to replay %d blocks\n", blocks); - for(int i = 0; i < blocks; i++) { - if(!DisconnectTip(state, chainparams.GetConsensus()) || !state.IsValid()) { - return false; - } - } - - return true; -} - -void ReprocessBlocks(int nBlocks) -{ - LOCK(cs_main); - - std::map::iterator it = mapRejectedBlocks.begin(); - while(it != mapRejectedBlocks.end()){ - //use a window twice as large as is usual for the nBlocks we want to reset - if((*it).second > GetTime() - (nBlocks*60*5)) { - BlockMap::iterator mi = mapBlockIndex.find((*it).first); - if (mi != mapBlockIndex.end() && (*mi).second) { - - CBlockIndex* pindex = (*mi).second; - LogPrintf("ReprocessBlocks -- %s\n", (*it).first.ToString()); - - CValidationState state; - ReconsiderBlock(state, pindex); - } - } - ++it; - } - - DisconnectBlocks(nBlocks); - - CValidationState state; - ActivateBestChain(state, Params()); -} - -/** - * Return the tip of the chain with the most work in it, that isn't - * known to be invalid (it's however far from certain to be valid). - */ -static CBlockIndex* FindMostWorkChain() { - do { - CBlockIndex *pindexNew = NULL; - - // Find the best candidate header. - { - std::set::reverse_iterator it = setBlockIndexCandidates.rbegin(); - if (it == setBlockIndexCandidates.rend()) - return NULL; - pindexNew = *it; - } - - // Check whether all blocks on the path between the currently active chain and the candidate are valid. - // Just going until the active chain is an optimization, as we know all blocks in it are valid already. - CBlockIndex *pindexTest = pindexNew; - bool fInvalidAncestor = false; - while (pindexTest && !chainActive.Contains(pindexTest)) { - assert(pindexTest->nChainTx || pindexTest->nHeight == 0); - - // Pruned nodes may have entries in setBlockIndexCandidates for - // which block files have been deleted. Remove those as candidates - // for the most work chain if we come across them; we can't switch - // to a chain unless we have all the non-active-chain parent blocks. - bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK; - bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA); - if (fFailedChain || fMissingData) { - // Candidate chain is not usable (either invalid or missing data) - if (fFailedChain && (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)) - pindexBestInvalid = pindexNew; - CBlockIndex *pindexFailed = pindexNew; - // Remove the entire chain from the set. - while (pindexTest != pindexFailed) { - if (fFailedChain) { - pindexFailed->nStatus |= BLOCK_FAILED_CHILD; - } else if (fMissingData) { - // If we're missing data, then add back to mapBlocksUnlinked, - // so that if the block arrives in the future we can try adding - // to setBlockIndexCandidates again. - mapBlocksUnlinked.insert(std::make_pair(pindexFailed->pprev, pindexFailed)); - } - setBlockIndexCandidates.erase(pindexFailed); - pindexFailed = pindexFailed->pprev; - } - setBlockIndexCandidates.erase(pindexTest); - fInvalidAncestor = true; - break; - } - pindexTest = pindexTest->pprev; - } - if (!fInvalidAncestor) - return pindexNew; - } while(true); -} - -/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ -static void PruneBlockIndexCandidates() { - // Note that we can't delete the current block itself, as we may need to return to it later in case a - // reorganization to a better block fails. - std::set::iterator it = setBlockIndexCandidates.begin(); - while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { - setBlockIndexCandidates.erase(it++); - } - // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. - assert(!setBlockIndexCandidates.empty()); -} - -/** - * Try to make some progress towards making pindexMostWork the active block. - * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. - */ -static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock) -{ - AssertLockHeld(cs_main); - bool fInvalidFound = false; - const CBlockIndex *pindexOldTip = chainActive.Tip(); - const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); - - // Disconnect active blocks which are no longer in the best chain. - bool fBlocksDisconnected = false; - while (chainActive.Tip() && chainActive.Tip() != pindexFork) { - if (!DisconnectTip(state, chainparams.GetConsensus())) - return false; - fBlocksDisconnected = true; - } - - // Build list of new blocks to connect. - std::vector vpindexToConnect; - bool fContinue = true; - int nHeight = pindexFork ? pindexFork->nHeight : -1; - while (fContinue && nHeight != pindexMostWork->nHeight) { - // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need - // a few blocks along the way. - int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); - vpindexToConnect.clear(); - vpindexToConnect.reserve(nTargetHeight - nHeight); - CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); - while (pindexIter && pindexIter->nHeight != nHeight) { - vpindexToConnect.push_back(pindexIter); - pindexIter = pindexIter->pprev; - } - nHeight = nTargetHeight; - - // Connect new blocks. - BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { - if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { - if (state.IsInvalid()) { - // The block violates a consensus rule. - if (!state.CorruptionPossible()) - InvalidChainFound(vpindexToConnect.back()); - state = CValidationState(); - fInvalidFound = true; - fContinue = false; - break; - } else { - // A system error occurred (disk space, database error, ...). - return false; - } - } else { - PruneBlockIndexCandidates(); - if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { - // We're in a better position than we were. Return temporarily to release the lock. - fContinue = false; - break; - } - } - } - } - - if (fBlocksDisconnected) { - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); - LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); - } - mempool.check(pcoinsTip); - - // Callbacks/notifications for a new best chain. - if (fInvalidFound) - CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); - else - CheckForkWarningConditions(); - - return true; -} - -/** - * Make the best chain active, in multiple steps. The result is either failure - * or an activated best chain. pblock is either NULL or a pointer to a block - * that is already loaded (to avoid loading it again from disk). - */ -bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { - CBlockIndex *pindexMostWork = NULL; - do { - boost::this_thread::interruption_point(); - if (ShutdownRequested()) - break; - - CBlockIndex *pindexNewTip = NULL; - const CBlockIndex *pindexFork; - bool fInitialDownload; - { - LOCK(cs_main); - CBlockIndex *pindexOldTip = chainActive.Tip(); - pindexMostWork = FindMostWorkChain(); - - // Whether we have anything to do at all. - if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) - return true; - - if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) - return false; - - pindexNewTip = chainActive.Tip(); - pindexFork = chainActive.FindFork(pindexOldTip); - fInitialDownload = IsInitialBlockDownload(); - } - // When we reach this point, we switched to a new tip (stored in pindexNewTip). - - // Notifications/callbacks that can run without cs_main - // Always notify the UI if a new block tip was connected - if (pindexFork != pindexNewTip) { - uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); - - if (!fInitialDownload) { - // Find the hashes of all blocks that weren't previously in the best chain. - std::vector vHashes; - CBlockIndex *pindexToAnnounce = pindexNewTip; - while (pindexToAnnounce != pindexFork) { - vHashes.push_back(pindexToAnnounce->GetBlockHash()); - pindexToAnnounce = pindexToAnnounce->pprev; - if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) { - // Limit announcements in case of a huge reorganization. - // Rely on the peer's synchronization mechanism in that case. - break; - } - } - // Relay inventory, but don't relay old inventory during initial block download. - int nBlockEstimate = 0; - if (fCheckpointsEnabled) - nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) { - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { - BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { - pnode->PushBlockHash(hash); - } - } - } - } - // Notify external listeners about the new tip. - if (!vHashes.empty()) { - GetMainSignals().UpdatedBlockTip(pindexNewTip); - } - } - } - } while(pindexMostWork != chainActive.Tip()); - CheckBlockIndex(chainparams.GetConsensus()); - - // Write changes periodically to disk, after relay. - if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { - return false; - } - - return true; -} - -bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex) -{ - AssertLockHeld(cs_main); - - // Mark the block itself as invalid. - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); - setBlockIndexCandidates.erase(pindex); - - while (chainActive.Contains(pindex)) { - CBlockIndex *pindexWalk = chainActive.Tip(); - pindexWalk->nStatus |= BLOCK_FAILED_CHILD; - setDirtyBlockIndex.insert(pindexWalk); - setBlockIndexCandidates.erase(pindexWalk); - // ActivateBestChain considers blocks already in chainActive - // unconditionally valid already, so force disconnect away from it. - if (!DisconnectTip(state, consensusParams)) { - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); - return false; - } - } - - LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); - - // The resulting new best tip may not be in setBlockIndexCandidates anymore, so - // add it again. - BlockMap::iterator it = mapBlockIndex.begin(); - while (it != mapBlockIndex.end()) { - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { - setBlockIndexCandidates.insert(it->second); - } - it++; - } - - InvalidChainFound(pindex); - mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); - return true; -} - -bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { - AssertLockHeld(cs_main); - - int nHeight = pindex->nHeight; - - // Remove the invalidity flag from this block and all its descendants. - BlockMap::iterator it = mapBlockIndex.begin(); - while (it != mapBlockIndex.end()) { - if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { - it->second->nStatus &= ~BLOCK_FAILED_MASK; - setDirtyBlockIndex.insert(it->second); - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { - setBlockIndexCandidates.insert(it->second); - } - if (it->second == pindexBestInvalid) { - // Reset invalid block marker if it was pointing to one of those. - pindexBestInvalid = NULL; - } - } - it++; - } - - // Remove the invalidity flag from all ancestors too. - while (pindex != NULL) { - if (pindex->nStatus & BLOCK_FAILED_MASK) { - pindex->nStatus &= ~BLOCK_FAILED_MASK; - setDirtyBlockIndex.insert(pindex); - } - pindex = pindex->pprev; - } - return true; -} - -CBlockIndex* AddToBlockIndex(const CBlockHeader& block) -{ - // Check for duplicate - uint256 hash = block.GetHash(); - BlockMap::iterator it = mapBlockIndex.find(hash); - if (it != mapBlockIndex.end()) - return it->second; - - // Construct new block index object - CBlockIndex* pindexNew = new CBlockIndex(block); - assert(pindexNew); - // We assign the sequence id to blocks only when the full data is available, - // to avoid miners withholding blocks but broadcasting headers, to get a - // competitive advantage. - pindexNew->nSequenceId = 0; - BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); - if (miPrev != mapBlockIndex.end()) - { - pindexNew->pprev = (*miPrev).second; - pindexNew->nHeight = pindexNew->pprev->nHeight + 1; - pindexNew->BuildSkip(); - } - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); - pindexNew->RaiseValidity(BLOCK_VALID_TREE); - if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) - pindexBestHeader = pindexNew; - - setDirtyBlockIndex.insert(pindexNew); - - return pindexNew; -} - -/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ -bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) -{ - pindexNew->nTx = block.vtx.size(); - pindexNew->nChainTx = 0; - pindexNew->nFile = pos.nFile; - pindexNew->nDataPos = pos.nPos; - pindexNew->nUndoPos = 0; - pindexNew->nStatus |= BLOCK_HAVE_DATA; - pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); - setDirtyBlockIndex.insert(pindexNew); - - if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { - // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. - deque queue; - queue.push_back(pindexNew); - - // Recursively process any descendant blocks that now may be eligible to be connected. - while (!queue.empty()) { - CBlockIndex *pindex = queue.front(); - queue.pop_front(); - pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; - { - LOCK(cs_nBlockSequenceId); - pindex->nSequenceId = nBlockSequenceId++; - } - if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { - setBlockIndexCandidates.insert(pindex); - } - std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex); - while (range.first != range.second) { - std::multimap::iterator it = range.first; - queue.push_back(it->second); - range.first++; - mapBlocksUnlinked.erase(it); - } - } - } else { - if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) { - mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew)); - } - } - - return true; -} - -bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) -{ - LOCK(cs_LastBlockFile); - - unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; - if (vinfoBlockFile.size() <= nFile) { - vinfoBlockFile.resize(nFile + 1); - } - - if (!fKnown) { - while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { - nFile++; - if (vinfoBlockFile.size() <= nFile) { - vinfoBlockFile.resize(nFile + 1); - } - } - pos.nFile = nFile; - pos.nPos = vinfoBlockFile[nFile].nSize; - } - - if ((int)nFile != nLastBlockFile) { - if (!fKnown) { - LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); - } - FlushBlockFile(!fKnown); - nLastBlockFile = nFile; - } - - vinfoBlockFile[nFile].AddBlock(nHeight, nTime); - if (fKnown) - vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); - else - vinfoBlockFile[nFile].nSize += nAddSize; - - if (!fKnown) { - unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; - unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; - if (nNewChunks > nOldChunks) { - if (fPruneMode) - fCheckForPruning = true; - if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { - FILE *file = OpenBlockFile(pos); - if (file) { - LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); - fclose(file); - } - } - else - return state.Error("out of disk space"); - } - } - - setDirtyFileInfo.insert(nFile); - return true; -} - -bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) -{ - pos.nFile = nFile; - - LOCK(cs_LastBlockFile); - - unsigned int nNewSize; - pos.nPos = vinfoBlockFile[nFile].nUndoSize; - nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; - setDirtyFileInfo.insert(nFile); - - unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; - unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; - if (nNewChunks > nOldChunks) { - if (fPruneMode) - fCheckForPruning = true; - if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { - FILE *file = OpenUndoFile(pos); - if (file) { - LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); - AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); - fclose(file); - } - } - else - return state.Error("out of disk space"); - } - - return true; -} - -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) -{ - // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) - { - LogPrintf("CheckBlockHeader(): \n--b-l-o-c-k---%s\n\n", block.ToString().c_str()); - return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), - REJECT_INVALID, "high-hash"); - } - // Check timestamp - if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) - return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), - REJECT_INVALID, "time-too-new"); - - return true; -} - -bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) -{ - // These are checks that are independent of context. - - if (block.fChecked) - return true; - - // Check that the header is valid (particularly PoW). This is mostly - // redundant with the call in AcceptBlockHeader. - if (!CheckBlockHeader(block, state, fCheckPOW)) - return false; - - // Check the merkle root. - if (fCheckMerkleRoot) { - bool mutated; - uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); - if (block.hashMerkleRoot != hashMerkleRoot2) - return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"), - REJECT_INVALID, "bad-txnmrklroot", true); - - // Check for merkle tree malleability (CVE-2012-2459): repeating sequences - // of transactions in a block without affecting the merkle root of a block, - // while still invalidating it. - if (mutated) - return state.DoS(100, error("CheckBlock(): duplicate transaction"), - REJECT_INVALID, "bad-txns-duplicate", true); - } - - // All potential-corruption validation must be done before we do any - // transaction validation, as otherwise we may mark the header as invalid - // because we receive the wrong transactions for it. - - // Size limits - if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, error("CheckBlock(): size limits failed"), - REJECT_INVALID, "bad-blk-length"); - - // First transaction must be coinbase, the rest must not be - if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), - REJECT_INVALID, "bad-cb-missing"); - for (unsigned int i = 1; i < block.vtx.size(); i++) - if (block.vtx[i].IsCoinBase()) - return state.DoS(100, error("CheckBlock(): more than one coinbase"), - REJECT_INVALID, "bad-cb-multiple"); - - - // PCH : CHECK TRANSACTIONS FOR INSTANTSEND - - if(sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { - // We should never accept block which conflicts with completed transaction lock, - // that's why this is in CheckBlock unlike coinbase payee/amount. - // Require other nodes to comply, send them some data in case they are missing it. - BOOST_FOREACH(const CTransaction& tx, block.vtx) { - // skip coinbase, it has no inputs - if (tx.IsCoinBase()) continue; - // LOOK FOR TRANSACTION LOCK IN OUR MAP OF OUTPOINTS - BOOST_FOREACH(const CTxIn& txin, tx.vin) { - uint256 hashLocked; - if(instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hashLocked != tx.GetHash()) { - // Every node which relayed this block to us must invalidate it - // but they probably need more data. - // Relay corresponding transaction lock request and all its votes - // to let other nodes complete the lock. - instantsend.Relay(hashLocked); - LOCK(cs_main); - mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); - return state.DoS(0, error("CheckBlock(PCH): transaction %s conflicts with transaction lock %s", - tx.GetHash().ToString(), hashLocked.ToString()), - REJECT_INVALID, "conflict-tx-lock"); - } - } - } - } else { - LogPrintf("CheckBlock(PCH): spork is off, skipping transaction locking checks\n"); - } - - // END PCH - - // Check transactions - BOOST_FOREACH(const CTransaction& tx, block.vtx) - if (!CheckTransaction(tx, state)) - return error("CheckBlock(): CheckTransaction of %s failed with %s", - tx.GetHash().ToString(), - FormatStateMessage(state)); - - unsigned int nSigOps = 0; - BOOST_FOREACH(const CTransaction& tx, block.vtx) - { - nSigOps += GetLegacySigOpCount(tx); - } - if (nSigOps > MAX_BLOCK_SIGOPS) - return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), - REJECT_INVALID, "bad-blk-sigops"); - - if (fCheckPOW && fCheckMerkleRoot) - block.fChecked = true; - - return true; -} - -static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash) -{ - if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock) - return true; - - int nHeight = pindexPrev->nHeight+1; - // Don't accept any forks from the main chain prior to last checkpoint - CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); - if (pcheckpoint && nHeight < pcheckpoint->nHeight) - return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight)); - - return true; -} - -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) -{ - const Consensus::Params& consensusParams = Params().GetConsensus(); - if (block.GetHash() == consensusParams.hashGenesisBlock) - return true; - - int nHeight = pindexPrev->nHeight + 1; - LogPrintf("check block header height %d \n", nHeight); - // Check proof of work - if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) - return state.DoS(100, error("%s : incorrect proof of work at %d", __func__, nHeight), - REJECT_INVALID, "bad-diffbits"); - - // Check timestamp against prev - if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return state.Invalid(error("%s: block's timestamp is too early", __func__), - REJECT_INVALID, "time-too-old"); - - // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(error("%s: rejected nVersion=1 block", __func__), - REJECT_OBSOLETE, "bad-version"); - - // Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(error("%s: rejected nVersion=2 block", __func__), - REJECT_OBSOLETE, "bad-version"); - - // Reject block.nVersion=3 blocks when 95% (75% on testnet) of the network has upgraded: - if (block.nVersion < 4 && IsSuperMajority(4, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) - return state.Invalid(error("%s : rejected nVersion=3 block", __func__), - REJECT_OBSOLETE, "bad-version"); - - return true; -} - -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) -{ - const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; - const Consensus::Params& consensusParams = Params().GetConsensus(); - - // Start enforcing BIP113 (Median Time Past) using versionbits logic. - int nLockTimeFlags = 0; - if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { - nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; - } - - int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) - ? pindexPrev->GetMedianTimePast() - : block.GetBlockTime(); - - // Check that all transactions are finalized - BOOST_FOREACH(const CTransaction& tx, block.vtx) { - if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { - return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); - } - } - - // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height - // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): - if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)) - { - CScript expect = CScript() << nHeight; - if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || - !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { - return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); - } - } - - return true; -} - -static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) -{ - AssertLockHeld(cs_main); - // Check for duplicate - uint256 hash = block.GetHash(); - BlockMap::iterator miSelf = mapBlockIndex.find(hash); - CBlockIndex *pindex = NULL; - - // TODO : ENABLE BLOCK CACHE IN SPECIFIC CASES - if (hash != chainparams.GetConsensus().hashGenesisBlock) { - - if (miSelf != mapBlockIndex.end()) { - // Block header is already known. - pindex = miSelf->second; - if (ppindex) - *ppindex = pindex; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); - return true; - } - - if (!CheckBlockHeader(block, state)) - return false; - - // Get prev block index - CBlockIndex* pindexPrev = NULL; - BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); - if (mi == mapBlockIndex.end()) - return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); - pindexPrev = (*mi).second; - if (pindexPrev->nStatus & BLOCK_FAILED_MASK) - return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); - - assert(pindexPrev); - if (fCheckpointsEnabled) - { - uint256 lastCheckpoint_t = Checkpoints::GetHeightCheckpoint(pindexPrev->nHeight+1 ,chainparams.Checkpoints()); - if(lastCheckpoint_t != uint256()) - { - if (hash != lastCheckpoint_t) - { - LogPrintf("synchronous chain height=%d hash = [%s][%s]\n",pindexPrev->nHeight+1,hash.ToString(),lastCheckpoint_t.ToString() ); - return state.DoS(100, error("%s: checkpoint block invalid", __func__), REJECT_INVALID, "bad-prevblk"); - } - else - { - LogPrintf("checkpoint verify correct.\n"); - } - } - } - - if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash)) - return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); - - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) - return false; - } - if (pindex == NULL) - pindex = AddToBlockIndex(block); - - if (ppindex) - *ppindex = pindex; - - return true; -} - -/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ -static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) -{ - AssertLockHeld(cs_main); - - CBlockIndex *&pindex = *ppindex; - - if (!AcceptBlockHeader(block, state, chainparams, &pindex)) - return false; - - // Try to process all requested blocks that we don't have, but only - // process an unrequested block if it's new and has enough work to - // advance our tip, and isn't too many blocks ahead. - bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; - bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); - // Blocks that are too out-of-order needlessly limit the effectiveness of - // pruning, because pruning will not delete block files that contain any - // blocks which are too close in height to the tip. Apply this test - // regardless of whether pruning is enabled; it should generally be safe to - // not process unrequested blocks. - bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); - - // TODO: deal better with return value and error conditions for duplicate - // and unrequested blocks. - if (fAlreadyHave) return true; - if (!fRequested) { // If we didn't ask for it: - if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned - if (!fHasMoreWork) return true; // Don't process less-work chains - if (fTooFarAhead) return true; // Block height is too high - } - - if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { - if (state.IsInvalid() && !state.CorruptionPossible()) { - pindex->nStatus |= BLOCK_FAILED_VALID; - setDirtyBlockIndex.insert(pindex); - } - return false; - } - - int nHeight = pindex->nHeight; - - // Write block to history file - try { - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - if (dbp != NULL) - blockPos = *dbp; - if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) - return error("AcceptBlock(): FindBlockPos failed"); - if (dbp == NULL) - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) - AbortNode(state, "Failed to write block"); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) - return error("AcceptBlock(): ReceivedBlockTransactions failed"); - } catch (const std::runtime_error& e) { - return AbortNode(state, std::string("System error: ") + e.what()); - } - - if (fCheckForPruning) - FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files - - return true; -} - -static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) -{ - unsigned int nFound = 0; - for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) - { - if (pstart->nVersion >= minVersion) - ++nFound; - pstart = pstart->pprev; - } - return (nFound >= nRequired); -} - - -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) -{ - // Preliminary checks - bool checked = CheckBlock(*pblock, state); - - { - LOCK(cs_main); - bool fRequested = MarkBlockAsReceived(pblock->GetHash()); - fRequested |= fForceProcessing; - if (!checked) { - return error("%s: CheckBlock FAILED", __func__); - } - - // Store to disk - CBlockIndex *pindex = NULL; - bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp); - if (pindex && pfrom) { - mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); - } - CheckBlockIndex(chainparams.GetConsensus()); - if (!ret) - return error("%s: AcceptBlock FAILED", __func__); - } - - if (!ActivateBestChain(state, chainparams, pblock)) - return error("%s: ActivateBestChain failed", __func__); - - popnodeSync.IsBlockchainSynced(true); - - LogPrintf("%s : ACCEPTED\n", __func__); - return true; -} - -bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) -{ - AssertLockHeld(cs_main); - assert(pindexPrev && pindexPrev == chainActive.Tip()); - if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) - return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); - - CCoinsViewCache viewNew(pcoinsTip); - CClaimTrieCache trieCache(pclaimTrie); - CBlockIndex indexDummy(block); - indexDummy.pprev = pindexPrev; - indexDummy.nHeight = pindexPrev->nHeight + 1; - - // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(block, state, pindexPrev)) - return false; - if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) - return false; - if (!ContextualCheckBlock(block, state, pindexPrev)) - return false; - if (!ConnectBlock(block, state, &indexDummy, viewNew, trieCache, true)) - return false; - assert(state.IsValid()); - - return true; -} - -/** - * BLOCK PRUNING CODE - */ - -/* Calculate the amount of disk space the block & undo files currently use */ -uint64_t CalculateCurrentUsage() -{ - uint64_t retval = 0; - BOOST_FOREACH(const CBlockFileInfo &file, vinfoBlockFile) { - retval += file.nSize + file.nUndoSize; - } - return retval; -} - -/* Prune a block file (modify associated database entries)*/ -void PruneOneBlockFile(const int fileNumber) -{ - for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) { - CBlockIndex* pindex = it->second; - if (pindex->nFile == fileNumber) { - pindex->nStatus &= ~BLOCK_HAVE_DATA; - pindex->nStatus &= ~BLOCK_HAVE_UNDO; - pindex->nFile = 0; - pindex->nDataPos = 0; - pindex->nUndoPos = 0; - setDirtyBlockIndex.insert(pindex); - - // Prune from mapBlocksUnlinked -- any block we prune would have - // to be downloaded again in order to consider its chain, at which - // point it would be considered as a candidate for - // mapBlocksUnlinked or setBlockIndexCandidates. - std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev); - while (range.first != range.second) { - std::multimap::iterator it = range.first; - range.first++; - if (it->second == pindex) { - mapBlocksUnlinked.erase(it); - } - } - } - } - - vinfoBlockFile[fileNumber].SetNull(); - setDirtyFileInfo.insert(fileNumber); -} - - -void UnlinkPrunedFiles(std::set& setFilesToPrune) -{ - for (set::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) { - CDiskBlockPos pos(*it, 0); - boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); - boost::filesystem::remove(GetBlockPosFilename(pos, "rev")); - LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it); - } -} - -/* Calculate the block/rev files that should be deleted to remain under target*/ -void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight) -{ - LOCK2(cs_main, cs_LastBlockFile); - if (chainActive.Tip() == NULL || nPruneTarget == 0) { - return; - } - if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) { - return; - } - - unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP; - uint64_t nCurrentUsage = CalculateCurrentUsage(); - // We don't check to prune until after we've allocated new space for files - // So we should leave a buffer under our target to account for another allocation - // before the next pruning. - uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; - uint64_t nBytesToPrune; - int count=0; - - if (nCurrentUsage + nBuffer >= nPruneTarget) { - for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { - nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; - - if (vinfoBlockFile[fileNumber].nSize == 0) - continue; - - if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target? - break; - - // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning - if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) - continue; - - PruneOneBlockFile(fileNumber); - // Queue up the files for removal - setFilesToPrune.insert(fileNumber); - nCurrentUsage -= nBytesToPrune; - count++; - } - } - - LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", - nPruneTarget/1024/1024, nCurrentUsage/1024/1024, - ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, - nLastBlockWeCanPrune, count); -} - -bool CheckDiskSpace(uint64_t nAdditionalBytes) -{ - uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; - - // Check for nMinDiskSpace bytes (currently 50MB) - if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) - return AbortNode("Disk space is low!", _("Error: Disk space is low!")); - - return true; -} - -FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) -{ - if (pos.IsNull()) - return NULL; - boost::filesystem::path path = GetBlockPosFilename(pos, prefix); - boost::filesystem::create_directories(path.parent_path()); - FILE* file = fopen(path.string().c_str(), "rb+"); - if (!file && !fReadOnly) - file = fopen(path.string().c_str(), "wb+"); - if (!file) { - LogPrintf("Unable to open file %s\n", path.string()); - return NULL; - } - if (pos.nPos) { - if (fseek(file, pos.nPos, SEEK_SET)) { - LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string()); - fclose(file); - return NULL; - } - } - return file; -} - -FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { - return OpenDiskFile(pos, "blk", fReadOnly); -} - -FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { - return OpenDiskFile(pos, "rev", fReadOnly); -} - -boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix) -{ - return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); -} - -CBlockIndex * InsertBlockIndex(uint256 hash) -{ - if (hash.IsNull()) - return NULL; - - // Return existing - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) - return (*mi).second; - - // Create new - CBlockIndex* pindexNew = new CBlockIndex(); - if (!pindexNew) - throw runtime_error("LoadBlockIndex(): new CBlockIndex failed"); - mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; - pindexNew->phashBlock = &((*mi).first); - - return pindexNew; -} - -bool static LoadBlockIndexDB() -{ - const CChainParams& chainparams = Params(); - if (!pblocktree->LoadBlockIndexGuts()) - return false; - - boost::this_thread::interruption_point(); - - // Calculate nChainWork - vector > vSortedByHeight; - vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); - // We can link the chain of blocks for which we've received transactions at some point. - // Pruned nodes may have deleted the block. - if (pindex->nTx > 0) { - if (pindex->pprev) { - if (pindex->pprev->nChainTx) { - pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; - } else { - pindex->nChainTx = 0; - mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); - } - } else { - pindex->nChainTx = pindex->nTx; - } - } - if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) - setBlockIndexCandidates.insert(pindex); - if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) - pindexBestInvalid = pindex; - if (pindex->pprev) - pindex->BuildSkip(); - if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) - pindexBestHeader = pindex; - } - - // Load block file info - pblocktree->ReadLastBlockFile(nLastBlockFile); - vinfoBlockFile.resize(nLastBlockFile + 1); - LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); - for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { - pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); - } - LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); - for (int nFile = nLastBlockFile + 1; true; nFile++) { - CBlockFileInfo info; - if (pblocktree->ReadBlockFileInfo(nFile, info)) { - vinfoBlockFile.push_back(info); - } else { - break; - } - } - - // Check presence of blk files - LogPrintf("Checking all blk files are present...\n"); - set setBlkDataFiles; - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - if (pindex->nStatus & BLOCK_HAVE_DATA) { - setBlkDataFiles.insert(pindex->nFile); - } - } - for (std::set::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) - { - CDiskBlockPos pos(*it, 0); - if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { - return false; - } - } - - // Check whether we have ever pruned block & undo files - pblocktree->ReadFlag("prunedblockfiles", fHavePruned); - if (fHavePruned) - LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); - - // Check whether we need to continue reindexing - bool fReindexing = false; - pblocktree->ReadReindexing(fReindexing); - fReindex |= fReindexing; - - // Check whether we have a transaction index - pblocktree->ReadFlag("txindex", fTxIndex); - LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); - - // Check whether we have an address index - pblocktree->ReadFlag("addressindex", fAddressIndex); - LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); - - // Check whether we have a timestamp index - pblocktree->ReadFlag("timestampindex", fTimestampIndex); - LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled"); - - // Check whether we have a spent index - pblocktree->ReadFlag("spentindex", fSpentIndex); - LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled"); - - // Load pointer to end of best chain - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - if (it == mapBlockIndex.end()) - return true; - chainActive.SetTip(it->second); - - PruneBlockIndexCandidates(); - - LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, - chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), - DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); - - return true; -} - -CVerifyDB::CVerifyDB() -{ - uiInterface.ShowProgress(_("Verifying blocks..."), 0); -} - -CVerifyDB::~CVerifyDB() -{ - uiInterface.ShowProgress("", 100); -} - -bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) -{ - LOCK(cs_main); - if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) - return true; - - // Verify blocks in the best chain - if (nCheckDepth <= 0) - nCheckDepth = 1000000000; // suffices until the year 19000 - if (nCheckDepth > chainActive.Height()) - nCheckDepth = chainActive.Height(); - nCheckLevel = std::max(0, std::min(4, nCheckLevel)); - LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); - CCoinsViewCache coins(coinsview); - CClaimTrieCache trieCache(pclaimTrie); - CBlockIndex* pindexState = chainActive.Tip(); - CBlockIndex* pindexFailure = NULL; - int nGoodTransactions = 0; - CValidationState state; - for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) - { - boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); - if (pindex->nHeight < chainActive.Height()-nCheckDepth) - break; - CBlock block; - // check level 0: read from disk - if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) - return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - // check level 1: verify block validity - if (nCheckLevel >= 1 && !CheckBlock(block, state)) - return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - // check level 2: verify undo validity - if (nCheckLevel >= 2 && pindex) { - CBlockUndo undo; - CDiskBlockPos pos = pindex->GetUndoPos(); - if (!pos.IsNull()) { - if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) - return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - } - } - // check level 3: check for inconsistencies during memory-only disconnect of tip blocks - if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { - bool fClean = true; - if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)) - return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - pindexState = pindex->pprev; - if (!fClean) { - nGoodTransactions = 0; - pindexFailure = pindex; - } else - nGoodTransactions += block.vtx.size(); - } - if (ShutdownRequested()) - return true; - } - if (pindexFailure) - return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); - - // check level 4: try reconnecting blocks - if (nCheckLevel >= 4) { - CBlockIndex *pindex = pindexState; - while (pindex != chainActive.Tip()) { - boost::this_thread::interruption_point(); - uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); - pindex = chainActive.Next(pindex); - CBlock block; - if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) - return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - if (!ConnectBlock(block, state, pindex, coins, trieCache)) - return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); - } - } - - LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); - - return true; -} - -bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof) -{ - AssertLockHeld(cs_main); - if (!chainActive.Contains(pindexProof)) - { - return false; - } - CCoinsViewCache coins(pcoinsTip); - CClaimTrieCache trieCache(pclaimTrie); - CBlockIndex* pindexState = chainActive.Tip(); - CValidationState state; - for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev && pindexState != pindexProof; pindex=pindex->pprev) - { - boost::this_thread::interruption_point(); - CBlock block; - if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) - { - return false; - } - if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) - { - bool fClean = true; - if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)) - { - return false; - } - pindexState = pindex->pprev; - } - if (ShutdownRequested()) - return false; - } - assert(pindexState == pindexProof); - proof = trieCache.getProofForName(name); - return true; -} - -void UnloadBlockIndex() -{ - LOCK(cs_main); - setBlockIndexCandidates.clear(); - chainActive.SetTip(NULL); - pindexBestInvalid = NULL; - pindexBestHeader = NULL; - mempool.clear(); - mapOrphanTransactions.clear(); - mapOrphanTransactionsByPrev.clear(); - nSyncStarted = 0; - mapBlocksUnlinked.clear(); - vinfoBlockFile.clear(); - nLastBlockFile = 0; - nBlockSequenceId = 1; - mapBlockSource.clear(); - mapBlocksInFlight.clear(); - nPreferredDownload = 0; - setDirtyBlockIndex.clear(); - setDirtyFileInfo.clear(); - mapNodeState.clear(); - recentRejects.reset(NULL); - versionbitscache.Clear(); - for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { - warningcache[b].clear(); - } - - BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { - delete entry.second; - } - mapBlockIndex.clear(); - fHavePruned = false; -} - -bool LoadBlockIndex() -{ - // Load block index from databases - if (!fReindex && !LoadBlockIndexDB()) - return false; - return true; -} - -bool InitBlockIndex(const CChainParams& chainparams) -{ - LOCK(cs_main); - - // Initialize global variables that cannot be constructed at startup. - recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); - - // Check whether we're already initialized - if (chainActive.Genesis() != NULL) - return true; - - // Use the provided setting for -txindex in the new database - fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX); - pblocktree->WriteFlag("txindex", fTxIndex); - - // Use the provided setting for -addressindex in the new database - fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX); - pblocktree->WriteFlag("addressindex", fAddressIndex); - - // Use the provided setting for -timestampindex in the new database - fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX); - pblocktree->WriteFlag("timestampindex", fTimestampIndex); - - fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX); - pblocktree->WriteFlag("spentindex", fSpentIndex); - - LogPrintf("Initializing databases...\n"); - - // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) - if (!fReindex) { - try { - CBlock &block = const_cast(chainparams.GenesisBlock()); - // Start new block file - unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); - CDiskBlockPos blockPos; - CValidationState state; - if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) - return error("LoadBlockIndex(): FindBlockPos failed"); - if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) - return error("LoadBlockIndex(): writing genesis block to disk failed"); - CBlockIndex *pindex = AddToBlockIndex(block); - if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) - return error("LoadBlockIndex(): genesis block not accepted"); - if (!ActivateBestChain(state, chainparams, &block)) - return error("LoadBlockIndex(): genesis block cannot be activated"); - // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data - return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); - } catch (const std::runtime_error& e) { - return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); - } - } - - return true; -} - -bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) -{ - // Map of disk positions for blocks with unknown parent (only used for reindex) - static std::multimap mapBlocksUnknownParent; - int64_t nStart = GetTimeMillis(); - - int nLoaded = 0; - try { - // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor - CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); - uint64_t nRewind = blkdat.GetPos(); - while (!blkdat.eof()) { - boost::this_thread::interruption_point(); - - blkdat.SetPos(nRewind); - nRewind++; // start one byte further next time, in case of failure - blkdat.SetLimit(); // remove former limit - unsigned int nSize = 0; - try { - // locate a header - unsigned char buf[MESSAGE_START_SIZE]; - blkdat.FindByte(chainparams.MessageStart()[0]); - nRewind = blkdat.GetPos()+1; - blkdat >> FLATDATA(buf); - if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) - continue; - // read size - blkdat >> nSize; - if (nSize < 80 || nSize > MAX_BLOCK_SIZE) - continue; - } catch (const std::exception&) { - // no valid block header found; don't complain - break; - } - try { - // read block - uint64_t nBlockPos = blkdat.GetPos(); - if (dbp) - dbp->nPos = nBlockPos; - blkdat.SetLimit(nBlockPos + nSize); - blkdat.SetPos(nBlockPos); - CBlock block; - blkdat >> block; - nRewind = blkdat.GetPos(); - - // detect out of order blocks, and store them for later - uint256 hash = block.GetHash(); - if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { - LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), - block.hashPrevBlock.ToString()); - if (dbp) - mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); - continue; - } - - // process in case the block isn't known yet - if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { - CValidationState state; - if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) - nLoaded++; - if (state.IsError()) - break; - } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); - } - - // Recursively process earlier encountered successors of this block - deque queue; - queue.push_back(hash); - while (!queue.empty()) { - uint256 head = queue.front(); - queue.pop_front(); - std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); - while (range.first != range.second) { - std::multimap::iterator it = range.first; - if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) - { - LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), - head.ToString()); - CValidationState dummy; - if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) - { - nLoaded++; - queue.push_back(block.GetHash()); - } - } - range.first++; - mapBlocksUnknownParent.erase(it); - } - } - } catch (const std::exception& e) { - LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); - } - } - } catch (const std::runtime_error& e) { - AbortNode(std::string("System error: ") + e.what()); - } - if (nLoaded > 0) - LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); - return nLoaded > 0; -} - -void static CheckBlockIndex(const Consensus::Params& consensusParams) -{ - if (!fCheckBlockIndex) { - return; - } - - LOCK(cs_main); - - // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, - // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when - // iterating the block tree require that chainActive has been initialized.) - if (chainActive.Height() < 0) { - assert(mapBlockIndex.size() <= 1); - return; - } - - // Build forward-pointing map of the entire block tree. - std::multimap forward; - for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { - forward.insert(std::make_pair(it->second->pprev, it->second)); - } - - assert(forward.size() == mapBlockIndex.size()); - - std::pair::iterator,std::multimap::iterator> rangeGenesis = forward.equal_range(NULL); - CBlockIndex *pindex = rangeGenesis.first->second; - rangeGenesis.first++; - assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL. - - // Iterate over the entire block tree, using depth-first search. - // Along the way, remember whether there are blocks on the path from genesis - // block being explored which are the first to have certain properties. - size_t nNodes = 0; - int nHeight = 0; - CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid. - CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA. - CBlockIndex* pindexFirstNeverProcessed = NULL; // Oldest ancestor of pindex for which nTx == 0. - CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not). - CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not). - CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not). - CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not). - while (pindex != NULL) { - nNodes++; - if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex; - if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex; - if (pindexFirstNeverProcessed == NULL && pindex->nTx == 0) pindexFirstNeverProcessed = pindex; - if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex; - if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex; - if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex; - if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex; - - // Begin: actual consistency checks. - if (pindex->pprev == NULL) { - // Genesis block checks. - assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. - assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. - } - if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked - // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). - // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. - if (!fHavePruned) { - // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0 - assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); - assert(pindexFirstMissing == pindexFirstNeverProcessed); - } else { - // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0 - if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0); - } - if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA); - assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent. - // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set. - assert((pindexFirstNeverProcessed != NULL) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned). - assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0)); - assert(pindex->nHeight == nHeight); // nHeight must be consistent. - assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's. - assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks. - assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid - if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid - if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid - if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid - if (pindexFirstInvalid == NULL) { - // Checks for not-invalid blocks. - assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. - } - if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) { - if (pindexFirstInvalid == NULL) { - // If this block sorts at least as good as the current tip and - // is valid and we have all data for its parents, it must be in - // setBlockIndexCandidates. chainActive.Tip() must also be there - // even if some data has been pruned. - if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) { - assert(setBlockIndexCandidates.count(pindex)); - } - // If some parent is missing, then it could be that this block was in - // setBlockIndexCandidates but had to be removed because of the missing data. - // In this case it must be in mapBlocksUnlinked -- see test below. - } - } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates. - assert(setBlockIndexCandidates.count(pindex) == 0); - } - // Check whether this block is in mapBlocksUnlinked. - std::pair::iterator,std::multimap::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev); - bool foundInUnlinked = false; - while (rangeUnlinked.first != rangeUnlinked.second) { - assert(rangeUnlinked.first->first == pindex->pprev); - if (rangeUnlinked.first->second == pindex) { - foundInUnlinked = true; - break; - } - rangeUnlinked.first++; - } - if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != NULL && pindexFirstInvalid == NULL) { - // If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked. - assert(foundInUnlinked); - } - if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA - if (pindexFirstMissing == NULL) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked. - if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == NULL && pindexFirstMissing != NULL) { - // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent. - assert(fHavePruned); // We must have pruned. - // This block may have entered mapBlocksUnlinked if: - // - it has a descendant that at some point had more work than the - // tip, and - // - we tried switching to that descendant but were missing - // data for some intermediate block between chainActive and the - // tip. - // So if this block is itself better than chainActive.Tip() and it wasn't in - // setBlockIndexCandidates, then it must be in mapBlocksUnlinked. - if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) { - if (pindexFirstInvalid == NULL) { - assert(foundInUnlinked); - } - } - } - // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow - // End: actual consistency checks. - - // Try descending into the first subnode. - std::pair::iterator,std::multimap::iterator> range = forward.equal_range(pindex); - if (range.first != range.second) { - // A subnode was found. - pindex = range.first->second; - nHeight++; - continue; - } - // This is a leaf node. - // Move upwards until we reach a node of which we have not yet visited the last child. - while (pindex) { - // We are going to either move to a parent or a sibling of pindex. - // If pindex was the first with a certain property, unset the corresponding variable. - if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL; - if (pindex == pindexFirstMissing) pindexFirstMissing = NULL; - if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = NULL; - if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL; - if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL; - if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL; - if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL; - // Find our parent. - CBlockIndex* pindexPar = pindex->pprev; - // Find which child we just visited. - std::pair::iterator,std::multimap::iterator> rangePar = forward.equal_range(pindexPar); - while (rangePar.first->second != pindex) { - assert(rangePar.first != rangePar.second); // Our parent must have at least the node we're coming from as child. - rangePar.first++; - } - // Proceed to the next one. - rangePar.first++; - if (rangePar.first != rangePar.second) { - // Move to the sibling. - pindex = rangePar.first->second; - break; - } else { - // Move up further. - pindex = pindexPar; - nHeight--; - continue; - } - } - } - - // Check that we actually traversed the entire map. - assert(nNodes == forward.size()); -} - -////////////////////////////////////////////////////////////////////////////// -// -// CAlert -// - -std::string GetWarnings(const std::string& strFor) -{ - int nPriority = 0; - string strStatusBar; - string strRPC; - string strGUI; - - if (!CLIENT_VERSION_IS_RELEASE) { - strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"; - strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); - } - - if (GetBoolArg("-testsafemode", DEFAULT_TESTSAFEMODE)) - strStatusBar = strRPC = strGUI = "testsafemode enabled"; - - // Misc warnings like out of disk space and clock is wrong - if (strMiscWarning != "") - { - nPriority = 1000; - strStatusBar = strGUI = strMiscWarning; - } - - if (fLargeWorkForkFound) - { - nPriority = 2000; - strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; - strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); - } - else if (fLargeWorkInvalidChainFound) - { - nPriority = 2000; - strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; - strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); - } - - // Alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - { - const CAlert& alert = item.second; - if (alert.AppliesToMe() && alert.nPriority > nPriority) - { - nPriority = alert.nPriority; - strStatusBar = strGUI = alert.strStatusBar; - } - } - } - - if (strFor == "gui") - return strGUI; - else if (strFor == "statusbar") - return strStatusBar; - else if (strFor == "rpc") - return strRPC; - assert(!"GetWarnings(): invalid parameter"); - return "error"; -} - - - - - - - - -////////////////////////////////////////////////////////////////////////////// -// -// Messages -// - - -bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) -{ - switch (inv.type) - { - case MSG_TX: - { - assert(recentRejects); - if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) - { - // If the chain tip has changed previously rejected transactions - // might be now valid, e.g. due to a nLockTime'd tx becoming valid, - // or a double-spend. Reset the rejects filter and give those - // txs a second chance. - hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); - recentRejects->reset(); - } - - return recentRejects->contains(inv.hash) || - mempool.exists(inv.hash) || - mapOrphanTransactions.count(inv.hash) || - pcoinsTip->HaveCoins(inv.hash); - } - - case MSG_BLOCK: - return mapBlockIndex.count(inv.hash); - - /* - Pop Related Inventory Messages - - -- - - We shouldn't update the sync times for each of the messages when we already have it. - We're going to be asking many nodes upfront for the full inventory list, so we'll get duplicates of these. - We want to only update the time on new hits, so that we can time out appropriately if needed. - */ - case MSG_TXLOCK_REQUEST: - return instantsend.AlreadyHave(inv.hash); - - case MSG_TXLOCK_VOTE: - return instantsend.AlreadyHave(inv.hash); - - case MSG_SPORK: - return mapSporks.count(inv.hash); - - case MSG_POPNODE_ANNOUNCE: - return mnodeman.mapSeenPopnodeBroadcast.count(inv.hash) && !mnodeman.IsMnbRecoveryRequested(inv.hash); - - case MSG_POPNODE_PING: - return mnodeman.mapSeenPopnodePing.count(inv.hash); - - case MSG_DSTX: - return mapDarksendBroadcastTxes.count(inv.hash); - - case MSG_POPNODE_VERIFY: - return mnodeman.mapSeenPopnodeVerification.count(inv.hash); - } - - // Don't know what it is, just say we already got one - return true; -} - -void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) -{ - std::deque::iterator it = pfrom->vRecvGetData.begin(); - - vector vNotFound; - - LOCK(cs_main); - - while (it != pfrom->vRecvGetData.end()) { - // Don't bother if send buffer is too full to respond anyway - if (pfrom->nSendSize >= SendBufferSize()) - break; - - const CInv &inv = *it; - LogPrint("net", "ProcessGetData -- inv = %s\n", inv.ToString()); - { - boost::this_thread::interruption_point(); - it++; - - if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) - { - bool send = false; - BlockMap::iterator mi = mapBlockIndex.find(inv.hash); - if (mi != mapBlockIndex.end()) - { - if (chainActive.Contains(mi->second)) { - send = true; - } else { - static const int nOneMonth = 30 * 24 * 60 * 60; - // To prevent fingerprinting attacks, only send blocks outside of the active - // chain if they are valid, and no more than a month older (both in time, and in - // best equivalent proof of work) than the best header chain we know about. - send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && - (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && - (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth); - if (!send) { - LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); - } - } - } - // disconnect node in case we have reached the outbound limit for serving historical blocks - // never disconnect whitelisted nodes - static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical - if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) - { - LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); - - //disconnect node - pfrom->fDisconnect = true; - send = false; - } - // Pruned nodes may have deleted the block, so check whether - // it's available before trying to send. - if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) { - // Send block from disk - CBlock block; - if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) - assert(!"cannot load block from disk"); - if (inv.type == MSG_BLOCK) - pfrom->PushMessage(NetMsgType::BLOCK, block); - else // MSG_FILTERED_BLOCK) - { - LOCK(pfrom->cs_filter); - if (pfrom->pfilter) - { - CMerkleBlock merkleBlock(block, *pfrom->pfilter); - pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock); - // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see - // This avoids hurting performance by pointlessly requiring a round-trip - // Note that there is currently no way for a node to request any single transactions we didn't send here - - // they must either disconnect and retry or request the full block. - // Thus, the protocol spec specified allows for us to provide duplicate txn here, - // however we MUST always provide at least what the remote peer needs - typedef std::pair PairType; - BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) - pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]); - } - // else - // no response - } - - // Trigger the peer node to send a getblocks request for the next batch of inventory - if (inv.hash == pfrom->hashContinue) - { - // Bypass PushInventory, this must send even if redundant, - // and we want it right after the last block so they don't - // wait for other stuff first. - vector vInv; - vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - pfrom->PushMessage(NetMsgType::INV, vInv); - pfrom->hashContinue.SetNull(); - } - } - } - else if (inv.IsKnownType()) - { - // Send stream from relay memory - bool pushed = false; - { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - { - LOCK(cs_mapRelay); - map::iterator mi = mapRelay.find(inv); - if (mi != mapRelay.end()) { - ss += (*mi).second; - pushed = true; - } - } - if(pushed) - pfrom->PushMessage(inv.GetCommand(), ss); - } - - if (!pushed && inv.type == MSG_TX) { - CTransaction tx; - if (mempool.lookup(inv.hash, tx)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << tx; - pfrom->PushMessage(NetMsgType::TX, ss); - pushed = true; - } - } - - if (!pushed && inv.type == MSG_TXLOCK_REQUEST) { - CTxLockRequest txLockRequest; - if(instantsend.GetTxLockRequest(inv.hash, txLockRequest)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << txLockRequest; - pfrom->PushMessage(NetMsgType::TXLOCKREQUEST, ss); - pushed = true; - } - } - - if (!pushed && inv.type == MSG_TXLOCK_VOTE) { - CTxLockVote vote; - if(instantsend.GetTxLockVote(inv.hash, vote)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << vote; - pfrom->PushMessage(NetMsgType::TXLOCKVOTE, ss); - pushed = true; - } - } - - if (!pushed && inv.type == MSG_SPORK) { - if(mapSporks.count(inv.hash)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << mapSporks[inv.hash]; - pfrom->PushMessage(NetMsgType::SPORK, ss); - pushed = true; - } - } - - - if (!pushed && inv.type == MSG_POPNODE_ANNOUNCE) { - if(mnodeman.mapSeenPopnodeBroadcast.count(inv.hash)){ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << mnodeman.mapSeenPopnodeBroadcast[inv.hash].second; - // backward compatibility patch - if(pfrom->nVersion < 70204) { - ss << (int64_t)0; - } - pfrom->PushMessage(NetMsgType::MNANNOUNCE, ss); - pushed = true; - } - } - - if (!pushed && inv.type == MSG_POPNODE_PING) { - if(mnodeman.mapSeenPopnodePing.count(inv.hash)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << mnodeman.mapSeenPopnodePing[inv.hash]; - pfrom->PushMessage(NetMsgType::MNPING, ss); - pushed = true; - } - } - - if (!pushed && inv.type == MSG_DSTX) { - if(mapDarksendBroadcastTxes.count(inv.hash)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << mapDarksendBroadcastTxes[inv.hash]; - pfrom->PushMessage(NetMsgType::DSTX, ss); - pushed = true; - } - } - - - if (!pushed && inv.type == MSG_POPNODE_VERIFY) { - if(mnodeman.mapSeenPopnodeVerification.count(inv.hash)) { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss.reserve(1000); - ss << mnodeman.mapSeenPopnodeVerification[inv.hash]; - pfrom->PushMessage(NetMsgType::MNVERIFY, ss); - pushed = true; - } - } - - if (!pushed) - vNotFound.push_back(inv); - } - - // Track requests for our stuff. - GetMainSignals().Inventory(inv.hash); - - if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) - break; - } - } - - pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it); - - if (!vNotFound.empty()) { - // Let the peer know that we didn't find what it asked for, so it doesn't - // have to wait around forever. Currently only SPV clients actually care - // about this message: it's needed when they are recursively walking the - // dependencies of relevant unconfirmed transactions. SPV clients want to - // do that because they want to know about (and store and rebroadcast and - // risk analyze) the dependencies of transactions relevant to them, without - // having to download the entire memory pool. - pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound); - } -} - -bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) -{ - const CChainParams& chainparams = Params(); - RandAddSeedPerfmon(); - LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); - - if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) - { - LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); - return true; - } - - if (!(nLocalServices & NODE_BLOOM) && - (strCommand == NetMsgType::FILTERLOAD || - strCommand == NetMsgType::FILTERADD || - strCommand == NetMsgType::FILTERCLEAR)) - { - if (pfrom->nVersion >= NO_BLOOM_VERSION) { - Misbehaving(pfrom->GetId(), 100); - return false; - } else if (GetBoolArg("-enforcenodebloom", false)) { - pfrom->fDisconnect = true; - return false; - } - } - - - if (strCommand == NetMsgType::VERSION) - { - // Each connection can only send one version message - if (pfrom->nVersion != 0) - { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); - Misbehaving(pfrom->GetId(), 1); - return false; - } - - int64_t nTime; - CAddress addrMe; - CAddress addrFrom; - uint64_t nNonce = 1; - vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; - if (pfrom->nVersion < MIN_PEER_PROTO_VERSION) - { - // disconnect from peers older than this proto version - LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, - strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); - pfrom->fDisconnect = true; - return false; - } - - if (pfrom->nVersion == 10300) - pfrom->nVersion = 300; - if (!vRecv.empty()) - vRecv >> addrFrom >> nNonce; - if (!vRecv.empty()) { - vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); - pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); - } - if (!vRecv.empty()) - vRecv >> pfrom->nStartingHeight; - if (!vRecv.empty()) - vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message - else - pfrom->fRelayTxes = true; - - // Disconnect if we connected to ourself - if (nNonce == nLocalHostNonce && nNonce > 1) - { - LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); - pfrom->fDisconnect = true; - return true; - } - - pfrom->addrLocal = addrMe; - if (pfrom->fInbound && addrMe.IsRoutable()) - { - SeenLocal(addrMe); - } - - // Be shy and don't send version until we hear - if (pfrom->fInbound) - pfrom->PushVersion(); - - pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); - - // Potentially mark this peer as a preferred download peer. - UpdatePreferredDownload(pfrom, State(pfrom->GetId())); - - // Change version - pfrom->PushMessage(NetMsgType::VERACK); - pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); - - if (!pfrom->fInbound) - { - // Advertise our address - if (fListen && !IsInitialBlockDownload()) - { - CAddress addr = GetLocalAddress(&pfrom->addr); - if (addr.IsRoutable()) - { - LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); - pfrom->PushAddress(addr); - } else if (IsPeerAddrLocalGood(pfrom)) { - addr.SetIP(pfrom->addrLocal); - LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); - pfrom->PushAddress(addr); - } - } - - // Get recent addresses - if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) - { - pfrom->PushMessage(NetMsgType::GETADDR); - pfrom->fGetAddr = true; - } - addrman.Good(pfrom->addr); - } else { - if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom) - { - addrman.Add(addrFrom, addrFrom); - addrman.Good(addrFrom); - } - } - - // Relay alerts - { - LOCK(cs_mapAlerts); - BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - item.second.RelayTo(pfrom); - } - - pfrom->fSuccessfullyConnected = true; - - string remoteAddr; - if (fLogIPs) - remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); - - LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", - pfrom->cleanSubVer, pfrom->nVersion, - pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, - remoteAddr); - - int64_t nTimeOffset = nTime - GetTime(); - pfrom->nTimeOffset = nTimeOffset; - AddTimeData(pfrom->addr, nTimeOffset); - } - - - else if (pfrom->nVersion == 0) - { - // Must have a version message before anything else - Misbehaving(pfrom->GetId(), 1); - return false; - } - - - else if (strCommand == NetMsgType::VERACK) - { - pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); - - // Mark this node as currently connected, so we update its timestamp later. - if (pfrom->fNetworkNode) { - LOCK(cs_main); - State(pfrom->GetId())->fCurrentlyConnected = true; - } - - if (pfrom->nVersion >= SENDHEADERS_VERSION) { - // Tell our peer we prefer to receive headers rather than inv's - // We send this to non-NODE NETWORK peers as well, because even - // non-NODE NETWORK peers can announce blocks (such as pruning - // nodes) - pfrom->PushMessage(NetMsgType::SENDHEADERS); - } - } - - - else if (strCommand == NetMsgType::ADDR) - { - vector vAddr; - vRecv >> vAddr; - - // Don't want addr from older versions unless seeding - if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) - return true; - if (vAddr.size() > 1000) - { - Misbehaving(pfrom->GetId(), 20); - return error("message addr size() = %u", vAddr.size()); - } - - // Store the new addresses - vector vAddrOk; - int64_t nNow = GetAdjustedTime(); - int64_t nSince = nNow - 10 * 60; - BOOST_FOREACH(CAddress& addr, vAddr) - { - boost::this_thread::interruption_point(); - - if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) - addr.nTime = nNow - 5 * 24 * 60 * 60; - pfrom->AddAddressKnown(addr); - bool fReachable = IsReachable(addr); - if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) - { - // Relay to a limited number of other nodes - { - LOCK(cs_vNodes); - // Use deterministic randomness to send to the same nodes for 24 hours - // at a time so the addrKnowns of the chosen nodes prevent repeats - static uint256 hashSalt; - if (hashSalt.IsNull()) - hashSalt = GetRandHash(); - uint64_t hashAddr = addr.GetHash(); - uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60))); - hashRand = Hash(BEGIN(hashRand), END(hashRand)); - multimap mapMix; - BOOST_FOREACH(CNode* pnode, vNodes) - { - if (pnode->nVersion < CADDR_TIME_VERSION) - continue; - unsigned int nPointer; - memcpy(&nPointer, &pnode, sizeof(nPointer)); - uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer); - hashKey = Hash(BEGIN(hashKey), END(hashKey)); - mapMix.insert(make_pair(hashKey, pnode)); - } - int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) - for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) - ((*mi).second)->PushAddress(addr); - } - } - // Do not store addresses outside our network - if (fReachable) - vAddrOk.push_back(addr); - } - addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); - if (vAddr.size() < 1000) - pfrom->fGetAddr = false; - if (pfrom->fOneShot) - pfrom->fDisconnect = true; - } - - else if (strCommand == NetMsgType::SENDHEADERS) - { - LOCK(cs_main); - State(pfrom->GetId())->fPreferHeaders = true; - } - - - else if (strCommand == NetMsgType::INV) - { - vector vInv; - vRecv >> vInv; - if (vInv.size() > MAX_INV_SZ) - { - Misbehaving(pfrom->GetId(), 20); - return error("message inv size() = %u", vInv.size()); - } - - bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); - - // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true - if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) - fBlocksOnly = false; - - LOCK(cs_main); - - std::vector vToFetch; - - - for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) - { - const CInv &inv = vInv[nInv]; - - if(!inv.IsKnownType()) { - LogPrint("net", "got inv of unknown type %d: %s peer=%d\n", inv.type, inv.hash.ToString(), pfrom->id); - continue; - } - - boost::this_thread::interruption_point(); - pfrom->AddInventoryKnown(inv); - - bool fAlreadyHave = AlreadyHave(inv); - LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); - - if (inv.type == MSG_BLOCK) { - UpdateBlockAvailability(pfrom->GetId(), inv.hash); - if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { - // First request the headers preceding the announced block. In the normal fully-synced - // case where a new block is announced that succeeds the current tip (no reorganization), - // there are no such headers. - // Secondly, and only when we are close to being synced, we request the announced block directly, - // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the - // time the block arrives, the header chain leading up to it is already validated. Not - // doing this will result in the received block being rejected as an orphan in case it is - // not a direct successor. - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); - CNodeState *nodestate = State(pfrom->GetId()); - if (CanDirectFetch(chainparams.GetConsensus()) && - nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - vToFetch.push_back(inv); - // Mark block as in flight already, even though the actual "getdata" message only goes out - // later (within the same cs_main lock, though). - MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); - } - LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); - } - } - else - { - if (fBlocksOnly) - LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id); - else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) - pfrom->AskFor(inv); - } - - // Track requests for our stuff - GetMainSignals().Inventory(inv.hash); - - if (pfrom->nSendSize > (SendBufferSize() * 2)) { - Misbehaving(pfrom->GetId(), 50); - return error("send buffer size() = %u", pfrom->nSendSize); - } - } - - if (!vToFetch.empty()) - pfrom->PushMessage(NetMsgType::GETDATA, vToFetch); - } - - - else if (strCommand == NetMsgType::GETDATA) - { - vector vInv; - vRecv >> vInv; - if (vInv.size() > MAX_INV_SZ) - { - Misbehaving(pfrom->GetId(), 20); - return error("message getdata size() = %u", vInv.size()); - } - - if (fDebug || (vInv.size() != 1)) - LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id); - - if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) - LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); - - pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); - ProcessGetData(pfrom, chainparams.GetConsensus()); - } - - - else if (strCommand == NetMsgType::GETBLOCKS) - { - CBlockLocator locator; - uint256 hashStop; - vRecv >> locator >> hashStop; - - LOCK(cs_main); - - // Find the last block the caller has in the main chain - CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); - - // Send the rest of the chain - if (pindex) - pindex = chainActive.Next(pindex); - int nLimit = 500; - LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->id); - for (; pindex; pindex = chainActive.Next(pindex)) - { - if (pindex->GetBlockHash() == hashStop) - { - LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - break; - } - // If pruning, don't inv blocks unless we have on disk and are likely to still have - // for some reasonable time window (1 hour) that block relay might require. - const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing; - if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) - { - LogPrint("net", " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - break; - } - pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); - if (--nLimit <= 0) - { - // When this block is requested, we'll send an inv that'll - // trigger the peer to getblocks the next batch of inventory. - LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); - pfrom->hashContinue = pindex->GetBlockHash(); - break; - } - } - } - - - else if (strCommand == NetMsgType::GETHEADERS) - { - CBlockLocator locator; - uint256 hashStop; - vRecv >> locator >> hashStop; - - LOCK(cs_main); - if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { - LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); - return true; - } - - CNodeState *nodestate = State(pfrom->GetId()); - CBlockIndex* pindex = NULL; - if (locator.IsNull()) - { - // If locator is null, return the hashStop block - BlockMap::iterator mi = mapBlockIndex.find(hashStop); - if (mi == mapBlockIndex.end()) - return true; - pindex = (*mi).second; - } - else - { - // Find the last block the caller has in the main chain - pindex = FindForkInGlobalIndex(chainActive, locator); - if (pindex) - pindex = chainActive.Next(pindex); - } - - // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end - vector vHeaders; - int nLimit = MAX_HEADERS_RESULTS; - LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); - for (; pindex; pindex = chainActive.Next(pindex)) - { - vHeaders.push_back(pindex->GetBlockHeader()); - if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) - break; - } - // pindex can be NULL either if we sent chainActive.Tip() OR - // if our peer has chainActive.Tip() (and thus we are sending an empty - // headers message). In both cases it's safe to update - // pindexBestHeaderSent to be our tip. - nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); - pfrom->PushMessage(NetMsgType::HEADERS, vHeaders); - } - - - else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX || strCommand == NetMsgType::TXLOCKREQUEST) - { - // Stop processing the transaction early if - // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off - if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) - { - LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id); - return true; - } - - vector vWorkQueue; - vector vEraseQueue; - CTransaction tx; - CTxLockRequest txLockRequest; - CDarksendBroadcastTx dstx; - int nInvType = MSG_TX; - - // Read data and assign inv type - if(strCommand == NetMsgType::TX) { - vRecv >> tx; - } else if(strCommand == NetMsgType::TXLOCKREQUEST) { - vRecv >> txLockRequest; - tx = txLockRequest; - nInvType = MSG_TXLOCK_REQUEST; - } else if (strCommand == NetMsgType::DSTX) { - vRecv >> dstx; - tx = dstx.tx; - nInvType = MSG_DSTX; - } - - CInv inv(nInvType, tx.GetHash()); - pfrom->AddInventoryKnown(inv); - pfrom->setAskFor.erase(inv.hash); - - // Process custom logic, no matter if tx will be accepted to mempool later or not - if (strCommand == NetMsgType::TXLOCKREQUEST) { - if(!instantsend.ProcessTxLockRequest(txLockRequest)) { - LogPrint("instantsend", "TXLOCKREQUEST -- failed %s\n", txLockRequest.GetHash().ToString()); - return false; - } - } else if (strCommand == NetMsgType::DSTX) { - uint256 hashTx = tx.GetHash(); - - if(mapDarksendBroadcastTxes.count(hashTx)) { - LogPrint("privatesend", "DSTX -- Already have %s, skipping...\n", hashTx.ToString()); - return true; // not an error - } - - CPopnode* pmn = mnodeman.Find(dstx.vin); - if(pmn == NULL) { - LogPrint("privatesend", "DSTX -- Can't find popnode %s to verify %s\n", dstx.vin.prevout.ToStringShort(), hashTx.ToString()); - return false; - } - - if(!pmn->fAllowMixingTx) { - LogPrint("privatesend", "DSTX -- Popnode %s is sending too many transactions %s\n", dstx.vin.prevout.ToStringShort(), hashTx.ToString()); - return true; - // TODO: Not an error? Could it be that someone is relaying old DSTXes - // we have no idea about (e.g we were offline)? How to handle them? - } - - if(!dstx.CheckSignature(pmn->pubKeyPopnode)) { - LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString()); - return false; - } - - LogPrintf("DSTX -- Got Popnode transaction %s\n", hashTx.ToString()); - mempool.PrioritiseTransaction(hashTx, hashTx.ToString(), 1000, 0.1*COIN); - pmn->fAllowMixingTx = false; - } - - LOCK(cs_main); - - bool fMissingInputs = false; - CValidationState state; - - mapAlreadyAskedFor.erase(inv.hash); - - if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) - { - // Process custom txes, this changes AlreadyHave to "true" - if (strCommand == NetMsgType::DSTX) { - LogPrintf("DSTX -- Popnode transaction accepted, txid=%s, peer=%d\n", - tx.GetHash().ToString(), pfrom->id); - mapDarksendBroadcastTxes.insert(make_pair(tx.GetHash(), dstx)); - } else if (strCommand == NetMsgType::TXLOCKREQUEST) { - LogPrintf("TXLOCKREQUEST -- Transaction Lock Request accepted, txid=%s, peer=%d\n", - tx.GetHash().ToString(), pfrom->id); - instantsend.AcceptLockRequest(txLockRequest); - } - - mempool.check(pcoinsTip); - RelayTransaction(tx); - vWorkQueue.push_back(inv.hash); - - LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", - pfrom->id, - tx.GetHash().ToString(), - mempool.size(), mempool.DynamicMemoryUsage() / 1000); - - // Recursively process any orphan transactions that depended on this one - set setMisbehaving; - for (unsigned int i = 0; i < vWorkQueue.size(); i++) - { - map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); - if (itByPrev == mapOrphanTransactionsByPrev.end()) - continue; - for (set::iterator mi = itByPrev->second.begin(); - mi != itByPrev->second.end(); - ++mi) - { - const uint256& orphanHash = *mi; - const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; - NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; - bool fMissingInputs2 = false; - // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan - // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get - // anyone relaying LegitTxX banned) - CValidationState stateDummy; - - - if (setMisbehaving.count(fromPeer)) - continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { - LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); - vWorkQueue.push_back(orphanHash); - vEraseQueue.push_back(orphanHash); - } - else if (!fMissingInputs2) - { - int nDos = 0; - if (stateDummy.IsInvalid(nDos) && nDos > 0) - { - // Punish peer that gave us an invalid orphan tx - Misbehaving(fromPeer, nDos); - setMisbehaving.insert(fromPeer); - LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); - } - // Has inputs but not accepted to mempool - // Probably non-standard or insufficient fee/priority - LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); - vEraseQueue.push_back(orphanHash); - assert(recentRejects); - recentRejects->insert(orphanHash); - } - mempool.check(pcoinsTip); - } - } - - BOOST_FOREACH(uint256 hash, vEraseQueue) - EraseOrphanTx(hash); - } - else if (fMissingInputs) - { - AddOrphanTx(tx, pfrom->GetId()); - - // DoS prevention: do not allow mapOrphanTransactions to grow unbounded - unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); - unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); - if (nEvicted > 0) - LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); - } else { - assert(recentRejects); - recentRejects->insert(tx.GetHash()); - - if (strCommand == NetMsgType::TXLOCKREQUEST && !AlreadyHave(inv)) { - // i.e. AcceptToMemoryPool failed, probably because it's conflicting - // with existing normal tx or tx lock for another tx. For the same tx lock - // AlreadyHave would have return "true" already. - - // It's the first time we failed for this tx lock request, - // this should switch AlreadyHave to "true". - instantsend.RejectLockRequest(txLockRequest); - // this lets other nodes to create lock request candidate i.e. - // this allows multiple conflicting lock requests to compete for votes - RelayTransaction(tx); - } - - if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { - // Always relay transactions received from whitelisted peers, even - // if they were already in the mempool or rejected from it due - // to policy, allowing the node to function as a gateway for - // nodes hidden behind it. - // - // Never relay transactions that we would assign a non-zero DoS - // score for, as we expect peers to do the same with us in that - // case. - int nDoS = 0; - if (!state.IsInvalid(nDoS) || nDoS == 0) { - LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); - RelayTransaction(tx); - } else { - LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); - } - } - } - - int nDoS = 0; - if (state.IsInvalid(nDoS)) - { - LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), - pfrom->id, - FormatStateMessage(state)); - if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); - if (nDoS > 0) - Misbehaving(pfrom->GetId(), nDoS); - } - FlushStateToDisk(state, FLUSH_STATE_PERIODIC); - } - - - else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing - { - std::vector headers; - - // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. - unsigned int nCount = ReadCompactSize(vRecv); - if (nCount > MAX_HEADERS_RESULTS) { - Misbehaving(pfrom->GetId(), 20); - return error("headers message size = %u", nCount); - } - headers.resize(nCount); - for (unsigned int n = 0; n < nCount; n++) { - vRecv >> headers[n]; - ReadCompactSize(vRecv); // ignore tx count; assume it is 0. - } - - LOCK(cs_main); - - if (nCount == 0) { - // Nothing interesting. Stop asking this peers for more headers. - return true; - } - - CBlockIndex *pindexLast = NULL; - - //prevent chain sync. - /*PairCheckpoints lastCheckpoint_t; - const CChainParams& chainparams_t = Params(); - if (fCheckpointsEnabled) { - lastCheckpoint_t = Checkpoints::ForceGetLastCheckpoint(chainparams_t.Checkpoints()); - }*/ - - BOOST_FOREACH(const CBlockHeader& header, headers) { - CValidationState state; - - /*if (pindexLast !=NULL && pindexLast->nHeight == lastCheckpoint_t.first && lastCheckpoint_t.first != 0){ - if (header.hashPrevBlock != lastCheckpoint_t.second){ - LogPrintf("synchronous chain hash = %s\n",header.hashPrevBlock.ToString()); - LogPrintf("lastCheckpoint height = %d, lastCheckpoint hash = %s\n",lastCheckpoint_t.first,lastCheckpoint_t.second.ToString()); - return error("prevent chain synchronization.\n"); - } - else LogPrintf("checkpoint verify correct.\n"); - }*/ - - if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { - Misbehaving(pfrom->GetId(), 20); - return error("non-continuous headers sequence"); - } - if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { - int nDoS; - if (state.IsInvalid(nDoS)) { - if (nDoS > 0) - Misbehaving(pfrom->GetId(), nDoS); - std::string strError = "invalid header received " + header.GetHash().ToString(); - return error(strError.c_str()); - } - } - } - - if (pindexLast) - UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); - - if (nCount == MAX_HEADERS_RESULTS && pindexLast) { - // Headers message had its maximum size; the peer may have more headers. - // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue - // from there instead. - LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); - } - - bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); - CNodeState *nodestate = State(pfrom->GetId()); - // If this set of headers is valid and ends in a block with at least as - // much work as our tip, download as much as possible. - if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { - vector vToFetch; - CBlockIndex *pindexWalk = pindexLast; - // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. - while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && - !mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { - // We don't have this block, and it's not yet in flight. - vToFetch.push_back(pindexWalk); - } - pindexWalk = pindexWalk->pprev; - } - // If pindexWalk still isn't on our main chain, we're looking at a - // very large reorg at a time we think we're close to caught up to - // the main chain -- this shouldn't really happen. Bail out on the - // direct fetch and rely on parallel download instead. - if (!chainActive.Contains(pindexWalk)) { - LogPrint("net", "Large reorg, won't direct fetch to %s (%d)\n", - pindexLast->GetBlockHash().ToString(), - pindexLast->nHeight); - } else { - vector vGetData; - // Download as much as possible, from earliest to latest. - BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vToFetch) { - if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - // Can't download any more from this peer - break; - } - vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); - MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex); - LogPrint("net", "Requesting block %s from peer=%d\n", - pindex->GetBlockHash().ToString(), pfrom->id); - } - if (vGetData.size() > 1) { - LogPrint("net", "Downloading blocks toward %s (%d) via headers direct fetch\n", - pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); - } - if (vGetData.size() > 0) { - pfrom->PushMessage(NetMsgType::GETDATA, vGetData); - } - } - } - - CheckBlockIndex(chainparams.GetConsensus()); - } - - else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing - { - CBlock block; - vRecv >> block; - - CInv inv(MSG_BLOCK, block.GetHash()); - LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id); - - pfrom->AddInventoryKnown(inv); - - CValidationState state; - // Process all blocks from whitelisted peers, even if not requested, - // unless we're still syncing with the network. - // Such an unrequested block may still be processed, subject to the - // conditions in AcceptBlock(). - bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); - ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); - int nDoS; - if (state.IsInvalid(nDoS)) { - assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); - if (nDoS > 0) { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDoS); - } - } - - } - - - else if (strCommand == NetMsgType::GETADDR) - { - // This asymmetric behavior for inbound and outbound connections was introduced - // to prevent a fingerprinting attack: an attacker can send specific fake addresses - // to users' AddrMan and later request them by sending getaddr messages. - // Making nodes which are behind NAT and can only make outgoing connections ignore - // the getaddr message mitigates the attack. - if (!pfrom->fInbound) { - LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id); - return true; - } - - pfrom->vAddrToSend.clear(); - vector vAddr = addrman.GetAddr(); - BOOST_FOREACH(const CAddress &addr, vAddr) - pfrom->PushAddress(addr); - } - - - else if (strCommand == NetMsgType::MEMPOOL) - { - if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) - { - LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); - pfrom->fDisconnect = true; - return true; - } - LOCK2(cs_main, pfrom->cs_filter); - - std::vector vtxid; - mempool.queryHashes(vtxid); - vector vInv; - BOOST_FOREACH(uint256& hash, vtxid) { - CInv inv(MSG_TX, hash); - if (pfrom->pfilter) { - CTransaction tx; - bool fInMemPool = mempool.lookup(hash, tx); - if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... - if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue; - } - vInv.push_back(inv); - if (vInv.size() == MAX_INV_SZ) { - pfrom->PushMessage(NetMsgType::INV, vInv); - vInv.clear(); - } - } - if (vInv.size() > 0) - pfrom->PushMessage(NetMsgType::INV, vInv); - } - - - else if (strCommand == NetMsgType::PING) - { - if (pfrom->nVersion > BIP0031_VERSION) - { - uint64_t nonce = 0; - vRecv >> nonce; - // Echo the message back with the nonce. This allows for two useful features: - // - // 1) A remote node can quickly check if the connection is operational - // 2) Remote nodes can measure the latency of the network thread. If this node - // is overloaded it won't respond to pings quickly and the remote node can - // avoid sending us more work, like chain download requests. - // - // The nonce stops the remote getting confused between different pings: without - // it, if the remote node sends a ping once per second and this node takes 5 - // seconds to respond to each, the 5th ping the remote sends would appear to - // return very quickly. - pfrom->PushMessage(NetMsgType::PONG, nonce); - } - } - - - else if (strCommand == NetMsgType::PONG) - { - int64_t pingUsecEnd = nTimeReceived; - uint64_t nonce = 0; - size_t nAvail = vRecv.in_avail(); - bool bPingFinished = false; - std::string sProblem; - - if (nAvail >= sizeof(nonce)) { - vRecv >> nonce; - - // Only process pong message if there is an outstanding ping (old ping without nonce should never pong) - if (pfrom->nPingNonceSent != 0) { - if (nonce == pfrom->nPingNonceSent) { - // Matching pong received, this ping is no longer outstanding - bPingFinished = true; - int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart; - if (pingUsecTime > 0) { - // Successful ping time measurement, replace previous - pfrom->nPingUsecTime = pingUsecTime; - pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); - } else { - // This should never happen - sProblem = "Timing mishap"; - } - } else { - // Nonce mismatches are normal when pings are overlapping - sProblem = "Nonce mismatch"; - if (nonce == 0) { - // This is most likely a bug in another implementation somewhere; cancel this ping - bPingFinished = true; - sProblem = "Nonce zero"; - } - } - } else { - sProblem = "Unsolicited pong without ping"; - } - } else { - // This is most likely a bug in another implementation somewhere; cancel this ping - bPingFinished = true; - sProblem = "Short payload"; - } - - if (!(sProblem.empty())) { - LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n", - pfrom->id, - sProblem, - pfrom->nPingNonceSent, - nonce, - nAvail); - } - if (bPingFinished) { - pfrom->nPingNonceSent = 0; - } - } - - - else if (fAlerts && strCommand == NetMsgType::ALERT) - { - CAlert alert; - vRecv >> alert; - - uint256 alertHash = alert.GetHash(); - if (pfrom->setKnown.count(alertHash) == 0) - { - if (alert.ProcessAlert(chainparams.AlertKey())) - { - // Relay - pfrom->setKnown.insert(alertHash); - { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - alert.RelayTo(pnode); - } - } - else { - // Small DoS penalty so peers that send us lots of - // duplicate/expired/invalid-signature/whatever alerts - // eventually get banned. - // This isn't a Misbehaving(100) (immediate ban) because the - // peer might be an older or different implementation with - // a different signature key, etc. - Misbehaving(pfrom->GetId(), 10); - } - } - } - - - else if (strCommand == NetMsgType::FILTERLOAD) - { - CBloomFilter filter; - vRecv >> filter; - - if (!filter.IsWithinSizeConstraints()) - // There is no excuse for sending a too-large filter - Misbehaving(pfrom->GetId(), 100); - else - { - LOCK(pfrom->cs_filter); - delete pfrom->pfilter; - pfrom->pfilter = new CBloomFilter(filter); - pfrom->pfilter->UpdateEmptyFull(); - } - pfrom->fRelayTxes = true; - } - - - else if (strCommand == NetMsgType::FILTERADD) - { - vector vData; - vRecv >> vData; - - // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, - // and thus, the maximum size any matched object can have) in a filteradd message - if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) - { - Misbehaving(pfrom->GetId(), 100); - } else { - LOCK(pfrom->cs_filter); - if (pfrom->pfilter) - pfrom->pfilter->insert(vData); - else - Misbehaving(pfrom->GetId(), 100); - } - } - - - else if (strCommand == NetMsgType::FILTERCLEAR) - { - LOCK(pfrom->cs_filter); - delete pfrom->pfilter; - pfrom->pfilter = new CBloomFilter(); - pfrom->fRelayTxes = true; - } - - - else if (strCommand == NetMsgType::REJECT) - { - if (fDebug) { - try { - string strMsg; unsigned char ccode; string strReason; - vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); - - ostringstream ss; - ss << strMsg << " code " << itostr(ccode) << ": " << strReason; - - if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) - { - uint256 hash; - vRecv >> hash; - ss << ": hash " << hash.ToString(); - } - LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); - } catch (const std::ios_base::failure&) { - // Avoid feedback loops by preventing reject messages from triggering a new reject message. - LogPrint("net", "Unparseable reject message received\n"); - } - } - } - else - { - bool found = false; - const std::vector &allMessages = getAllNetMessageTypes(); - BOOST_FOREACH(const std::string msg, allMessages) { - if(msg == strCommand) { - found = true; - break; - } - } - - if (found) - { - //probably one the extensions - darkSendPool.ProcessMessage(pfrom, strCommand, vRecv); - mnodeman.ProcessMessage(pfrom, strCommand, vRecv); - instantsend.ProcessMessage(pfrom, strCommand, vRecv); - sporkManager.ProcessSpork(pfrom, strCommand, vRecv); - popnodeSync.ProcessMessage(pfrom, strCommand, vRecv); - } - else - { - // Ignore unknown commands for extensibility - LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); - } - } - - return true; -} - -// requires LOCK(cs_vRecvMsg) -bool ProcessMessages(CNode* pfrom) -{ - const CChainParams& chainparams = Params(); - //if (fDebug) - // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); - - // - // Message format - // (4) message start - // (12) command - // (4) size - // (4) checksum - // (x) data - // - bool fOk = true; - - if (!pfrom->vRecvGetData.empty()) - ProcessGetData(pfrom, chainparams.GetConsensus()); - - // this maintains the order of responses - if (!pfrom->vRecvGetData.empty()) return fOk; - - std::deque::iterator it = pfrom->vRecvMsg.begin(); - while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { - // Don't bother if send buffer is too full to respond anyway - if (pfrom->nSendSize >= SendBufferSize()) - break; - - // get next message - CNetMessage& msg = *it; - - //if (fDebug) - // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__, - // msg.hdr.nMessageSize, msg.vRecv.size(), - // msg.complete() ? "Y" : "N"); - - // end, if an incomplete message is found - if (!msg.complete()) - break; - - // at this point, any failure means we can delete the current message - it++; - - // Scan for message start - if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), MESSAGE_START_SIZE) != 0) { - LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); - fOk = false; - break; - } - - // Read header - CMessageHeader& hdr = msg.hdr; - if (!hdr.IsValid(chainparams.MessageStart())) - { - LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); - continue; - } - string strCommand = hdr.GetCommand(); - - // Message size - unsigned int nMessageSize = hdr.nMessageSize; - - // Checksum - CDataStream& vRecv = msg.vRecv; - uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); - unsigned int nChecksum = ReadLE32((unsigned char*)&hash); - if (nChecksum != hdr.nChecksum) - { - LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__, - SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); - continue; - } - - // Process message - bool fRet = false; - try - { - fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); - boost::this_thread::interruption_point(); - } - catch (const std::ios_base::failure& e) - { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); - if (strstr(e.what(), "end of data")) - { - // Allow exceptions from under-length message on vRecv - LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); - } - else if (strstr(e.what(), "size too large")) - { - // Allow exceptions from over-long size - LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); - } - else - { - PrintExceptionContinue(&e, "ProcessMessages()"); - } - } - catch (const boost::thread_interrupted&) { - throw; - } - catch (const std::exception& e) { - PrintExceptionContinue(&e, "ProcessMessages()"); - } catch (...) { - PrintExceptionContinue(NULL, "ProcessMessages()"); - } - - if (!fRet) - LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); - - break; - } - - // In case the connection got shut down, its receive buffer was wiped - if (!pfrom->fDisconnect) - pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it); - - return fOk; -} - - -bool SendMessages(CNode* pto) -{ - const Consensus::Params& consensusParams = Params().GetConsensus(); - { - // Don't send anything until we get its version message - if (pto->nVersion == 0) - return true; - - // - // Message: ping - // - bool pingSend = false; - if (pto->fPingQueued) { - // RPC ping request by user - pingSend = true; - } - if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) { - // Ping automatically sent as a latency probe & keepalive. - pingSend = true; - } - if (pingSend) { - uint64_t nonce = 0; - while (nonce == 0) { - GetRandBytes((unsigned char*)&nonce, sizeof(nonce)); - } - pto->fPingQueued = false; - pto->nPingUsecStart = GetTimeMicros(); - if (pto->nVersion > BIP0031_VERSION) { - pto->nPingNonceSent = nonce; - pto->PushMessage(NetMsgType::PING, nonce); - } else { - // Peer is too old to support ping command with nonce, pong will never arrive. - pto->nPingNonceSent = 0; - pto->PushMessage(NetMsgType::PING); - } - } - - TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState() - if (!lockMain) - return true; - - // Address refresh broadcast - int64_t nNow = GetTimeMicros(); - if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { - AdvertiseLocal(pto); - pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); - } - - // - // Message: addr - // - if (pto->nNextAddrSend < nNow) { - pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL); - vector vAddr; - vAddr.reserve(pto->vAddrToSend.size()); - BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) - { - if (!pto->addrKnown.contains(addr.GetKey())) - { - pto->addrKnown.insert(addr.GetKey()); - vAddr.push_back(addr); - // receiver rejects addr messages larger than 1000 - if (vAddr.size() >= 1000) - { - pto->PushMessage(NetMsgType::ADDR, vAddr); - vAddr.clear(); - } - } - } - pto->vAddrToSend.clear(); - if (!vAddr.empty()) - pto->PushMessage(NetMsgType::ADDR, vAddr); - } - - CNodeState &state = *State(pto->GetId()); - if (state.fShouldBan) { - if (pto->fWhitelisted) - LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); - else { - pto->fDisconnect = true; - if (pto->addr.IsLocal()) - LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); - else - { - CNode::Ban(pto->addr, BanReasonNodeMisbehaving); - } - } - state.fShouldBan = false; - } - - BOOST_FOREACH(const CBlockReject& reject, state.rejects) - pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); - state.rejects.clear(); - - // Start block sync - if (pindexBestHeader == NULL) - pindexBestHeader = chainActive.Tip(); - bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. - if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { - // Only actively request headers from a single peer, unless we're close to end of initial download. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 6 * 60 * 60) { // NOTE: was "close to today" and 24h in Bitcoin - state.fSyncStarted = true; - nSyncStarted++; - const CBlockIndex *pindexStart = pindexBestHeader; - /* If possible, start at the block preceding the currently - best known header. This ensures that we always get a - non-empty list of headers back as long as the peer - is up-to-date. With a non-empty response, we can initialise - the peer's known best block. This wouldn't be possible - if we requested starting at pindexBestHeader and - got back an empty response. */ - if (pindexStart->pprev) - pindexStart = pindexStart->pprev; - LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); - pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); - } - } - - // Resend wallet transactions that haven't gotten in a block yet - // Except during reindex, importing and IBD, when old wallet - // transactions become unconfirmed and spams other nodes. - if (!fReindex && !fImporting && !IsInitialBlockDownload()) - { - GetMainSignals().Broadcast(nTimeBestReceived); - } - - // - // Try sending block announcements via headers - // - { - // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our - // list of block hashes we're relaying, and our peer wants - // headers announcements, then find the first header - // not yet known to our peer but would connect, and send. - // If no header would connect, or if we have too many - // blocks, or if the peer doesn't want headers, just - // add all to the inv queue. - LOCK(pto->cs_inventory); - vector vHeaders; - bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); - CBlockIndex *pBestIndex = NULL; // last header queued for delivery - ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date - - if (!fRevertToInv) { - bool fFoundStartingHeader = false; - // Try to find first header that our peer doesn't have, and - // then send all headers past that one. If we come across any - // headers that aren't on chainActive, give up. - BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) { - BlockMap::iterator mi = mapBlockIndex.find(hash); - assert(mi != mapBlockIndex.end()); - CBlockIndex *pindex = mi->second; - if (chainActive[pindex->nHeight] != pindex) { - // Bail out if we reorged away from this block - fRevertToInv = true; - break; - } - if (pBestIndex != NULL && pindex->pprev != pBestIndex) { - // This means that the list of blocks to announce don't - // connect to each other. - // This shouldn't really be possible to hit during - // regular operation (because reorgs should take us to - // a chain that has some block not on the prior chain, - // which should be caught by the prior check), but one - // way this could happen is by using invalidateblock / - // reconsiderblock repeatedly on the tip, causing it to - // be added multiple times to vBlockHashesToAnnounce. - // Robustly deal with this rare situation by reverting - // to an inv. - fRevertToInv = true; - break; - } - pBestIndex = pindex; - if (fFoundStartingHeader) { - // add this to the headers message - vHeaders.push_back(pindex->GetBlockHeader()); - } else if (PeerHasHeader(&state, pindex)) { - continue; // keep looking for the first new block - } else if (pindex->pprev == NULL || PeerHasHeader(&state, pindex->pprev)) { - // Peer doesn't have this header but they do have the prior one. - // Start sending headers. - fFoundStartingHeader = true; - vHeaders.push_back(pindex->GetBlockHeader()); - } else { - // Peer doesn't have this header or the prior one -- nothing will - // connect, so bail out. - fRevertToInv = true; - break; - } - } - } - if (fRevertToInv) { - // If falling back to using an inv, just try to inv the tip. - // The last entry in vBlockHashesToAnnounce was our tip at some point - // in the past. - if (!pto->vBlockHashesToAnnounce.empty()) { - const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); - BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); - assert(mi != mapBlockIndex.end()); - CBlockIndex *pindex = mi->second; - - // Warn if we're announcing a block that is not on the main chain. - // This should be very rare and could be optimized out. - // Just log for now. - if (chainActive[pindex->nHeight] != pindex) { - LogPrint("net", "Announcing block %s not on main chain (tip=%s)\n", - hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString()); - } - - // If the peer announced this block to us, don't inv it back. - // (Since block announcements may not be via inv's, we can't solely rely on - // setInventoryKnown to track this.) - if (!PeerHasHeader(&state, pindex)) { - pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce)); - LogPrint("net", "%s: sending inv peer=%d hash=%s\n", __func__, - pto->id, hashToAnnounce.ToString()); - } - } - } else if (!vHeaders.empty()) { - if (vHeaders.size() > 1) { - LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, - vHeaders.size(), - vHeaders.front().GetHash().ToString(), - vHeaders.back().GetHash().ToString(), pto->id); - } else { - LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, - vHeaders.front().GetHash().ToString(), pto->id); - } - pto->PushMessage(NetMsgType::HEADERS, vHeaders); - state.pindexBestHeaderSent = pBestIndex; - } - pto->vBlockHashesToAnnounce.clear(); - } - - // - // Message: inventory - // - vector vInv; - vector vInvWait; - { - bool fSendTrickle = pto->fWhitelisted; - if (pto->nNextInvSend < nNow) { - fSendTrickle = true; - pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL); - } - LOCK(pto->cs_inventory); - vInv.reserve(std::min(1000, pto->vInventoryToSend.size())); - vInvWait.reserve(pto->vInventoryToSend.size()); - BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) - { - if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash)) - continue; - - // trickle out tx inv to protect privacy - if (inv.type == MSG_TX && !fSendTrickle) - { - // 1/4 of tx invs blast to all immediately - static uint256 hashSalt; - if (hashSalt.IsNull()) - hashSalt = GetRandHash(); - uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt)); - hashRand = Hash(BEGIN(hashRand), END(hashRand)); - bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0); - - if (fTrickleWait) - { - LogPrint("net", "SendMessages -- queued inv(vInvWait): %s index=%d peer=%d\n", inv.ToString(), vInvWait.size(), pto->id); - vInvWait.push_back(inv); - continue; - } - } - - pto->filterInventoryKnown.insert(inv.hash); - - LogPrint("net", "SendMessages -- queued inv: %s index=%d peer=%d\n", inv.ToString(), vInv.size(), pto->id); - vInv.push_back(inv); - if (vInv.size() >= 1000) - { - LogPrint("net", "SendMessages -- pushing inv's: count=%d peer=%d\n", vInv.size(), pto->id); - pto->PushMessage(NetMsgType::INV, vInv); - vInv.clear(); - } - } - pto->vInventoryToSend = vInvWait; - } - if (!vInv.empty()) { - LogPrint("net", "SendMessages -- pushing tailing inv's: count=%d peer=%d\n", vInv.size(), pto->id); - pto->PushMessage(NetMsgType::INV, vInv); - } - - // Detect whether we're stalling - nNow = GetTimeMicros(); - if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { - // Stalling only triggers when the block download window cannot move. During normal steady state, - // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection - // should only happen during initial block download. - LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); - pto->fDisconnect = true; - } - // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval - // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout. - // We compensate for other peers to prevent killing off peers due to our own downstream link - // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes - // to unreasonably increase our timeout. - if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { - QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); - int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); - if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { - LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); - pto->fDisconnect = true; - } - } - - // - // Message: getdata (blocks) - // - vector vGetData; - if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { - vector vToDownload; - NodeId staller = -1; - FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); - BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { - vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); - MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); - LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), - pindex->nHeight, pto->id); - } - if (state.nBlocksInFlight == 0 && staller != -1) { - if (State(staller)->nStallingSince == 0) { - State(staller)->nStallingSince = nNow; - LogPrint("net", "Stall started peer=%d\n", staller); - } - } - } - - // - // Message: getdata (non-blocks) - // - int64_t nFirst = -1; - if(!pto->mapAskFor.empty()) { - nFirst = (*pto->mapAskFor.begin()).first; - } - LogPrint("net", "SendMessages (mapAskFor) -- before loop: nNow = %d, nFirst = %d\n", nNow, nFirst); - while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) - { - const CInv& inv = (*pto->mapAskFor.begin()).second; - LogPrint("net", "SendMessages (mapAskFor) -- inv = %s peer=%d\n", inv.ToString(), pto->id); - if (!AlreadyHave(inv)) - { - if (fDebug) - LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id); - vGetData.push_back(inv); - if (vGetData.size() >= 1000) - { - pto->PushMessage(NetMsgType::GETDATA, vGetData); - vGetData.clear(); - } - } else { - //If we're not going to ask, don't expect a response. - LogPrint("net", "SendMessages -- already have inv = %s peer=%d\n", inv.ToString(), pto->id); - pto->setAskFor.erase(inv.hash); - } - pto->mapAskFor.erase(pto->mapAskFor.begin()); - } - if (!vGetData.empty()) - pto->PushMessage(NetMsgType::GETDATA, vGetData); - - } - return true; -} - - std::string CBlockFileInfo::ToString() const { - return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); - } - -ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) -{ - LOCK(cs_main); - return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); -} - -class CMainCleanup -{ -public: - CMainCleanup() {} - ~CMainCleanup() { - // block headers - BlockMap::iterator it1 = mapBlockIndex.begin(); - for (; it1 != mapBlockIndex.end(); it1++) - delete (*it1).second; - mapBlockIndex.clear(); - - // orphan transactions - mapOrphanTransactions.clear(); - mapOrphanTransactionsByPrev.clear(); - } -} instance_of_cmaincleanup; +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "main.h" + +#include "nameclaim.h" +#include "addrman.h" +#include "alert.h" +#include "arith_uint256.h" +#include "chainparams.h" +#include "checkpoints.h" +#include "checkqueue.h" +#include "consensus/consensus.h" +#include "consensus/merkle.h" +#include "consensus/validation.h" +#include "hash.h" +#include "init.h" +#include "merkleblock.h" +#include "net.h" +#include "policy/policy.h" +#include "pow.h" +#include "primitives/block.h" +#include "primitives/transaction.h" +#include "script/script.h" +#include "script/sigcache.h" +#include "script/standard.h" +#include "tinyformat.h" +#include "txdb.h" +#include "txmempool.h" +#include "ui_interface.h" +#include "undo.h" +#include "util.h" +#include "spork.h" +#include "utilmoneystr.h" +#include "utilstrencodings.h" +#include "validationinterface.h" +#include "versionbits.h" + +#include "darksend.h" +#include "instantx.h" +#include "popnode-payments.h" +#include "popnode-sync.h" +#include "popnodeman.h" + +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; + +#if defined(NDEBUG) +# error "Pop Core cannot be compiled without assertions." +#endif + +/** + * Global state + */ + +CCriticalSection cs_main; + +BlockMap mapBlockIndex; +CChain chainActive; +CBlockIndex *pindexBestHeader = NULL; +int64_t nTimeBestReceived = 0; +CWaitableCriticalSection csBestBlock; +CConditionVariable cvBlockChange; +int nScriptCheckThreads = 0; +bool fImporting = false; +bool fReindex = false; +bool fTxIndex = true; +bool fAddressIndex = false; +bool fTimestampIndex = false; +bool fSpentIndex = false; +bool fHavePruned = false; +bool fPruneMode = false; +bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG; +bool fRequireStandard = true; +unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP; +bool fCheckBlockIndex = false; +bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; +size_t nCoinCacheUsage = 5000 * 300; +uint64_t nPruneTarget = 0; +bool fAlerts = DEFAULT_ALERTS; +bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT; + +/** Fees smaller than this (in duffs) are considered zero fee (for relaying, mining and transaction creation) */ +CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); + +CTxMemPool mempool(::minRelayTxFee); + +struct COrphanTx { + CTransaction tx; + NodeId fromPeer; +}; +map mapOrphanTransactions GUARDED_BY(cs_main);; +map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; +map mapRejectedBlocks GUARDED_BY(cs_main); +void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + +/** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards. + */ +static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams); +static void CheckBlockIndex(const Consensus::Params& consensusParams); + +/** Constant stuff for coinbase transactions we create: */ +CScript COINBASE_FLAGS; + +const string strMessageMagic = "Pop Signed Message:\n"; + +// Internal stuff +namespace { + + struct CBlockIndexWorkComparator + { + bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { + // First sort by most total work, ... + if (pa->nChainWork > pb->nChainWork) return false; + if (pa->nChainWork < pb->nChainWork) return true; + + // ... then by earliest time received, ... + if (pa->nSequenceId < pb->nSequenceId) return false; + if (pa->nSequenceId > pb->nSequenceId) return true; + + // Use pointer address as tie breaker (should only happen with blocks + // loaded from disk, as those all have id 0). + if (pa < pb) return false; + if (pa > pb) return true; + + // Identical blocks. + return false; + } + }; + + CBlockIndex *pindexBestInvalid; + + /** + * The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and + * as good as our current tip or better. Entries may be failed, though, and pruning nodes may be + * missing the data for the block. + */ + set setBlockIndexCandidates; + /** Number of nodes with fSyncStarted. */ + int nSyncStarted = 0; + /** All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. + * Pruned nodes may have entries where B is missing data. + */ + multimap mapBlocksUnlinked; + + CCriticalSection cs_LastBlockFile; + std::vector vinfoBlockFile; + int nLastBlockFile = 0; + /** Global flag to indicate we should check to see if there are + * block/undo files that should be deleted. Set on startup + * or if we allocate more file space when we're in prune mode + */ + bool fCheckForPruning = false; + + /** + * Every received block is assigned a unique and increasing identifier, so we + * know which one to give priority in case of a fork. + */ + CCriticalSection cs_nBlockSequenceId; + /** Blocks loaded from disk are assigned id 0, so start the counter at 1. */ + uint32_t nBlockSequenceId = 1; + + /** + * Sources of received blocks, saved to be able to send them reject + * messages or ban them when processing happens afterwards. Protected by + * cs_main. + */ + map mapBlockSource; + + /** + * Filter for transactions that were recently rejected by + * AcceptToMemoryPool. These are not rerequested until the chain tip + * changes, at which point the entire filter is reset. Protected by + * cs_main. + * + * Without this filter we'd be re-requesting txs from each of our peers, + * increasing bandwidth consumption considerably. For instance, with 100 + * peers, half of which relay a tx we don't accept, that might be a 50x + * bandwidth increase. A flooding attacker attempting to roll-over the + * filter using minimum-sized, 60byte, transactions might manage to send + * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a + * two minute window to send invs to us. + * + * Decreasing the false positive rate is fairly cheap, so we pick one in a + * million to make it highly unlikely for users to have issues with this + * filter. + * + * Memory used: 1.7MB + */ + boost::scoped_ptr recentRejects; + uint256 hashRecentRejectsChainTip; + + /** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */ + struct QueuedBlock { + uint256 hash; + CBlockIndex* pindex; //!< Optional. + bool fValidatedHeaders; //!< Whether this block has validated headers at the time of request. + }; + map::iterator> > mapBlocksInFlight; + + /** Number of preferable block download peers. */ + int nPreferredDownload = 0; + + /** Dirty block index entries. */ + set setDirtyBlockIndex; + + /** Dirty block file entries. */ + set setDirtyFileInfo; + + /** Number of peers from which we're downloading blocks. */ + int nPeersWithValidatedDownloads = 0; +} // anon namespace + +////////////////////////////////////////////////////////////////////////////// +// +// Registration of network node signals. +// + +namespace { + +struct CBlockReject { + unsigned char chRejectCode; + string strRejectReason; + uint256 hashBlock; +}; + +/** + * Maintain validation-specific state about nodes, protected by cs_main, instead + * by CNode's own locks. This simplifies asynchronous operation, where + * processing of incoming data is done after the ProcessMessage call returns, + * and we're no longer holding the node's locks. + */ +struct CNodeState { + //! The peer's address + CService address; + //! Whether we have a fully established connection. + bool fCurrentlyConnected; + //! Accumulated misbehaviour score for this peer. + int nMisbehavior; + //! Whether this peer should be disconnected and banned (unless whitelisted). + bool fShouldBan; + //! String name of this peer (debugging/logging purposes). + std::string name; + //! List of asynchronously-determined block rejections to notify this peer about. + std::vector rejects; + //! The best known block we know this peer has announced. + CBlockIndex *pindexBestKnownBlock; + //! The hash of the last unknown block this peer has announced. + uint256 hashLastUnknownBlock; + //! The last full block we both have. + CBlockIndex *pindexLastCommonBlock; + //! The best header we have sent our peer. + CBlockIndex *pindexBestHeaderSent; + //! Whether we've started headers synchronization with this peer. + bool fSyncStarted; + //! Since when we're stalling block download progress (in microseconds), or 0. + int64_t nStallingSince; + list vBlocksInFlight; + //! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty. + int64_t nDownloadingSince; + int nBlocksInFlight; + int nBlocksInFlightValidHeaders; + //! Whether we consider this a preferred download peer. + bool fPreferredDownload; + //! Whether this peer wants invs or headers (when possible) for block announcements. + bool fPreferHeaders; + + CNodeState() { + fCurrentlyConnected = false; + nMisbehavior = 0; + fShouldBan = false; + pindexBestKnownBlock = NULL; + hashLastUnknownBlock.SetNull(); + pindexLastCommonBlock = NULL; + pindexBestHeaderSent = NULL; + fSyncStarted = false; + nStallingSince = 0; + nDownloadingSince = 0; + nBlocksInFlight = 0; + nBlocksInFlightValidHeaders = 0; + fPreferredDownload = false; + fPreferHeaders = false; + } +}; + +/** Map maintaining per-node state. Requires cs_main. */ +map mapNodeState; + +// Requires cs_main. +CNodeState *State(NodeId pnode) { + map::iterator it = mapNodeState.find(pnode); + if (it == mapNodeState.end()) + return NULL; + return &it->second; +} + +int GetHeight() +{ + LOCK(cs_main); + return chainActive.Height(); +} + +void UpdatePreferredDownload(CNode* node, CNodeState* state) +{ + nPreferredDownload -= state->fPreferredDownload; + + // Whether this node should be marked as a preferred download node. + state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; + + nPreferredDownload += state->fPreferredDownload; +} + +void InitializeNode(NodeId nodeid, const CNode *pnode) { + LOCK(cs_main); + CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; + state.name = pnode->addrName; + state.address = pnode->addr; +} + +void FinalizeNode(NodeId nodeid) { + LOCK(cs_main); + CNodeState *state = State(nodeid); + + if (state->fSyncStarted) + nSyncStarted--; + + if (state->nMisbehavior == 0 && state->fCurrentlyConnected) { + AddressCurrentlyConnected(state->address); + } + + BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) { + mapBlocksInFlight.erase(entry.hash); + } + EraseOrphansFor(nodeid); + nPreferredDownload -= state->fPreferredDownload; + nPeersWithValidatedDownloads -= (state->nBlocksInFlightValidHeaders != 0); + assert(nPeersWithValidatedDownloads >= 0); + + mapNodeState.erase(nodeid); + + if (mapNodeState.empty()) { + // Do a consistency check after the last peer is removed. + assert(mapBlocksInFlight.empty()); + assert(nPreferredDownload == 0); + assert(nPeersWithValidatedDownloads == 0); + } +} + +// Requires cs_main. +// Returns a bool indicating whether we requested this block. +bool MarkBlockAsReceived(const uint256& hash) { + map::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash); + if (itInFlight != mapBlocksInFlight.end()) { + CNodeState *state = State(itInFlight->second.first); + state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders; + if (state->nBlocksInFlightValidHeaders == 0 && itInFlight->second.second->fValidatedHeaders) { + // Last validated block on the queue was received. + nPeersWithValidatedDownloads--; + } + if (state->vBlocksInFlight.begin() == itInFlight->second.second) { + // First block on the queue was received, update the start download time for the next one + state->nDownloadingSince = std::max(state->nDownloadingSince, GetTimeMicros()); + } + state->vBlocksInFlight.erase(itInFlight->second.second); + state->nBlocksInFlight--; + state->nStallingSince = 0; + mapBlocksInFlight.erase(itInFlight); + return true; + } + return false; +} + +// Requires cs_main. +void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + // Make sure it's not listed somewhere already. + MarkBlockAsReceived(hash); + + QueuedBlock newentry = {hash, pindex, pindex != NULL}; + list::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry); + state->nBlocksInFlight++; + state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders; + if (state->nBlocksInFlight == 1) { + // We're starting a block download (batch) from this peer. + state->nDownloadingSince = GetTimeMicros(); + } + if (state->nBlocksInFlightValidHeaders == 1 && pindex != NULL) { + nPeersWithValidatedDownloads++; + } + mapBlocksInFlight[hash] = std::make_pair(nodeid, it); +} + +/** Check whether the last unknown block a peer advertised is not yet known. */ +void ProcessBlockAvailability(NodeId nodeid) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + if (!state->hashLastUnknownBlock.IsNull()) { + BlockMap::iterator itOld = mapBlockIndex.find(state->hashLastUnknownBlock); + if (itOld != mapBlockIndex.end() && itOld->second->nChainWork > 0) { + if (state->pindexBestKnownBlock == NULL || itOld->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = itOld->second; + state->hashLastUnknownBlock.SetNull(); + } + } +} + +/** Update tracking information about which blocks a peer is assumed to have. */ +void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) { + CNodeState *state = State(nodeid); + assert(state != NULL); + + ProcessBlockAvailability(nodeid); + + BlockMap::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end() && it->second->nChainWork > 0) { + // An actually better block was announced. + if (state->pindexBestKnownBlock == NULL || it->second->nChainWork >= state->pindexBestKnownBlock->nChainWork) + state->pindexBestKnownBlock = it->second; + } else { + // An unknown block was announced; just assume that the latest one is the best one. + state->hashLastUnknownBlock = hash; + } +} + +// Requires cs_main +bool CanDirectFetch(const Consensus::Params &consensusParams) +{ + return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; +} + +// Requires cs_main +bool PeerHasHeader(CNodeState *state, CBlockIndex *pindex) +{ + if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight)) + return true; + if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight)) + return true; + return false; +} + +/** Find the last common ancestor two blocks have. + * Both pa and pb must be non-NULL. */ +CBlockIndex* LastCommonAncestor(CBlockIndex* pa, CBlockIndex* pb) { + if (pa->nHeight > pb->nHeight) { + pa = pa->GetAncestor(pb->nHeight); + } else if (pb->nHeight > pa->nHeight) { + pb = pb->GetAncestor(pa->nHeight); + } + + while (pa != pb && pa && pb) { + pa = pa->pprev; + pb = pb->pprev; + } + + // Eventually all chain branches meet at the genesis block. + assert(pa == pb); + return pa; +} + +/** Update pindexLastCommonBlock and add not-in-flight missing successors to vBlocks, until it has + * at most count entries. */ +void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector& vBlocks, NodeId& nodeStaller) { + if (count == 0) + return; + + vBlocks.reserve(vBlocks.size() + count); + CNodeState *state = State(nodeid); + assert(state != NULL); + + // Make sure pindexBestKnownBlock is up to date, we'll need it. + ProcessBlockAvailability(nodeid); + + if (state->pindexBestKnownBlock == NULL || state->pindexBestKnownBlock->nChainWork < chainActive.Tip()->nChainWork) { + // This peer has nothing interesting. + return; + } + + if (state->pindexLastCommonBlock == NULL) { + // Bootstrap quickly by guessing a parent of our best tip is the forking point. + // Guessing wrong in either direction is not a problem. + state->pindexLastCommonBlock = chainActive[std::min(state->pindexBestKnownBlock->nHeight, chainActive.Height())]; + } + + // If the peer reorganized, our previous pindexLastCommonBlock may not be an ancestor + // of its current tip anymore. Go back enough to fix that. + state->pindexLastCommonBlock = LastCommonAncestor(state->pindexLastCommonBlock, state->pindexBestKnownBlock); + if (state->pindexLastCommonBlock == state->pindexBestKnownBlock) + return; + + std::vector vToFetch; + CBlockIndex *pindexWalk = state->pindexLastCommonBlock; + // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last + // linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to + // download that next block if the window were 1 larger. + int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW; + int nMaxHeight = std::min(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1); + NodeId waitingfor = -1; + while (pindexWalk->nHeight < nMaxHeight) { + // Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards + // pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive + // as iterating over ~100 CBlockIndex* entries anyway. + int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max(count - vBlocks.size(), 128)); + vToFetch.resize(nToFetch); + pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch); + vToFetch[nToFetch - 1] = pindexWalk; + for (unsigned int i = nToFetch - 1; i > 0; i--) { + vToFetch[i - 1] = vToFetch[i]->pprev; + } + + // Iterate over those blocks in vToFetch (in forward direction), adding the ones that + // are not yet downloaded and not in flight to vBlocks. In the mean time, update + // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's + // already part of our chain (and therefore don't need it even if pruned). + BOOST_FOREACH(CBlockIndex* pindex, vToFetch) { + if (!pindex->IsValid(BLOCK_VALID_TREE)) { + // We consider the chain that this peer is on invalid. + return; + } + if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { + if (pindex->nChainTx) + state->pindexLastCommonBlock = pindex; + } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { + // The block is not already downloaded, and not yet in flight. + if (pindex->nHeight > nWindowEnd) { + // We reached the end of the window. + if (vBlocks.size() == 0 && waitingfor != nodeid) { + // We aren't able to fetch anything, but we would be if the download window was one larger. + nodeStaller = waitingfor; + } + return; + } + vBlocks.push_back(pindex); + if (vBlocks.size() == count) { + return; + } + } else if (waitingfor == -1) { + // This is the first already-in-flight block. + waitingfor = mapBlocksInFlight[pindex->GetBlockHash()].first; + } + } + } +} + +} // anon namespace + +bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { + LOCK(cs_main); + CNodeState *state = State(nodeid); + if (state == NULL) + return false; + stats.nMisbehavior = state->nMisbehavior; + stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; + stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; + BOOST_FOREACH(const QueuedBlock& queue, state->vBlocksInFlight) { + if (queue.pindex) + stats.vHeightInFlight.push_back(queue.pindex->nHeight); + } + return true; +} + +void RegisterNodeSignals(CNodeSignals& nodeSignals) +{ + nodeSignals.GetHeight.connect(&GetHeight); + nodeSignals.ProcessMessages.connect(&ProcessMessages); + nodeSignals.SendMessages.connect(&SendMessages); + nodeSignals.InitializeNode.connect(&InitializeNode); + nodeSignals.FinalizeNode.connect(&FinalizeNode); +} + +void UnregisterNodeSignals(CNodeSignals& nodeSignals) +{ + nodeSignals.GetHeight.disconnect(&GetHeight); + nodeSignals.ProcessMessages.disconnect(&ProcessMessages); + nodeSignals.SendMessages.disconnect(&SendMessages); + nodeSignals.InitializeNode.disconnect(&InitializeNode); + nodeSignals.FinalizeNode.disconnect(&FinalizeNode); +} + +CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) +{ + // Find the first block the caller has in the main chain + BOOST_FOREACH(const uint256& hash, locator.vHave) { + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*mi).second; + if (chain.Contains(pindex)) + return pindex; + } + } + return chain.Genesis(); +} + +CCoinsViewCache *pcoinsTip = NULL; +CClaimTrie *pclaimTrie = NULL; // claim operation +CBlockTreeDB *pblocktree = NULL; + +////////////////////////////////////////////////////////////////////////////// +// +// mapOrphanTransactions +// + +bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + uint256 hash = tx.GetHash(); + if (mapOrphanTransactions.count(hash)) + return false; + + // Ignore big transactions, to avoid a + // send-big-orphans memory exhaustion attack. If a peer has a legitimate + // large transaction with a missing parent then we assume + // it will rebroadcast it later, after the parent transaction(s) + // have been mined or received. + // 10,000 orphans, each of which is at most 5,000 bytes big is + // at most 500 megabytes of orphans: + unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); + if (sz > 5000) + { + LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); + return false; + } + + mapOrphanTransactions[hash].tx = tx; + mapOrphanTransactions[hash].fromPeer = peer; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash); + + LogPrint("mempool", "stored orphan tx %s (mapsz %u prevsz %u)\n", hash.ToString(), + mapOrphanTransactions.size(), mapOrphanTransactionsByPrev.size()); + return true; +} + +void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + map::iterator it = mapOrphanTransactions.find(hash); + if (it == mapOrphanTransactions.end()) + return; + BOOST_FOREACH(const CTxIn& txin, it->second.tx.vin) + { + map >::iterator itPrev = mapOrphanTransactionsByPrev.find(txin.prevout.hash); + if (itPrev == mapOrphanTransactionsByPrev.end()) + continue; + itPrev->second.erase(hash); + if (itPrev->second.empty()) + mapOrphanTransactionsByPrev.erase(itPrev); + } + mapOrphanTransactions.erase(it); +} + +void EraseOrphansFor(NodeId peer) +{ + int nErased = 0; + map::iterator iter = mapOrphanTransactions.begin(); + while (iter != mapOrphanTransactions.end()) + { + map::iterator maybeErase = iter++; // increment to avoid iterator becoming invalid + if (maybeErase->second.fromPeer == peer) + { + EraseOrphanTx(maybeErase->second.tx.GetHash()); + ++nErased; + } + } + if (nErased > 0) LogPrint("mempool", "Erased %d orphan tx from peer %d\n", nErased, peer); +} + + +unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + unsigned int nEvicted = 0; + while (mapOrphanTransactions.size() > nMaxOrphans) + { + // Evict a random orphan: + uint256 randomhash = GetRandHash(); + map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + if (it == mapOrphanTransactions.end()) + it = mapOrphanTransactions.begin(); + EraseOrphanTx(it->first); + ++nEvicted; + } + return nEvicted; +} + +bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) +{ + if (tx.nLockTime == 0) + return true; + if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) + return true; + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) + return false; + } + return true; +} + +bool CheckFinalTx(const CTransaction &tx, int flags) +{ + AssertLockHeld(cs_main); + + // By convention a negative value for flags indicates that the + // current network-enforced consensus rules should be used. In + // a future soft-fork scenario that would mean checking which + // rules would be enforced for the next block and setting the + // appropriate flags. At the present time no soft-forks are + // scheduled, so no flags are set. + flags = std::max(flags, 0); + + // CheckFinalTx() uses chainActive.Height()+1 to evaluate + // nLockTime because when IsFinalTx() is called within + // CBlock::AcceptBlock(), the height of the block *being* + // evaluated is what is used. Thus if we want to know if a + // transaction can be part of the *next* block, we need to call + // IsFinalTx() with one more than chainActive.Height(). + const int nBlockHeight = chainActive.Height() + 1; + + // BIP113 will require that time-locked transactions have nLockTime set to + // less than the median time of the previous block they're contained in. + // When the next block is created its previous block will be the current + // chain tip, so we use that to calculate the median time passed to + // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set. + const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) + ? chainActive.Tip()->GetMedianTimePast() + : GetAdjustedTime(); + + return IsFinalTx(tx, nBlockHeight, nBlockTime); +} + +/** + * Calculates the block height and previous block's median time past at + * which the transaction will be considered final in the context of BIP 68. + * Also removes from the vector of input heights any entries which did not + * correspond to sequence locked inputs as they do not affect the calculation. + */ +static std::pair CalculateSequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) +{ + assert(prevHeights->size() == tx.vin.size()); + + // Will be set to the equivalent height- and time-based nLockTime + // values that would be necessary to satisfy all relative lock- + // time constraints given our view of block chain history. + // The semantics of nLockTime are the last invalid height/time, so + // use -1 to have the effect of any height or time being valid. + int nMinHeight = -1; + int64_t nMinTime = -1; + + // tx.nVersion is signed integer so requires cast to unsigned otherwise + // we would be doing a signed comparison and half the range of nVersion + // wouldn't support BIP 68. + bool fEnforceBIP68 = static_cast(tx.nVersion) >= 2 + && flags & LOCKTIME_VERIFY_SEQUENCE; + + // Do not enforce sequence numbers as a relative lock time + // unless we have been instructed to + if (!fEnforceBIP68) { + return std::make_pair(nMinHeight, nMinTime); + } + + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; + + // Sequence numbers with the most significant bit set are not + // treated as relative lock-times, nor are they given any + // consensus-enforced meaning at this point. + if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { + // The height of this input is not relevant for sequence locks + (*prevHeights)[txinIndex] = 0; + continue; + } + + int nCoinHeight = (*prevHeights)[txinIndex]; + + if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) { + int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight-1, 0))->GetMedianTimePast(); + // NOTE: Subtract 1 to maintain nLockTime semantics + // BIP 68 relative lock times have the semantics of calculating + // the first block or time at which the transaction would be + // valid. When calculating the effective block time or height + // for the entire transaction, we switch to using the + // semantics of nLockTime which is the last invalid block + // time or height. Thus we subtract 1 from the calculated + // time or height. + + // Time-based relative lock-times are measured from the + // smallest allowed timestamp of the block containing the + // txout being spent, which is the median time past of the + // block prior. + nMinTime = std::max(nMinTime, nCoinTime + (int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) << CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - 1); + } else { + nMinHeight = std::max(nMinHeight, nCoinHeight + (int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1); + } + } + + return std::make_pair(nMinHeight, nMinTime); +} + +static bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair lockPair) +{ + assert(block.pprev); + int64_t nBlockTime = block.pprev->GetMedianTimePast(); + if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime) + return false; + + return true; +} + +bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block) +{ + return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); +} + +bool TestLockPointValidity(const LockPoints* lp) +{ + AssertLockHeld(cs_main); + assert(lp); + // If there are relative lock times then the maxInputBlock will be set + // If there are no relative lock times, the LockPoints don't depend on the chain + if (lp->maxInputBlock) { + // Check whether chainActive is an extension of the block at which the LockPoints + // calculation was valid. If not LockPoints are no longer valid + if (!chainActive.Contains(lp->maxInputBlock)) { + return false; + } + } + + // LockPoints still valid + return true; +} + +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) +{ + AssertLockHeld(cs_main); + AssertLockHeld(mempool.cs); + + CBlockIndex* tip = chainActive.Tip(); + CBlockIndex index; + index.pprev = tip; + // CheckSequenceLocks() uses chainActive.Height()+1 to evaluate + // height based locks because when SequenceLocks() is called within + // ConnectBlock(), the height of the block *being* + // evaluated is what is used. + // Thus if we want to know if a transaction can be part of the + // *next* block, we need to use one more than chainActive.Height() + index.nHeight = tip->nHeight + 1; + + std::pair lockPair; + if (useExistingLockPoints) { + assert(lp); + lockPair.first = lp->height; + lockPair.second = lp->time; + } + else { + // pcoinsTip contains the UTXO set for chainActive.Tip() + CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + std::vector prevheights; + prevheights.resize(tx.vin.size()); + for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { + const CTxIn& txin = tx.vin[txinIndex]; + CCoins coins; + if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) { + return error("%s: Missing input", __func__); + } + if (coins.nHeight == MEMPOOL_HEIGHT) { + // Assume all mempool transaction confirm in the next block + prevheights[txinIndex] = tip->nHeight + 1; + } else { + prevheights[txinIndex] = coins.nHeight; + } + } + lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); + if (lp) { + lp->height = lockPair.first; + lp->time = lockPair.second; + // Also store the hash of the block with the highest height of + // all the blocks which have sequence locked prevouts. + // This hash needs to still be on the chain + // for these LockPoint calculations to be valid + // Note: It is impossible to correctly calculate a maxInputBlock + // if any of the sequence locked inputs depend on unconfirmed txs, + // except in the special case where the relative lock time/height + // is 0, which is equivalent to no sequence lock. Since we assume + // input height of tip+1 for mempool txs and test the resulting + // lockPair from CalculateSequenceLocks against tip+1. We know + // EvaluateSequenceLocks will fail if there was a non-zero sequence + // lock on a mempool input, so we can use the return value of + // CheckSequenceLocks to indicate the LockPoints validity + int maxInputHeight = 0; + BOOST_FOREACH(int height, prevheights) { + // Can ignore mempool inputs since we'll fail if they had non-zero locks + if (height != tip->nHeight+1) { + maxInputHeight = std::max(maxInputHeight, height); + } + } + lp->maxInputBlock = tip->GetAncestor(maxInputHeight); + } + } + return EvaluateSequenceLocks(index, lockPair); +} + + +unsigned int GetLegacySigOpCount(const CTransaction& tx) +{ + unsigned int nSigOps = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + nSigOps += txin.scriptSig.GetSigOpCount(false); + } + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nSigOps += txout.scriptPubKey.GetSigOpCount(false); + } + return nSigOps; +} + +unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs) +{ + if (tx.IsCoinBase()) + return 0; + + unsigned int nSigOps = 0; + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); + if (prevout.scriptPubKey.IsPayToScriptHash()) + nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); + } + return nSigOps; +} + +int GetUTXOHeight(const COutPoint& outpoint) +{ + LOCK(cs_main); + CCoins coins; + if(!pcoinsTip->GetCoins(outpoint.hash, coins) || + (unsigned int)outpoint.n>=coins.vout.size() || + coins.vout[outpoint.n].IsNull()) { + return -1; + } + return coins.nHeight; +} + +int GetInputAge(const CTxIn &txin) +{ + CCoinsView viewDummy; + CCoinsViewCache view(&viewDummy); + { + LOCK(mempool.cs); + CCoinsViewMemPool viewMempool(pcoinsTip, mempool); + view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view + + const CCoins* coins = view.AccessCoins(txin.prevout.hash); + + if (coins) { + if(coins->nHeight < 0) return 0; + return chainActive.Height() - coins->nHeight + 1; + } else { + return -1; + } + } +} + +int GetInputAgeIX(const uint256 &nTXHash, const CTxIn &txin) +{ + int nResult = GetInputAge(txin); + if(nResult < 0) return -1; + + if (nResult < 6 && instantsend.IsLockedInstantSendTransaction(nTXHash)) + return nInstantSendDepth + nResult; + + return nResult; +} + +int GetIXConfirmations(const uint256 &nTXHash) +{ + if (instantsend.IsLockedInstantSendTransaction(nTXHash)) + return nInstantSendDepth; + + return 0; +} + + +bool CheckTransaction(const CTransaction& tx, CValidationState &state) +{ + // Basic checks that don't depend on any context + if (tx.vin.empty()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); + if (tx.vout.empty()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); + // Size limits + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); + + // Check for negative or overflow output values + CAmount nValueOut = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + if (txout.nValue < 0) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); + if (txout.nValue > MAX_MONEY) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge"); + nValueOut += txout.nValue; + if (!MoneyRange(nValueOut)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + } + + // Check for duplicate inputs + set vInOutPoints; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + if (vInOutPoints.count(txin.prevout)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); + vInOutPoints.insert(txin.prevout); + } + + if (tx.IsCoinBase()) + { + if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) + return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); + } + else + { + BOOST_FOREACH(const CTxIn& txin, tx.vin) + if (txin.prevout.IsNull()) + return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); + } + + return true; +} + +void LimitMempoolSize(CTxMemPool& pool, size_t limit, unsigned long age) { + int expired = pool.Expire(GetTime() - age); + if (expired != 0) + LogPrint("mempool", "Expired %i transactions from the memory pool\n", expired); + + std::vector vNoSpendsRemaining; + pool.TrimToSize(limit, &vNoSpendsRemaining); + BOOST_FOREACH(const uint256& removed, vNoSpendsRemaining) + pcoinsTip->Uncache(removed); +} + +/** Convert CValidationState to a human-readable message for logging */ +std::string FormatStateMessage(const CValidationState &state) +{ + return strprintf("%s%s (code %i)", + state.GetRejectReason(), + state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), + state.GetRejectCode()); +} + +bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, + bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, + std::vector& vHashTxnToUncache, bool fDryRun) +{ + AssertLockHeld(cs_main); + if (pfMissingInputs) + *pfMissingInputs = false; + + if (!CheckTransaction(tx, state)) + return false; + + // Coinbase is only valid in a block, not as a loose transaction + if (tx.IsCoinBase()) + return state.DoS(100, false, REJECT_INVALID, "coinbase"); + + // Rather not work on nonstandard transactions (unless -testnet/-regtest) + string reason; + if (fRequireStandard && !IsStandardTx(tx, reason)) + return state.DoS(0, false, REJECT_NONSTANDARD, reason); + + // Don't relay version 2 transactions until CSV is active, and we can be + // sure that such transactions will be mined (unless we're on + // -testnet/-regtest). + const CChainParams& chainparams = Params(); + if (fRequireStandard && tx.nVersion >= 2 && VersionBitsTipState(chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV) != THRESHOLD_ACTIVE) { + return state.DoS(0, false, REJECT_NONSTANDARD, "premature-version2-tx"); + } + + // Only accept nLockTime-using transactions that can be mined in the next + // block; we don't want our mempool filled up with transactions that can't + // be mined yet. + if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) + return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); + + // is it already in the memory pool? + uint256 hash = tx.GetHash(); + if (pool.exists(hash)) + return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); + + // If this is a Transaction Lock Request check to see if it's valid + if(instantsend.HasTxLockRequest(hash) && !CTxLockRequest(tx).IsValid()) + return state.DoS(10, error("AcceptToMemoryPool : CTxLockRequest %s is invalid", hash.ToString()), + REJECT_INVALID, "bad-txlockrequest"); + + // Check for conflicts with a completed Transaction Lock + BOOST_FOREACH(const CTxIn &txin, tx.vin) + { + uint256 hashLocked; + if(instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hash != hashLocked) + return state.DoS(10, error("AcceptToMemoryPool : Transaction %s conflicts with completed Transaction Lock %s", + hash.ToString(), hashLocked.ToString()), + REJECT_INVALID, "tx-txlock-conflict"); + } + + // Check for conflicts with in-memory transactions + set setConflicts; + { + LOCK(pool.cs); // protect pool.mapNextTx + BOOST_FOREACH(const CTxIn &txin, tx.vin) + { + if (pool.mapNextTx.count(txin.prevout)) + { + const CTransaction *ptxConflicting = pool.mapNextTx[txin.prevout].ptx; + if (!setConflicts.count(ptxConflicting->GetHash())) + { + // InstantSend txes are not replacable + if(instantsend.HasTxLockRequest(ptxConflicting->GetHash())) { + // this tx conflicts with a Transaction Lock Request candidate + return state.DoS(0, error("AcceptToMemoryPool : Transaction %s conflicts with Transaction Lock Request %s", + hash.ToString(), ptxConflicting->GetHash().ToString()), + REJECT_INVALID, "tx-txlockreq-mempool-conflict"); + } else if (instantsend.HasTxLockRequest(hash)) { + // this tx is a tx lock request and it conflicts with a normal tx + return state.DoS(0, error("AcceptToMemoryPool : Transaction Lock Request %s conflicts with transaction %s", + hash.ToString(), ptxConflicting->GetHash().ToString()), + REJECT_INVALID, "txlockreq-tx-mempool-conflict"); + } + // Allow opt-out of transaction replacement by setting + // nSequence >= maxint-1 on all inputs. + // + // maxint-1 is picked to still allow use of nLockTime by + // non-replacable transactions. All inputs rather than just one + // is for the sake of multi-party protocols, where we don't + // want a single party to be able to disable replacement. + // + // The opt-out ignores descendants as anyone relying on + // first-seen mempool behavior should be checking all + // unconfirmed ancestors anyway; doing otherwise is hopelessly + // insecure. + bool fReplacementOptOut = true; + if (fEnableReplacement) + { + BOOST_FOREACH(const CTxIn &txin, ptxConflicting->vin) + { + if (txin.nSequence < std::numeric_limits::max()-1) + { + fReplacementOptOut = false; + break; + } + } + } + if (fReplacementOptOut) + return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); + + setConflicts.insert(ptxConflicting->GetHash()); + } + } + } + } + + { + CCoinsView dummy; + CCoinsViewCache view(&dummy); + + CAmount nValueIn = 0; + LockPoints lp; + { + LOCK(pool.cs); + CCoinsViewMemPool viewMemPool(pcoinsTip, pool); + view.SetBackend(viewMemPool); + + // do we already have it? + bool fHadTxInCache = pcoinsTip->HaveCoinsInCache(hash); + if (view.HaveCoins(hash)) { + if (!fHadTxInCache) + vHashTxnToUncache.push_back(hash); + return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known"); + } + + // do all inputs exist? + // Note that this does not check for the presence of actual outputs (see the next check for that), + // and only helps with filling in pfMissingInputs (to determine missing vs spent). + BOOST_FOREACH(const CTxIn txin, tx.vin) { + if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) + vHashTxnToUncache.push_back(txin.prevout.hash); + if (!view.HaveCoins(txin.prevout.hash)) { + if (pfMissingInputs) + *pfMissingInputs = true; + return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() + } + } + + // are the actual inputs available? + if (!view.HaveInputs(tx)) + return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent"); + + // Bring the best block into scope + view.GetBestBlock(); + + nValueIn = view.GetValueIn(tx); + + // we have all inputs cached now, so switch back to dummy, so we don't need to keep lock on mempool + view.SetBackend(dummy); + + // Only accept BIP68 sequence locked transactions that can be mined in the next + // block; we don't want our mempool filled up with transactions that can't + // be mined yet. + // Must keep pool.cs for this unless we change CheckSequenceLocks to take a + // CoinsViewCache instead of create its own + if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) + return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); + } + + // Check for non-standard pay-to-script-hash in inputs + if (fRequireStandard && !AreInputsStandard(tx, view)) + return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); + + unsigned int nSigOps = GetLegacySigOpCount(tx); + nSigOps += GetP2SHSigOpCount(tx, view); + + CAmount nValueOut = tx.GetValueOut(); + CAmount nFees = nValueIn-nValueOut; + // nModifiedFees includes any fee deltas from PrioritiseTransaction + if(nFees<=0) + { + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient nFees"); + } + CAmount nModifiedFees = nFees; + double nPriorityDummy = 0; + pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees); + + CAmount inChainInputValue; + double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + + // Keep track of transactions that spend a coinbase, which we re-scan + // during reorgs to ensure COINBASE_MATURITY is still met. + bool fSpendsCoinbase = false; + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + const CCoins *coins = view.AccessCoins(txin.prevout.hash); + if (coins->IsCoinBase()) { + fSpendsCoinbase = true; + break; + } + } + + CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); + unsigned int nSize = entry.GetTxSize(); + + // Check that the transaction doesn't have an excessive number of + // sigops, making it impossible to mine. Since the coinbase transaction + // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than + // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than + // merely non-standard transaction. + if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp)) + return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, + strprintf("%d", nSigOps)); + + CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); + if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee)); + } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { + // Require that free transactions have sufficient priority to be mined in the next block. + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority"); + } + + // Continuously rate-limit free (really, very-low-fee) transactions + // This mitigates 'penny-flooding' -- sending thousands of free transactions just to + // be annoying or make others' transactions take longer to confirm. + if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) + { + static CCriticalSection csFreeLimiter; + static double dFreeCount; + static int64_t nLastTime; + int64_t nNow = GetTime(); + + LOCK(csFreeLimiter); + + // Use an exponentially decaying ~10-minute window: + dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); + nLastTime = nNow; + // -limitfreerelay unit is thousand-bytes-per-minute + // At default rate it would take over a month to fill 1GB + if (dFreeCount >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction"); + LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); + dFreeCount += nSize; + } + + if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) + return state.Invalid(false, + REJECT_HIGHFEE, "absurdly-high-fee", + strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); + + // Calculate in-mempool ancestors, up to a limit. + CTxMemPool::setEntries setAncestors; + size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); + size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; + size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); + size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; + std::string errString; + if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { + return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString); + } + + // A transaction that spends outputs that would be replaced by it is invalid. Now + // that we have the set of all ancestors we can detect this + // pathological case by making sure setConflicts and setAncestors don't + // intersect. + BOOST_FOREACH(CTxMemPool::txiter ancestorIt, setAncestors) + { + const uint256 &hashAncestor = ancestorIt->GetTx().GetHash(); + if (setConflicts.count(hashAncestor)) + { + return state.DoS(10, error("AcceptToMemoryPool: %s spends conflicting transaction %s", + hash.ToString(), + hashAncestor.ToString()), + REJECT_INVALID, "bad-txns-spends-conflicting-tx"); + } + } + + // Check if it's economically rational to mine this transaction rather + // than the ones it replaces. + CAmount nConflictingFees = 0; + size_t nConflictingSize = 0; + uint64_t nConflictingCount = 0; + CTxMemPool::setEntries allConflicting; + + // If we don't hold the lock allConflicting might be incomplete; the + // subsequent RemoveStaged() and addUnchecked() calls don't guarantee + // mempool consistency for us. + LOCK(pool.cs); + if (setConflicts.size()) + { + CFeeRate newFeeRate(nModifiedFees, nSize); + set setConflictsParents; + const int maxDescendantsToVisit = 100; + CTxMemPool::setEntries setIterConflicting; + BOOST_FOREACH(const uint256 &hashConflicting, setConflicts) + { + CTxMemPool::txiter mi = pool.mapTx.find(hashConflicting); + if (mi == pool.mapTx.end()) + continue; + + // Save these to avoid repeated lookups + setIterConflicting.insert(mi); + + // If this entry is "dirty", then we don't have descendant + // state for this transaction, which means we probably have + // lots of in-mempool descendants. + // Don't allow replacements of dirty transactions, to ensure + // that we don't spend too much time walking descendants. + // This should be rare. + if (mi->IsDirty()) { + return state.DoS(0, + error("AcceptToMemoryPool: rejecting replacement %s; cannot replace tx %s with untracked descendants", + hash.ToString(), + mi->GetTx().GetHash().ToString()), + REJECT_NONSTANDARD, "too many potential replacements"); + } + + // Don't allow the replacement to reduce the feerate of the + // mempool. + // + // We usually don't want to accept replacements with lower + // feerates than what they replaced as that would lower the + // feerate of the next block. Requiring that the feerate always + // be increased is also an easy-to-reason about way to prevent + // DoS attacks via replacements. + // + // The mining code doesn't (currently) take children into + // account (CPFP) so we only consider the feerates of + // transactions being directly replaced, not their indirect + // descendants. While that does mean high feerate children are + // ignored when deciding whether or not to replace, we do + // require the replacement to pay more overall fees too, + // mitigating most cases. + CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize()); + if (newFeeRate <= oldFeeRate) + { + return state.DoS(0, + error("AcceptToMemoryPool: rejecting replacement %s; new feerate %s <= old feerate %s", + hash.ToString(), + newFeeRate.ToString(), + oldFeeRate.ToString()), + REJECT_INSUFFICIENTFEE, "insufficient fee"); + } + + BOOST_FOREACH(const CTxIn &txin, mi->GetTx().vin) + { + setConflictsParents.insert(txin.prevout.hash); + } + + nConflictingCount += mi->GetCountWithDescendants(); + } + // This potentially overestimates the number of actual descendants + // but we just want to be conservative to avoid doing too much + // work. + if (nConflictingCount <= maxDescendantsToVisit) { + // If not too many to replace, then calculate the set of + // transactions that would have to be evicted + BOOST_FOREACH(CTxMemPool::txiter it, setIterConflicting) { + pool.CalculateDescendants(it, allConflicting); + } + BOOST_FOREACH(CTxMemPool::txiter it, allConflicting) { + nConflictingFees += it->GetModifiedFee(); + nConflictingSize += it->GetTxSize(); + } + } else { + return state.DoS(0, + error("AcceptToMemoryPool: rejecting replacement %s; too many potential replacements (%d > %d)\n", + hash.ToString(), + nConflictingCount, + maxDescendantsToVisit), + REJECT_NONSTANDARD, "too many potential replacements"); + } + + for (unsigned int j = 0; j < tx.vin.size(); j++) + { + // We don't want to accept replacements that require low + // feerate junk to be mined first. Ideally we'd keep track of + // the ancestor feerates and make the decision based on that, + // but for now requiring all new inputs to be confirmed works. + if (!setConflictsParents.count(tx.vin[j].prevout.hash)) + { + // Rather than check the UTXO set - potentially expensive - + // it's cheaper to just check if the new input refers to a + // tx that's in the mempool. + if (pool.mapTx.find(tx.vin[j].prevout.hash) != pool.mapTx.end()) + return state.DoS(0, error("AcceptToMemoryPool: replacement %s adds unconfirmed input, idx %d", + hash.ToString(), j), + REJECT_NONSTANDARD, "replacement-adds-unconfirmed"); + } + } + + // The replacement must pay greater fees than the transactions it + // replaces - if we did the bandwidth used by those conflicting + // transactions would not be paid for. + if (nModifiedFees < nConflictingFees) + { + return state.DoS(0, error("AcceptToMemoryPool: rejecting replacement %s, less fees than conflicting txs; %s < %s", + hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)), + REJECT_INSUFFICIENTFEE, "insufficient fee"); + } + + // Finally in addition to paying more fees than the conflicts the + // new transaction must pay for its own bandwidth. + CAmount nDeltaFees = nModifiedFees - nConflictingFees; + if (nDeltaFees < ::minRelayTxFee.GetFee(nSize)) + { + return state.DoS(0, + error("AcceptToMemoryPool: rejecting replacement %s, not enough additional fees to relay; %s < %s", + hash.ToString(), + FormatMoney(nDeltaFees), + FormatMoney(::minRelayTxFee.GetFee(nSize))), + REJECT_INSUFFICIENTFEE, "insufficient fee"); + } + } + + // If we aren't going to actually accept it but just were verifying it, we are fine already + if(fDryRun) return true; + + // Check against previous transactions + // This is done last to help prevent CPU exhaustion denial-of-service attacks. + if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) + return false; + + // Check again against just the consensus-critical mandatory script + // verification flags, in case of bugs in the standard flags that cause + // transactions to pass as valid when they're actually invalid. For + // instance the STRICTENC flag was incorrectly allowing certain + // CHECKSIG NOT scripts to pass, even though they were invalid. + // + // There is a similar check in CreateNewBlock() to prevent creating + // invalid blocks, however allowing such transactions into the mempool + // can be exploited as a DoS attack. + if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) + { + return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", + __func__, hash.ToString(), FormatStateMessage(state)); + } + + // Remove conflicting transactions from the mempool + BOOST_FOREACH(const CTxMemPool::txiter it, allConflicting) + { + LogPrint("mempool", "replacing tx %s with %s for %s PCH additional fees, %d delta bytes\n", + it->GetTx().GetHash().ToString(), + hash.ToString(), + FormatMoney(nModifiedFees - nConflictingFees), + (int)nSize - (int)nConflictingSize); + } + pool.RemoveStaged(allConflicting); + + // Store transaction in memory + pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); + + // Add memory address index + if (fAddressIndex) { + pool.addAddressIndex(entry, view); + } + + // Add memory spent index + if (fSpentIndex) { + pool.addSpentIndex(entry, view); + } + + // trim mempool and check if tx was trimmed + if (!fOverrideMempoolLimit) { + LimitMempoolSize(pool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); + if (!pool.exists(hash)) + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool full"); + } + } + + if(!fDryRun) SyncWithWallets(tx, NULL); + + return true; +} + +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, + bool* pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, bool fDryRun) +{ + std::vector vHashTxToUncache; + bool res = AcceptToMemoryPoolWorker(pool, state, tx, fLimitFree, pfMissingInputs, fOverrideMempoolLimit, fRejectAbsurdFee, vHashTxToUncache, fDryRun); + if (!res || fDryRun) { + if(!res) LogPrint("mempool", "%s: %s %s\n", __func__, tx.GetHash().ToString(), state.GetRejectReason()); + BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache) + pcoinsTip->Uncache(hashTx); + } + return res; +} + +bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes) +{ + if (!fTimestampIndex) + return error("Timestamp index not enabled"); + + if (!pblocktree->ReadTimestampIndex(high, low, hashes)) + return error("Unable to get hashes for timestamps"); + + return true; +} + +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value) +{ + if (!fSpentIndex) + return false; + + if (mempool.getSpentIndex(key, value)) + return true; + + if (!pblocktree->ReadSpentIndex(key, value)) + return false; + + return true; +} + +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, int start, int end) +{ + if (!fAddressIndex) + { + return error("address index not enabled"); + } + if (!pblocktree->ReadAddressIndex(addressHash, type, addressIndex, start, end)) + { + return error("unable to get txids for address"); + } + + return true; +} + +bool GetAddressUnspent(uint160 addressHash, int type, + std::vector > &unspentOutputs) +{ + if (!fAddressIndex) + return error("address index not enabled"); + + if (!pblocktree->ReadAddressUnspentIndex(addressHash, type, unspentOutputs)) + return error("unable to get txids for address"); + + return true; +} + +/** Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock */ +bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params& consensusParams, uint256 &hashBlock, bool fAllowSlow) +{ + CBlockIndex *pindexSlow = NULL; + + LOCK(cs_main); + + if (mempool.lookup(hash, txOut)) + { + return true; + } + + if (fTxIndex) { + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(hash, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + if (file.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + hashBlock = header.GetHash(); + if (txOut.GetHash() != hash) + return error("%s: txid mismatch", __func__); + return true; + } + } + + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it + int nHeight = -1; + { + CCoinsViewCache &view = *pcoinsTip; + const CCoins* coins = view.AccessCoins(hash); + if (coins) + nHeight = coins->nHeight; + } + if (nHeight > 0) + pindexSlow = chainActive[nHeight]; + } + + if (pindexSlow) { + CBlock block; + if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + if (tx.GetHash() == hash) { + txOut = tx; + hashBlock = pindexSlow->GetBlockHash(); + return true; + } + } + } + } + + return false; +} + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// CBlock and CBlockIndex +// + +bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) +{ + // Open history file to append + CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("WriteBlockToDisk: OpenBlockFile failed"); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(block); + fileout << FLATDATA(messageStart) << nSize; + + // Write block + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) + return error("WriteBlockToDisk: ftell failed"); + pos.nPos = (unsigned int)fileOutPos; + fileout << block; + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) +{ + block.SetNull(); + + // Open history file to read + CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString()); + + // Read block + try { + filein >> block; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); + } + + // Check the header + +//arith_uint256 k = UintToArith256(block.GetHash()); +//LogPrintf("\t\t\tblock = %s\n\t\t\thash = %s\n\t\t\tarith hash = %s\n", block.ToString().c_str(), block.GetHash().ToString().c_str(), k.ToString().c_str()); + if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) + return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); + + return true; +} + +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams) +{ + if (!ReadBlockFromDisk(block, pindex->GetBlockPos(), consensusParams)) + return false; + if (block.GetHash() != pindex->GetBlockHash()) + return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s", + pindex->ToString(), pindex->GetBlockPos().ToString()); + return true; +} + +CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) +{ + // genesis + if (!height) + { + return cp.genesisReward; + } + // first block + else if (height == 1) + { + return cp.premine; + } + // the others + else + { + const int intval = cp.nSubsidyHalvingInterval; + + // first 4 years + if (height < intval) + { + return cp.minerReward4; + } + // from the 5th year on + else + { + int halvings = (height - intval) / intval; + // force subsidy to 0 when right shift 64 bit is undifined + if (halvings > 63) + { + return 0; + } + CAmount subsidy(cp.minerReward5); + subsidy >>= halvings; + return subsidy; + } + } +} + +CAmount GetFoundersReward(const int height, const Consensus::Params &cp) +{ + const int beg = cp.nSuperblockStartBlock; + const int end = cp.endOfFoundersReward(); + if (height >= beg && height < end) // before super block starting + { + return cp.foundersReward; + } + return 0; +} + +// return all subsidy +CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp) +{ + return GetMinerSubsidy(height, cp) + + GetFoundersReward(height, cp); +} + +bool IsInitialBlockDownload() +{ + static bool lockIBDState = false; + if (lockIBDState) + return false; + if (fImporting || fReindex) + return true; + LOCK(cs_main); + const CChainParams& chainParams = Params(); + if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints())) + return true; + bool state = + (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || + std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - chainParams.MaxTipAge()); + if (!state) + lockIBDState = true; + return state; +} + +bool fLargeWorkForkFound = false; +bool fLargeWorkInvalidChainFound = false; +CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL; + +void CheckForkWarningConditions() +{ + AssertLockHeld(cs_main); + // Before we get past initial download, we cannot reliably alert about forks + // (we assume we don't get stuck on a fork before the last checkpoint) + if (IsInitialBlockDownload()) + return; + + // If our best fork is no longer within 72 blocks (+/- 3 hours if no one mines it) + // of our head, drop it + if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) + pindexBestForkTip = NULL; + + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) + { + if (!fLargeWorkForkFound && pindexBestForkBase) + { + if(pindexBestForkBase->phashBlock){ + std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + + pindexBestForkBase->phashBlock->ToString() + std::string("'"); + CAlert::Notify(warning, true); + } + } + if (pindexBestForkTip && pindexBestForkBase) + { + if(pindexBestForkBase->phashBlock){ + LogPrintf("%s: Warning: Large valid fork found\n forking the chain at height %d (%s)\n lasting to height %d (%s).\nChain state database corruption likely.\n", __func__, + pindexBestForkBase->nHeight, pindexBestForkBase->phashBlock->ToString(), + pindexBestForkTip->nHeight, pindexBestForkTip->phashBlock->ToString()); + fLargeWorkForkFound = true; + } + } + else + { + if(pindexBestInvalid->nHeight > chainActive.Height() + 6) + LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__); + else + LogPrintf("%s: Warning: Found invalid chain which has higher work (at least ~6 blocks worth of work) than our best chain.\nChain state database corruption likely.\n", __func__); + fLargeWorkInvalidChainFound = true; + } + } + else + { + fLargeWorkForkFound = false; + fLargeWorkInvalidChainFound = false; + } +} + +void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) +{ + AssertLockHeld(cs_main); + // If we are on a fork that is sufficiently large, set a warning flag + CBlockIndex* pfork = pindexNewForkTip; + CBlockIndex* plonger = chainActive.Tip(); + while (pfork && pfork != plonger) + { + while (plonger && plonger->nHeight > pfork->nHeight) + plonger = plonger->pprev; + if (pfork == plonger) + break; + pfork = pfork->pprev; + } + + // We define a condition where we should warn the user about as a fork of at least 7 blocks + // with a tip within 72 blocks (+/- 3 hours if no one mines it) of ours + // or a chain that is entirely longer than ours and invalid (note that this should be detected by both) + // We use 7 blocks rather arbitrarily as it represents just under 10% of sustained network + // hash rate operating on the fork. + // We define it this way because it allows us to only store the highest fork tip (+ base) which meets + // the 7-block condition and from this always have the most-likely-to-cause-warning fork + if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && + pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && + chainActive.Height() - pindexNewForkTip->nHeight < 72) + { + pindexBestForkTip = pindexNewForkTip; + pindexBestForkBase = pfork; + } + + CheckForkWarningConditions(); +} + +// Requires cs_main. +void Misbehaving(NodeId pnode, int howmuch) +{ + if (howmuch == 0) + return; + + CNodeState *state = State(pnode); + if (state == NULL) + return; + + state->nMisbehavior += howmuch; + int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); + if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) + { + LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); + state->fShouldBan = true; + } else + LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior); +} + +void static InvalidChainFound(CBlockIndex* pindexNew) +{ + if (!pindexBestInvalid || pindexNew->nChainWork > pindexBestInvalid->nChainWork) + pindexBestInvalid = pindexNew; + + LogPrintf("%s: invalid block=%s height=%d log2_work=%.8g date=%s\n", __func__, + pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, + log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S", + pindexNew->GetBlockTime())); + CBlockIndex *tip = chainActive.Tip(); + assert (tip); + LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__, + tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime())); + CheckForkWarningConditions(); +} + +void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) { + int nDoS = 0; + if (state.IsInvalid(nDoS)) { + std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); + if (it != mapBlockSource.end() && State(it->second)) { + assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes + CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; + State(it->second)->rejects.push_back(reject); + if (nDoS > 0) + Misbehaving(it->second, nDoS); + } + } + if (!state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + setBlockIndexCandidates.erase(pindex); + InvalidChainFound(pindex); + } +} + +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) +{ + // mark inputs spent + if (!tx.IsCoinBase()) { + txundo.vprevout.reserve(tx.vin.size()); + BOOST_FOREACH(const CTxIn &txin, tx.vin) { + CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); + unsigned nPos = txin.prevout.n; + + if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull()) + assert(false); + // mark an outpoint spent, and construct undo information + txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); + coins->Spend(nPos); + if (coins->vout.size() == 0) { + CTxInUndo& undo = txundo.vprevout.back(); + undo.nHeight = coins->nHeight; + undo.fCoinBase = coins->fCoinBase; + undo.nVersion = coins->nVersion; + } + } + // add outputs + inputs.ModifyNewCoins(tx.GetHash())->FromTx(tx, nHeight); + } + else { + // add outputs for coinbase tx + // In this case call the full ModifyCoins which will do a database + // lookup to be sure the coins do not already exist otherwise we do not + // know whether to mark them fresh or not. We want the duplicate coinbases + // before BIP30 to still be properly overwritten. + inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); + } +} + +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) +{ + CTxUndo txundo; + UpdateCoins(tx, state, inputs, txundo, nHeight); +} + +bool CScriptCheck::operator()() { + const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) { + return false; + } + return true; +} + +int GetSpendHeight(const CCoinsViewCache& inputs) +{ + LOCK(cs_main); + CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; + return pindexPrev->nHeight + 1; +} + +namespace Consensus { +bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight) +{ + // This doesn't trigger the DoS code on purpose; if it did, it would make it easier + // for an attacker to attempt to split the network. + if (!inputs.HaveInputs(tx)) + return state.Invalid(false, 0, "", "Inputs unavailable"); + + CAmount nValueIn = 0; + CAmount nFees = 0; + for (unsigned int i = 0; i < tx.vin.size(); i++) + { + const COutPoint &prevout = tx.vin[i].prevout; + const CCoins *coins = inputs.AccessCoins(prevout.hash); + assert(coins); + + // If prev is coinbase, check that it's matured + if (coins->IsCoinBase()) { + if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) + return state.Invalid(false, + REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", + strprintf("tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight)); + } + + // Check for negative or overflow input values + nValueIn += coins->vout[prevout.n].nValue; + if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); + + } + + if (nValueIn < tx.GetValueOut()) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, + strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()))); + + // Tally transaction fees + CAmount nTxFee = nValueIn - tx.GetValueOut(); + if (nTxFee < 0) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); + nFees += nTxFee; + if (!MoneyRange(nFees)) + return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); + return true; +} +}// namespace Consensus + +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector *pvChecks) +{ + if (!tx.IsCoinBase()) + { + if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs))) + return false; + + if (pvChecks) + pvChecks->reserve(tx.vin.size()); + + // The first loop above does all the inexpensive checks. + // Only if ALL inputs pass do we perform expensive ECDSA signature checks. + // Helps prevent CPU exhaustion attacks. + + // Skip ECDSA signature verification when connecting blocks + // before the last block chain checkpoint. This is safe because block merkle hashes are + // still computed and checked, and any change will be caught at the next checkpoint. + if (fScriptChecks) { + for (unsigned int i = 0; i < tx.vin.size(); i++) { + const COutPoint &prevout = tx.vin[i].prevout; + const CCoins* coins = inputs.AccessCoins(prevout.hash); + assert(coins); + + // Verify signature + CScriptCheck check(*coins, tx, i, flags, cacheStore); + if (pvChecks) { + pvChecks->push_back(CScriptCheck()); + check.swap(pvChecks->back()); + } else if (!check()) { + if (flags & STANDARD_NOT_MANDATORY_VERIFY_FLAGS) { + // Check whether the failure was caused by a + // non-mandatory script verification check, such as + // non-standard DER encodings or non-null dummy + // arguments; if so, don't trigger DoS protection to + // avoid splitting the network between upgraded and + // non-upgraded nodes. + CScriptCheck check2(*coins, tx, i, + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); + if (check2()) + return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); + } + // Failures of other flags indicate a transaction that is + // invalid in new blocks, e.g. a invalid P2SH. We DoS ban + // such nodes as they are not following the protocol. That + // said during an upgrade careful thought should be taken + // as to the correct behavior - we may want to continue + // peering with non-upgraded nodes even after a soft-fork + // super-majority vote has passed. + return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + } + } + } + } + + return true; +} + +namespace { + +bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart) +{ + // Open history file to append + CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s: OpenUndoFile failed", __func__); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(blockundo); + fileout << FLATDATA(messageStart) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) + return error("%s: ftell failed", __func__); + pos.nPos = (unsigned int)fileOutPos; + fileout << blockundo; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + fileout << hasher.GetHash(); + + return true; +} + +bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) +{ + // Open history file to read + CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + + // Read block + uint256 hashChecksum; + try { + filein >> blockundo; + filein >> hashChecksum; + } + catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + if (hashChecksum != hasher.GetHash()) + return error("%s: Checksum mismatch", __func__); + + return true; +} + +/** Abort with a message */ +bool AbortNode(const std::string& strMessage, const std::string& userMessage="") +{ + strMiscWarning = strMessage; + LogPrintf("*** %s\n", strMessage); + uiInterface.ThreadSafeMessageBox( + userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage, + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return false; +} + +bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="") +{ + AbortNode(strMessage, userMessage); + return state.Error(strMessage); +} + +} // anon namespace + +/** + * Apply the undo operation of a CTxInUndo to the given chain state. + * @param undo The undo object. + * @param view The coins view to which to apply the changes. + * @param trieCache + * @param out The out point that corresponds to the tx input. + * @return True on success. + */ +static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, CClaimTrieCache& trieCache, const COutPoint& out) +{ + bool fClean = true; + + CCoinsModifier coins = view.ModifyCoins(out.hash); + if (undo.nHeight != 0) { + // undo data contains height: this is the last output of the prevout tx being spent + if (!coins->IsPruned()) + fClean = fClean && error("%s: undo data overwriting existing transaction", __func__); + coins->Clear(); + coins->fCoinBase = undo.fCoinBase; + coins->nHeight = undo.nHeight; + coins->nVersion = undo.nVersion; + } else { + if (coins->IsPruned()) + fClean = fClean && error("%s: undo data adding output to missing transaction", __func__); + } + if (coins->IsAvailable(out.n)) + fClean = fClean && error("%s: undo data overwriting existing output", __func__); + if (coins->vout.size() < out.n+1) + coins->vout.resize(out.n+1); + + //restore claim if applicable + int op; + std::vector > vvchParams; + if(undo.fIsClaim && DecodeClaimScript(undo.txout.scriptPubKey,op,vvchParams)) + { + if(op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) + { + uint160 claimId; + if(op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2 ); + claimId = ClaimIdHash(out.hash,out.n); + } + else if( op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3 ); + claimId = uint160(vvchParams[1]); + } + std::string name(vvchParams[0].begin(),vvchParams[0].end()); + int nValidHeight = undo.nClaimValidHeight; + if(nValidHeight > 0 && nValidHeight >= coins->nHeight) + { + LogPrintf("%s: (txid: %s, nOut: %d) Restoring %s to the claim trie due to a block being disconnected\n", __func__, out.hash.ToString(), out.n, name.c_str()); + if ( !trieCache.undoSpendClaim(name, COutPoint(out.hash, out.n), claimId, undo.txout.nValue, coins->nHeight, nValidHeight)) + LogPrintf("%s: Something went wrong inserting the claim\n", __func__); + else + { + LogPrintf("%s: (txid: %s, nOut: %d) Not restoring %s to the claim trie because it expired before it was spent\n", __func__, out.hash.ToString(), out.n, name.c_str()); + } + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 supportedClaimId(vvchParams[1]); + int nValidHeight = undo.nClaimValidHeight; + if (nValidHeight > 0 && nValidHeight >= coins->nHeight) + { + LogPrintf("%s: (txid: %s, nOut: %d) Restoring support for %s in claimid %s due to a block being disconnected\n", __func__, out.hash.ToString(), out.n, name, supportedClaimId.ToString()); + if (!trieCache.undoSpendSupport(name, COutPoint(out.hash, out.n), supportedClaimId, undo.txout.nValue, coins->nHeight, nValidHeight)) + LogPrintf("%s: Something went wrong inserting support for the claim\n", __func__); + } + else + { + LogPrintf("%s: (txid: %s, nOut: %d) Not restoring support for %s in claimid %s because the support expired before it was spent\n", __func__, out.hash.ToString(), out.n, name, supportedClaimId.ToString()); + } + } + } + + coins->vout[out.n] = undo.txout; + + return fClean; +} + +bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, CClaimTrieCache& trieCache, bool* pfClean) +{ + assert(pindex->GetBlockHash() == view.GetBestBlock()); + //assert(pindex->GetBlockHash() == trieCache.getBestBlock()); + + if (pfClean) + *pfClean = false; + + bool fClean = true; + + CBlockUndo blockUndo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (pos.IsNull()) + return error("DisconnectBlock(): no undo data available"); + if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) + return error("DisconnectBlock(): failure reading undo data"); + + if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) + return error("DisconnectBlock(): block and undo data inconsistent"); + + std::vector > addressIndex; + std::vector > addressUnspentIndex; + std::vector > spentIndex; + + assert(trieCache.decrementBlock(blockUndo.insertUndo, blockUndo.expireUndo, blockUndo.insertSupportUndo, blockUndo.expireSupportUndo, blockUndo.takeoverHeightUndo)); + + // undo transactions in reverse order + for (int i = block.vtx.size() - 1; i >= 0; i--) { + const CTransaction &tx = block.vtx[i]; + uint256 hash = tx.GetHash(); + + if (fAddressIndex) { + + for (unsigned int k = tx.vout.size(); k-- > 0;) { + const CTxOut &out = tx.vout[k]; + uint160 hashBytes; + int addressType; + + if(DecodeAddressHash(out.scriptPubKey, hashBytes, addressType)) + { + // undo receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, hash, k, false), out.nValue)); + + // undo unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, hash, k), CAddressUnspentValue())); + } + } + + } + + // Check that all outputs are available and match the outputs in the block itself + // exactly. + { + CCoinsModifier outs = view.ModifyCoins(hash); + outs->ClearUnspendable(); + + CCoins outsBlock(tx, pindex->nHeight); + // The CCoins serialization does not serialize negative numbers. + // No network rules currently depend on the version here, so an inconsistency is harmless + // but it must be corrected before txout nversion ever influences a network rule. +if (outs->nVersion != outsBlock.nVersion) +{ +LogPrintf("main.cpp:2365, outs->nVersion(%d) != outsBlock.nVer(%d), ", outs->nVersion, outsBlock.nVersion); +outs->nVersion = outsBlock.nVersion; +} + if (outsBlock.nVersion < 0) + outs->nVersion = outsBlock.nVersion; + if (*outs != outsBlock) + fClean = fClean && error("DisconnectBlock(): added transaction mismatch? database corrupted"); + + // remove any claims + for (unsigned int i = 0; i < tx.vout.size(); ++i) + { + const CTxOut& txout = tx.vout[i]; + + int op; + std::vector > vvchParams; + if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) + { + if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) + { + uint160 claimId; + if (op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2); + claimId = ClaimIdHash(hash, i); + } + else if (op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3); + claimId = uint160(vvchParams[1]); + } + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + LogPrintf("%s: (txid: %s, nOut: %d) Trying to remove %s from the claim trie due to its block being disconnected\n", __func__, hash.ToString(), i, name.c_str()); + if (!trieCache.undoAddClaim(name, COutPoint(hash, i), pindex->nHeight)) + { + LogPrintf("%s: Could not find the claim in the trie or the cache\n", __func__); + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 supportedClaimId(vvchParams[1]); + LogPrintf("%s: (txid: %s, nOut: %d) Removing support for claim id %s on %s due to its block being disconnected\n", __func__, hash.ToString(), i, supportedClaimId.ToString(), name.c_str()); + if (!trieCache.undoAddSupport(name, COutPoint(hash, i), pindex->nHeight)) + LogPrintf("%s: Something went wrong removing support for name %s in hash %s\n", __func__, name.c_str(), hash.ToString()); + } + } + } + + // remove outputs + outs->Clear(); + } + + // restore inputs + if (i > 0) { // not coinbases + const CTxUndo &txundo = blockUndo.vtxundo[i-1]; + if (txundo.vprevout.size() != tx.vin.size()) + return error("DisconnectBlock(): transaction and undo data inconsistent"); + for (unsigned int j = tx.vin.size(); j-- > 0;) { + const COutPoint &out = tx.vin[j].prevout; + const CTxInUndo &undo = txundo.vprevout[j]; + if (!ApplyTxInUndo(undo, view, trieCache, out)) + fClean = false; + + const CTxIn input = tx.vin[j]; + + if (fSpentIndex) { + // undo and delete the spent index + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue())); + } + + if (fAddressIndex) { + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + uint160 hashBytes; + int addressType; + + if(DecodeAddressHash(prevout.scriptPubKey, hashBytes, addressType)) + { + // undo spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, hash, j, true), prevout.nValue * -1)); + + // restore unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue(prevout.nValue, prevout.scriptPubKey, undo.nHeight))); + } + } + + } + } + } + + + // move best block pointer to prevout block + view.SetBestBlock(pindex->pprev->GetBlockHash()); + assert(trieCache.finalizeDecrement()); + //trieCache.setBestBlock(pindex->pprev->GetBlockHash()); + //assert(trieCache.getMerkleHash() == pindex->pprev->hashClaimTrie); + + if (pfClean) { + *pfClean = fClean; + return true; + } + + if (fAddressIndex) { + if (!pblocktree->EraseAddressIndex(addressIndex)) { + return AbortNode(state, "Failed to delete address index"); + } + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + return AbortNode(state, "Failed to write address unspent index"); + } + } + + return fClean; +} + +void static FlushBlockFile(bool fFinalize = false) +{ + LOCK(cs_LastBlockFile); + + CDiskBlockPos posOld(nLastBlockFile, 0); + + FILE *fileOld = OpenBlockFile(posOld); + if (fileOld) { + if (fFinalize) + TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nSize); + FileCommit(fileOld); + fclose(fileOld); + } + + fileOld = OpenUndoFile(posOld); + if (fileOld) { + if (fFinalize) + TruncateFile(fileOld, vinfoBlockFile[nLastBlockFile].nUndoSize); + FileCommit(fileOld); + fclose(fileOld); + } +} + +bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize); + +static CCheckQueue scriptcheckqueue(128); + +void ThreadScriptCheck() { + RenameThread("pop-scriptch"); + scriptcheckqueue.Thread(); +} + +// +// Called periodically asynchronously; alerts if it smells like +// we're being fed a bad chain (blocks being generated much +// too slowly or too quickly). +// +void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, + int64_t nPowTargetSpacing) +{ + if (bestHeader == NULL || initialDownloadCheck()) return; + + static int64_t lastAlertTime = 0; + int64_t now = GetAdjustedTime(); + if (lastAlertTime > now-60*60*24) return; // Alert at most once per day + + const int SPAN_HOURS=1; // was 4h in bitcoin but we have 4x faster blocks + const int SPAN_SECONDS=SPAN_HOURS*60*60; + int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; + + boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); + + std::string strWarning; + int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; + + LOCK(cs); + const CBlockIndex* i = bestHeader; + int nBlocks = 0; + while (i->GetBlockTime() >= startTime) { + ++nBlocks; + i = i->pprev; + if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed + } + + // How likely is it to find that many by chance? + double p = boost::math::pdf(poisson, nBlocks); + + LogPrint("partitioncheck", "%s: Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); + LogPrint("partitioncheck", "%s: likelihood: %g\n", __func__, p); + + // Aim for one false-positive about every fifty years of normal running: + const int FIFTY_YEARS = 50*365*24*60*60; + double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); + + if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) + { + // Many fewer blocks than expected: alert! + strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"), + nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); + } + else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED) + { + // Many more blocks than expected: alert! + strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"), + nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); + } + if (!strWarning.empty()) + { + strMiscWarning = strWarning; + CAlert::Notify(strWarning, true); + lastAlertTime = now; + } +} + +// Protected by cs_main +static VersionBitsCache versionbitscache; + +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params) +{ + LOCK(cs_main); + int32_t nVersion = VERSIONBITS_TOP_BITS; + + for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) { + ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache); + if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { + nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); + } + } + + return nVersion; +} + +bool GetBlockHash(uint256& hashRet, int nBlockHeight) +{ + LOCK(cs_main); + if(chainActive.Tip() == NULL) return false; + if(nBlockHeight < -1 || nBlockHeight > chainActive.Height()) return false; + if(nBlockHeight == -1) nBlockHeight = chainActive.Height(); + hashRet = chainActive[nBlockHeight]->GetBlockHash(); + return true; +} + +/** + * Threshold condition checker that triggers when unknown versionbits are seen on the network. + */ +class WarningBitsConditionChecker : public AbstractThresholdConditionChecker +{ +private: + int bit; + +public: + WarningBitsConditionChecker(int bitIn) : bit(bitIn) {} + + int64_t BeginTime(const Consensus::Params& params) const { return 0; } + int64_t EndTime(const Consensus::Params& params) const { return std::numeric_limits::max(); } + int Period(const Consensus::Params& params) const { return params.nMinerConfirmationWindow; } + int Threshold(const Consensus::Params& params) const { return params.nRuleChangeActivationThreshold; } + + bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const + { + return ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && + ((pindex->nVersion >> bit) & 1) != 0 && + ((ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0; + } +}; + +// Protected by cs_main +static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS]; + +static int64_t nTimeCheck = 0; +static int64_t nTimeForks = 0; +static int64_t nTimeVerify = 0; +static int64_t nTimeConnect = 0; +static int64_t nTimeIndex = 0; +static int64_t nTimeCallbacks = 0; +static int64_t nTimeTotal = 0; + +// added trieCache arg +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, CClaimTrieCache& trieCache, bool fJustCheck) +{ + const CChainParams& chainparams = Params(); + AssertLockHeld(cs_main); + + int64_t nTimeStart = GetTimeMicros(); + + // Check it again in case a previous version let a bad block in + if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) + return false; + + // verify that the view's current state corresponds to the previous block + uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); + assert(hashPrevBlock == view.GetBestBlock()); + + // also verify that the trie cache's current state corresponds to the previous block + //assert(hashPrevBlock == trieCache.getBestBlock()); + + // Special case for the genesis block, skipping connection of its transactions + // (its coinbase is unspendable) + if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { + if (!fJustCheck) + { + view.SetBestBlock(pindex->GetBlockHash()); + trieCache.setBestBlock(pindex->GetBlockHash()); + } + return true; + } + + bool fScriptChecks = true; + if (fCheckpointsEnabled) { + CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); + if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { + // This block is an ancestor of a checkpoint: disable script checks + fScriptChecks = false; + } + } + + int64_t nTime1 = GetTimeMicros(); nTimeCheck += nTime1 - nTimeStart; + LogPrint("bench", " - Sanity checks: %.2fms [%.2fs]\n", 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); + + // Do not allow blocks that contain transactions which 'overwrite' older transactions, + // unless those are already completely spent. + // If such overwrites are allowed, coinbases and transactions depending upon those + // can be duplicated to remove the ability to spend the first instance -- even after + // being sent to another address. + // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. + // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool + // already refuses previously-known transaction ids entirely. + // This rule was originally applied to all blocks with a timestamp after March 15, 2012, 0:00 UTC. + // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the + // two in the chain that violate it. This prevents exploiting the issue against nodes during their + // initial block download. + bool fEnforceBIP30 = (!pindex->phashBlock) || // Enforce on CreateNewBlock invocations which don't have a hash. + !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || + (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"))); + + // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting + // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the + // time BIP34 activated, in each of the existing pairs the duplicate coinbase had overwritten the first + // before the first had been spent. Since those coinbases are sufficiently buried its no longer possible to create further + // duplicate transactions descending from the known pairs either. + // If we're on the known chain at height greater than where BIP34 activated, we can save the db accesses needed for the BIP30 check. + CBlockIndex *pindexBIP34height = pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); + //Only continue to enforce if we're below BIP34 activation height or the block hash at that height doesn't correspond. + fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); + + if (fEnforceBIP30) { + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + const CCoins* coins = view.AccessCoins(tx.GetHash()); + if (coins && !coins->IsPruned()) + return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), + REJECT_INVALID, "bad-txns-BIP30"); + } + } + + // BIP16 didn't become active until Apr 1 2012 + int64_t nBIP16SwitchTime = 1333238400; + bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime); + + unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; + + // Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, + // when 75% of the network has upgraded: + if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + flags |= SCRIPT_VERIFY_DERSIG; + } + + // Start enforcing CHECKLOCKTIMEVERIFY, (BIP65) for block.nVersion=4 + // blocks, when 75% of the network has upgraded: + if (block.nVersion >= 4 && IsSuperMajority(4, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) { + flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; + } + + // Start enforcing BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY) using versionbits logic. + int nLockTimeFlags = 0; + if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; + nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; + } + + int64_t nTime2 = GetTimeMicros(); nTimeForks += nTime2 - nTime1; + LogPrint("bench", " - Fork checks: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeForks * 0.000001); + + CBlockUndo blockundo; + + CCheckQueueControl control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); + + std::vector prevheights; + CAmount nFees = 0; + int nInputs = 0; + unsigned int nSigOps = 0; + CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); + std::vector > vPos; + vPos.reserve(block.vtx.size()); + blockundo.vtxundo.reserve(block.vtx.size() - 1); + std::vector > addressIndex; + std::vector > addressUnspentIndex; + std::vector > spentIndex; + + for (unsigned int i = 0; i < block.vtx.size(); i++) + { + const CTransaction &tx = block.vtx[i]; + const uint256 txhash = tx.GetHash(); + + nInputs += tx.vin.size(); + nSigOps += GetLegacySigOpCount(tx); + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("ConnectBlock(): too many sigops"), + REJECT_INVALID, "bad-blk-sigops"); + std::map mClaimUndoHeights; // claim + + if (!tx.IsCoinBase()) + { + if (!view.HaveInputs(tx)) + return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), + REJECT_INVALID, "bad-txns-inputs-missingorspent"); + + // Check that transaction is BIP68 final + // BIP68 lock checks (as opposed to nLockTime checks) must + // be in ConnectBlock because they require the UTXO set + prevheights.resize(tx.vin.size()); + for (size_t j = 0; j < tx.vin.size(); j++) { + prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight; + } + + if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { + return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__), + REJECT_INVALID, "bad-txns-nonfinal"); + } + + if (fAddressIndex || fSpentIndex) + { + for (size_t j = 0; j < tx.vin.size(); j++) { + + const CTxIn input = tx.vin[j]; + const CTxOut &prevout = view.GetOutputFor(tx.vin[j]); + uint160 hashBytes; + int addressType; + if(DecodeAddressHash(prevout.scriptPubKey, hashBytes, addressType)) + { + if (fAddressIndex && addressType > 0) { + // record spending activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, j, true), prevout.nValue * -1)); + + // remove address from unspent index + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, input.prevout.hash, input.prevout.n), CAddressUnspentValue())); + } + } + if (fSpentIndex) { + // add the spent index to determine the txid and input that spent an output + // and to find the amount and address from an input + spentIndex.push_back(make_pair(CSpentIndexKey(input.prevout.hash, input.prevout.n), CSpentIndexValue(txhash, j, pindex->nHeight, prevout.nValue, addressType, hashBytes))); + } + } + + } + + if (fStrictPayToScriptHash) + { + // Add in sigops done by pay-to-script-hash inputs; + // this is to prevent a "rogue miner" from creating + // an incredibly-expensive-to-validate block. + nSigOps += GetP2SHSigOpCount(tx, view); + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("ConnectBlock(): too many sigops"), + REJECT_INVALID, "bad-blk-sigops"); + } + + nFees += view.GetValueIn(tx)-tx.GetValueOut(); + + std::vector vChecks; + bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ + if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) + return error("ConnectBlock(): CheckInputs on %s failed with %s", + tx.GetHash().ToString(), FormatStateMessage(state)); + control.Add(vChecks); + + // To handle claim updates, stick all claims found in the inputs into a map of + // name: (txhash, nOut). When running through the outputs, if any claim's + // name is found in the map, send the name's txhash and nOut to the trie cache, + // and then remove the name: (txhash, nOut) mapping from the map. + // If there are two or more claims in the inputs with the same name, only + // use the first. + + typedef std::vector > spentClaimsType; + spentClaimsType spentClaims; + + for (unsigned int m = 0; m < tx.vin.size(); ++m) + { + const CTxIn& txin = tx.vin[m]; + const CCoins* coins = view.AccessCoins(txin.prevout.hash); + assert(coins); + + int op; + std::vector > vvchParams; + if (DecodeClaimScript(coins->vout[txin.prevout.n].scriptPubKey, op, vvchParams)) + { + if (op == OP_CLAIM_NAME || op == OP_UPDATE_CLAIM) + { + uint160 claimId; + if (op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2); + claimId = ClaimIdHash(txin.prevout.hash, txin.prevout.n); + } + else if (op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3); + claimId = uint160(vvchParams[1]); + } + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + int nValidAtHeight; + LogPrintf("%s: Removing %s from the claim trie. Tx: %s, nOut: %d\n", __func__, name, txin.prevout.hash.GetHex(), txin.prevout.n); + if (trieCache.spendClaim(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) + { + mClaimUndoHeights[m] = nValidAtHeight; + std::pair entry(name, claimId); + spentClaims.push_back(entry); + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 supportedClaimId(vvchParams[1]); + int nValidAtHeight; + LogPrintf("%s: Removing support for %s in %s. Tx: %s, nOut: %d, removed txid: %s\n", __func__, supportedClaimId.ToString(), name, txin.prevout.hash.ToString(), txin.prevout.n,tx.GetHash().ToString()); + if (trieCache.spendSupport(name, COutPoint(txin.prevout.hash, txin.prevout.n), coins->nHeight, nValidAtHeight)) + { + mClaimUndoHeights[m] = nValidAtHeight; + } + } + } + } + + for(unsigned int l =0 ; l< tx.vout.size();++l) + { + const CTxOut& txout = tx.vout[l]; + int op; + std::vector > vvchParams; + if (DecodeClaimScript(txout.scriptPubKey, op, vvchParams)) + { + if (op == OP_CLAIM_NAME) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + LogPrintf("%s: Inserting %s into the claim trie. Tx: %s, nOut: %d\n", __func__, name, tx.GetHash().GetHex(), l); + if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), l), ClaimIdHash(tx.GetHash(), l), txout.nValue, pindex->nHeight)) + { + LogPrintf("%s: Something went wrong inserting the claim\n", __func__); + } + } + else if (op == OP_UPDATE_CLAIM) + { + assert(vvchParams.size() == 3); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 claimId(vvchParams[1]); + LogPrintf("%s: Got a claim update. Name: %s, claimId: %s, new txid: %s, nOut: %d\n", __func__, name, claimId.GetHex(), tx.GetHash().GetHex(), l); + spentClaimsType::iterator itSpent; + for (itSpent = spentClaims.begin(); itSpent != spentClaims.end(); ++itSpent) + { + if (itSpent->first == name && itSpent->second == claimId) + { + break; + } + } + if (itSpent != spentClaims.end()) + { + spentClaims.erase(itSpent); + if (!trieCache.addClaim(name, COutPoint(tx.GetHash(), l), claimId, txout.nValue, pindex->nHeight)) + { + LogPrintf("%s: Something went wrong updating the claim\n", __func__); + } + } + } + else if (op == OP_SUPPORT_CLAIM) + { + assert(vvchParams.size() == 2); + std::string name(vvchParams[0].begin(), vvchParams[0].end()); + uint160 supportedClaimId(vvchParams[1]); + if (!trieCache.addSupport(name, COutPoint(tx.GetHash(), l), txout.nValue, supportedClaimId, pindex->nHeight)) + { + LogPrintf("%s: Something went wrong inserting the support\n", __func__); + } + } + } + } + } + + if (fAddressIndex) { + for (unsigned int k = 0; k < tx.vout.size(); k++) { + const CTxOut &out = tx.vout[k]; + uint160 hashBytes; + int addressType; + if(DecodeAddressHash(out.scriptPubKey, hashBytes, addressType)) + { + // record receiving activity + addressIndex.push_back(make_pair(CAddressIndexKey(addressType, hashBytes, pindex->nHeight, i, txhash, k, false), out.nValue)); + + // record unspent output + addressUnspentIndex.push_back(make_pair(CAddressUnspentKey(addressType, hashBytes, txhash, k), CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight))); + } + } + } + + CTxUndo undoDummy; + if (i > 0) { + blockundo.vtxundo.push_back(CTxUndo()); + } + UpdateCoins(tx, state, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight); + if (i > 0 && !mClaimUndoHeights.empty()) + { + std::vector& txinUndos = blockundo.vtxundo.back().vprevout; + for (std::map::iterator itHeight = mClaimUndoHeights.begin(); itHeight != mClaimUndoHeights.end(); ++itHeight) + { + txinUndos[itHeight->first].nClaimValidHeight = itHeight->second; + txinUndos[itHeight->first].fIsClaim = true; + } + } + // The CTxUndo vector contains the heights at which claims should be put into the trie. + // This is necessary because some claims are inserted immediately into the trie, and + // others are inserted after a delay, depending on the state of the claim trie at the time + // that the claim was originally inserted into the blockchain. That state will not be + // available when and if this block is disconnected. + // It also contains whether or not any given txin represents a claim that should + // be put back into the trie. If we didn't find a claim or support in the trie + // or cache when trying to spend it, we shouldn't try to put a claim or support back + // in. Some OP_UPDATE_CLAIM's, for example, may be invalid, and so may never have been + // inserted into the trie in the first place. + + vPos.push_back(std::make_pair(tx.GetHash(), pos)); + pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); + } + + assert(trieCache.incrementBlock(blockundo.insertUndo, blockundo.expireUndo, blockundo.insertSupportUndo, blockundo.expireSupportUndo, blockundo.takeoverHeightUndo)); + + /*if (trieCache.getMerkleHash() != block.hashClaimTrie) + { + return state.DoS(100,error("ConnectBlock() : the merkle root of the claim trie does not match " + "(actual=%s vs block=%s)", trieCache.getMerkleHash().GetHex(), + block.hashClaimTrie.GetHex()), REJECT_INVALID, "bad-claim-merkle-hash"); + }*/ + + int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2; + LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); + + // It's possible that we simply don't have enough data and this could fail + // (i.e. block itself could be a correct one and we need to store it), + // that's why this is in ConnectBlock. Could be the other way around however - + // the peer who sent us this block is missing some data and wasn't able + // to recognize that block is actually invalid. + // TODO: resync data (both ways?) and try to reprocess this block later. + CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); + std::string strError = ""; + if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) { + return state.DoS(0, error("ConnectBlock(PCH): %s", strError), REJECT_INVALID, "bad-cb-amount"); + } + + if (!IsBlockPayeeValid(block.vtx[0], pindex->nHeight, blockReward)) { + mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); + return state.DoS(0, error("ConnectBlock(PCH): couldn't find popnode or superblock payments"), + REJECT_INVALID, "bad-cb-payee"); + } + // END PCH + + if (!control.Wait()) + return state.DoS(100, false); + int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2; + LogPrint("bench", " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n", nInputs - 1, 0.001 * (nTime4 - nTime2), nInputs <= 1 ? 0 : 0.001 * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * 0.000001); + + if (fJustCheck) + return true; + + // Write undo information to disk + if (pindex->GetUndoPos().IsNull() || !pindex->IsValid(BLOCK_VALID_SCRIPTS)) + { + if (pindex->GetUndoPos().IsNull()) { + CDiskBlockPos pos; + if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) + return error("ConnectBlock(): FindUndoPos failed"); + if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart())) + return AbortNode(state, "Failed to write undo data"); + + // update nUndoPos in block index + pindex->nUndoPos = pos.nPos; + pindex->nStatus |= BLOCK_HAVE_UNDO; + } + + pindex->RaiseValidity(BLOCK_VALID_SCRIPTS); + setDirtyBlockIndex.insert(pindex); + } + + if (fTxIndex) + if (!pblocktree->WriteTxIndex(vPos)) + return AbortNode(state, "Failed to write transaction index"); + + if (fAddressIndex) { + if (!pblocktree->WriteAddressIndex(addressIndex)) { + return AbortNode(state, "Failed to write address index"); + } + + if (!pblocktree->UpdateAddressUnspentIndex(addressUnspentIndex)) { + return AbortNode(state, "Failed to write address unspent index"); + } + } + + if (fSpentIndex) + if (!pblocktree->UpdateSpentIndex(spentIndex)) + return AbortNode(state, "Failed to write transaction index"); + + if (fTimestampIndex) + if (!pblocktree->WriteTimestampIndex(CTimestampIndexKey(pindex->nTime, pindex->GetBlockHash()))) + return AbortNode(state, "Failed to write timestamp index"); + + // add this block to the view's block chain + view.SetBestBlock(pindex->GetBlockHash()); + trieCache.setBestBlock(pindex->GetBlockHash()); + + int64_t nTime5 = GetTimeMicros(); nTimeIndex += nTime5 - nTime4; + LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); + + // Watch for changes to the previous coinbase transaction. + static uint256 hashPrevBestCoinBase; + GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); + hashPrevBestCoinBase = block.vtx[0].GetHash(); + + int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5; + LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); + + return true; +} + +enum FlushStateMode { + FLUSH_STATE_NONE, + FLUSH_STATE_IF_NEEDED, + FLUSH_STATE_PERIODIC, + FLUSH_STATE_ALWAYS +}; + +/** + * Update the on-disk chain state. + * The caches and indexes are flushed depending on the mode we're called with + * if they're too large, if it's been a while since the last write, + * or always and in all cases if we're in prune mode and are deleting files. + */ +bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { + const CChainParams& chainparams = Params(); + LOCK2(cs_main, cs_LastBlockFile); + static int64_t nLastWrite = 0; + static int64_t nLastFlush = 0; + static int64_t nLastSetChain = 0; + std::set setFilesToPrune; + bool fFlushForPrune = false; + try { + if (fPruneMode && fCheckForPruning && !fReindex) { + FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight()); + fCheckForPruning = false; + if (!setFilesToPrune.empty()) { + fFlushForPrune = true; + if (!fHavePruned) { + pblocktree->WriteFlag("prunedblockfiles", true); + fHavePruned = true; + } + } + } + int64_t nNow = GetTimeMicros(); + // Avoid writing/flushing immediately after startup. + if (nLastWrite == 0) { + nLastWrite = nNow; + } + if (nLastFlush == 0) { + nLastFlush = nNow; + } + if (nLastSetChain == 0) { + nLastSetChain = nNow; + } + size_t cacheSize = pcoinsTip->DynamicMemoryUsage(); + // The cache is large and close to the limit, but we have time now (not in the middle of a block processing). + bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage; + // The cache is over the limit, we have to write now. + bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage; + // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. + bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000; + // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. + bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000; + // Combine all conditions that result in a full cache flush. + bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune; + // Write blocks and block index to disk. + if (fDoFullFlush || fPeriodicWrite) { + // Depend on nMinDiskSpace to ensure we can write block index + if (!CheckDiskSpace(0)) + return state.Error("out of disk space"); + // First make sure all block and undo data is flushed to disk. + FlushBlockFile(); + // Then update all block file information (which may refer to block and undo files). + { + std::vector > vFiles; + vFiles.reserve(setDirtyFileInfo.size()); + for (set::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) { + vFiles.push_back(make_pair(*it, &vinfoBlockFile[*it])); + setDirtyFileInfo.erase(it++); + } + std::vector vBlocks; + vBlocks.reserve(setDirtyBlockIndex.size()); + for (set::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) { + vBlocks.push_back(*it); + setDirtyBlockIndex.erase(it++); + } + if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) { + return AbortNode(state, "Files to write to block index database"); + } + } + // Finally remove any pruned files + if (fFlushForPrune) + UnlinkPrunedFiles(setFilesToPrune); + nLastWrite = nNow; + } + // Flush best chain related state. This can only be done if the blocks / block index write was also done. + if (fDoFullFlush) { + // Typical CCoins structures on disk are around 128 bytes in size. + // Pushing a new one to the database can cause it to be written + // twice (once in the log, and once in the tables). This is already + // an overestimation, as most will delete an existing entry or + // overwrite one. Still, use a conservative safety factor of 2. + if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize())) + return state.Error("out of disk space"); + if(!pclaimTrie->WriteToDisk()) + return AbortNode("Failed to write to claim trie database"); + // Flush the chainstate (which may refer to block index entries). + if (!pcoinsTip->Flush()) + return AbortNode(state, "Failed to write to coin database"); + nLastFlush = nNow; + } + if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) { + // Update best block in wallet (so we can detect restored wallets). + GetMainSignals().SetBestChain(chainActive.GetLocator()); + nLastSetChain = nNow; + } + } catch (const std::runtime_error& e) { + return AbortNode(state, std::string("System error while flushing: ") + e.what()); + } + return true; +} + +void FlushStateToDisk() { + CValidationState state; + FlushStateToDisk(state, FLUSH_STATE_ALWAYS); +} + +void PruneAndFlush() { + CValidationState state; + fCheckForPruning = true; + FlushStateToDisk(state, FLUSH_STATE_NONE); +} + +/** Update chainActive and related internal data structures. */ +void static UpdateTip(CBlockIndex *pindexNew) { + const CChainParams& chainParams = Params(); + chainActive.SetTip(pindexNew); + + // New best block + nTimeBestReceived = GetTime(); + mempool.AddTransactionsUpdated(1); + + LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); + + cvBlockChange.notify_all(); + + // Check the version of the last 100 blocks to see if we need to upgrade: + static bool fWarned = false; + if (!IsInitialBlockDownload()) + { + int nUpgraded = 0; + const CBlockIndex* pindex = chainActive.Tip(); + for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) { + WarningBitsConditionChecker checker(bit); + ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); + if (state == THRESHOLD_ACTIVE || state == THRESHOLD_LOCKED_IN) { + if (state == THRESHOLD_ACTIVE) { + strMiscWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + if (!fWarned) { + CAlert::Notify(strMiscWarning, true); + fWarned = true; + } + } else { + LogPrintf("%s: unknown new rules are about to activate (versionbit %i)\n", __func__, bit); + } + } + } + for (int i = 0; i < 100 && pindex != NULL; i++) + { + int32_t nExpectedVersion = ComputeBlockVersion(pindex->pprev, chainParams.GetConsensus()); + if (pindex->nVersion > VERSIONBITS_LAST_OLD_BLOCK_VERSION && (pindex->nVersion & ~nExpectedVersion) != 0) + ++nUpgraded; + pindex = pindex->pprev; + } + if (nUpgraded > 0) + LogPrintf("%s: %d of last 100 blocks have unexpected version\n", __func__, nUpgraded); + if (nUpgraded > 100/2) + { + // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: + strMiscWarning = _("Warning: Unknown block versions being mined! It's possible unknown rules are in effect"); + if (!fWarned) { + CAlert::Notify(strMiscWarning, true); + fWarned = true; + } + } + } +} + +/** Disconnect chainActive's tip. You probably want to call mempool.removeForReorg and manually re-limit mempool size after this, with cs_main held. */ +bool static DisconnectTip(CValidationState& state, const Consensus::Params& consensusParams) +{ + CBlockIndex *pindexDelete = chainActive.Tip(); + assert(pindexDelete); + // Read block from disk. + CBlock block; + if (!ReadBlockFromDisk(block, pindexDelete, consensusParams)) + return AbortNode(state, "Failed to read block"); + // Apply the block atomically to the chain state. + int64_t nStart = GetTimeMicros(); + { + CCoinsViewCache view(pcoinsTip); + CClaimTrieCache trieCache(pclaimTrie); + if (!DisconnectBlock(block, state, pindexDelete, view, trieCache)) + return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); + assert(view.Flush()); + assert(trieCache.flush()); + //assert(pindexDelete->pprev->hashClaimTrie == trieCache.getMerkleHash()); + } + LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); + // Write the chain state to disk, if necessary. + if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) + return false; + // Resurrect mempool transactions from the disconnected block. + std::vector vHashUpdate; + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + // ignore validation errors in resurrected transactions + list removed; + CValidationState stateDummy; + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { + mempool.remove(tx, removed, true); + } else if (mempool.exists(tx.GetHash())) { + vHashUpdate.push_back(tx.GetHash()); + } + } + // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have + // no in-mempool children, which is generally not true when adding + // previously-confirmed transactions back to the mempool. + // UpdateTransactionsFromBlock finds descendants of any transactions in this + // block that were added back and cleans up the mempool state. + mempool.UpdateTransactionsFromBlock(vHashUpdate); + // Update chainActive and related variables. + UpdateTip(pindexDelete->pprev); + // Let wallets know transactions went from 1-confirmed to + // 0-confirmed or conflicted: + BOOST_FOREACH(const CTransaction &tx, block.vtx) { + SyncWithWallets(tx, NULL); + } + return true; +} + +static int64_t nTimeReadFromDisk = 0; +static int64_t nTimeConnectTotal = 0; +static int64_t nTimeFlush = 0; +static int64_t nTimeChainState = 0; +static int64_t nTimePostConnect = 0; + +/** + * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock + * corresponding to pindexNew, to bypass loading it again from disk. + */ +bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock) +{ + assert(pindexNew->pprev == chainActive.Tip()); + // Read block from disk. + int64_t nTime1 = GetTimeMicros(); + CBlock block; + if (!pblock) { + if (!ReadBlockFromDisk(block, pindexNew, chainparams.GetConsensus())) + return AbortNode(state, "Failed to read block"); + pblock = █ + } + // Apply the block atomically to the chain state. + int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; + int64_t nTime3; + LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); + { + CCoinsViewCache view(pcoinsTip); + CClaimTrieCache trieCache(pclaimTrie); + bool rv = ConnectBlock(*pblock, state, pindexNew, view, trieCache); + GetMainSignals().BlockChecked(*pblock, state); + if (!rv) { + if (state.IsInvalid()) + InvalidBlockFound(pindexNew, state); + return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); + } + mapBlockSource.erase(pindexNew->GetBlockHash()); + nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2; + LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001); + assert(view.Flush()); + assert(trieCache.flush()); + } + int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3; + LogPrint("bench", " - Flush: %.2fms [%.2fs]\n", (nTime4 - nTime3) * 0.001, nTimeFlush * 0.000001); + // Write the chain state to disk, if necessary. + if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) + return false; + int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; + LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); + // Remove conflicting transactions from the mempool. + list txConflicted; + mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload()); + // Update chainActive & related variables. + UpdateTip(pindexNew); + // Tell wallet about transactions that went from mempool + // to conflicted: + BOOST_FOREACH(const CTransaction &tx, txConflicted) { + SyncWithWallets(tx, NULL); + } + // ... and about transactions that got confirmed: + BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { + SyncWithWallets(tx, pblock); + } + + int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; + LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); + LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); + return true; +} + +bool DisconnectBlocks(int blocks) +{ + LOCK(cs_main); + + CValidationState state; + const CChainParams& chainparams = Params(); + + LogPrintf("DisconnectBlocks -- Got command to replay %d blocks\n", blocks); + for(int i = 0; i < blocks; i++) { + if(!DisconnectTip(state, chainparams.GetConsensus()) || !state.IsValid()) { + return false; + } + } + + return true; +} + +void ReprocessBlocks(int nBlocks) +{ + LOCK(cs_main); + + std::map::iterator it = mapRejectedBlocks.begin(); + while(it != mapRejectedBlocks.end()){ + //use a window twice as large as is usual for the nBlocks we want to reset + if((*it).second > GetTime() - (nBlocks*60*5)) { + BlockMap::iterator mi = mapBlockIndex.find((*it).first); + if (mi != mapBlockIndex.end() && (*mi).second) { + + CBlockIndex* pindex = (*mi).second; + LogPrintf("ReprocessBlocks -- %s\n", (*it).first.ToString()); + + CValidationState state; + ReconsiderBlock(state, pindex); + } + } + ++it; + } + + DisconnectBlocks(nBlocks); + + CValidationState state; + ActivateBestChain(state, Params()); +} + +/** + * Return the tip of the chain with the most work in it, that isn't + * known to be invalid (it's however far from certain to be valid). + */ +static CBlockIndex* FindMostWorkChain() { + do { + CBlockIndex *pindexNew = NULL; + + // Find the best candidate header. + { + std::set::reverse_iterator it = setBlockIndexCandidates.rbegin(); + if (it == setBlockIndexCandidates.rend()) + return NULL; + pindexNew = *it; + } + + // Check whether all blocks on the path between the currently active chain and the candidate are valid. + // Just going until the active chain is an optimization, as we know all blocks in it are valid already. + CBlockIndex *pindexTest = pindexNew; + bool fInvalidAncestor = false; + while (pindexTest && !chainActive.Contains(pindexTest)) { + assert(pindexTest->nChainTx || pindexTest->nHeight == 0); + + // Pruned nodes may have entries in setBlockIndexCandidates for + // which block files have been deleted. Remove those as candidates + // for the most work chain if we come across them; we can't switch + // to a chain unless we have all the non-active-chain parent blocks. + bool fFailedChain = pindexTest->nStatus & BLOCK_FAILED_MASK; + bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA); + if (fFailedChain || fMissingData) { + // Candidate chain is not usable (either invalid or missing data) + if (fFailedChain && (pindexBestInvalid == NULL || pindexNew->nChainWork > pindexBestInvalid->nChainWork)) + pindexBestInvalid = pindexNew; + CBlockIndex *pindexFailed = pindexNew; + // Remove the entire chain from the set. + while (pindexTest != pindexFailed) { + if (fFailedChain) { + pindexFailed->nStatus |= BLOCK_FAILED_CHILD; + } else if (fMissingData) { + // If we're missing data, then add back to mapBlocksUnlinked, + // so that if the block arrives in the future we can try adding + // to setBlockIndexCandidates again. + mapBlocksUnlinked.insert(std::make_pair(pindexFailed->pprev, pindexFailed)); + } + setBlockIndexCandidates.erase(pindexFailed); + pindexFailed = pindexFailed->pprev; + } + setBlockIndexCandidates.erase(pindexTest); + fInvalidAncestor = true; + break; + } + pindexTest = pindexTest->pprev; + } + if (!fInvalidAncestor) + return pindexNew; + } while(true); +} + +/** Delete all entries in setBlockIndexCandidates that are worse than the current tip. */ +static void PruneBlockIndexCandidates() { + // Note that we can't delete the current block itself, as we may need to return to it later in case a + // reorganization to a better block fails. + std::set::iterator it = setBlockIndexCandidates.begin(); + while (it != setBlockIndexCandidates.end() && setBlockIndexCandidates.value_comp()(*it, chainActive.Tip())) { + setBlockIndexCandidates.erase(it++); + } + // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. + assert(!setBlockIndexCandidates.empty()); +} + +/** + * Try to make some progress towards making pindexMostWork the active block. + * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. + */ +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock) +{ + AssertLockHeld(cs_main); + bool fInvalidFound = false; + const CBlockIndex *pindexOldTip = chainActive.Tip(); + const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork); + + // Disconnect active blocks which are no longer in the best chain. + bool fBlocksDisconnected = false; + while (chainActive.Tip() && chainActive.Tip() != pindexFork) { + if (!DisconnectTip(state, chainparams.GetConsensus())) + return false; + fBlocksDisconnected = true; + } + + // Build list of new blocks to connect. + std::vector vpindexToConnect; + bool fContinue = true; + int nHeight = pindexFork ? pindexFork->nHeight : -1; + while (fContinue && nHeight != pindexMostWork->nHeight) { + // Don't iterate the entire list of potential improvements toward the best tip, as we likely only need + // a few blocks along the way. + int nTargetHeight = std::min(nHeight + 32, pindexMostWork->nHeight); + vpindexToConnect.clear(); + vpindexToConnect.reserve(nTargetHeight - nHeight); + CBlockIndex *pindexIter = pindexMostWork->GetAncestor(nTargetHeight); + while (pindexIter && pindexIter->nHeight != nHeight) { + vpindexToConnect.push_back(pindexIter); + pindexIter = pindexIter->pprev; + } + nHeight = nTargetHeight; + + // Connect new blocks. + BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) { + if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : NULL)) { + if (state.IsInvalid()) { + // The block violates a consensus rule. + if (!state.CorruptionPossible()) + InvalidChainFound(vpindexToConnect.back()); + state = CValidationState(); + fInvalidFound = true; + fContinue = false; + break; + } else { + // A system error occurred (disk space, database error, ...). + return false; + } + } else { + PruneBlockIndexCandidates(); + if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) { + // We're in a better position than we were. Return temporarily to release the lock. + fContinue = false; + break; + } + } + } + } + + if (fBlocksDisconnected) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); + } + mempool.check(pcoinsTip); + + // Callbacks/notifications for a new best chain. + if (fInvalidFound) + CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); + else + CheckForkWarningConditions(); + + return true; +} + +/** + * Make the best chain active, in multiple steps. The result is either failure + * or an activated best chain. pblock is either NULL or a pointer to a block + * that is already loaded (to avoid loading it again from disk). + */ +bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { + CBlockIndex *pindexMostWork = NULL; + do { + boost::this_thread::interruption_point(); + if (ShutdownRequested()) + break; + + CBlockIndex *pindexNewTip = NULL; + const CBlockIndex *pindexFork; + bool fInitialDownload; + { + LOCK(cs_main); + CBlockIndex *pindexOldTip = chainActive.Tip(); + pindexMostWork = FindMostWorkChain(); + + // Whether we have anything to do at all. + if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) + return true; + + if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) + return false; + + pindexNewTip = chainActive.Tip(); + pindexFork = chainActive.FindFork(pindexOldTip); + fInitialDownload = IsInitialBlockDownload(); + } + // When we reach this point, we switched to a new tip (stored in pindexNewTip). + + // Notifications/callbacks that can run without cs_main + // Always notify the UI if a new block tip was connected + if (pindexFork != pindexNewTip) { + uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip); + + if (!fInitialDownload) { + // Find the hashes of all blocks that weren't previously in the best chain. + std::vector vHashes; + CBlockIndex *pindexToAnnounce = pindexNewTip; + while (pindexToAnnounce != pindexFork) { + vHashes.push_back(pindexToAnnounce->GetBlockHash()); + pindexToAnnounce = pindexToAnnounce->pprev; + if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) { + // Limit announcements in case of a huge reorganization. + // Rely on the peer's synchronization mechanism in that case. + break; + } + } + // Relay inventory, but don't relay old inventory during initial block download. + int nBlockEstimate = 0; + if (fCheckpointsEnabled) + nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { + if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) { + BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) { + pnode->PushBlockHash(hash); + } + } + } + } + // Notify external listeners about the new tip. + if (!vHashes.empty()) { + GetMainSignals().UpdatedBlockTip(pindexNewTip); + } + } + } + } while(pindexMostWork != chainActive.Tip()); + CheckBlockIndex(chainparams.GetConsensus()); + + // Write changes periodically to disk, after relay. + if (!FlushStateToDisk(state, FLUSH_STATE_PERIODIC)) { + return false; + } + + return true; +} + +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex) +{ + AssertLockHeld(cs_main); + + // Mark the block itself as invalid. + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + setBlockIndexCandidates.erase(pindex); + + while (chainActive.Contains(pindex)) { + CBlockIndex *pindexWalk = chainActive.Tip(); + pindexWalk->nStatus |= BLOCK_FAILED_CHILD; + setDirtyBlockIndex.insert(pindexWalk); + setBlockIndexCandidates.erase(pindexWalk); + // ActivateBestChain considers blocks already in chainActive + // unconditionally valid already, so force disconnect away from it. + if (!DisconnectTip(state, consensusParams)) { + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + return false; + } + } + + LimitMempoolSize(mempool, GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60); + + // The resulting new best tip may not be in setBlockIndexCandidates anymore, so + // add it again. + BlockMap::iterator it = mapBlockIndex.begin(); + while (it != mapBlockIndex.end()) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { + setBlockIndexCandidates.insert(it->second); + } + it++; + } + + InvalidChainFound(pindex); + mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS); + return true; +} + +bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex) { + AssertLockHeld(cs_main); + + int nHeight = pindex->nHeight; + + // Remove the invalidity flag from this block and all its descendants. + BlockMap::iterator it = mapBlockIndex.begin(); + while (it != mapBlockIndex.end()) { + if (!it->second->IsValid() && it->second->GetAncestor(nHeight) == pindex) { + it->second->nStatus &= ~BLOCK_FAILED_MASK; + setDirtyBlockIndex.insert(it->second); + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + setBlockIndexCandidates.insert(it->second); + } + if (it->second == pindexBestInvalid) { + // Reset invalid block marker if it was pointing to one of those. + pindexBestInvalid = NULL; + } + } + it++; + } + + // Remove the invalidity flag from all ancestors too. + while (pindex != NULL) { + if (pindex->nStatus & BLOCK_FAILED_MASK) { + pindex->nStatus &= ~BLOCK_FAILED_MASK; + setDirtyBlockIndex.insert(pindex); + } + pindex = pindex->pprev; + } + return true; +} + +CBlockIndex* AddToBlockIndex(const CBlockHeader& block) +{ + // Check for duplicate + uint256 hash = block.GetHash(); + BlockMap::iterator it = mapBlockIndex.find(hash); + if (it != mapBlockIndex.end()) + return it->second; + + // Construct new block index object + CBlockIndex* pindexNew = new CBlockIndex(block); + assert(pindexNew); + // We assign the sequence id to blocks only when the full data is available, + // to avoid miners withholding blocks but broadcasting headers, to get a + // competitive advantage. + pindexNew->nSequenceId = 0; + BlockMap::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + BlockMap::iterator miPrev = mapBlockIndex.find(block.hashPrevBlock); + if (miPrev != mapBlockIndex.end()) + { + pindexNew->pprev = (*miPrev).second; + pindexNew->nHeight = pindexNew->pprev->nHeight + 1; + pindexNew->BuildSkip(); + } + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); + pindexNew->RaiseValidity(BLOCK_VALID_TREE); + if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) + pindexBestHeader = pindexNew; + + setDirtyBlockIndex.insert(pindexNew); + + return pindexNew; +} + +/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ +bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) +{ + pindexNew->nTx = block.vtx.size(); + pindexNew->nChainTx = 0; + pindexNew->nFile = pos.nFile; + pindexNew->nDataPos = pos.nPos; + pindexNew->nUndoPos = 0; + pindexNew->nStatus |= BLOCK_HAVE_DATA; + pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS); + setDirtyBlockIndex.insert(pindexNew); + + if (pindexNew->pprev == NULL || pindexNew->pprev->nChainTx) { + // If pindexNew is the genesis block or all parents are BLOCK_VALID_TRANSACTIONS. + deque queue; + queue.push_back(pindexNew); + + // Recursively process any descendant blocks that now may be eligible to be connected. + while (!queue.empty()) { + CBlockIndex *pindex = queue.front(); + queue.pop_front(); + pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; + { + LOCK(cs_nBlockSequenceId); + pindex->nSequenceId = nBlockSequenceId++; + } + if (chainActive.Tip() == NULL || !setBlockIndexCandidates.value_comp()(pindex, chainActive.Tip())) { + setBlockIndexCandidates.insert(pindex); + } + std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex); + while (range.first != range.second) { + std::multimap::iterator it = range.first; + queue.push_back(it->second); + range.first++; + mapBlocksUnlinked.erase(it); + } + } + } else { + if (pindexNew->pprev && pindexNew->pprev->IsValid(BLOCK_VALID_TREE)) { + mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew)); + } + } + + return true; +} + +bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) +{ + LOCK(cs_LastBlockFile); + + unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; + if (vinfoBlockFile.size() <= nFile) { + vinfoBlockFile.resize(nFile + 1); + } + + if (!fKnown) { + while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { + nFile++; + if (vinfoBlockFile.size() <= nFile) { + vinfoBlockFile.resize(nFile + 1); + } + } + pos.nFile = nFile; + pos.nPos = vinfoBlockFile[nFile].nSize; + } + + if ((int)nFile != nLastBlockFile) { + if (!fKnown) { + LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString()); + } + FlushBlockFile(!fKnown); + nLastBlockFile = nFile; + } + + vinfoBlockFile[nFile].AddBlock(nHeight, nTime); + if (fKnown) + vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); + else + vinfoBlockFile[nFile].nSize += nAddSize; + + if (!fKnown) { + unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + if (fPruneMode) + fCheckForPruning = true; + if (CheckDiskSpace(nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenBlockFile(pos); + if (file) { + LogPrintf("Pre-allocating up to position 0x%x in blk%05u.dat\n", nNewChunks * BLOCKFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * BLOCKFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } + } + else + return state.Error("out of disk space"); + } + } + + setDirtyFileInfo.insert(nFile); + return true; +} + +bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) +{ + pos.nFile = nFile; + + LOCK(cs_LastBlockFile); + + unsigned int nNewSize; + pos.nPos = vinfoBlockFile[nFile].nUndoSize; + nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; + setDirtyFileInfo.insert(nFile); + + unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + unsigned int nNewChunks = (nNewSize + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; + if (nNewChunks > nOldChunks) { + if (fPruneMode) + fCheckForPruning = true; + if (CheckDiskSpace(nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos)) { + FILE *file = OpenUndoFile(pos); + if (file) { + LogPrintf("Pre-allocating up to position 0x%x in rev%05u.dat\n", nNewChunks * UNDOFILE_CHUNK_SIZE, pos.nFile); + AllocateFileRange(file, pos.nPos, nNewChunks * UNDOFILE_CHUNK_SIZE - pos.nPos); + fclose(file); + } + } + else + return state.Error("out of disk space"); + } + + return true; +} + +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) +{ + // Check proof of work matches claimed amount + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + { + LogPrintf("CheckBlockHeader(): \n--b-l-o-c-k---%s\n\n", block.ToString().c_str()); + return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), + REJECT_INVALID, "high-hash"); + } + // Check timestamp + if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) + return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), + REJECT_INVALID, "time-too-new"); + + return true; +} + +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) +{ + // These are checks that are independent of context. + + if (block.fChecked) + return true; + + // Check that the header is valid (particularly PoW). This is mostly + // redundant with the call in AcceptBlockHeader. + if (!CheckBlockHeader(block, state, fCheckPOW)) + return false; + + // Check the merkle root. + if (fCheckMerkleRoot) { + bool mutated; + uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); + if (block.hashMerkleRoot != hashMerkleRoot2) + return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"), + REJECT_INVALID, "bad-txnmrklroot", true); + + // Check for merkle tree malleability (CVE-2012-2459): repeating sequences + // of transactions in a block without affecting the merkle root of a block, + // while still invalidating it. + if (mutated) + return state.DoS(100, error("CheckBlock(): duplicate transaction"), + REJECT_INVALID, "bad-txns-duplicate", true); + } + + // All potential-corruption validation must be done before we do any + // transaction validation, as otherwise we may mark the header as invalid + // because we receive the wrong transactions for it. + + // Size limits + if (block.vtx.empty() || block.vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + return state.DoS(100, error("CheckBlock(): size limits failed"), + REJECT_INVALID, "bad-blk-length"); + + // First transaction must be coinbase, the rest must not be + if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) + return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), + REJECT_INVALID, "bad-cb-missing"); + for (unsigned int i = 1; i < block.vtx.size(); i++) + if (block.vtx[i].IsCoinBase()) + return state.DoS(100, error("CheckBlock(): more than one coinbase"), + REJECT_INVALID, "bad-cb-multiple"); + + + // PCH : CHECK TRANSACTIONS FOR INSTANTSEND + + if(sporkManager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { + // We should never accept block which conflicts with completed transaction lock, + // that's why this is in CheckBlock unlike coinbase payee/amount. + // Require other nodes to comply, send them some data in case they are missing it. + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + // skip coinbase, it has no inputs + if (tx.IsCoinBase()) continue; + // LOOK FOR TRANSACTION LOCK IN OUR MAP OF OUTPOINTS + BOOST_FOREACH(const CTxIn& txin, tx.vin) { + uint256 hashLocked; + if(instantsend.GetLockedOutPointTxHash(txin.prevout, hashLocked) && hashLocked != tx.GetHash()) { + // Every node which relayed this block to us must invalidate it + // but they probably need more data. + // Relay corresponding transaction lock request and all its votes + // to let other nodes complete the lock. + instantsend.Relay(hashLocked); + LOCK(cs_main); + mapRejectedBlocks.insert(make_pair(block.GetHash(), GetTime())); + return state.DoS(0, error("CheckBlock(PCH): transaction %s conflicts with transaction lock %s", + tx.GetHash().ToString(), hashLocked.ToString()), + REJECT_INVALID, "conflict-tx-lock"); + } + } + } + } else { + LogPrintf("CheckBlock(PCH): spork is off, skipping transaction locking checks\n"); + } + + // END PCH + + // Check transactions + BOOST_FOREACH(const CTransaction& tx, block.vtx) + if (!CheckTransaction(tx, state)) + return error("CheckBlock(): CheckTransaction of %s failed with %s", + tx.GetHash().ToString(), + FormatStateMessage(state)); + + unsigned int nSigOps = 0; + BOOST_FOREACH(const CTransaction& tx, block.vtx) + { + nSigOps += GetLegacySigOpCount(tx); + } + if (nSigOps > MAX_BLOCK_SIGOPS) + return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), + REJECT_INVALID, "bad-blk-sigops"); + + if (fCheckPOW && fCheckMerkleRoot) + block.fChecked = true; + + return true; +} + +static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash) +{ + if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock) + return true; + + int nHeight = pindexPrev->nHeight+1; + // Don't accept any forks from the main chain prior to last checkpoint + CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); + if (pcheckpoint && nHeight < pcheckpoint->nHeight) + return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight)); + + return true; +} + +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev) +{ + const Consensus::Params& consensusParams = Params().GetConsensus(); + if (block.GetHash() == consensusParams.hashGenesisBlock) + return true; + + int nHeight = pindexPrev->nHeight + 1; + LogPrintf("check block header height %d \n", nHeight); + // Check proof of work + if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + return state.DoS(100, error("%s : incorrect proof of work at %d", __func__, nHeight), + REJECT_INVALID, "bad-diffbits"); + + // Check timestamp against prev + if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) + return state.Invalid(error("%s: block's timestamp is too early", __func__), + REJECT_INVALID, "time-too-old"); + + // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: + if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) + return state.Invalid(error("%s: rejected nVersion=1 block", __func__), + REJECT_OBSOLETE, "bad-version"); + + // Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded: + if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) + return state.Invalid(error("%s: rejected nVersion=2 block", __func__), + REJECT_OBSOLETE, "bad-version"); + + // Reject block.nVersion=3 blocks when 95% (75% on testnet) of the network has upgraded: + if (block.nVersion < 4 && IsSuperMajority(4, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams)) + return state.Invalid(error("%s : rejected nVersion=3 block", __func__), + REJECT_OBSOLETE, "bad-version"); + + return true; +} + +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev) +{ + const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1; + const Consensus::Params& consensusParams = Params().GetConsensus(); + + // Start enforcing BIP113 (Median Time Past) using versionbits logic. + int nLockTimeFlags = 0; + if (VersionBitsState(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV, versionbitscache) == THRESHOLD_ACTIVE) { + nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST; + } + + int64_t nLockTimeCutoff = (nLockTimeFlags & LOCKTIME_MEDIAN_TIME_PAST) + ? pindexPrev->GetMedianTimePast() + : block.GetBlockTime(); + + // Check that all transactions are finalized + BOOST_FOREACH(const CTransaction& tx, block.vtx) { + if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { + return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); + } + } + + // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height + // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): + if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)) + { + CScript expect = CScript() << nHeight; + if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); + } + } + + return true; +} +/*popchain ghost*/ +static bool AcceptBlockHeader(const CBlock & block, CValidationState& state, const CChainParams& chainparams) +{ + + std::vector blockHeaders = block.vuh; + if (blockHeaders.size() > 2 || blockHeaders.size() < 0) + { + return false; + } + + + uint256 hashHeaders; + hashHeaders.SetNull(); + + + if(blockHeaders.size() > 0) + { + vector::iterator it = blockHeaders.begin(); + while( it != blockHeaders.end()) { + CBlockHeader tmpBH = *it; + uint256 tmpHash; + tmpHash.SetNull(); + if(!CheckBlockHeader(tmpBH, state, true)) + { + return false; + } + tmpHash = tmpBH.GetHash(); + CHash256().Write(tmpHash.begin(), 32).Write(hashHeaders.begin(), 32).Finalize(hashHeaders.begin()); + it++; + } + } + else + { + return true; + } + + if(block.hashUncles != hashHeaders) + { + return false; + } +} + +/*popchain ghost*/ + +static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) +{ + AssertLockHeld(cs_main); + // Check for duplicate + uint256 hash = block.GetHash(); + BlockMap::iterator miSelf = mapBlockIndex.find(hash); + CBlockIndex *pindex = NULL; + + // TODO : ENABLE BLOCK CACHE IN SPECIFIC CASES + if (hash != chainparams.GetConsensus().hashGenesisBlock) { + + if (miSelf != mapBlockIndex.end()) { + // Block header is already known. + pindex = miSelf->second; + if (ppindex) + *ppindex = pindex; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); + return true; + } + + if (!CheckBlockHeader(block, state)) + return false; + + // Get prev block index + CBlockIndex* pindexPrev = NULL; + BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); + if (mi == mapBlockIndex.end()) + return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk"); + pindexPrev = (*mi).second; + if (pindexPrev->nStatus & BLOCK_FAILED_MASK) + return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + + assert(pindexPrev); + if (fCheckpointsEnabled) + { + uint256 lastCheckpoint_t = Checkpoints::GetHeightCheckpoint(pindexPrev->nHeight+1 ,chainparams.Checkpoints()); + if(lastCheckpoint_t != uint256()) + { + if (hash != lastCheckpoint_t) + { + LogPrintf("synchronous chain height=%d hash = [%s][%s]\n",pindexPrev->nHeight+1,hash.ToString(),lastCheckpoint_t.ToString() ); + return state.DoS(100, error("%s: checkpoint block invalid", __func__), REJECT_INVALID, "bad-prevblk"); + } + else + { + LogPrintf("checkpoint verify correct.\n"); + } + } + } + + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash)) + return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); + + if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + return false; + } + if (pindex == NULL) + pindex = AddToBlockIndex(block); + + if (ppindex) + *ppindex = pindex; + + return true; +} + +/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ +static bool AcceptBlock(const CBlock& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp) +{ + AssertLockHeld(cs_main); + + CBlockIndex *&pindex = *ppindex; + + if (!AcceptBlockHeader(block, state, chainparams, &pindex)) + return false; + + // Try to process all requested blocks that we don't have, but only + // process an unrequested block if it's new and has enough work to + // advance our tip, and isn't too many blocks ahead. + bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; + bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true); + // Blocks that are too out-of-order needlessly limit the effectiveness of + // pruning, because pruning will not delete block files that contain any + // blocks which are too close in height to the tip. Apply this test + // regardless of whether pruning is enabled; it should generally be safe to + // not process unrequested blocks. + bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP)); + + // TODO: deal better with return value and error conditions for duplicate + // and unrequested blocks. + if (fAlreadyHave) return true; + if (!fRequested) { // If we didn't ask for it: + if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned + if (!fHasMoreWork) return true; // Don't process less-work chains + if (fTooFarAhead) return true; // Block height is too high + } + + if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { + if (state.IsInvalid() && !state.CorruptionPossible()) { + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + } + return false; + } + + int nHeight = pindex->nHeight; + + // Write block to history file + try { + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + if (dbp != NULL) + blockPos = *dbp; + if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) + return error("AcceptBlock(): FindBlockPos failed"); + if (dbp == NULL) + if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) + AbortNode(state, "Failed to write block"); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("AcceptBlock(): ReceivedBlockTransactions failed"); + } catch (const std::runtime_error& e) { + return AbortNode(state, std::string("System error: ") + e.what()); + } + + if (fCheckForPruning) + FlushStateToDisk(state, FLUSH_STATE_NONE); // we just allocated more disk space for block files + + return true; +} + +static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams) +{ + unsigned int nFound = 0; + for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++) + { + if (pstart->nVersion >= minVersion) + ++nFound; + pstart = pstart->pprev; + } + return (nFound >= nRequired); +} + + +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp) +{ + // Preliminary checks + bool checked = CheckBlock(*pblock, state); + + { + LOCK(cs_main); + bool fRequested = MarkBlockAsReceived(pblock->GetHash()); + fRequested |= fForceProcessing; + if (!checked) { + return error("%s: CheckBlock FAILED", __func__); + } + + // Store to disk + CBlockIndex *pindex = NULL; + bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp); + if (pindex && pfrom) { + mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); + } + CheckBlockIndex(chainparams.GetConsensus()); + if (!ret) + return error("%s: AcceptBlock FAILED", __func__); + } + + if (!ActivateBestChain(state, chainparams, pblock)) + return error("%s: ActivateBestChain failed", __func__); + + popnodeSync.IsBlockchainSynced(true); + + LogPrintf("%s : ACCEPTED\n", __func__); + return true; +} + +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +{ + AssertLockHeld(cs_main); + assert(pindexPrev && pindexPrev == chainActive.Tip()); + if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash())) + return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str()); + + CCoinsViewCache viewNew(pcoinsTip); + CClaimTrieCache trieCache(pclaimTrie); + CBlockIndex indexDummy(block); + indexDummy.pprev = pindexPrev; + indexDummy.nHeight = pindexPrev->nHeight + 1; + + // NOTE: CheckBlockHeader is called by CheckBlock + if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + return false; + if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) + return false; + if (!ContextualCheckBlock(block, state, pindexPrev)) + return false; + if (!ConnectBlock(block, state, &indexDummy, viewNew, trieCache, true)) + return false; + assert(state.IsValid()); + + return true; +} + +/** + * BLOCK PRUNING CODE + */ + +/* Calculate the amount of disk space the block & undo files currently use */ +uint64_t CalculateCurrentUsage() +{ + uint64_t retval = 0; + BOOST_FOREACH(const CBlockFileInfo &file, vinfoBlockFile) { + retval += file.nSize + file.nUndoSize; + } + return retval; +} + +/* Prune a block file (modify associated database entries)*/ +void PruneOneBlockFile(const int fileNumber) +{ + for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); ++it) { + CBlockIndex* pindex = it->second; + if (pindex->nFile == fileNumber) { + pindex->nStatus &= ~BLOCK_HAVE_DATA; + pindex->nStatus &= ~BLOCK_HAVE_UNDO; + pindex->nFile = 0; + pindex->nDataPos = 0; + pindex->nUndoPos = 0; + setDirtyBlockIndex.insert(pindex); + + // Prune from mapBlocksUnlinked -- any block we prune would have + // to be downloaded again in order to consider its chain, at which + // point it would be considered as a candidate for + // mapBlocksUnlinked or setBlockIndexCandidates. + std::pair::iterator, std::multimap::iterator> range = mapBlocksUnlinked.equal_range(pindex->pprev); + while (range.first != range.second) { + std::multimap::iterator it = range.first; + range.first++; + if (it->second == pindex) { + mapBlocksUnlinked.erase(it); + } + } + } + } + + vinfoBlockFile[fileNumber].SetNull(); + setDirtyFileInfo.insert(fileNumber); +} + + +void UnlinkPrunedFiles(std::set& setFilesToPrune) +{ + for (set::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) { + CDiskBlockPos pos(*it, 0); + boost::filesystem::remove(GetBlockPosFilename(pos, "blk")); + boost::filesystem::remove(GetBlockPosFilename(pos, "rev")); + LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, *it); + } +} + +/* Calculate the block/rev files that should be deleted to remain under target*/ +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight) +{ + LOCK2(cs_main, cs_LastBlockFile); + if (chainActive.Tip() == NULL || nPruneTarget == 0) { + return; + } + if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) { + return; + } + + unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP; + uint64_t nCurrentUsage = CalculateCurrentUsage(); + // We don't check to prune until after we've allocated new space for files + // So we should leave a buffer under our target to account for another allocation + // before the next pruning. + uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; + uint64_t nBytesToPrune; + int count=0; + + if (nCurrentUsage + nBuffer >= nPruneTarget) { + for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { + nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize; + + if (vinfoBlockFile[fileNumber].nSize == 0) + continue; + + if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target? + break; + + // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning + if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) + continue; + + PruneOneBlockFile(fileNumber); + // Queue up the files for removal + setFilesToPrune.insert(fileNumber); + nCurrentUsage -= nBytesToPrune; + count++; + } + } + + LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n", + nPruneTarget/1024/1024, nCurrentUsage/1024/1024, + ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024, + nLastBlockWeCanPrune, count); +} + +bool CheckDiskSpace(uint64_t nAdditionalBytes) +{ + uint64_t nFreeBytesAvailable = boost::filesystem::space(GetDataDir()).available; + + // Check for nMinDiskSpace bytes (currently 50MB) + if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) + return AbortNode("Disk space is low!", _("Error: Disk space is low!")); + + return true; +} + +FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) +{ + if (pos.IsNull()) + return NULL; + boost::filesystem::path path = GetBlockPosFilename(pos, prefix); + boost::filesystem::create_directories(path.parent_path()); + FILE* file = fopen(path.string().c_str(), "rb+"); + if (!file && !fReadOnly) + file = fopen(path.string().c_str(), "wb+"); + if (!file) { + LogPrintf("Unable to open file %s\n", path.string()); + return NULL; + } + if (pos.nPos) { + if (fseek(file, pos.nPos, SEEK_SET)) { + LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string()); + fclose(file); + return NULL; + } + } + return file; +} + +FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly) { + return OpenDiskFile(pos, "blk", fReadOnly); +} + +FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly) { + return OpenDiskFile(pos, "rev", fReadOnly); +} + +boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix) +{ + return GetDataDir() / "blocks" / strprintf("%s%05u.dat", prefix, pos.nFile); +} + +CBlockIndex * InsertBlockIndex(uint256 hash) +{ + if (hash.IsNull()) + return NULL; + + // Return existing + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) + return (*mi).second; + + // Create new + CBlockIndex* pindexNew = new CBlockIndex(); + if (!pindexNew) + throw runtime_error("LoadBlockIndex(): new CBlockIndex failed"); + mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; + pindexNew->phashBlock = &((*mi).first); + + return pindexNew; +} + +bool static LoadBlockIndexDB() +{ + const CChainParams& chainparams = Params(); + if (!pblocktree->LoadBlockIndexGuts()) + return false; + + boost::this_thread::interruption_point(); + + // Calculate nChainWork + vector > vSortedByHeight; + vSortedByHeight.reserve(mapBlockIndex.size()); + BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) + { + CBlockIndex* pindex = item.second; + vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); + } + sort(vSortedByHeight.begin(), vSortedByHeight.end()); + BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) + { + CBlockIndex* pindex = item.second; + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); + // We can link the chain of blocks for which we've received transactions at some point. + // Pruned nodes may have deleted the block. + if (pindex->nTx > 0) { + if (pindex->pprev) { + if (pindex->pprev->nChainTx) { + pindex->nChainTx = pindex->pprev->nChainTx + pindex->nTx; + } else { + pindex->nChainTx = 0; + mapBlocksUnlinked.insert(std::make_pair(pindex->pprev, pindex)); + } + } else { + pindex->nChainTx = pindex->nTx; + } + } + if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && (pindex->nChainTx || pindex->pprev == NULL)) + setBlockIndexCandidates.insert(pindex); + if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork)) + pindexBestInvalid = pindex; + if (pindex->pprev) + pindex->BuildSkip(); + if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == NULL || CBlockIndexWorkComparator()(pindexBestHeader, pindex))) + pindexBestHeader = pindex; + } + + // Load block file info + pblocktree->ReadLastBlockFile(nLastBlockFile); + vinfoBlockFile.resize(nLastBlockFile + 1); + LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); + for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { + pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); + } + LogPrintf("%s: last block file info: %s\n", __func__, vinfoBlockFile[nLastBlockFile].ToString()); + for (int nFile = nLastBlockFile + 1; true; nFile++) { + CBlockFileInfo info; + if (pblocktree->ReadBlockFileInfo(nFile, info)) { + vinfoBlockFile.push_back(info); + } else { + break; + } + } + + // Check presence of blk files + LogPrintf("Checking all blk files are present...\n"); + set setBlkDataFiles; + BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) + { + CBlockIndex* pindex = item.second; + if (pindex->nStatus & BLOCK_HAVE_DATA) { + setBlkDataFiles.insert(pindex->nFile); + } + } + for (std::set::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) + { + CDiskBlockPos pos(*it, 0); + if (CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION).IsNull()) { + return false; + } + } + + // Check whether we have ever pruned block & undo files + pblocktree->ReadFlag("prunedblockfiles", fHavePruned); + if (fHavePruned) + LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n"); + + // Check whether we need to continue reindexing + bool fReindexing = false; + pblocktree->ReadReindexing(fReindexing); + fReindex |= fReindexing; + + // Check whether we have a transaction index + pblocktree->ReadFlag("txindex", fTxIndex); + LogPrintf("%s: transaction index %s\n", __func__, fTxIndex ? "enabled" : "disabled"); + + // Check whether we have an address index + pblocktree->ReadFlag("addressindex", fAddressIndex); + LogPrintf("%s: address index %s\n", __func__, fAddressIndex ? "enabled" : "disabled"); + + // Check whether we have a timestamp index + pblocktree->ReadFlag("timestampindex", fTimestampIndex); + LogPrintf("%s: timestamp index %s\n", __func__, fTimestampIndex ? "enabled" : "disabled"); + + // Check whether we have a spent index + pblocktree->ReadFlag("spentindex", fSpentIndex); + LogPrintf("%s: spent index %s\n", __func__, fSpentIndex ? "enabled" : "disabled"); + + // Load pointer to end of best chain + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + if (it == mapBlockIndex.end()) + return true; + chainActive.SetTip(it->second); + + PruneBlockIndexCandidates(); + + LogPrintf("%s: hashBestChain=%s height=%d date=%s progress=%f\n", __func__, + chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), + Checkpoints::GuessVerificationProgress(chainparams.Checkpoints(), chainActive.Tip())); + + return true; +} + +CVerifyDB::CVerifyDB() +{ + uiInterface.ShowProgress(_("Verifying blocks..."), 0); +} + +CVerifyDB::~CVerifyDB() +{ + uiInterface.ShowProgress("", 100); +} + +bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth) +{ + LOCK(cs_main); + if (chainActive.Tip() == NULL || chainActive.Tip()->pprev == NULL) + return true; + + // Verify blocks in the best chain + if (nCheckDepth <= 0) + nCheckDepth = 1000000000; // suffices until the year 19000 + if (nCheckDepth > chainActive.Height()) + nCheckDepth = chainActive.Height(); + nCheckLevel = std::max(0, std::min(4, nCheckLevel)); + LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); + CCoinsViewCache coins(coinsview); + CClaimTrieCache trieCache(pclaimTrie); + CBlockIndex* pindexState = chainActive.Tip(); + CBlockIndex* pindexFailure = NULL; + int nGoodTransactions = 0; + CValidationState state; + for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) + { + boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))))); + if (pindex->nHeight < chainActive.Height()-nCheckDepth) + break; + CBlock block; + // check level 0: read from disk + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) + return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + // check level 1: verify block validity + if (nCheckLevel >= 1 && !CheckBlock(block, state)) + return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + // check level 2: verify undo validity + if (nCheckLevel >= 2 && pindex) { + CBlockUndo undo; + CDiskBlockPos pos = pindex->GetUndoPos(); + if (!pos.IsNull()) { + if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) + return error("VerifyDB(): *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + } + } + // check level 3: check for inconsistencies during memory-only disconnect of tip blocks + if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) { + bool fClean = true; + if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)) + return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + pindexState = pindex->pprev; + if (!fClean) { + nGoodTransactions = 0; + pindexFailure = pindex; + } else + nGoodTransactions += block.vtx.size(); + } + if (ShutdownRequested()) + return true; + } + if (pindexFailure) + return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions); + + // check level 4: try reconnecting blocks + if (nCheckLevel >= 4) { + CBlockIndex *pindex = pindexState; + while (pindex != chainActive.Tip()) { + boost::this_thread::interruption_point(); + uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50)))); + pindex = chainActive.Next(pindex); + CBlock block; + if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) + return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + if (!ConnectBlock(block, state, pindex, coins, trieCache)) + return error("VerifyDB(): *** found unconnectable block at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); + } + } + + LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions); + + return true; +} + +bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof) +{ + AssertLockHeld(cs_main); + if (!chainActive.Contains(pindexProof)) + { + return false; + } + CCoinsViewCache coins(pcoinsTip); + CClaimTrieCache trieCache(pclaimTrie); + CBlockIndex* pindexState = chainActive.Tip(); + CValidationState state; + for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev && pindexState != pindexProof; pindex=pindex->pprev) + { + boost::this_thread::interruption_point(); + CBlock block; + if (!ReadBlockFromDisk(block, pindex, Params().GetConsensus())) + { + return false; + } + if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) + { + bool fClean = true; + if (!DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)) + { + return false; + } + pindexState = pindex->pprev; + } + if (ShutdownRequested()) + return false; + } + assert(pindexState == pindexProof); + proof = trieCache.getProofForName(name); + return true; +} + +void UnloadBlockIndex() +{ + LOCK(cs_main); + setBlockIndexCandidates.clear(); + chainActive.SetTip(NULL); + pindexBestInvalid = NULL; + pindexBestHeader = NULL; + mempool.clear(); + mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); + nSyncStarted = 0; + mapBlocksUnlinked.clear(); + vinfoBlockFile.clear(); + nLastBlockFile = 0; + nBlockSequenceId = 1; + mapBlockSource.clear(); + mapBlocksInFlight.clear(); + nPreferredDownload = 0; + setDirtyBlockIndex.clear(); + setDirtyFileInfo.clear(); + mapNodeState.clear(); + recentRejects.reset(NULL); + versionbitscache.Clear(); + for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) { + warningcache[b].clear(); + } + + BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) { + delete entry.second; + } + mapBlockIndex.clear(); + fHavePruned = false; +} + +bool LoadBlockIndex() +{ + // Load block index from databases + if (!fReindex && !LoadBlockIndexDB()) + return false; + return true; +} + +bool InitBlockIndex(const CChainParams& chainparams) +{ + LOCK(cs_main); + + // Initialize global variables that cannot be constructed at startup. + recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); + + // Check whether we're already initialized + if (chainActive.Genesis() != NULL) + return true; + + // Use the provided setting for -txindex in the new database + fTxIndex = GetBoolArg("-txindex", DEFAULT_TXINDEX); + pblocktree->WriteFlag("txindex", fTxIndex); + + // Use the provided setting for -addressindex in the new database + fAddressIndex = GetBoolArg("-addressindex", DEFAULT_ADDRESSINDEX); + pblocktree->WriteFlag("addressindex", fAddressIndex); + + // Use the provided setting for -timestampindex in the new database + fTimestampIndex = GetBoolArg("-timestampindex", DEFAULT_TIMESTAMPINDEX); + pblocktree->WriteFlag("timestampindex", fTimestampIndex); + + fSpentIndex = GetBoolArg("-spentindex", DEFAULT_SPENTINDEX); + pblocktree->WriteFlag("spentindex", fSpentIndex); + + LogPrintf("Initializing databases...\n"); + + // Only add the genesis block if not reindexing (in which case we reuse the one already on disk) + if (!fReindex) { + try { + CBlock &block = const_cast(chainparams.GenesisBlock()); + // Start new block file + unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); + CDiskBlockPos blockPos; + CValidationState state; + if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) + return error("LoadBlockIndex(): FindBlockPos failed"); + if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) + return error("LoadBlockIndex(): writing genesis block to disk failed"); + CBlockIndex *pindex = AddToBlockIndex(block); + if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) + return error("LoadBlockIndex(): genesis block not accepted"); + if (!ActivateBestChain(state, chainparams, &block)) + return error("LoadBlockIndex(): genesis block cannot be activated"); + // Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data + return FlushStateToDisk(state, FLUSH_STATE_ALWAYS); + } catch (const std::runtime_error& e) { + return error("LoadBlockIndex(): failed to initialize block database: %s", e.what()); + } + } + + return true; +} + +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp) +{ + // Map of disk positions for blocks with unknown parent (only used for reindex) + static std::multimap mapBlocksUnknownParent; + int64_t nStart = GetTimeMillis(); + + int nLoaded = 0; + try { + // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor + CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); + uint64_t nRewind = blkdat.GetPos(); + while (!blkdat.eof()) { + boost::this_thread::interruption_point(); + + blkdat.SetPos(nRewind); + nRewind++; // start one byte further next time, in case of failure + blkdat.SetLimit(); // remove former limit + unsigned int nSize = 0; + try { + // locate a header + unsigned char buf[MESSAGE_START_SIZE]; + blkdat.FindByte(chainparams.MessageStart()[0]); + nRewind = blkdat.GetPos()+1; + blkdat >> FLATDATA(buf); + if (memcmp(buf, chainparams.MessageStart(), MESSAGE_START_SIZE)) + continue; + // read size + blkdat >> nSize; + if (nSize < 80 || nSize > MAX_BLOCK_SIZE) + continue; + } catch (const std::exception&) { + // no valid block header found; don't complain + break; + } + try { + // read block + uint64_t nBlockPos = blkdat.GetPos(); + if (dbp) + dbp->nPos = nBlockPos; + blkdat.SetLimit(nBlockPos + nSize); + blkdat.SetPos(nBlockPos); + CBlock block; + blkdat >> block; + nRewind = blkdat.GetPos(); + + // detect out of order blocks, and store them for later + uint256 hash = block.GetHash(); + if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex.find(block.hashPrevBlock) == mapBlockIndex.end()) { + LogPrint("reindex", "%s: Out of order block %s, parent %s not known\n", __func__, hash.ToString(), + block.hashPrevBlock.ToString()); + if (dbp) + mapBlocksUnknownParent.insert(std::make_pair(block.hashPrevBlock, *dbp)); + continue; + } + + // process in case the block isn't known yet + if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { + CValidationState state; + if (ProcessNewBlock(state, chainparams, NULL, &block, true, dbp)) + nLoaded++; + if (state.IsError()) + break; + } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->nHeight % 1000 == 0) { + LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); + } + + // Recursively process earlier encountered successors of this block + deque queue; + queue.push_back(hash); + while (!queue.empty()) { + uint256 head = queue.front(); + queue.pop_front(); + std::pair::iterator, std::multimap::iterator> range = mapBlocksUnknownParent.equal_range(head); + while (range.first != range.second) { + std::multimap::iterator it = range.first; + if (ReadBlockFromDisk(block, it->second, chainparams.GetConsensus())) + { + LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), + head.ToString()); + CValidationState dummy; + if (ProcessNewBlock(dummy, chainparams, NULL, &block, true, &it->second)) + { + nLoaded++; + queue.push_back(block.GetHash()); + } + } + range.first++; + mapBlocksUnknownParent.erase(it); + } + } + } catch (const std::exception& e) { + LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what()); + } + } + } catch (const std::runtime_error& e) { + AbortNode(std::string("System error: ") + e.what()); + } + if (nLoaded > 0) + LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); + return nLoaded > 0; +} + +void static CheckBlockIndex(const Consensus::Params& consensusParams) +{ + if (!fCheckBlockIndex) { + return; + } + + LOCK(cs_main); + + // During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain, + // so we have the genesis block in mapBlockIndex but no active chain. (A few of the tests when + // iterating the block tree require that chainActive has been initialized.) + if (chainActive.Height() < 0) { + assert(mapBlockIndex.size() <= 1); + return; + } + + // Build forward-pointing map of the entire block tree. + std::multimap forward; + for (BlockMap::iterator it = mapBlockIndex.begin(); it != mapBlockIndex.end(); it++) { + forward.insert(std::make_pair(it->second->pprev, it->second)); + } + + assert(forward.size() == mapBlockIndex.size()); + + std::pair::iterator,std::multimap::iterator> rangeGenesis = forward.equal_range(NULL); + CBlockIndex *pindex = rangeGenesis.first->second; + rangeGenesis.first++; + assert(rangeGenesis.first == rangeGenesis.second); // There is only one index entry with parent NULL. + + // Iterate over the entire block tree, using depth-first search. + // Along the way, remember whether there are blocks on the path from genesis + // block being explored which are the first to have certain properties. + size_t nNodes = 0; + int nHeight = 0; + CBlockIndex* pindexFirstInvalid = NULL; // Oldest ancestor of pindex which is invalid. + CBlockIndex* pindexFirstMissing = NULL; // Oldest ancestor of pindex which does not have BLOCK_HAVE_DATA. + CBlockIndex* pindexFirstNeverProcessed = NULL; // Oldest ancestor of pindex for which nTx == 0. + CBlockIndex* pindexFirstNotTreeValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TREE (regardless of being valid or not). + CBlockIndex* pindexFirstNotTransactionsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_TRANSACTIONS (regardless of being valid or not). + CBlockIndex* pindexFirstNotChainValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_CHAIN (regardless of being valid or not). + CBlockIndex* pindexFirstNotScriptsValid = NULL; // Oldest ancestor of pindex which does not have BLOCK_VALID_SCRIPTS (regardless of being valid or not). + while (pindex != NULL) { + nNodes++; + if (pindexFirstInvalid == NULL && pindex->nStatus & BLOCK_FAILED_VALID) pindexFirstInvalid = pindex; + if (pindexFirstMissing == NULL && !(pindex->nStatus & BLOCK_HAVE_DATA)) pindexFirstMissing = pindex; + if (pindexFirstNeverProcessed == NULL && pindex->nTx == 0) pindexFirstNeverProcessed = pindex; + if (pindex->pprev != NULL && pindexFirstNotTreeValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TREE) pindexFirstNotTreeValid = pindex; + if (pindex->pprev != NULL && pindexFirstNotTransactionsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_TRANSACTIONS) pindexFirstNotTransactionsValid = pindex; + if (pindex->pprev != NULL && pindexFirstNotChainValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_CHAIN) pindexFirstNotChainValid = pindex; + if (pindex->pprev != NULL && pindexFirstNotScriptsValid == NULL && (pindex->nStatus & BLOCK_VALID_MASK) < BLOCK_VALID_SCRIPTS) pindexFirstNotScriptsValid = pindex; + + // Begin: actual consistency checks. + if (pindex->pprev == NULL) { + // Genesis block checks. + assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match. + assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block. + } + if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked + // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred). + // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred. + if (!fHavePruned) { + // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0 + assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0)); + assert(pindexFirstMissing == pindexFirstNeverProcessed); + } else { + // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0 + if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0); + } + if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA); + assert(((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TRANSACTIONS) == (pindex->nTx > 0)); // This is pruning-independent. + // All parents having had data (at some point) is equivalent to all parents being VALID_TRANSACTIONS, which is equivalent to nChainTx being set. + assert((pindexFirstNeverProcessed != NULL) == (pindex->nChainTx == 0)); // nChainTx != 0 is used to signal that all parent blocks have been processed (but may have been pruned). + assert((pindexFirstNotTransactionsValid != NULL) == (pindex->nChainTx == 0)); + assert(pindex->nHeight == nHeight); // nHeight must be consistent. + assert(pindex->pprev == NULL || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's. + assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks. + assert(pindexFirstNotTreeValid == NULL); // All mapBlockIndex entries must at least be TREE valid + if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == NULL); // TREE valid implies all parents are TREE valid + if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_CHAIN) assert(pindexFirstNotChainValid == NULL); // CHAIN valid implies all parents are CHAIN valid + if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_SCRIPTS) assert(pindexFirstNotScriptsValid == NULL); // SCRIPTS valid implies all parents are SCRIPTS valid + if (pindexFirstInvalid == NULL) { + // Checks for not-invalid blocks. + assert((pindex->nStatus & BLOCK_FAILED_MASK) == 0); // The failed mask cannot be set for blocks without invalid parents. + } + if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && pindexFirstNeverProcessed == NULL) { + if (pindexFirstInvalid == NULL) { + // If this block sorts at least as good as the current tip and + // is valid and we have all data for its parents, it must be in + // setBlockIndexCandidates. chainActive.Tip() must also be there + // even if some data has been pruned. + if (pindexFirstMissing == NULL || pindex == chainActive.Tip()) { + assert(setBlockIndexCandidates.count(pindex)); + } + // If some parent is missing, then it could be that this block was in + // setBlockIndexCandidates but had to be removed because of the missing data. + // In this case it must be in mapBlocksUnlinked -- see test below. + } + } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates. + assert(setBlockIndexCandidates.count(pindex) == 0); + } + // Check whether this block is in mapBlocksUnlinked. + std::pair::iterator,std::multimap::iterator> rangeUnlinked = mapBlocksUnlinked.equal_range(pindex->pprev); + bool foundInUnlinked = false; + while (rangeUnlinked.first != rangeUnlinked.second) { + assert(rangeUnlinked.first->first == pindex->pprev); + if (rangeUnlinked.first->second == pindex) { + foundInUnlinked = true; + break; + } + rangeUnlinked.first++; + } + if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed != NULL && pindexFirstInvalid == NULL) { + // If this block has block data available, some parent was never received, and has no invalid parents, it must be in mapBlocksUnlinked. + assert(foundInUnlinked); + } + if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in mapBlocksUnlinked if we don't HAVE_DATA + if (pindexFirstMissing == NULL) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in mapBlocksUnlinked. + if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == NULL && pindexFirstMissing != NULL) { + // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent. + assert(fHavePruned); // We must have pruned. + // This block may have entered mapBlocksUnlinked if: + // - it has a descendant that at some point had more work than the + // tip, and + // - we tried switching to that descendant but were missing + // data for some intermediate block between chainActive and the + // tip. + // So if this block is itself better than chainActive.Tip() and it wasn't in + // setBlockIndexCandidates, then it must be in mapBlocksUnlinked. + if (!CBlockIndexWorkComparator()(pindex, chainActive.Tip()) && setBlockIndexCandidates.count(pindex) == 0) { + if (pindexFirstInvalid == NULL) { + assert(foundInUnlinked); + } + } + } + // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow + // End: actual consistency checks. + + // Try descending into the first subnode. + std::pair::iterator,std::multimap::iterator> range = forward.equal_range(pindex); + if (range.first != range.second) { + // A subnode was found. + pindex = range.first->second; + nHeight++; + continue; + } + // This is a leaf node. + // Move upwards until we reach a node of which we have not yet visited the last child. + while (pindex) { + // We are going to either move to a parent or a sibling of pindex. + // If pindex was the first with a certain property, unset the corresponding variable. + if (pindex == pindexFirstInvalid) pindexFirstInvalid = NULL; + if (pindex == pindexFirstMissing) pindexFirstMissing = NULL; + if (pindex == pindexFirstNeverProcessed) pindexFirstNeverProcessed = NULL; + if (pindex == pindexFirstNotTreeValid) pindexFirstNotTreeValid = NULL; + if (pindex == pindexFirstNotTransactionsValid) pindexFirstNotTransactionsValid = NULL; + if (pindex == pindexFirstNotChainValid) pindexFirstNotChainValid = NULL; + if (pindex == pindexFirstNotScriptsValid) pindexFirstNotScriptsValid = NULL; + // Find our parent. + CBlockIndex* pindexPar = pindex->pprev; + // Find which child we just visited. + std::pair::iterator,std::multimap::iterator> rangePar = forward.equal_range(pindexPar); + while (rangePar.first->second != pindex) { + assert(rangePar.first != rangePar.second); // Our parent must have at least the node we're coming from as child. + rangePar.first++; + } + // Proceed to the next one. + rangePar.first++; + if (rangePar.first != rangePar.second) { + // Move to the sibling. + pindex = rangePar.first->second; + break; + } else { + // Move up further. + pindex = pindexPar; + nHeight--; + continue; + } + } + } + + // Check that we actually traversed the entire map. + assert(nNodes == forward.size()); +} + +////////////////////////////////////////////////////////////////////////////// +// +// CAlert +// + +std::string GetWarnings(const std::string& strFor) +{ + int nPriority = 0; + string strStatusBar; + string strRPC; + string strGUI; + + if (!CLIENT_VERSION_IS_RELEASE) { + strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"; + strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); + } + + if (GetBoolArg("-testsafemode", DEFAULT_TESTSAFEMODE)) + strStatusBar = strRPC = strGUI = "testsafemode enabled"; + + // Misc warnings like out of disk space and clock is wrong + if (strMiscWarning != "") + { + nPriority = 1000; + strStatusBar = strGUI = strMiscWarning; + } + + if (fLargeWorkForkFound) + { + nPriority = 2000; + strStatusBar = strRPC = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; + strGUI = _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); + } + else if (fLargeWorkInvalidChainFound) + { + nPriority = 2000; + strStatusBar = strRPC = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; + strGUI = _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); + } + + // Alerts + { + LOCK(cs_mapAlerts); + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + { + const CAlert& alert = item.second; + if (alert.AppliesToMe() && alert.nPriority > nPriority) + { + nPriority = alert.nPriority; + strStatusBar = strGUI = alert.strStatusBar; + } + } + } + + if (strFor == "gui") + return strGUI; + else if (strFor == "statusbar") + return strStatusBar; + else if (strFor == "rpc") + return strRPC; + assert(!"GetWarnings(): invalid parameter"); + return "error"; +} + + + + + + + + +////////////////////////////////////////////////////////////////////////////// +// +// Messages +// + + +bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) +{ + switch (inv.type) + { + case MSG_TX: + { + assert(recentRejects); + if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip) + { + // If the chain tip has changed previously rejected transactions + // might be now valid, e.g. due to a nLockTime'd tx becoming valid, + // or a double-spend. Reset the rejects filter and give those + // txs a second chance. + hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash(); + recentRejects->reset(); + } + + return recentRejects->contains(inv.hash) || + mempool.exists(inv.hash) || + mapOrphanTransactions.count(inv.hash) || + pcoinsTip->HaveCoins(inv.hash); + } + + case MSG_BLOCK: + return mapBlockIndex.count(inv.hash); + + /* + Pop Related Inventory Messages + + -- + + We shouldn't update the sync times for each of the messages when we already have it. + We're going to be asking many nodes upfront for the full inventory list, so we'll get duplicates of these. + We want to only update the time on new hits, so that we can time out appropriately if needed. + */ + case MSG_TXLOCK_REQUEST: + return instantsend.AlreadyHave(inv.hash); + + case MSG_TXLOCK_VOTE: + return instantsend.AlreadyHave(inv.hash); + + case MSG_SPORK: + return mapSporks.count(inv.hash); + + case MSG_POPNODE_ANNOUNCE: + return mnodeman.mapSeenPopnodeBroadcast.count(inv.hash) && !mnodeman.IsMnbRecoveryRequested(inv.hash); + + case MSG_POPNODE_PING: + return mnodeman.mapSeenPopnodePing.count(inv.hash); + + case MSG_DSTX: + return mapDarksendBroadcastTxes.count(inv.hash); + + case MSG_POPNODE_VERIFY: + return mnodeman.mapSeenPopnodeVerification.count(inv.hash); + } + + // Don't know what it is, just say we already got one + return true; +} + +void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParams) +{ + std::deque::iterator it = pfrom->vRecvGetData.begin(); + + vector vNotFound; + + LOCK(cs_main); + + while (it != pfrom->vRecvGetData.end()) { + // Don't bother if send buffer is too full to respond anyway + if (pfrom->nSendSize >= SendBufferSize()) + break; + + const CInv &inv = *it; + LogPrint("net", "ProcessGetData -- inv = %s\n", inv.ToString()); + { + boost::this_thread::interruption_point(); + it++; + + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + { + bool send = false; + BlockMap::iterator mi = mapBlockIndex.find(inv.hash); + if (mi != mapBlockIndex.end()) + { + if (chainActive.Contains(mi->second)) { + send = true; + } else { + static const int nOneMonth = 30 * 24 * 60 * 60; + // To prevent fingerprinting attacks, only send blocks outside of the active + // chain if they are valid, and no more than a month older (both in time, and in + // best equivalent proof of work) than the best header chain we know about. + send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) && + (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) && + (GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, consensusParams) < nOneMonth); + if (!send) { + LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId()); + } + } + } + // disconnect node in case we have reached the outbound limit for serving historical blocks + // never disconnect whitelisted nodes + static const int nOneWeek = 7 * 24 * 60 * 60; // assume > 1 week = historical + if (send && CNode::OutboundTargetReached(true) && ( ((pindexBestHeader != NULL) && (pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() > nOneWeek)) || inv.type == MSG_FILTERED_BLOCK) && !pfrom->fWhitelisted) + { + LogPrint("net", "historical block serving limit reached, disconnect peer=%d\n", pfrom->GetId()); + + //disconnect node + pfrom->fDisconnect = true; + send = false; + } + // Pruned nodes may have deleted the block, so check whether + // it's available before trying to send. + if (send && (mi->second->nStatus & BLOCK_HAVE_DATA)) { + // Send block from disk + CBlock block; + if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) + assert(!"cannot load block from disk"); + if (inv.type == MSG_BLOCK) + pfrom->PushMessage(NetMsgType::BLOCK, block); + else // MSG_FILTERED_BLOCK) + { + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) + { + CMerkleBlock merkleBlock(block, *pfrom->pfilter); + pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock); + // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see + // This avoids hurting performance by pointlessly requiring a round-trip + // Note that there is currently no way for a node to request any single transactions we didn't send here - + // they must either disconnect and retry or request the full block. + // Thus, the protocol spec specified allows for us to provide duplicate txn here, + // however we MUST always provide at least what the remote peer needs + typedef std::pair PairType; + BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) + pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]); + } + // else + // no response + } + + // Trigger the peer node to send a getblocks request for the next batch of inventory + if (inv.hash == pfrom->hashContinue) + { + // Bypass PushInventory, this must send even if redundant, + // and we want it right after the last block so they don't + // wait for other stuff first. + vector vInv; + vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); + pfrom->PushMessage(NetMsgType::INV, vInv); + pfrom->hashContinue.SetNull(); + } + } + } + else if (inv.IsKnownType()) + { + // Send stream from relay memory + bool pushed = false; + { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + { + LOCK(cs_mapRelay); + map::iterator mi = mapRelay.find(inv); + if (mi != mapRelay.end()) { + ss += (*mi).second; + pushed = true; + } + } + if(pushed) + pfrom->PushMessage(inv.GetCommand(), ss); + } + + if (!pushed && inv.type == MSG_TX) { + CTransaction tx; + if (mempool.lookup(inv.hash, tx)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << tx; + pfrom->PushMessage(NetMsgType::TX, ss); + pushed = true; + } + } + + if (!pushed && inv.type == MSG_TXLOCK_REQUEST) { + CTxLockRequest txLockRequest; + if(instantsend.GetTxLockRequest(inv.hash, txLockRequest)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << txLockRequest; + pfrom->PushMessage(NetMsgType::TXLOCKREQUEST, ss); + pushed = true; + } + } + + if (!pushed && inv.type == MSG_TXLOCK_VOTE) { + CTxLockVote vote; + if(instantsend.GetTxLockVote(inv.hash, vote)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << vote; + pfrom->PushMessage(NetMsgType::TXLOCKVOTE, ss); + pushed = true; + } + } + + if (!pushed && inv.type == MSG_SPORK) { + if(mapSporks.count(inv.hash)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mapSporks[inv.hash]; + pfrom->PushMessage(NetMsgType::SPORK, ss); + pushed = true; + } + } + + + if (!pushed && inv.type == MSG_POPNODE_ANNOUNCE) { + if(mnodeman.mapSeenPopnodeBroadcast.count(inv.hash)){ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mnodeman.mapSeenPopnodeBroadcast[inv.hash].second; + // backward compatibility patch + if(pfrom->nVersion < 70204) { + ss << (int64_t)0; + } + pfrom->PushMessage(NetMsgType::MNANNOUNCE, ss); + pushed = true; + } + } + + if (!pushed && inv.type == MSG_POPNODE_PING) { + if(mnodeman.mapSeenPopnodePing.count(inv.hash)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mnodeman.mapSeenPopnodePing[inv.hash]; + pfrom->PushMessage(NetMsgType::MNPING, ss); + pushed = true; + } + } + + if (!pushed && inv.type == MSG_DSTX) { + if(mapDarksendBroadcastTxes.count(inv.hash)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mapDarksendBroadcastTxes[inv.hash]; + pfrom->PushMessage(NetMsgType::DSTX, ss); + pushed = true; + } + } + + + if (!pushed && inv.type == MSG_POPNODE_VERIFY) { + if(mnodeman.mapSeenPopnodeVerification.count(inv.hash)) { + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss.reserve(1000); + ss << mnodeman.mapSeenPopnodeVerification[inv.hash]; + pfrom->PushMessage(NetMsgType::MNVERIFY, ss); + pushed = true; + } + } + + if (!pushed) + vNotFound.push_back(inv); + } + + // Track requests for our stuff. + GetMainSignals().Inventory(inv.hash); + + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) + break; + } + } + + pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it); + + if (!vNotFound.empty()) { + // Let the peer know that we didn't find what it asked for, so it doesn't + // have to wait around forever. Currently only SPV clients actually care + // about this message: it's needed when they are recursively walking the + // dependencies of relevant unconfirmed transactions. SPV clients want to + // do that because they want to know about (and store and rebroadcast and + // risk analyze) the dependencies of transactions relevant to them, without + // having to download the entire memory pool. + pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound); + } +} + +bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) +{ + const CChainParams& chainparams = Params(); + RandAddSeedPerfmon(); + LogPrint("net", "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->id); + + if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) + { + LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n"); + return true; + } + + if (!(nLocalServices & NODE_BLOOM) && + (strCommand == NetMsgType::FILTERLOAD || + strCommand == NetMsgType::FILTERADD || + strCommand == NetMsgType::FILTERCLEAR)) + { + if (pfrom->nVersion >= NO_BLOOM_VERSION) { + Misbehaving(pfrom->GetId(), 100); + return false; + } else if (GetBoolArg("-enforcenodebloom", false)) { + pfrom->fDisconnect = true; + return false; + } + } + + + if (strCommand == NetMsgType::VERSION) + { + // Each connection can only send one version message + if (pfrom->nVersion != 0) + { + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); + Misbehaving(pfrom->GetId(), 1); + return false; + } + + int64_t nTime; + CAddress addrMe; + CAddress addrFrom; + uint64_t nNonce = 1; + vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; + if (pfrom->nVersion < MIN_PEER_PROTO_VERSION) + { + // disconnect from peers older than this proto version + LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); + pfrom->fDisconnect = true; + return false; + } + + if (pfrom->nVersion == 10300) + pfrom->nVersion = 300; + if (!vRecv.empty()) + vRecv >> addrFrom >> nNonce; + if (!vRecv.empty()) { + vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); + pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); + } + if (!vRecv.empty()) + vRecv >> pfrom->nStartingHeight; + if (!vRecv.empty()) + vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message + else + pfrom->fRelayTxes = true; + + // Disconnect if we connected to ourself + if (nNonce == nLocalHostNonce && nNonce > 1) + { + LogPrintf("connected to self at %s, disconnecting\n", pfrom->addr.ToString()); + pfrom->fDisconnect = true; + return true; + } + + pfrom->addrLocal = addrMe; + if (pfrom->fInbound && addrMe.IsRoutable()) + { + SeenLocal(addrMe); + } + + // Be shy and don't send version until we hear + if (pfrom->fInbound) + pfrom->PushVersion(); + + pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); + + // Potentially mark this peer as a preferred download peer. + UpdatePreferredDownload(pfrom, State(pfrom->GetId())); + + // Change version + pfrom->PushMessage(NetMsgType::VERACK); + pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + + if (!pfrom->fInbound) + { + // Advertise our address + if (fListen && !IsInitialBlockDownload()) + { + CAddress addr = GetLocalAddress(&pfrom->addr); + if (addr.IsRoutable()) + { + LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); + pfrom->PushAddress(addr); + } else if (IsPeerAddrLocalGood(pfrom)) { + addr.SetIP(pfrom->addrLocal); + LogPrintf("ProcessMessages: advertising address %s\n", addr.ToString()); + pfrom->PushAddress(addr); + } + } + + // Get recent addresses + if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000) + { + pfrom->PushMessage(NetMsgType::GETADDR); + pfrom->fGetAddr = true; + } + addrman.Good(pfrom->addr); + } else { + if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom) + { + addrman.Add(addrFrom, addrFrom); + addrman.Good(addrFrom); + } + } + + // Relay alerts + { + LOCK(cs_mapAlerts); + BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) + item.second.RelayTo(pfrom); + } + + pfrom->fSuccessfullyConnected = true; + + string remoteAddr; + if (fLogIPs) + remoteAddr = ", peeraddr=" + pfrom->addr.ToString(); + + LogPrintf("receive version message: %s: version %d, blocks=%d, us=%s, peer=%d%s\n", + pfrom->cleanSubVer, pfrom->nVersion, + pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, + remoteAddr); + + int64_t nTimeOffset = nTime - GetTime(); + pfrom->nTimeOffset = nTimeOffset; + AddTimeData(pfrom->addr, nTimeOffset); + } + + + else if (pfrom->nVersion == 0) + { + // Must have a version message before anything else + Misbehaving(pfrom->GetId(), 1); + return false; + } + + + else if (strCommand == NetMsgType::VERACK) + { + pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + + // Mark this node as currently connected, so we update its timestamp later. + if (pfrom->fNetworkNode) { + LOCK(cs_main); + State(pfrom->GetId())->fCurrentlyConnected = true; + } + + if (pfrom->nVersion >= SENDHEADERS_VERSION) { + // Tell our peer we prefer to receive headers rather than inv's + // We send this to non-NODE NETWORK peers as well, because even + // non-NODE NETWORK peers can announce blocks (such as pruning + // nodes) + pfrom->PushMessage(NetMsgType::SENDHEADERS); + } + } + + + else if (strCommand == NetMsgType::ADDR) + { + vector vAddr; + vRecv >> vAddr; + + // Don't want addr from older versions unless seeding + if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000) + return true; + if (vAddr.size() > 1000) + { + Misbehaving(pfrom->GetId(), 20); + return error("message addr size() = %u", vAddr.size()); + } + + // Store the new addresses + vector vAddrOk; + int64_t nNow = GetAdjustedTime(); + int64_t nSince = nNow - 10 * 60; + BOOST_FOREACH(CAddress& addr, vAddr) + { + boost::this_thread::interruption_point(); + + if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) + addr.nTime = nNow - 5 * 24 * 60 * 60; + pfrom->AddAddressKnown(addr); + bool fReachable = IsReachable(addr); + if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) + { + // Relay to a limited number of other nodes + { + LOCK(cs_vNodes); + // Use deterministic randomness to send to the same nodes for 24 hours + // at a time so the addrKnowns of the chosen nodes prevent repeats + static uint256 hashSalt; + if (hashSalt.IsNull()) + hashSalt = GetRandHash(); + uint64_t hashAddr = addr.GetHash(); + uint256 hashRand = ArithToUint256(UintToArith256(hashSalt) ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60))); + hashRand = Hash(BEGIN(hashRand), END(hashRand)); + multimap mapMix; + BOOST_FOREACH(CNode* pnode, vNodes) + { + if (pnode->nVersion < CADDR_TIME_VERSION) + continue; + unsigned int nPointer; + memcpy(&nPointer, &pnode, sizeof(nPointer)); + uint256 hashKey = ArithToUint256(UintToArith256(hashRand) ^ nPointer); + hashKey = Hash(BEGIN(hashKey), END(hashKey)); + mapMix.insert(make_pair(hashKey, pnode)); + } + int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s) + for (multimap::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi) + ((*mi).second)->PushAddress(addr); + } + } + // Do not store addresses outside our network + if (fReachable) + vAddrOk.push_back(addr); + } + addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60); + if (vAddr.size() < 1000) + pfrom->fGetAddr = false; + if (pfrom->fOneShot) + pfrom->fDisconnect = true; + } + + else if (strCommand == NetMsgType::SENDHEADERS) + { + LOCK(cs_main); + State(pfrom->GetId())->fPreferHeaders = true; + } + + + else if (strCommand == NetMsgType::INV) + { + vector vInv; + vRecv >> vInv; + if (vInv.size() > MAX_INV_SZ) + { + Misbehaving(pfrom->GetId(), 20); + return error("message inv size() = %u", vInv.size()); + } + + bool fBlocksOnly = GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + + // Allow whitelisted peers to send data other than blocks in blocks only mode if whitelistrelay is true + if (pfrom->fWhitelisted && GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY)) + fBlocksOnly = false; + + LOCK(cs_main); + + std::vector vToFetch; + + + for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) + { + const CInv &inv = vInv[nInv]; + + if(!inv.IsKnownType()) { + LogPrint("net", "got inv of unknown type %d: %s peer=%d\n", inv.type, inv.hash.ToString(), pfrom->id); + continue; + } + + boost::this_thread::interruption_point(); + pfrom->AddInventoryKnown(inv); + + bool fAlreadyHave = AlreadyHave(inv); + LogPrint("net", "got inv: %s %s peer=%d\n", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom->id); + + if (inv.type == MSG_BLOCK) { + UpdateBlockAvailability(pfrom->GetId(), inv.hash); + if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { + // First request the headers preceding the announced block. In the normal fully-synced + // case where a new block is announced that succeeds the current tip (no reorganization), + // there are no such headers. + // Secondly, and only when we are close to being synced, we request the announced block directly, + // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the + // time the block arrives, the header chain leading up to it is already validated. Not + // doing this will result in the received block being rejected as an orphan in case it is + // not a direct successor. + pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); + CNodeState *nodestate = State(pfrom->GetId()); + if (CanDirectFetch(chainparams.GetConsensus()) && + nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + vToFetch.push_back(inv); + // Mark block as in flight already, even though the actual "getdata" message only goes out + // later (within the same cs_main lock, though). + MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); + } + LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); + } + } + else + { + if (fBlocksOnly) + LogPrint("net", "transaction (%s) inv sent in violation of protocol peer=%d\n", inv.hash.ToString(), pfrom->id); + else if (!fAlreadyHave && !fImporting && !fReindex && !IsInitialBlockDownload()) + pfrom->AskFor(inv); + } + + // Track requests for our stuff + GetMainSignals().Inventory(inv.hash); + + if (pfrom->nSendSize > (SendBufferSize() * 2)) { + Misbehaving(pfrom->GetId(), 50); + return error("send buffer size() = %u", pfrom->nSendSize); + } + } + + if (!vToFetch.empty()) + pfrom->PushMessage(NetMsgType::GETDATA, vToFetch); + } + + + else if (strCommand == NetMsgType::GETDATA) + { + vector vInv; + vRecv >> vInv; + if (vInv.size() > MAX_INV_SZ) + { + Misbehaving(pfrom->GetId(), 20); + return error("message getdata size() = %u", vInv.size()); + } + + if (fDebug || (vInv.size() != 1)) + LogPrint("net", "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom->id); + + if ((fDebug && vInv.size() > 0) || (vInv.size() == 1)) + LogPrint("net", "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom->id); + + pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); + ProcessGetData(pfrom, chainparams.GetConsensus()); + } + + + else if (strCommand == NetMsgType::GETBLOCKS) + { + CBlockLocator locator; + uint256 hashStop; + vRecv >> locator >> hashStop; + + LOCK(cs_main); + + // Find the last block the caller has in the main chain + CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); + + // Send the rest of the chain + if (pindex) + pindex = chainActive.Next(pindex); + int nLimit = 500; + LogPrint("net", "getblocks %d to %s limit %d from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.IsNull() ? "end" : hashStop.ToString(), nLimit, pfrom->id); + for (; pindex; pindex = chainActive.Next(pindex)) + { + if (pindex->GetBlockHash() == hashStop) + { + LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + break; + } + // If pruning, don't inv blocks unless we have on disk and are likely to still have + // for some reasonable time window (1 hour) that block relay might require. + const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing; + if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) + { + LogPrint("net", " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + break; + } + pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); + if (--nLimit <= 0) + { + // When this block is requested, we'll send an inv that'll + // trigger the peer to getblocks the next batch of inventory. + LogPrint("net", " getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + pfrom->hashContinue = pindex->GetBlockHash(); + break; + } + } + } + + + else if (strCommand == NetMsgType::GETHEADERS) + { + CBlockLocator locator; + uint256 hashStop; + vRecv >> locator >> hashStop; + + LOCK(cs_main); + if (IsInitialBlockDownload() && !pfrom->fWhitelisted) { + LogPrint("net", "Ignoring getheaders from peer=%d because node is in initial block download\n", pfrom->id); + return true; + } + + CNodeState *nodestate = State(pfrom->GetId()); + CBlockIndex* pindex = NULL; + if (locator.IsNull()) + { + // If locator is null, return the hashStop block + BlockMap::iterator mi = mapBlockIndex.find(hashStop); + if (mi == mapBlockIndex.end()) + return true; + pindex = (*mi).second; + } + else + { + // Find the last block the caller has in the main chain + pindex = FindForkInGlobalIndex(chainActive, locator); + if (pindex) + pindex = chainActive.Next(pindex); + } + + // we must use CBlocks, as CBlockHeaders won't include the 0x00 nTx count at the end + vector vHeaders; + int nLimit = MAX_HEADERS_RESULTS; + LogPrint("net", "getheaders %d to %s from peer=%d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString(), pfrom->id); + for (; pindex; pindex = chainActive.Next(pindex)) + { + vHeaders.push_back(pindex->GetBlockHeader()); + if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop) + break; + } + // pindex can be NULL either if we sent chainActive.Tip() OR + // if our peer has chainActive.Tip() (and thus we are sending an empty + // headers message). In both cases it's safe to update + // pindexBestHeaderSent to be our tip. + nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); + pfrom->PushMessage(NetMsgType::HEADERS, vHeaders); + } + + + else if (strCommand == NetMsgType::TX || strCommand == NetMsgType::DSTX || strCommand == NetMsgType::TXLOCKREQUEST) + { + // Stop processing the transaction early if + // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off + if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && (!pfrom->fWhitelisted || !GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) + { + LogPrint("net", "transaction sent in violation of protocol peer=%d\n", pfrom->id); + return true; + } + + vector vWorkQueue; + vector vEraseQueue; + CTransaction tx; + CTxLockRequest txLockRequest; + CDarksendBroadcastTx dstx; + int nInvType = MSG_TX; + + // Read data and assign inv type + if(strCommand == NetMsgType::TX) { + vRecv >> tx; + } else if(strCommand == NetMsgType::TXLOCKREQUEST) { + vRecv >> txLockRequest; + tx = txLockRequest; + nInvType = MSG_TXLOCK_REQUEST; + } else if (strCommand == NetMsgType::DSTX) { + vRecv >> dstx; + tx = dstx.tx; + nInvType = MSG_DSTX; + } + + CInv inv(nInvType, tx.GetHash()); + pfrom->AddInventoryKnown(inv); + pfrom->setAskFor.erase(inv.hash); + + // Process custom logic, no matter if tx will be accepted to mempool later or not + if (strCommand == NetMsgType::TXLOCKREQUEST) { + if(!instantsend.ProcessTxLockRequest(txLockRequest)) { + LogPrint("instantsend", "TXLOCKREQUEST -- failed %s\n", txLockRequest.GetHash().ToString()); + return false; + } + } else if (strCommand == NetMsgType::DSTX) { + uint256 hashTx = tx.GetHash(); + + if(mapDarksendBroadcastTxes.count(hashTx)) { + LogPrint("privatesend", "DSTX -- Already have %s, skipping...\n", hashTx.ToString()); + return true; // not an error + } + + CPopnode* pmn = mnodeman.Find(dstx.vin); + if(pmn == NULL) { + LogPrint("privatesend", "DSTX -- Can't find popnode %s to verify %s\n", dstx.vin.prevout.ToStringShort(), hashTx.ToString()); + return false; + } + + if(!pmn->fAllowMixingTx) { + LogPrint("privatesend", "DSTX -- Popnode %s is sending too many transactions %s\n", dstx.vin.prevout.ToStringShort(), hashTx.ToString()); + return true; + // TODO: Not an error? Could it be that someone is relaying old DSTXes + // we have no idea about (e.g we were offline)? How to handle them? + } + + if(!dstx.CheckSignature(pmn->pubKeyPopnode)) { + LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString()); + return false; + } + + LogPrintf("DSTX -- Got Popnode transaction %s\n", hashTx.ToString()); + mempool.PrioritiseTransaction(hashTx, hashTx.ToString(), 1000, 0.1*COIN); + pmn->fAllowMixingTx = false; + } + + LOCK(cs_main); + + bool fMissingInputs = false; + CValidationState state; + + mapAlreadyAskedFor.erase(inv.hash); + + if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) + { + // Process custom txes, this changes AlreadyHave to "true" + if (strCommand == NetMsgType::DSTX) { + LogPrintf("DSTX -- Popnode transaction accepted, txid=%s, peer=%d\n", + tx.GetHash().ToString(), pfrom->id); + mapDarksendBroadcastTxes.insert(make_pair(tx.GetHash(), dstx)); + } else if (strCommand == NetMsgType::TXLOCKREQUEST) { + LogPrintf("TXLOCKREQUEST -- Transaction Lock Request accepted, txid=%s, peer=%d\n", + tx.GetHash().ToString(), pfrom->id); + instantsend.AcceptLockRequest(txLockRequest); + } + + mempool.check(pcoinsTip); + RelayTransaction(tx); + vWorkQueue.push_back(inv.hash); + + LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u txn, %u kB)\n", + pfrom->id, + tx.GetHash().ToString(), + mempool.size(), mempool.DynamicMemoryUsage() / 1000); + + // Recursively process any orphan transactions that depended on this one + set setMisbehaving; + for (unsigned int i = 0; i < vWorkQueue.size(); i++) + { + map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); + if (itByPrev == mapOrphanTransactionsByPrev.end()) + continue; + for (set::iterator mi = itByPrev->second.begin(); + mi != itByPrev->second.end(); + ++mi) + { + const uint256& orphanHash = *mi; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; + NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; + bool fMissingInputs2 = false; + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan + // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get + // anyone relaying LegitTxX banned) + CValidationState stateDummy; + + + if (setMisbehaving.count(fromPeer)) + continue; + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) + { + LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); + RelayTransaction(orphanTx); + vWorkQueue.push_back(orphanHash); + vEraseQueue.push_back(orphanHash); + } + else if (!fMissingInputs2) + { + int nDos = 0; + if (stateDummy.IsInvalid(nDos) && nDos > 0) + { + // Punish peer that gave us an invalid orphan tx + Misbehaving(fromPeer, nDos); + setMisbehaving.insert(fromPeer); + LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); + } + // Has inputs but not accepted to mempool + // Probably non-standard or insufficient fee/priority + LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); + vEraseQueue.push_back(orphanHash); + assert(recentRejects); + recentRejects->insert(orphanHash); + } + mempool.check(pcoinsTip); + } + } + + BOOST_FOREACH(uint256 hash, vEraseQueue) + EraseOrphanTx(hash); + } + else if (fMissingInputs) + { + AddOrphanTx(tx, pfrom->GetId()); + + // DoS prevention: do not allow mapOrphanTransactions to grow unbounded + unsigned int nMaxOrphanTx = (unsigned int)std::max((int64_t)0, GetArg("-maxorphantx", DEFAULT_MAX_ORPHAN_TRANSACTIONS)); + unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx); + if (nEvicted > 0) + LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); + } else { + assert(recentRejects); + recentRejects->insert(tx.GetHash()); + + if (strCommand == NetMsgType::TXLOCKREQUEST && !AlreadyHave(inv)) { + // i.e. AcceptToMemoryPool failed, probably because it's conflicting + // with existing normal tx or tx lock for another tx. For the same tx lock + // AlreadyHave would have return "true" already. + + // It's the first time we failed for this tx lock request, + // this should switch AlreadyHave to "true". + instantsend.RejectLockRequest(txLockRequest); + // this lets other nodes to create lock request candidate i.e. + // this allows multiple conflicting lock requests to compete for votes + RelayTransaction(tx); + } + + if (pfrom->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { + // Always relay transactions received from whitelisted peers, even + // if they were already in the mempool or rejected from it due + // to policy, allowing the node to function as a gateway for + // nodes hidden behind it. + // + // Never relay transactions that we would assign a non-zero DoS + // score for, as we expect peers to do the same with us in that + // case. + int nDoS = 0; + if (!state.IsInvalid(nDoS) || nDoS == 0) { + LogPrintf("Force relaying tx %s from whitelisted peer=%d\n", tx.GetHash().ToString(), pfrom->id); + RelayTransaction(tx); + } else { + LogPrintf("Not relaying invalid transaction %s from whitelisted peer=%d (%s)\n", tx.GetHash().ToString(), pfrom->id, FormatStateMessage(state)); + } + } + } + + int nDoS = 0; + if (state.IsInvalid(nDoS)) + { + LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), + pfrom->id, + FormatStateMessage(state)); + if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P + pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); + if (nDoS > 0) + Misbehaving(pfrom->GetId(), nDoS); + } + FlushStateToDisk(state, FLUSH_STATE_PERIODIC); + } + + + else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing + { + std::vector headers; + + // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. + unsigned int nCount = ReadCompactSize(vRecv); + if (nCount > MAX_HEADERS_RESULTS) { + Misbehaving(pfrom->GetId(), 20); + return error("headers message size = %u", nCount); + } + headers.resize(nCount); + for (unsigned int n = 0; n < nCount; n++) { + vRecv >> headers[n]; + ReadCompactSize(vRecv); // ignore tx count; assume it is 0. + } + + LOCK(cs_main); + + if (nCount == 0) { + // Nothing interesting. Stop asking this peers for more headers. + return true; + } + + CBlockIndex *pindexLast = NULL; + + //prevent chain sync. + /*PairCheckpoints lastCheckpoint_t; + const CChainParams& chainparams_t = Params(); + if (fCheckpointsEnabled) { + lastCheckpoint_t = Checkpoints::ForceGetLastCheckpoint(chainparams_t.Checkpoints()); + }*/ + + BOOST_FOREACH(const CBlockHeader& header, headers) { + CValidationState state; + + /*if (pindexLast !=NULL && pindexLast->nHeight == lastCheckpoint_t.first && lastCheckpoint_t.first != 0){ + if (header.hashPrevBlock != lastCheckpoint_t.second){ + LogPrintf("synchronous chain hash = %s\n",header.hashPrevBlock.ToString()); + LogPrintf("lastCheckpoint height = %d, lastCheckpoint hash = %s\n",lastCheckpoint_t.first,lastCheckpoint_t.second.ToString()); + return error("prevent chain synchronization.\n"); + } + else LogPrintf("checkpoint verify correct.\n"); + }*/ + + if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { + Misbehaving(pfrom->GetId(), 20); + return error("non-continuous headers sequence"); + } + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { + int nDoS; + if (state.IsInvalid(nDoS)) { + if (nDoS > 0) + Misbehaving(pfrom->GetId(), nDoS); + std::string strError = "invalid header received " + header.GetHash().ToString(); + return error(strError.c_str()); + } + } + } + + if (pindexLast) + UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash()); + + if (nCount == MAX_HEADERS_RESULTS && pindexLast) { + // Headers message had its maximum size; the peer may have more headers. + // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue + // from there instead. + LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); + pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); + } + + bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); + CNodeState *nodestate = State(pfrom->GetId()); + // If this set of headers is valid and ends in a block with at least as + // much work as our tip, download as much as possible. + if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) { + vector vToFetch; + CBlockIndex *pindexWalk = pindexLast; + // Calculate all the blocks we'd need to switch to pindexLast, up to a limit. + while (pindexWalk && !chainActive.Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) && + !mapBlocksInFlight.count(pindexWalk->GetBlockHash())) { + // We don't have this block, and it's not yet in flight. + vToFetch.push_back(pindexWalk); + } + pindexWalk = pindexWalk->pprev; + } + // If pindexWalk still isn't on our main chain, we're looking at a + // very large reorg at a time we think we're close to caught up to + // the main chain -- this shouldn't really happen. Bail out on the + // direct fetch and rely on parallel download instead. + if (!chainActive.Contains(pindexWalk)) { + LogPrint("net", "Large reorg, won't direct fetch to %s (%d)\n", + pindexLast->GetBlockHash().ToString(), + pindexLast->nHeight); + } else { + vector vGetData; + // Download as much as possible, from earliest to latest. + BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vToFetch) { + if (nodestate->nBlocksInFlight >= MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + // Can't download any more from this peer + break; + } + vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); + MarkBlockAsInFlight(pfrom->GetId(), pindex->GetBlockHash(), chainparams.GetConsensus(), pindex); + LogPrint("net", "Requesting block %s from peer=%d\n", + pindex->GetBlockHash().ToString(), pfrom->id); + } + if (vGetData.size() > 1) { + LogPrint("net", "Downloading blocks toward %s (%d) via headers direct fetch\n", + pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); + } + if (vGetData.size() > 0) { + pfrom->PushMessage(NetMsgType::GETDATA, vGetData); + } + } + } + + CheckBlockIndex(chainparams.GetConsensus()); + } + + else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + { + CBlock block; + vRecv >> block; + + CInv inv(MSG_BLOCK, block.GetHash()); + LogPrint("net", "received block %s peer=%d\n", inv.hash.ToString(), pfrom->id); + + pfrom->AddInventoryKnown(inv); + + CValidationState state; + // Process all blocks from whitelisted peers, even if not requested, + // unless we're still syncing with the network. + // Such an unrequested block may still be processed, subject to the + // conditions in AcceptBlock(). + bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); + int nDoS; + if (state.IsInvalid(nDoS)) { + assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes + pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); + if (nDoS > 0) { + LOCK(cs_main); + Misbehaving(pfrom->GetId(), nDoS); + } + } + + } + + + else if (strCommand == NetMsgType::GETADDR) + { + // This asymmetric behavior for inbound and outbound connections was introduced + // to prevent a fingerprinting attack: an attacker can send specific fake addresses + // to users' AddrMan and later request them by sending getaddr messages. + // Making nodes which are behind NAT and can only make outgoing connections ignore + // the getaddr message mitigates the attack. + if (!pfrom->fInbound) { + LogPrint("net", "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom->id); + return true; + } + + pfrom->vAddrToSend.clear(); + vector vAddr = addrman.GetAddr(); + BOOST_FOREACH(const CAddress &addr, vAddr) + pfrom->PushAddress(addr); + } + + + else if (strCommand == NetMsgType::MEMPOOL) + { + if (CNode::OutboundTargetReached(false) && !pfrom->fWhitelisted) + { + LogPrint("net", "mempool request with bandwidth limit reached, disconnect peer=%d\n", pfrom->GetId()); + pfrom->fDisconnect = true; + return true; + } + LOCK2(cs_main, pfrom->cs_filter); + + std::vector vtxid; + mempool.queryHashes(vtxid); + vector vInv; + BOOST_FOREACH(uint256& hash, vtxid) { + CInv inv(MSG_TX, hash); + if (pfrom->pfilter) { + CTransaction tx; + bool fInMemPool = mempool.lookup(hash, tx); + if (!fInMemPool) continue; // another thread removed since queryHashes, maybe... + if (!pfrom->pfilter->IsRelevantAndUpdate(tx)) continue; + } + vInv.push_back(inv); + if (vInv.size() == MAX_INV_SZ) { + pfrom->PushMessage(NetMsgType::INV, vInv); + vInv.clear(); + } + } + if (vInv.size() > 0) + pfrom->PushMessage(NetMsgType::INV, vInv); + } + + + else if (strCommand == NetMsgType::PING) + { + if (pfrom->nVersion > BIP0031_VERSION) + { + uint64_t nonce = 0; + vRecv >> nonce; + // Echo the message back with the nonce. This allows for two useful features: + // + // 1) A remote node can quickly check if the connection is operational + // 2) Remote nodes can measure the latency of the network thread. If this node + // is overloaded it won't respond to pings quickly and the remote node can + // avoid sending us more work, like chain download requests. + // + // The nonce stops the remote getting confused between different pings: without + // it, if the remote node sends a ping once per second and this node takes 5 + // seconds to respond to each, the 5th ping the remote sends would appear to + // return very quickly. + pfrom->PushMessage(NetMsgType::PONG, nonce); + } + } + + + else if (strCommand == NetMsgType::PONG) + { + int64_t pingUsecEnd = nTimeReceived; + uint64_t nonce = 0; + size_t nAvail = vRecv.in_avail(); + bool bPingFinished = false; + std::string sProblem; + + if (nAvail >= sizeof(nonce)) { + vRecv >> nonce; + + // Only process pong message if there is an outstanding ping (old ping without nonce should never pong) + if (pfrom->nPingNonceSent != 0) { + if (nonce == pfrom->nPingNonceSent) { + // Matching pong received, this ping is no longer outstanding + bPingFinished = true; + int64_t pingUsecTime = pingUsecEnd - pfrom->nPingUsecStart; + if (pingUsecTime > 0) { + // Successful ping time measurement, replace previous + pfrom->nPingUsecTime = pingUsecTime; + pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); + } else { + // This should never happen + sProblem = "Timing mishap"; + } + } else { + // Nonce mismatches are normal when pings are overlapping + sProblem = "Nonce mismatch"; + if (nonce == 0) { + // This is most likely a bug in another implementation somewhere; cancel this ping + bPingFinished = true; + sProblem = "Nonce zero"; + } + } + } else { + sProblem = "Unsolicited pong without ping"; + } + } else { + // This is most likely a bug in another implementation somewhere; cancel this ping + bPingFinished = true; + sProblem = "Short payload"; + } + + if (!(sProblem.empty())) { + LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n", + pfrom->id, + sProblem, + pfrom->nPingNonceSent, + nonce, + nAvail); + } + if (bPingFinished) { + pfrom->nPingNonceSent = 0; + } + } + + + else if (fAlerts && strCommand == NetMsgType::ALERT) + { + CAlert alert; + vRecv >> alert; + + uint256 alertHash = alert.GetHash(); + if (pfrom->setKnown.count(alertHash) == 0) + { + if (alert.ProcessAlert(chainparams.AlertKey())) + { + // Relay + pfrom->setKnown.insert(alertHash); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + alert.RelayTo(pnode); + } + } + else { + // Small DoS penalty so peers that send us lots of + // duplicate/expired/invalid-signature/whatever alerts + // eventually get banned. + // This isn't a Misbehaving(100) (immediate ban) because the + // peer might be an older or different implementation with + // a different signature key, etc. + Misbehaving(pfrom->GetId(), 10); + } + } + } + + + else if (strCommand == NetMsgType::FILTERLOAD) + { + CBloomFilter filter; + vRecv >> filter; + + if (!filter.IsWithinSizeConstraints()) + // There is no excuse for sending a too-large filter + Misbehaving(pfrom->GetId(), 100); + else + { + LOCK(pfrom->cs_filter); + delete pfrom->pfilter; + pfrom->pfilter = new CBloomFilter(filter); + pfrom->pfilter->UpdateEmptyFull(); + } + pfrom->fRelayTxes = true; + } + + + else if (strCommand == NetMsgType::FILTERADD) + { + vector vData; + vRecv >> vData; + + // Nodes must NEVER send a data item > 520 bytes (the max size for a script data object, + // and thus, the maximum size any matched object can have) in a filteradd message + if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) + { + Misbehaving(pfrom->GetId(), 100); + } else { + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) + pfrom->pfilter->insert(vData); + else + Misbehaving(pfrom->GetId(), 100); + } + } + + + else if (strCommand == NetMsgType::FILTERCLEAR) + { + LOCK(pfrom->cs_filter); + delete pfrom->pfilter; + pfrom->pfilter = new CBloomFilter(); + pfrom->fRelayTxes = true; + } + + + else if (strCommand == NetMsgType::REJECT) + { + if (fDebug) { + try { + string strMsg; unsigned char ccode; string strReason; + vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, MAX_REJECT_MESSAGE_LENGTH); + + ostringstream ss; + ss << strMsg << " code " << itostr(ccode) << ": " << strReason; + + if (strMsg == NetMsgType::BLOCK || strMsg == NetMsgType::TX) + { + uint256 hash; + vRecv >> hash; + ss << ": hash " << hash.ToString(); + } + LogPrint("net", "Reject %s\n", SanitizeString(ss.str())); + } catch (const std::ios_base::failure&) { + // Avoid feedback loops by preventing reject messages from triggering a new reject message. + LogPrint("net", "Unparseable reject message received\n"); + } + } + } + else + { + bool found = false; + const std::vector &allMessages = getAllNetMessageTypes(); + BOOST_FOREACH(const std::string msg, allMessages) { + if(msg == strCommand) { + found = true; + break; + } + } + + if (found) + { + //probably one the extensions + darkSendPool.ProcessMessage(pfrom, strCommand, vRecv); + mnodeman.ProcessMessage(pfrom, strCommand, vRecv); + instantsend.ProcessMessage(pfrom, strCommand, vRecv); + sporkManager.ProcessSpork(pfrom, strCommand, vRecv); + popnodeSync.ProcessMessage(pfrom, strCommand, vRecv); + } + else + { + // Ignore unknown commands for extensibility + LogPrint("net", "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->id); + } + } + + return true; +} + +// requires LOCK(cs_vRecvMsg) +bool ProcessMessages(CNode* pfrom) +{ + const CChainParams& chainparams = Params(); + //if (fDebug) + // LogPrintf("%s(%u messages)\n", __func__, pfrom->vRecvMsg.size()); + + // + // Message format + // (4) message start + // (12) command + // (4) size + // (4) checksum + // (x) data + // + bool fOk = true; + + if (!pfrom->vRecvGetData.empty()) + ProcessGetData(pfrom, chainparams.GetConsensus()); + + // this maintains the order of responses + if (!pfrom->vRecvGetData.empty()) return fOk; + + std::deque::iterator it = pfrom->vRecvMsg.begin(); + while (!pfrom->fDisconnect && it != pfrom->vRecvMsg.end()) { + // Don't bother if send buffer is too full to respond anyway + if (pfrom->nSendSize >= SendBufferSize()) + break; + + // get next message + CNetMessage& msg = *it; + + //if (fDebug) + // LogPrintf("%s(message %u msgsz, %u bytes, complete:%s)\n", __func__, + // msg.hdr.nMessageSize, msg.vRecv.size(), + // msg.complete() ? "Y" : "N"); + + // end, if an incomplete message is found + if (!msg.complete()) + break; + + // at this point, any failure means we can delete the current message + it++; + + // Scan for message start + if (memcmp(msg.hdr.pchMessageStart, chainparams.MessageStart(), MESSAGE_START_SIZE) != 0) { + LogPrintf("PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.hdr.GetCommand()), pfrom->id); + fOk = false; + break; + } + + // Read header + CMessageHeader& hdr = msg.hdr; + if (!hdr.IsValid(chainparams.MessageStart())) + { + LogPrintf("PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(hdr.GetCommand()), pfrom->id); + continue; + } + string strCommand = hdr.GetCommand(); + + // Message size + unsigned int nMessageSize = hdr.nMessageSize; + + // Checksum + CDataStream& vRecv = msg.vRecv; + uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); + unsigned int nChecksum = ReadLE32((unsigned char*)&hash); + if (nChecksum != hdr.nChecksum) + { + LogPrintf("%s(%s, %u bytes): CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n", __func__, + SanitizeString(strCommand), nMessageSize, nChecksum, hdr.nChecksum); + continue; + } + + // Process message + bool fRet = false; + try + { + fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime); + boost::this_thread::interruption_point(); + } + catch (const std::ios_base::failure& e) + { + pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); + if (strstr(e.what(), "end of data")) + { + // Allow exceptions from under-length message on vRecv + LogPrintf("%s(%s, %u bytes): Exception '%s' caught, normally caused by a message being shorter than its stated length\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); + } + else if (strstr(e.what(), "size too large")) + { + // Allow exceptions from over-long size + LogPrintf("%s(%s, %u bytes): Exception '%s' caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what()); + } + else + { + PrintExceptionContinue(&e, "ProcessMessages()"); + } + } + catch (const boost::thread_interrupted&) { + throw; + } + catch (const std::exception& e) { + PrintExceptionContinue(&e, "ProcessMessages()"); + } catch (...) { + PrintExceptionContinue(NULL, "ProcessMessages()"); + } + + if (!fRet) + LogPrintf("%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->id); + + break; + } + + // In case the connection got shut down, its receive buffer was wiped + if (!pfrom->fDisconnect) + pfrom->vRecvMsg.erase(pfrom->vRecvMsg.begin(), it); + + return fOk; +} + + +bool SendMessages(CNode* pto) +{ + const Consensus::Params& consensusParams = Params().GetConsensus(); + { + // Don't send anything until we get its version message + if (pto->nVersion == 0) + return true; + + // + // Message: ping + // + bool pingSend = false; + if (pto->fPingQueued) { + // RPC ping request by user + pingSend = true; + } + if (pto->nPingNonceSent == 0 && pto->nPingUsecStart + PING_INTERVAL * 1000000 < GetTimeMicros()) { + // Ping automatically sent as a latency probe & keepalive. + pingSend = true; + } + if (pingSend) { + uint64_t nonce = 0; + while (nonce == 0) { + GetRandBytes((unsigned char*)&nonce, sizeof(nonce)); + } + pto->fPingQueued = false; + pto->nPingUsecStart = GetTimeMicros(); + if (pto->nVersion > BIP0031_VERSION) { + pto->nPingNonceSent = nonce; + pto->PushMessage(NetMsgType::PING, nonce); + } else { + // Peer is too old to support ping command with nonce, pong will never arrive. + pto->nPingNonceSent = 0; + pto->PushMessage(NetMsgType::PING); + } + } + + TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState() + if (!lockMain) + return true; + + // Address refresh broadcast + int64_t nNow = GetTimeMicros(); + if (!IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) { + AdvertiseLocal(pto); + pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); + } + + // + // Message: addr + // + if (pto->nNextAddrSend < nNow) { + pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL); + vector vAddr; + vAddr.reserve(pto->vAddrToSend.size()); + BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend) + { + if (!pto->addrKnown.contains(addr.GetKey())) + { + pto->addrKnown.insert(addr.GetKey()); + vAddr.push_back(addr); + // receiver rejects addr messages larger than 1000 + if (vAddr.size() >= 1000) + { + pto->PushMessage(NetMsgType::ADDR, vAddr); + vAddr.clear(); + } + } + } + pto->vAddrToSend.clear(); + if (!vAddr.empty()) + pto->PushMessage(NetMsgType::ADDR, vAddr); + } + + CNodeState &state = *State(pto->GetId()); + if (state.fShouldBan) { + if (pto->fWhitelisted) + LogPrintf("Warning: not punishing whitelisted peer %s!\n", pto->addr.ToString()); + else { + pto->fDisconnect = true; + if (pto->addr.IsLocal()) + LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString()); + else + { + CNode::Ban(pto->addr, BanReasonNodeMisbehaving); + } + } + state.fShouldBan = false; + } + + BOOST_FOREACH(const CBlockReject& reject, state.rejects) + pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); + state.rejects.clear(); + + // Start block sync + if (pindexBestHeader == NULL) + pindexBestHeader = chainActive.Tip(); + bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. + if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { + // Only actively request headers from a single peer, unless we're close to end of initial download. + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 6 * 60 * 60) { // NOTE: was "close to today" and 24h in Bitcoin + state.fSyncStarted = true; + nSyncStarted++; + const CBlockIndex *pindexStart = pindexBestHeader; + /* If possible, start at the block preceding the currently + best known header. This ensures that we always get a + non-empty list of headers back as long as the peer + is up-to-date. With a non-empty response, we can initialise + the peer's known best block. This wouldn't be possible + if we requested starting at pindexBestHeader and + got back an empty response. */ + if (pindexStart->pprev) + pindexStart = pindexStart->pprev; + LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); + pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); + } + } + + // Resend wallet transactions that haven't gotten in a block yet + // Except during reindex, importing and IBD, when old wallet + // transactions become unconfirmed and spams other nodes. + if (!fReindex && !fImporting && !IsInitialBlockDownload()) + { + GetMainSignals().Broadcast(nTimeBestReceived); + } + + // + // Try sending block announcements via headers + // + { + // If we have less than MAX_BLOCKS_TO_ANNOUNCE in our + // list of block hashes we're relaying, and our peer wants + // headers announcements, then find the first header + // not yet known to our peer but would connect, and send. + // If no header would connect, or if we have too many + // blocks, or if the peer doesn't want headers, just + // add all to the inv queue. + LOCK(pto->cs_inventory); + vector vHeaders; + bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE); + CBlockIndex *pBestIndex = NULL; // last header queued for delivery + ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date + + if (!fRevertToInv) { + bool fFoundStartingHeader = false; + // Try to find first header that our peer doesn't have, and + // then send all headers past that one. If we come across any + // headers that aren't on chainActive, give up. + BOOST_FOREACH(const uint256 &hash, pto->vBlockHashesToAnnounce) { + BlockMap::iterator mi = mapBlockIndex.find(hash); + assert(mi != mapBlockIndex.end()); + CBlockIndex *pindex = mi->second; + if (chainActive[pindex->nHeight] != pindex) { + // Bail out if we reorged away from this block + fRevertToInv = true; + break; + } + if (pBestIndex != NULL && pindex->pprev != pBestIndex) { + // This means that the list of blocks to announce don't + // connect to each other. + // This shouldn't really be possible to hit during + // regular operation (because reorgs should take us to + // a chain that has some block not on the prior chain, + // which should be caught by the prior check), but one + // way this could happen is by using invalidateblock / + // reconsiderblock repeatedly on the tip, causing it to + // be added multiple times to vBlockHashesToAnnounce. + // Robustly deal with this rare situation by reverting + // to an inv. + fRevertToInv = true; + break; + } + pBestIndex = pindex; + if (fFoundStartingHeader) { + // add this to the headers message + vHeaders.push_back(pindex->GetBlockHeader()); + } else if (PeerHasHeader(&state, pindex)) { + continue; // keep looking for the first new block + } else if (pindex->pprev == NULL || PeerHasHeader(&state, pindex->pprev)) { + // Peer doesn't have this header but they do have the prior one. + // Start sending headers. + fFoundStartingHeader = true; + vHeaders.push_back(pindex->GetBlockHeader()); + } else { + // Peer doesn't have this header or the prior one -- nothing will + // connect, so bail out. + fRevertToInv = true; + break; + } + } + } + if (fRevertToInv) { + // If falling back to using an inv, just try to inv the tip. + // The last entry in vBlockHashesToAnnounce was our tip at some point + // in the past. + if (!pto->vBlockHashesToAnnounce.empty()) { + const uint256 &hashToAnnounce = pto->vBlockHashesToAnnounce.back(); + BlockMap::iterator mi = mapBlockIndex.find(hashToAnnounce); + assert(mi != mapBlockIndex.end()); + CBlockIndex *pindex = mi->second; + + // Warn if we're announcing a block that is not on the main chain. + // This should be very rare and could be optimized out. + // Just log for now. + if (chainActive[pindex->nHeight] != pindex) { + LogPrint("net", "Announcing block %s not on main chain (tip=%s)\n", + hashToAnnounce.ToString(), chainActive.Tip()->GetBlockHash().ToString()); + } + + // If the peer announced this block to us, don't inv it back. + // (Since block announcements may not be via inv's, we can't solely rely on + // setInventoryKnown to track this.) + if (!PeerHasHeader(&state, pindex)) { + pto->PushInventory(CInv(MSG_BLOCK, hashToAnnounce)); + LogPrint("net", "%s: sending inv peer=%d hash=%s\n", __func__, + pto->id, hashToAnnounce.ToString()); + } + } + } else if (!vHeaders.empty()) { + if (vHeaders.size() > 1) { + LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__, + vHeaders.size(), + vHeaders.front().GetHash().ToString(), + vHeaders.back().GetHash().ToString(), pto->id); + } else { + LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, + vHeaders.front().GetHash().ToString(), pto->id); + } + pto->PushMessage(NetMsgType::HEADERS, vHeaders); + state.pindexBestHeaderSent = pBestIndex; + } + pto->vBlockHashesToAnnounce.clear(); + } + + // + // Message: inventory + // + vector vInv; + vector vInvWait; + { + bool fSendTrickle = pto->fWhitelisted; + if (pto->nNextInvSend < nNow) { + fSendTrickle = true; + pto->nNextInvSend = PoissonNextSend(nNow, AVG_INVENTORY_BROADCAST_INTERVAL); + } + LOCK(pto->cs_inventory); + vInv.reserve(std::min(1000, pto->vInventoryToSend.size())); + vInvWait.reserve(pto->vInventoryToSend.size()); + BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) + { + if (inv.type == MSG_TX && pto->filterInventoryKnown.contains(inv.hash)) + continue; + + // trickle out tx inv to protect privacy + if (inv.type == MSG_TX && !fSendTrickle) + { + // 1/4 of tx invs blast to all immediately + static uint256 hashSalt; + if (hashSalt.IsNull()) + hashSalt = GetRandHash(); + uint256 hashRand = ArithToUint256(UintToArith256(inv.hash) ^ UintToArith256(hashSalt)); + hashRand = Hash(BEGIN(hashRand), END(hashRand)); + bool fTrickleWait = ((UintToArith256(hashRand) & 3) != 0); + + if (fTrickleWait) + { + LogPrint("net", "SendMessages -- queued inv(vInvWait): %s index=%d peer=%d\n", inv.ToString(), vInvWait.size(), pto->id); + vInvWait.push_back(inv); + continue; + } + } + + pto->filterInventoryKnown.insert(inv.hash); + + LogPrint("net", "SendMessages -- queued inv: %s index=%d peer=%d\n", inv.ToString(), vInv.size(), pto->id); + vInv.push_back(inv); + if (vInv.size() >= 1000) + { + LogPrint("net", "SendMessages -- pushing inv's: count=%d peer=%d\n", vInv.size(), pto->id); + pto->PushMessage(NetMsgType::INV, vInv); + vInv.clear(); + } + } + pto->vInventoryToSend = vInvWait; + } + if (!vInv.empty()) { + LogPrint("net", "SendMessages -- pushing tailing inv's: count=%d peer=%d\n", vInv.size(), pto->id); + pto->PushMessage(NetMsgType::INV, vInv); + } + + // Detect whether we're stalling + nNow = GetTimeMicros(); + if (!pto->fDisconnect && state.nStallingSince && state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { + // Stalling only triggers when the block download window cannot move. During normal steady state, + // the download window should be much larger than the to-be-downloaded set of blocks, so disconnection + // should only happen during initial block download. + LogPrintf("Peer=%d is stalling block download, disconnecting\n", pto->id); + pto->fDisconnect = true; + } + // In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval + // (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout. + // We compensate for other peers to prevent killing off peers due to our own downstream link + // being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes + // to unreasonably increase our timeout. + if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { + QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); + int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); + if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { + LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); + pto->fDisconnect = true; + } + } + + // + // Message: getdata (blocks) + // + vector vGetData; + if (!pto->fDisconnect && !pto->fClient && (fFetch || !IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + vector vToDownload; + NodeId staller = -1; + FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); + BOOST_FOREACH(CBlockIndex *pindex, vToDownload) { + vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash())); + MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex); + LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(), + pindex->nHeight, pto->id); + } + if (state.nBlocksInFlight == 0 && staller != -1) { + if (State(staller)->nStallingSince == 0) { + State(staller)->nStallingSince = nNow; + LogPrint("net", "Stall started peer=%d\n", staller); + } + } + } + + // + // Message: getdata (non-blocks) + // + int64_t nFirst = -1; + if(!pto->mapAskFor.empty()) { + nFirst = (*pto->mapAskFor.begin()).first; + } + LogPrint("net", "SendMessages (mapAskFor) -- before loop: nNow = %d, nFirst = %d\n", nNow, nFirst); + while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow) + { + const CInv& inv = (*pto->mapAskFor.begin()).second; + LogPrint("net", "SendMessages (mapAskFor) -- inv = %s peer=%d\n", inv.ToString(), pto->id); + if (!AlreadyHave(inv)) + { + if (fDebug) + LogPrint("net", "Requesting %s peer=%d\n", inv.ToString(), pto->id); + vGetData.push_back(inv); + if (vGetData.size() >= 1000) + { + pto->PushMessage(NetMsgType::GETDATA, vGetData); + vGetData.clear(); + } + } else { + //If we're not going to ask, don't expect a response. + LogPrint("net", "SendMessages -- already have inv = %s peer=%d\n", inv.ToString(), pto->id); + pto->setAskFor.erase(inv.hash); + } + pto->mapAskFor.erase(pto->mapAskFor.begin()); + } + if (!vGetData.empty()) + pto->PushMessage(NetMsgType::GETDATA, vGetData); + + } + return true; +} + + std::string CBlockFileInfo::ToString() const { + return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); + } + +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos) +{ + LOCK(cs_main); + return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); +} + +class CMainCleanup +{ +public: + CMainCleanup() {} + ~CMainCleanup() { + // block headers + BlockMap::iterator it1 = mapBlockIndex.begin(); + for (; it1 != mapBlockIndex.end(); it1++) + delete (*it1).second; + mapBlockIndex.clear(); + + // orphan transactions + mapOrphanTransactions.clear(); + mapOrphanTransactionsByPrev.clear(); + } +} instance_of_cmaincleanup; From 976c6836a63cb771361c0f7a61bb70154c449ed3 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 25 Jul 2018 20:15:20 +0800 Subject: [PATCH 007/120] add the return of uncle headers check --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 2e0cfd1..e0f88ca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4101,6 +4101,7 @@ static bool AcceptBlockHeader(const CBlock & block, CValidationState& state, con { return false; } + return true; } /*popchain ghost*/ From f89b38f33eb38b172728a8895aa5b1520dfd75e9 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 26 Jul 2018 16:21:38 +0800 Subject: [PATCH 008/120] change name of uncles header check --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index e0f88ca..3cd5b34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4062,7 +4062,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } /*popchain ghost*/ -static bool AcceptBlockHeader(const CBlock & block, CValidationState& state, const CChainParams& chainparams) +static bool AcceptUnclesHeader(const CBlock & block, CValidationState& state, const CChainParams& chainparams) { std::vector blockHeaders = block.vuh; From ccd76930c14815723b03b1e1947fddfefd52559d Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 28 Jul 2018 09:43:50 +0800 Subject: [PATCH 009/120] change the the td work of levelDB --- src/main.h | 1773 +++++++++++++++++++++++++------------------------- src/txdb.cpp | 21 +- src/txdb.h | 13 +- 3 files changed, 926 insertions(+), 881 deletions(-) diff --git a/src/main.h b/src/main.h index bc8b648..b961a13 100644 --- a/src/main.h +++ b/src/main.h @@ -1,870 +1,903 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#ifndef BITCOIN_MAIN_H -#define BITCOIN_MAIN_H - - -#if defined(HAVE_CONFIG_H) -#include "config/pop-config.h" -#endif - -#include "amount.h" -#include "chain.h" -#include "coins.h" -#include "net.h" -#include "claimtrie.h" -#include "script/script_error.h" -#include "sync.h" -#include "versionbits.h" -#include "spentindex.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -class CBlockIndex; -class CBlockTreeDB; -class CBloomFilter; -class CChainParams; -class CInv; -class CScriptCheck; -class CTxMemPool; -class CValidationInterface; -class CValidationState; - -struct CNodeStateStats; -struct LockPoints; - -/** Default for accepting alerts from the P2P network. */ -static const bool DEFAULT_ALERTS = false; -/** Default for DEFAULT_WHITELISTRELAY. */ -static const bool DEFAULT_WHITELISTRELAY = true; -/** Default for DEFAULT_WHITELISTFORCERELAY. */ -static const bool DEFAULT_WHITELISTFORCERELAY = true; -/** Default for -minrelaytxfee, minimum relay fee for transactions - * We are ~100 times smaller then bitcoin now (2016-03-01), set minRelayTxFee only 10 times higher - * so it's still 10 times lower comparing to bitcoin. - */ -static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 10000; // was 1000 -/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ -static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; -/** Default for -limitancestorcount, max number of in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; -/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ -static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101; -/** Default for -limitdescendantcount, max number of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; -/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ -static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; -/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ -static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72; -/** The maximum size of a blk?????.dat file (since 0.8) */ -static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB -/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ -static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB -/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ -static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB - -/** Maximum number of script-checking threads allowed */ -static const int MAX_SCRIPTCHECK_THREADS = 16; -/** -par default (number of script-checking threads, 0 = auto) */ -static const int DEFAULT_SCRIPTCHECK_THREADS = 0; -/** Number of blocks that can be requested at any given time from a single peer. */ -static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; -/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */ -static const unsigned int BLOCK_STALLING_TIMEOUT = 2; -/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends - * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ -static const unsigned int MAX_HEADERS_RESULTS = 2000; -/** Size of the "block download window": how far ahead of our current height do we fetch? - * Larger windows tolerate larger download speed differences between peer, but increase the potential - * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning - * harder). We'll probably want to make this a per-peer adaptive value at some point. */ -static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024; -/** Time to wait (in seconds) between writing blocks/block index to disk. */ -static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; -/** Time to wait (in seconds) between flushing chainstate to disk. */ -static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; -/** Maximum length of reject messages. */ -static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; -/** Average delay between local address broadcasts in seconds. */ -static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60; -/** Average delay between peer address broadcasts in seconds. */ -static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; -/** Average delay between trickled inventory broadcasts in seconds. - * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */ -static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; -/** Block download timeout base, expressed in millionths of the block interval (i.e. 2.5 min) */ -static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000; -/** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */ -static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 125000; - -static const unsigned int DEFAULT_LIMITFREERELAY = 15; -static const bool DEFAULT_RELAYPRIORITY = true; - -/** Default for -permitbaremultisig */ -static const bool DEFAULT_PERMIT_BAREMULTISIG = true; -static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; -static const bool DEFAULT_CHECKPOINTS_ENABLED = true; -static const bool DEFAULT_TXINDEX = true; -static const bool DEFAULT_ADDRESSINDEX = false; -static const bool DEFAULT_TIMESTAMPINDEX = false; -static const bool DEFAULT_SPENTINDEX = false; -static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; - -static const bool DEFAULT_TESTSAFEMODE = false; -/** Default for -mempoolreplacement */ -static const bool DEFAULT_ENABLE_REPLACEMENT = false; - -/** Maximum number of headers to announce when relaying blocks with headers message.*/ -static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; - -struct BlockHasher -{ - size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } -}; - -extern CScript COINBASE_FLAGS; -extern CCriticalSection cs_main; -extern CTxMemPool mempool; -typedef boost::unordered_map BlockMap; -extern BlockMap mapBlockIndex; -extern uint64_t nLastBlockTx; -extern uint64_t nLastBlockSize; -extern const std::string strMessageMagic; -extern CWaitableCriticalSection csBestBlock; -extern CConditionVariable cvBlockChange; -extern bool fImporting; -extern bool fReindex; -extern int nScriptCheckThreads; -extern bool fTxIndex; -extern bool fIsBareMultisigStd; -extern bool fRequireStandard; -extern unsigned int nBytesPerSigOp; -extern bool fCheckBlockIndex; -extern bool fCheckpointsEnabled; -extern size_t nCoinCacheUsage; -extern CFeeRate minRelayTxFee; -extern bool fAlerts; -extern bool fEnableReplacement; - -extern std::map mapRejectedBlocks; - -/** Best header we've seen so far (used for getheaders queries' starting points). */ -extern CBlockIndex *pindexBestHeader; - -/** Minimum disk space required - used in CheckDiskSpace() */ -static const uint64_t nMinDiskSpace = 52428800; - -/** Pruning-related variables and constants */ -/** True if any block files have ever been pruned. */ -extern bool fHavePruned; -/** True if we're running in -prune mode. */ -extern bool fPruneMode; -/** Number of MiB of block files that we're trying to stay below. */ -extern uint64_t nPruneTarget; -/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ -static const unsigned int MIN_BLOCKS_TO_KEEP = 288; - -static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP; -static const unsigned int DEFAULT_CHECKLEVEL = 3; - -// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) -// At 1MB per block, 288 blocks = 288MB. -// Add 15% for Undo data = 331MB -// Add 20% for Orphan block rate = 397MB -// We want the low water mark after pruning to be at least 397 MB and since we prune in -// full block file chunks, we need the high water mark which triggers the prune to be -// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB -// Setting the target to > than 550MB will make it likely we can respect the target. -static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; - -/** Register with a network node to receive its signals */ -void RegisterNodeSignals(CNodeSignals& nodeSignals); -/** Unregister a network node */ -void UnregisterNodeSignals(CNodeSignals& nodeSignals); - -/** - * Process an incoming block. This only returns after the best known valid - * block is made active. Note that it does not, however, guarantee that the - * specific block passed to it has been checked for validity! - * - * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation. - * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. - * @param[in] pblock The block we want to process. - * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. - * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. - * @return True if state.IsValid() - */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); -/** Check whether enough disk space is available for an incoming block */ -bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); -/** Open a block file (blk?????.dat) */ -FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); -/** Open an undo file (rev?????.dat) */ -FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); -/** Translation to a filesystem path */ -boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix); -/** Import blocks from an external file */ -bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); -/** Initialize a new block tree database + block data on disk */ -bool InitBlockIndex(const CChainParams& chainparams); -/** Load the block tree and coins database from disk */ -bool LoadBlockIndex(); -/** Unload database information */ -void UnloadBlockIndex(); -/** Process protocol messages received from a given node */ -bool ProcessMessages(CNode* pfrom); -/** - * Send queued protocol messages to be sent to a give node. - * - * @param[in] pto The node which we are sending messages to. - */ -bool SendMessages(CNode* pto); -/** Run an instance of the script checking thread */ -void ThreadScriptCheck(); - -/** Try to detect Partition (network isolation) attacks against us */ -void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); -/** Check whether we are doing an initial block download (synchronizing from disk or network) */ -bool IsInitialBlockDownload(); -/** Format a string that describes several potential problems detected by the core. - * strFor can have three values: - * - "rpc": get critical warnings, which should put the client in safe mode if non-empty - * - "statusbar": get all warnings - * - "gui": get all warnings, translated (where possible) for GUI - * This function only returns the highest priority warning of the set selected by strFor. - */ -std::string GetWarnings(const std::string& strFor); - -/** Get a cryptographic proof that a name maps to a value **/ -bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof); - -/** Retrieve a transaction (from memory pool, or from disk, if possible) */ -bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); -/** Find the best known block, and make it the tip of the block chain */ -bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); - -CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp); -CAmount GetFoundersReward(const int height, const Consensus::Params &cp); -CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp); - -/** - * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. - * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new - * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex - * (which in this case means the blockchain must be re-downloaded.) - * - * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. - * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) - * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). - * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. - * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. - * A db flag records the fact that at least some block files have been pruned. - * - * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned - */ -void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight); - -/** - * Actually unlink the specified files - */ -void UnlinkPrunedFiles(std::set& setFilesToPrune); - -/** Create a new block index entry for a given block hash */ -CBlockIndex * InsertBlockIndex(uint256 hash); -/** Get statistics from node state */ -bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); -/** Increase a node's misbehavior score. */ -void Misbehaving(NodeId nodeid, int howmuch); -/** Flush all state, indexes and buffers to disk. */ -void FlushStateToDisk(); -/** Prune block files and flush state to disk. */ -void PruneAndFlush(); - -/** (try to) add transaction to memory pool **/ -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false, bool fDryRun=false); - -int GetUTXOHeight(const COutPoint& outpoint); -int GetInputAge(const CTxIn &txin); -int GetInputAgeIX(const uint256 &nTXHash, const CTxIn &txin); -int GetIXConfirmations(const uint256 &nTXHash); - -/** Convert CValidationState to a human-readable message for logging */ -std::string FormatStateMessage(const CValidationState &state); - -/** Get the BIP9 state for a given deployment at the current tip. */ -ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); - -struct CNodeStateStats { - int nMisbehavior; - int nSyncHeight; - int nCommonHeight; - std::vector vHeightInFlight; -}; - -struct CTimestampIndexIteratorKey { - unsigned int timestamp; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 4; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata32be(s, timestamp); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - timestamp = ser_readdata32be(s); - } - - CTimestampIndexIteratorKey(unsigned int time) { - timestamp = time; - } - - CTimestampIndexIteratorKey() { - SetNull(); - } - - void SetNull() { - timestamp = 0; - } -}; - -struct CTimestampIndexKey { - unsigned int timestamp; - uint256 blockHash; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 36; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata32be(s, timestamp); - blockHash.Serialize(s, nType, nVersion); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - timestamp = ser_readdata32be(s); - blockHash.Unserialize(s, nType, nVersion); - } - - CTimestampIndexKey(unsigned int time, uint256 hash) { - timestamp = time; - blockHash = hash; - } - - CTimestampIndexKey() { - SetNull(); - } - - void SetNull() { - timestamp = 0; - blockHash.SetNull(); - } -}; - -struct CAddressUnspentKey { - unsigned int type; - uint160 hashBytes; - uint256 txhash; - size_t index; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 57; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata8(s, type); - hashBytes.Serialize(s, nType, nVersion); - txhash.Serialize(s, nType, nVersion); - ser_writedata32(s, index); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - type = ser_readdata8(s); - hashBytes.Unserialize(s, nType, nVersion); - txhash.Unserialize(s, nType, nVersion); - index = ser_readdata32(s); - } - - CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) { - type = addressType; - hashBytes = addressHash; - txhash = txid; - index = indexValue; - } - - CAddressUnspentKey() { - SetNull(); - } - - void SetNull() { - type = 0; - hashBytes.SetNull(); - txhash.SetNull(); - index = 0; - } -}; - -struct CAddressUnspentValue { - CAmount satoshis; - CScript script; - int blockHeight; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(satoshis); - READWRITE(*(CScriptBase*)(&script)); - READWRITE(blockHeight); - } - - CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) { - satoshis = sats; - script = scriptPubKey; - blockHeight = height; - } - - CAddressUnspentValue() { - SetNull(); - } - - void SetNull() { - satoshis = -1; - script.clear(); - blockHeight = 0; - } - - bool IsNull() const { - return (satoshis == -1); - } -}; - -struct CAddressIndexKey { - unsigned int type; - uint160 hashBytes; - int blockHeight; - unsigned int txindex; - uint256 txhash; - size_t index; - bool spending; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 66; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata8(s, type); - hashBytes.Serialize(s, nType, nVersion); - // Heights are stored big-endian for key sorting in LevelDB - ser_writedata32be(s, blockHeight); - ser_writedata32be(s, txindex); - txhash.Serialize(s, nType, nVersion); - ser_writedata32(s, index); - char f = spending; - ser_writedata8(s, f); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - type = ser_readdata8(s); - hashBytes.Unserialize(s, nType, nVersion); - blockHeight = ser_readdata32be(s); - txindex = ser_readdata32be(s); - txhash.Unserialize(s, nType, nVersion); - index = ser_readdata32(s); - char f = ser_readdata8(s); - spending = f; - } - - CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex, - uint256 txid, size_t indexValue, bool isSpending) { - type = addressType; - hashBytes = addressHash; - blockHeight = height; - txindex = blockindex; - txhash = txid; - index = indexValue; - spending = isSpending; - } - - CAddressIndexKey() { - SetNull(); - } - - void SetNull() { - type = 0; - hashBytes.SetNull(); - blockHeight = 0; - txindex = 0; - txhash.SetNull(); - index = 0; - spending = false; - } - -}; - -struct CAddressIndexIteratorKey { - unsigned int type; - uint160 hashBytes; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 21; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata8(s, type); - hashBytes.Serialize(s, nType, nVersion); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - type = ser_readdata8(s); - hashBytes.Unserialize(s, nType, nVersion); - } - - CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) { - type = addressType; - hashBytes = addressHash; - } - - CAddressIndexIteratorKey() { - SetNull(); - } - - void SetNull() { - type = 0; - hashBytes.SetNull(); - } -}; - -struct CAddressIndexIteratorHeightKey { - unsigned int type; - uint160 hashBytes; - int blockHeight; - - size_t GetSerializeSize(int nType, int nVersion) const { - return 25; - } - template - void Serialize(Stream& s, int nType, int nVersion) const { - ser_writedata8(s, type); - hashBytes.Serialize(s, nType, nVersion); - ser_writedata32be(s, blockHeight); - } - template - void Unserialize(Stream& s, int nType, int nVersion) { - type = ser_readdata8(s); - hashBytes.Unserialize(s, nType, nVersion); - blockHeight = ser_readdata32be(s); - } - - CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) { - type = addressType; - hashBytes = addressHash; - blockHeight = height; - } - - CAddressIndexIteratorHeightKey() { - SetNull(); - } - - void SetNull() { - type = 0; - hashBytes.SetNull(); - blockHeight = 0; - } -}; - -struct CDiskTxPos : public CDiskBlockPos -{ - unsigned int nTxOffset; // after header - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(*(CDiskBlockPos*)this); - READWRITE(VARINT(nTxOffset)); - } - - CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { - } - - CDiskTxPos() { - SetNull(); - } - - void SetNull() { - CDiskBlockPos::SetNull(); - nTxOffset = 0; - } -}; - - -/** - * Count ECDSA signature operations the old-fashioned (pre-0.6) way - * @return number of sigops this transaction's outputs will produce when spent - * @see CTransaction::FetchInputs - */ -unsigned int GetLegacySigOpCount(const CTransaction& tx); - -/** - * Count ECDSA signature operations in pay-to-script-hash inputs. - * - * @param[in] mapInputs Map of previous transactions that have outputs we're spending - * @return maximum number of sigops required to validate this transaction's inputs - * @see CTransaction::FetchInputs - */ -unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs); - - -/** - * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) - * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it - * instead of being performed inline. - */ -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, - unsigned int flags, bool cacheStore, std::vector *pvChecks = NULL); - -/** Apply the effects of this transaction on the UTXO set represented by view */ -void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); - -/** Context-independent validity checks */ -bool CheckTransaction(const CTransaction& tx, CValidationState& state); - -/** - * Check if transaction is final and can be included in a block with the - * specified height and time. Consensus critical. - */ -bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); - -/** - * Check if transaction will be final in the next block to be created. - * - * Calls IsFinalTx() with current block height and appropriate block time. - * - * See consensus/consensus.h for flag definitions. - */ -bool CheckFinalTx(const CTransaction &tx, int flags = -1); - -/** - * Test whether the LockPoints height and time are still valid on the current chain - */ -bool TestLockPointValidity(const LockPoints* lp); - -/** - * Check if transaction is final per BIP 68 sequence numbers and can be included in a block. - * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed. - */ -bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block); - -/** - * Check if transaction will be BIP 68 final in the next block to be created. - * - * Simulates calling SequenceLocks() with data from the tip of the current active chain. - * Optionally stores in LockPoints the resulting height and time calculated and the hash - * of the block needed for calculation or skips the calculation and uses the LockPoints - * passed in for evaluation. - * The LockPoints should not be considered valid if CheckSequenceLocks returns false. - * - * See consensus/consensus.h for flag definitions. - */ -bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false); - -/** - * Closure representing one script verification - * Note that this stores references to the spending transaction - */ -class CScriptCheck -{ -private: - CScript scriptPubKey; - const CTransaction *ptxTo; - unsigned int nIn; - unsigned int nFlags; - bool cacheStore; - ScriptError error; - -public: - CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : - scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { } - - bool operator()(); - - void swap(CScriptCheck &check) { - scriptPubKey.swap(check.scriptPubKey); - std::swap(ptxTo, check.ptxTo); - std::swap(nIn, check.nIn); - std::swap(nFlags, check.nFlags); - std::swap(cacheStore, check.cacheStore); - std::swap(error, check.error); - } - - ScriptError GetScriptError() const { return error; } -}; - -bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes); -bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); -bool GetAddressIndex(uint160 addressHash, int type, - std::vector > &addressIndex, - int start = 0, int end = 0); -bool GetAddressUnspent(uint160 addressHash, int type, - std::vector > &unspentOutputs); - -/** Functions for disk access for blocks */ -bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); -bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams); -bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); - -/** Functions for validating blocks and updating the block tree */ - -/** Undo the effects of this block (with given index) on the UTXO set represented by coins. - * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean - * will be true if no problems were found. Otherwise, the return value will be false in case - * of problems. Note that in any case, coins may be modified. */ -bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool* pfClean = NULL); - -/** Reprocess a number of blocks to try and get on the correct chain again **/ -bool DisconnectBlocks(int blocks); -void ReprocessBlocks(int nBlocks); - -/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ -bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool fJustCheck = false); - -/** Context-independent validity checks */ -bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); -bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); - -/** Context-dependent validity checks */ -bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); -bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); - -/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ -bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); - - -class CBlockFileInfo -{ -public: - unsigned int nBlocks; //! number of blocks stored in file - unsigned int nSize; //! number of used bytes of block file - unsigned int nUndoSize; //! number of used bytes in the undo file - unsigned int nHeightFirst; //! lowest height of block in file - unsigned int nHeightLast; //! highest height of block in file - uint64_t nTimeFirst; //! earliest time of block in file - uint64_t nTimeLast; //! latest time of block in file - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(nBlocks)); - READWRITE(VARINT(nSize)); - READWRITE(VARINT(nUndoSize)); - READWRITE(VARINT(nHeightFirst)); - READWRITE(VARINT(nHeightLast)); - READWRITE(VARINT(nTimeFirst)); - READWRITE(VARINT(nTimeLast)); - } - - void SetNull() { - nBlocks = 0; - nSize = 0; - nUndoSize = 0; - nHeightFirst = 0; - nHeightLast = 0; - nTimeFirst = 0; - nTimeLast = 0; - } - - CBlockFileInfo() { - SetNull(); - } - - std::string ToString() const; - - /** update statistics (does not update nSize) */ - void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { - if (nBlocks==0 || nHeightFirst > nHeightIn) - nHeightFirst = nHeightIn; - if (nBlocks==0 || nTimeFirst > nTimeIn) - nTimeFirst = nTimeIn; - nBlocks++; - if (nHeightIn > nHeightLast) - nHeightLast = nHeightIn; - if (nTimeIn > nTimeLast) - nTimeLast = nTimeIn; - } -}; - -/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ -class CVerifyDB { -public: - CVerifyDB(); - ~CVerifyDB(); - bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); -}; - -/** Find the last common block between the parameter chain and a locator. */ -CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); - -/** Mark a block as invalid. */ -bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); - -/** Remove invalidity status from a block and its descendants. */ -bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); - -/** The currently-connected chain of blocks (protected by cs_main). */ -extern CChain chainActive; - -/** Global variable that points to the active CCoinsView (protected by cs_main) */ -extern CCoinsViewCache *pcoinsTip; - -/** Global variable that points to the active CClaimTrie (protected by cs_main) */ -extern CClaimTrie *pclaimTrie; - -/** Global variable that points to the active block tree (protected by cs_main) */ -extern CBlockTreeDB *pblocktree; - -/** - * Return the spend height, which is one more than the inputs.GetBestBlock(). - * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) - * This is also true for mempool checks. - */ -int GetSpendHeight(const CCoinsViewCache& inputs); - -/** - * Determine what nVersion a new block should use. - */ -int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); - -/** - * Return true if hash can be found in chainActive at nBlockHeight height. - * Fills hashRet with found hash, if no nBlockHeight is specified - chainActive.Height() is used. - */ -bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); - -/** Reject codes greater or equal to this can be returned by AcceptToMemPool - * for transactions, to signal internal conditions. They cannot and should not - * be sent over the P2P network. - */ -static const unsigned int REJECT_INTERNAL = 0x100; -/** Too high fee. Can not be triggered by P2P transactions */ -static const unsigned int REJECT_HIGHFEE = 0x100; -/** Transaction is already known (either in mempool or blockchain) */ -static const unsigned int REJECT_ALREADY_KNOWN = 0x101; -/** Transaction conflicts with a transaction already known */ -static const unsigned int REJECT_CONFLICT = 0x102; - -#endif // BITCOIN_MAIN_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_MAIN_H +#define BITCOIN_MAIN_H + + +#if defined(HAVE_CONFIG_H) +#include "config/pop-config.h" +#endif + +#include "amount.h" +#include "chain.h" +#include "coins.h" +#include "net.h" +#include "claimtrie.h" +#include "script/script_error.h" +#include "sync.h" +#include "versionbits.h" +#include "spentindex.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +class CBlockIndex; +class CBlockTreeDB; +class CBloomFilter; +class CChainParams; +class CInv; +class CScriptCheck; +class CTxMemPool; +class CValidationInterface; +class CValidationState; + +struct CNodeStateStats; +struct LockPoints; + +/** Default for accepting alerts from the P2P network. */ +static const bool DEFAULT_ALERTS = false; +/** Default for DEFAULT_WHITELISTRELAY. */ +static const bool DEFAULT_WHITELISTRELAY = true; +/** Default for DEFAULT_WHITELISTFORCERELAY. */ +static const bool DEFAULT_WHITELISTFORCERELAY = true; +/** Default for -minrelaytxfee, minimum relay fee for transactions + * We are ~100 times smaller then bitcoin now (2016-03-01), set minRelayTxFee only 10 times higher + * so it's still 10 times lower comparing to bitcoin. + */ +static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 10000; // was 1000 +/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ +static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; +/** Default for -limitancestorcount, max number of in-mempool ancestors */ +static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25; +/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */ +static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101; +/** Default for -limitdescendantcount, max number of in-mempool descendants */ +static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; +/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ +static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; +/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ +static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 72; +/** The maximum size of a blk?????.dat file (since 0.8) */ +static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB +/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ +static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB +/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ +static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB + +/** Maximum number of script-checking threads allowed */ +static const int MAX_SCRIPTCHECK_THREADS = 16; +/** -par default (number of script-checking threads, 0 = auto) */ +static const int DEFAULT_SCRIPTCHECK_THREADS = 0; +/** Number of blocks that can be requested at any given time from a single peer. */ +static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16; +/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */ +static const unsigned int BLOCK_STALLING_TIMEOUT = 2; +/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends + * less than this number, we reached its tip. Changing this value is a protocol upgrade. */ +static const unsigned int MAX_HEADERS_RESULTS = 2000; +/** Size of the "block download window": how far ahead of our current height do we fetch? + * Larger windows tolerate larger download speed differences between peer, but increase the potential + * degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning + * harder). We'll probably want to make this a per-peer adaptive value at some point. */ +static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024; +/** Time to wait (in seconds) between writing blocks/block index to disk. */ +static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60; +/** Time to wait (in seconds) between flushing chainstate to disk. */ +static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60; +/** Maximum length of reject messages. */ +static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111; +/** Average delay between local address broadcasts in seconds. */ +static const unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 24 * 60; +/** Average delay between peer address broadcasts in seconds. */ +static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; +/** Average delay between trickled inventory broadcasts in seconds. + * Blocks, whitelisted receivers, and a random 25% of transactions bypass this. */ +static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; +/** Block download timeout base, expressed in millionths of the block interval (i.e. 2.5 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000; +/** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 125000; + +static const unsigned int DEFAULT_LIMITFREERELAY = 15; +static const bool DEFAULT_RELAYPRIORITY = true; + +/** Default for -permitbaremultisig */ +static const bool DEFAULT_PERMIT_BAREMULTISIG = true; +static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20; +static const bool DEFAULT_CHECKPOINTS_ENABLED = true; +static const bool DEFAULT_TXINDEX = true; +static const bool DEFAULT_ADDRESSINDEX = false; +static const bool DEFAULT_TIMESTAMPINDEX = false; +static const bool DEFAULT_SPENTINDEX = false; +static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100; + +static const bool DEFAULT_TESTSAFEMODE = false; +/** Default for -mempoolreplacement */ +static const bool DEFAULT_ENABLE_REPLACEMENT = false; + +/** Maximum number of headers to announce when relaying blocks with headers message.*/ +static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; + +struct BlockHasher +{ + size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); } +}; + +extern CScript COINBASE_FLAGS; +extern CCriticalSection cs_main; +extern CTxMemPool mempool; +typedef boost::unordered_map BlockMap; +extern BlockMap mapBlockIndex; +extern uint64_t nLastBlockTx; +extern uint64_t nLastBlockSize; +extern const std::string strMessageMagic; +extern CWaitableCriticalSection csBestBlock; +extern CConditionVariable cvBlockChange; +extern bool fImporting; +extern bool fReindex; +extern int nScriptCheckThreads; +extern bool fTxIndex; +extern bool fIsBareMultisigStd; +extern bool fRequireStandard; +extern unsigned int nBytesPerSigOp; +extern bool fCheckBlockIndex; +extern bool fCheckpointsEnabled; +extern size_t nCoinCacheUsage; +extern CFeeRate minRelayTxFee; +extern bool fAlerts; +extern bool fEnableReplacement; + +extern std::map mapRejectedBlocks; + +/** Best header we've seen so far (used for getheaders queries' starting points). */ +extern CBlockIndex *pindexBestHeader; + +/** Minimum disk space required - used in CheckDiskSpace() */ +static const uint64_t nMinDiskSpace = 52428800; + +/** Pruning-related variables and constants */ +/** True if any block files have ever been pruned. */ +extern bool fHavePruned; +/** True if we're running in -prune mode. */ +extern bool fPruneMode; +/** Number of MiB of block files that we're trying to stay below. */ +extern uint64_t nPruneTarget; +/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */ +static const unsigned int MIN_BLOCKS_TO_KEEP = 288; + +static const signed int DEFAULT_CHECKBLOCKS = MIN_BLOCKS_TO_KEEP; +static const unsigned int DEFAULT_CHECKLEVEL = 3; + +// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat) +// At 1MB per block, 288 blocks = 288MB. +// Add 15% for Undo data = 331MB +// Add 20% for Orphan block rate = 397MB +// We want the low water mark after pruning to be at least 397 MB and since we prune in +// full block file chunks, we need the high water mark which triggers the prune to be +// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB +// Setting the target to > than 550MB will make it likely we can respect the target. +static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; + +/** Register with a network node to receive its signals */ +void RegisterNodeSignals(CNodeSignals& nodeSignals); +/** Unregister a network node */ +void UnregisterNodeSignals(CNodeSignals& nodeSignals); + +/** + * Process an incoming block. This only returns after the best known valid + * block is made active. Note that it does not, however, guarantee that the + * specific block passed to it has been checked for validity! + * + * @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation. + * @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. + * @param[in] pblock The block we want to process. + * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. + * @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. + * @return True if state.IsValid() + */ +bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos* dbp); +/** Check whether enough disk space is available for an incoming block */ +bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); +/** Open a block file (blk?????.dat) */ +FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false); +/** Open an undo file (rev?????.dat) */ +FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); +/** Translation to a filesystem path */ +boost::filesystem::path GetBlockPosFilename(const CDiskBlockPos &pos, const char *prefix); +/** Import blocks from an external file */ +bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskBlockPos *dbp = NULL); +/** Initialize a new block tree database + block data on disk */ +bool InitBlockIndex(const CChainParams& chainparams); +/** Load the block tree and coins database from disk */ +bool LoadBlockIndex(); +/** Unload database information */ +void UnloadBlockIndex(); +/** Process protocol messages received from a given node */ +bool ProcessMessages(CNode* pfrom); +/** + * Send queued protocol messages to be sent to a give node. + * + * @param[in] pto The node which we are sending messages to. + */ +bool SendMessages(CNode* pto); +/** Run an instance of the script checking thread */ +void ThreadScriptCheck(); + +/** Try to detect Partition (network isolation) attacks against us */ +void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing); +/** Check whether we are doing an initial block download (synchronizing from disk or network) */ +bool IsInitialBlockDownload(); +/** Format a string that describes several potential problems detected by the core. + * strFor can have three values: + * - "rpc": get critical warnings, which should put the client in safe mode if non-empty + * - "statusbar": get all warnings + * - "gui": get all warnings, translated (where possible) for GUI + * This function only returns the highest priority warning of the set selected by strFor. + */ +std::string GetWarnings(const std::string& strFor); + +/** Get a cryptographic proof that a name maps to a value **/ +bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CClaimTrieProof& proof); + +/** Retrieve a transaction (from memory pool, or from disk, if possible) */ +bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); +/** Find the best known block, and make it the tip of the block chain */ +bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); + +CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp); +CAmount GetFoundersReward(const int height, const Consensus::Params &cp); +CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp); + +/** + * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. + * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new + * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex + * (which in this case means the blockchain must be re-downloaded.) + * + * Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set. + * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) + * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest). + * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. + * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. + * A db flag records the fact that at least some block files have been pruned. + * + * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned + */ +void FindFilesToPrune(std::set& setFilesToPrune, uint64_t nPruneAfterHeight); + +/** + * Actually unlink the specified files + */ +void UnlinkPrunedFiles(std::set& setFilesToPrune); + +/** Create a new block index entry for a given block hash */ +CBlockIndex * InsertBlockIndex(uint256 hash); +/** Get statistics from node state */ +bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); +/** Increase a node's misbehavior score. */ +void Misbehaving(NodeId nodeid, int howmuch); +/** Flush all state, indexes and buffers to disk. */ +void FlushStateToDisk(); +/** Prune block files and flush state to disk. */ +void PruneAndFlush(); + +/** (try to) add transaction to memory pool **/ +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, + bool* pfMissingInputs, bool fOverrideMempoolLimit=false, bool fRejectAbsurdFee=false, bool fDryRun=false); + +int GetUTXOHeight(const COutPoint& outpoint); +int GetInputAge(const CTxIn &txin); +int GetInputAgeIX(const uint256 &nTXHash, const CTxIn &txin); +int GetIXConfirmations(const uint256 &nTXHash); + +/** Convert CValidationState to a human-readable message for logging */ +std::string FormatStateMessage(const CValidationState &state); + +/** Get the BIP9 state for a given deployment at the current tip. */ +ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos); + +struct CNodeStateStats { + int nMisbehavior; + int nSyncHeight; + int nCommonHeight; + std::vector vHeightInFlight; +}; + +struct CTimestampIndexIteratorKey { + unsigned int timestamp; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 4; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata32be(s, timestamp); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + timestamp = ser_readdata32be(s); + } + + CTimestampIndexIteratorKey(unsigned int time) { + timestamp = time; + } + + CTimestampIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + } +}; + +struct CTimestampIndexKey { + unsigned int timestamp; + uint256 blockHash; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 36; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata32be(s, timestamp); + blockHash.Serialize(s, nType, nVersion); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + timestamp = ser_readdata32be(s); + blockHash.Unserialize(s, nType, nVersion); + } + + CTimestampIndexKey(unsigned int time, uint256 hash) { + timestamp = time; + blockHash = hash; + } + + CTimestampIndexKey() { + SetNull(); + } + + void SetNull() { + timestamp = 0; + blockHash.SetNull(); + } +}; + +struct CAddressUnspentKey { + unsigned int type; + uint160 hashBytes; + uint256 txhash; + size_t index; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 57; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + txhash.Serialize(s, nType, nVersion); + ser_writedata32(s, index); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + txhash.Unserialize(s, nType, nVersion); + index = ser_readdata32(s); + } + + CAddressUnspentKey(unsigned int addressType, uint160 addressHash, uint256 txid, size_t indexValue) { + type = addressType; + hashBytes = addressHash; + txhash = txid; + index = indexValue; + } + + CAddressUnspentKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + txhash.SetNull(); + index = 0; + } +}; + +struct CAddressUnspentValue { + CAmount satoshis; + CScript script; + int blockHeight; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(satoshis); + READWRITE(*(CScriptBase*)(&script)); + READWRITE(blockHeight); + } + + CAddressUnspentValue(CAmount sats, CScript scriptPubKey, int height) { + satoshis = sats; + script = scriptPubKey; + blockHeight = height; + } + + CAddressUnspentValue() { + SetNull(); + } + + void SetNull() { + satoshis = -1; + script.clear(); + blockHeight = 0; + } + + bool IsNull() const { + return (satoshis == -1); + } +}; + +struct CAddressIndexKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + unsigned int txindex; + uint256 txhash; + size_t index; + bool spending; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 66; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + // Heights are stored big-endian for key sorting in LevelDB + ser_writedata32be(s, blockHeight); + ser_writedata32be(s, txindex); + txhash.Serialize(s, nType, nVersion); + ser_writedata32(s, index); + char f = spending; + ser_writedata8(s, f); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + blockHeight = ser_readdata32be(s); + txindex = ser_readdata32be(s); + txhash.Unserialize(s, nType, nVersion); + index = ser_readdata32(s); + char f = ser_readdata8(s); + spending = f; + } + + CAddressIndexKey(unsigned int addressType, uint160 addressHash, int height, int blockindex, + uint256 txid, size_t indexValue, bool isSpending) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + txindex = blockindex; + txhash = txid; + index = indexValue; + spending = isSpending; + } + + CAddressIndexKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + txindex = 0; + txhash.SetNull(); + index = 0; + spending = false; + } + +}; + +struct CAddressIndexIteratorKey { + unsigned int type; + uint160 hashBytes; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 21; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + } + + CAddressIndexIteratorKey(unsigned int addressType, uint160 addressHash) { + type = addressType; + hashBytes = addressHash; + } + + CAddressIndexIteratorKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + } +}; + +struct CAddressIndexIteratorHeightKey { + unsigned int type; + uint160 hashBytes; + int blockHeight; + + size_t GetSerializeSize(int nType, int nVersion) const { + return 25; + } + template + void Serialize(Stream& s, int nType, int nVersion) const { + ser_writedata8(s, type); + hashBytes.Serialize(s, nType, nVersion); + ser_writedata32be(s, blockHeight); + } + template + void Unserialize(Stream& s, int nType, int nVersion) { + type = ser_readdata8(s); + hashBytes.Unserialize(s, nType, nVersion); + blockHeight = ser_readdata32be(s); + } + + CAddressIndexIteratorHeightKey(unsigned int addressType, uint160 addressHash, int height) { + type = addressType; + hashBytes = addressHash; + blockHeight = height; + } + + CAddressIndexIteratorHeightKey() { + SetNull(); + } + + void SetNull() { + type = 0; + hashBytes.SetNull(); + blockHeight = 0; + } +}; +/*popchain ghost*/ +struct CBlockTdKey { + + uint256 blockHash; + uint32_t blockNumber; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(blockHash); + READWRITE(blockNumber); + } + + CBlockTdKey(uint256 bH, uint32_t bN) { + blockHash = bH; + blockNumber = bN; + } + + CBlockTdKey() { + SetNull(); + } + + void SetNull() { + blockHash.SetNull(); + blockNumber = 0; + } + +}; + + + +/*popchain ghost*/ + +struct CDiskTxPos : public CDiskBlockPos +{ + unsigned int nTxOffset; // after header + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(*(CDiskBlockPos*)this); + READWRITE(VARINT(nTxOffset)); + } + + CDiskTxPos(const CDiskBlockPos &blockIn, unsigned int nTxOffsetIn) : CDiskBlockPos(blockIn.nFile, blockIn.nPos), nTxOffset(nTxOffsetIn) { + } + + CDiskTxPos() { + SetNull(); + } + + void SetNull() { + CDiskBlockPos::SetNull(); + nTxOffset = 0; + } +}; + + +/** + * Count ECDSA signature operations the old-fashioned (pre-0.6) way + * @return number of sigops this transaction's outputs will produce when spent + * @see CTransaction::FetchInputs + */ +unsigned int GetLegacySigOpCount(const CTransaction& tx); + +/** + * Count ECDSA signature operations in pay-to-script-hash inputs. + * + * @param[in] mapInputs Map of previous transactions that have outputs we're spending + * @return maximum number of sigops required to validate this transaction's inputs + * @see CTransaction::FetchInputs + */ +unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs); + + +/** + * Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) + * This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it + * instead of being performed inline. + */ +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, + unsigned int flags, bool cacheStore, std::vector *pvChecks = NULL); + +/** Apply the effects of this transaction on the UTXO set represented by view */ +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); + +/** Context-independent validity checks */ +bool CheckTransaction(const CTransaction& tx, CValidationState& state); + +/** + * Check if transaction is final and can be included in a block with the + * specified height and time. Consensus critical. + */ +bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime); + +/** + * Check if transaction will be final in the next block to be created. + * + * Calls IsFinalTx() with current block height and appropriate block time. + * + * See consensus/consensus.h for flag definitions. + */ +bool CheckFinalTx(const CTransaction &tx, int flags = -1); + +/** + * Test whether the LockPoints height and time are still valid on the current chain + */ +bool TestLockPointValidity(const LockPoints* lp); + +/** + * Check if transaction is final per BIP 68 sequence numbers and can be included in a block. + * Consensus critical. Takes as input a list of heights at which tx's inputs (in order) confirmed. + */ +bool SequenceLocks(const CTransaction &tx, int flags, std::vector* prevHeights, const CBlockIndex& block); + +/** + * Check if transaction will be BIP 68 final in the next block to be created. + * + * Simulates calling SequenceLocks() with data from the tip of the current active chain. + * Optionally stores in LockPoints the resulting height and time calculated and the hash + * of the block needed for calculation or skips the calculation and uses the LockPoints + * passed in for evaluation. + * The LockPoints should not be considered valid if CheckSequenceLocks returns false. + * + * See consensus/consensus.h for flag definitions. + */ +bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp = NULL, bool useExistingLockPoints = false); + +/** + * Closure representing one script verification + * Note that this stores references to the spending transaction + */ +class CScriptCheck +{ +private: + CScript scriptPubKey; + const CTransaction *ptxTo; + unsigned int nIn; + unsigned int nFlags; + bool cacheStore; + ScriptError error; + +public: + CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false), error(SCRIPT_ERR_UNKNOWN_ERROR) {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : + scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), error(SCRIPT_ERR_UNKNOWN_ERROR) { } + + bool operator()(); + + void swap(CScriptCheck &check) { + scriptPubKey.swap(check.scriptPubKey); + std::swap(ptxTo, check.ptxTo); + std::swap(nIn, check.nIn); + std::swap(nFlags, check.nFlags); + std::swap(cacheStore, check.cacheStore); + std::swap(error, check.error); + } + + ScriptError GetScriptError() const { return error; } +}; + +bool GetTimestampIndex(const unsigned int &high, const unsigned int &low, std::vector &hashes); +bool GetSpentIndex(CSpentIndexKey &key, CSpentIndexValue &value); +bool GetAddressIndex(uint160 addressHash, int type, + std::vector > &addressIndex, + int start = 0, int end = 0); +bool GetAddressUnspent(uint160 addressHash, int type, + std::vector > &unspentOutputs); + +/** Functions for disk access for blocks */ +bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); +bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams); +bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); + +/** Functions for validating blocks and updating the block tree */ + +/** Undo the effects of this block (with given index) on the UTXO set represented by coins. + * In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean + * will be true if no problems were found. Otherwise, the return value will be false in case + * of problems. Note that in any case, coins may be modified. */ +bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool* pfClean = NULL); + +/** Reprocess a number of blocks to try and get on the correct chain again **/ +bool DisconnectBlocks(int blocks); +void ReprocessBlocks(int nBlocks); + +/** Apply the effects of this block (with given index) on the UTXO set represented by coins */ +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, CClaimTrieCache& trieCache, bool fJustCheck = false); + +/** Context-independent validity checks */ +bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); +bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); + +/** Context-dependent validity checks */ +bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); +bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); + +/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ +bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); + + +class CBlockFileInfo +{ +public: + unsigned int nBlocks; //! number of blocks stored in file + unsigned int nSize; //! number of used bytes of block file + unsigned int nUndoSize; //! number of used bytes in the undo file + unsigned int nHeightFirst; //! lowest height of block in file + unsigned int nHeightLast; //! highest height of block in file + uint64_t nTimeFirst; //! earliest time of block in file + uint64_t nTimeLast; //! latest time of block in file + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nBlocks)); + READWRITE(VARINT(nSize)); + READWRITE(VARINT(nUndoSize)); + READWRITE(VARINT(nHeightFirst)); + READWRITE(VARINT(nHeightLast)); + READWRITE(VARINT(nTimeFirst)); + READWRITE(VARINT(nTimeLast)); + } + + void SetNull() { + nBlocks = 0; + nSize = 0; + nUndoSize = 0; + nHeightFirst = 0; + nHeightLast = 0; + nTimeFirst = 0; + nTimeLast = 0; + } + + CBlockFileInfo() { + SetNull(); + } + + std::string ToString() const; + + /** update statistics (does not update nSize) */ + void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) { + if (nBlocks==0 || nHeightFirst > nHeightIn) + nHeightFirst = nHeightIn; + if (nBlocks==0 || nTimeFirst > nTimeIn) + nTimeFirst = nTimeIn; + nBlocks++; + if (nHeightIn > nHeightLast) + nHeightLast = nHeightIn; + if (nTimeIn > nTimeLast) + nTimeLast = nTimeIn; + } +}; + +/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */ +class CVerifyDB { +public: + CVerifyDB(); + ~CVerifyDB(); + bool VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); +}; + +/** Find the last common block between the parameter chain and a locator. */ +CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); + +/** Mark a block as invalid. */ +bool InvalidateBlock(CValidationState& state, const Consensus::Params& consensusParams, CBlockIndex *pindex); + +/** Remove invalidity status from a block and its descendants. */ +bool ReconsiderBlock(CValidationState& state, CBlockIndex *pindex); + +/** The currently-connected chain of blocks (protected by cs_main). */ +extern CChain chainActive; + +/** Global variable that points to the active CCoinsView (protected by cs_main) */ +extern CCoinsViewCache *pcoinsTip; + +/** Global variable that points to the active CClaimTrie (protected by cs_main) */ +extern CClaimTrie *pclaimTrie; + +/** Global variable that points to the active block tree (protected by cs_main) */ +extern CBlockTreeDB *pblocktree; + +/** + * Return the spend height, which is one more than the inputs.GetBestBlock(). + * While checking, GetBestBlock() refers to the parent block. (protected by cs_main) + * This is also true for mempool checks. + */ +int GetSpendHeight(const CCoinsViewCache& inputs); + +/** + * Determine what nVersion a new block should use. + */ +int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params); + +/** + * Return true if hash can be found in chainActive at nBlockHeight height. + * Fills hashRet with found hash, if no nBlockHeight is specified - chainActive.Height() is used. + */ +bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); + +/** Reject codes greater or equal to this can be returned by AcceptToMemPool + * for transactions, to signal internal conditions. They cannot and should not + * be sent over the P2P network. + */ +static const unsigned int REJECT_INTERNAL = 0x100; +/** Too high fee. Can not be triggered by P2P transactions */ +static const unsigned int REJECT_HIGHFEE = 0x100; +/** Transaction is already known (either in mempool or blockchain) */ +static const unsigned int REJECT_ALREADY_KNOWN = 0x101; +/** Transaction conflicts with a transaction already known */ +static const unsigned int REJECT_CONFLICT = 0x102; + +#endif // BITCOIN_MAIN_H diff --git a/src/txdb.cpp b/src/txdb.cpp index 60cf89e..4dc96b9 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -30,7 +30,7 @@ static const char DB_REINDEX_FLAG = 'R'; static const char DB_LAST_BLOCK = 'l'; /*popchain ghost*/ -static const char DB_TOTALDIFFICULT = 'd'; +static const char DB_TOTALDIFFICULT = 'd';//key is DB_TOTALDIFFICULT + hash + height /*popchain ghost*/ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe, true) @@ -352,16 +352,19 @@ bool CBlockTreeDB::LoadBlockIndexGuts() } -bool CBlockTreeDB::WriteTd(const uint256 &hash, uint256 td) +bool CBlockTreeDB::WriteTd(CBlockTdKey &key, uint256 td) { - return Write(std::make_pair(DB_TOTALDIFFICULT, hash), td); + + return Write(std::make_pair(DB_TOTALDIFFICULT, key), td); + } -bool CBlockTreeDB::ReadTd(const uint256 &hash, uint256 &td) -{ - if (!Read(std::make_pair(DB_TOTALDIFFICULT, hash), td)) - return false; - return true; -} +bool CBlockTreeDB::ReadTd(CBlockTdKey &key, uint256 &td) +{ + + if (!Read(std::make_pair(DB_TOTALDIFFICULT, key), td)) + return false; + return true; +} diff --git a/src/txdb.h b/src/txdb.h index 2dbd7d6..ca9bec3 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -23,8 +23,17 @@ struct CTimestampIndexKey; struct CTimestampIndexIteratorKey; struct CSpentIndexKey; struct CSpentIndexValue; + +/*popchain ghost*/ +struct CBlockTdKey; +/*popchain ghost*/ + + class uint256; + + + //! -dbcache default (MiB) static const int64_t nDefaultDbCache = 100; //! max. -dbcache in (MiB) @@ -79,8 +88,8 @@ class CBlockTreeDB : public CDBWrapper bool ReadFlag(const std::string &name, bool &fValue); bool LoadBlockIndexGuts(); /*popchain ghost*/ - bool WriteTd(const uint256 &hash, uint256 td); - bool ReadTd(const uint256 &hash, uint256 &td) ; + bool WriteTd(CBlockTdKey &key, uint256 td); + bool ReadTd(CBlockTdKey &key, uint256 &td); /*popchain ghost*/ }; From a02e04b14e928a705fd1aaa987046889e3d7845f Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 30 Jul 2018 20:40:41 +0800 Subject: [PATCH 010/120] add the difficulty to block header and other work --- src/arith_uint256.cpp | 528 +++++++++--------- src/arith_uint256.h | 579 ++++++++++---------- src/chain.h | 9 +- src/chainparams.cpp | 1102 +++++++++++++++++++------------------- src/primitives/block.cpp | 10 +- src/primitives/block.h | 4 + 6 files changed, 1134 insertions(+), 1098 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 3d2d7b3..8d8a3b6 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -1,257 +1,271 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "arith_uint256.h" - -#include "uint256.h" -#include "utilstrencodings.h" -#include "crypto/common.h" - -#include -#include - -template -base_uint::base_uint(const std::string& str) -{ - SetHex(str); -} - -template -base_uint& base_uint::operator<<=(unsigned int shift) -{ - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i + k + 1 < WIDTH && shift != 0) - pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); - if (i + k < WIDTH) - pn[i + k] |= (a.pn[i] << shift); - } - return *this; -} - -template -base_uint& base_uint::operator>>=(unsigned int shift) -{ - base_uint a(*this); - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - int k = shift / 32; - shift = shift % 32; - for (int i = 0; i < WIDTH; i++) { - if (i - k - 1 >= 0 && shift != 0) - pn[i - k - 1] |= (a.pn[i] << (32 - shift)); - if (i - k >= 0) - pn[i - k] |= (a.pn[i] >> shift); - } - return *this; -} - -template -base_uint& base_uint::operator*=(uint32_t b32) -{ - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) { - uint64_t n = carry + (uint64_t)b32 * pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; -} - -template -base_uint& base_uint::operator*=(const base_uint& b) -{ - base_uint a = *this; - *this = 0; - for (int j = 0; j < WIDTH; j++) { - uint64_t carry = 0; - for (int i = 0; i + j < WIDTH; i++) { - uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; - pn[i + j] = n & 0xffffffff; - carry = n >> 32; - } - } - return *this; -} - -template -base_uint& base_uint::operator/=(const base_uint& b) -{ - base_uint div = b; // make a copy, so we can shift. - base_uint num = *this; // make a copy, so we can subtract. - *this = 0; // the quotient. - int num_bits = num.bits(); - int div_bits = div.bits(); - if (div_bits == 0) - throw uint_error("Division by zero"); - if (div_bits > num_bits) // the result is certainly 0. - return *this; - int shift = num_bits - div_bits; - div <<= shift; // shift so that div and num align. - while (shift >= 0) { - if (num >= div) { - num -= div; - pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. - } - div >>= 1; // shift back. - shift--; - } - // num now contains the remainder of the division. - return *this; -} - -template -int base_uint::CompareTo(const base_uint& b) const -{ - for (int i = WIDTH - 1; i >= 0; i--) { - if (pn[i] < b.pn[i]) - return -1; - if (pn[i] > b.pn[i]) - return 1; - } - return 0; -} - -template -bool base_uint::EqualTo(uint64_t b) const -{ - for (int i = WIDTH - 1; i >= 2; i--) { - if (pn[i]) - return false; - } - if (pn[1] != (b >> 32)) - return false; - if (pn[0] != (b & 0xfffffffful)) - return false; - return true; -} - -template -double base_uint::getdouble() const -{ - double ret = 0.0; - double fact = 1.0; - for (int i = 0; i < WIDTH; i++) { - ret += fact * pn[i]; - fact *= 4294967296.0; - } - return ret; -} - -template -std::string base_uint::GetHex() const -{ - return ArithToUint256(*this).GetHex(); -} - -template -void base_uint::SetHex(const char* psz) -{ - *this = UintToArith256(uint256S(psz)); -} - -template -void base_uint::SetHex(const std::string& str) -{ - SetHex(str.c_str()); -} - -template -std::string base_uint::ToString() const -{ - return (GetHex()); -} - -template -unsigned int base_uint::bits() const -{ - for (int pos = WIDTH - 1; pos >= 0; pos--) { - if (pn[pos]) { - for (int bits = 31; bits > 0; bits--) { - if (pn[pos] & 1 << bits) - return 32 * pos + bits + 1; - } - return 32 * pos + 1; - } - } - return 0; -} - -// Explicit instantiations for base_uint<256> -template base_uint<256>::base_uint(const std::string&); -template base_uint<256>& base_uint<256>::operator<<=(unsigned int); -template base_uint<256>& base_uint<256>::operator>>=(unsigned int); -template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); -template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); -template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); -template int base_uint<256>::CompareTo(const base_uint<256>&) const; -template bool base_uint<256>::EqualTo(uint64_t) const; -template double base_uint<256>::getdouble() const; -template std::string base_uint<256>::GetHex() const; -template std::string base_uint<256>::ToString() const; -template void base_uint<256>::SetHex(const char*); -template void base_uint<256>::SetHex(const std::string&); -template unsigned int base_uint<256>::bits() const; - -// This implementation directly uses shifts instead of going -// through an intermediate MPI representation. -arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow) -{ - int nSize = nCompact >> 24; - uint32_t nWord = nCompact & 0x007fffff; - if (nSize <= 3) { - nWord >>= 8 * (3 - nSize); - *this = nWord; - } else { - *this = nWord; - *this <<= 8 * (nSize - 3); - } - if (pfNegative) - *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; - if (pfOverflow) - *pfOverflow = nWord != 0 && ((nSize > 34) || - (nWord > 0xff && nSize > 33) || - (nWord > 0xffff && nSize > 32)); - return *this; -} - -uint32_t arith_uint256::GetCompact(bool fNegative) const -{ - int nSize = (bits() + 7) / 8; - uint32_t nCompact = 0; - if (nSize <= 3) { - nCompact = GetLow64() << 8 * (3 - nSize); - } else { - arith_uint256 bn = *this >> 8 * (nSize - 3); - nCompact = bn.GetLow64(); - } - // The 0x00800000 bit denotes the sign. - // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. - if (nCompact & 0x00800000) { - nCompact >>= 8; - nSize++; - } - assert((nCompact & ~0x007fffff) == 0); - assert(nSize < 256); - nCompact |= nSize << 24; - nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); - return nCompact; -} - -uint256 ArithToUint256(const arith_uint256 &a) -{ - uint256 b; - for(int x=0; x +#include + +template +base_uint::base_uint(const std::string& str) +{ + SetHex(str); +} + +template +base_uint& base_uint::operator<<=(unsigned int shift) +{ + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) { + if (i + k + 1 < WIDTH && shift != 0) + pn[i + k + 1] |= (a.pn[i] >> (32 - shift)); + if (i + k < WIDTH) + pn[i + k] |= (a.pn[i] << shift); + } + return *this; +} + +template +base_uint& base_uint::operator>>=(unsigned int shift) +{ + base_uint a(*this); + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + int k = shift / 32; + shift = shift % 32; + for (int i = 0; i < WIDTH; i++) { + if (i - k - 1 >= 0 && shift != 0) + pn[i - k - 1] |= (a.pn[i] << (32 - shift)); + if (i - k >= 0) + pn[i - k] |= (a.pn[i] >> shift); + } + return *this; +} + +template +base_uint& base_uint::operator*=(uint32_t b32) +{ + uint64_t carry = 0; + for (int i = 0; i < WIDTH; i++) { + uint64_t n = carry + (uint64_t)b32 * pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; +} + +template +base_uint& base_uint::operator*=(const base_uint& b) +{ + base_uint a = *this; + *this = 0; + for (int j = 0; j < WIDTH; j++) { + uint64_t carry = 0; + for (int i = 0; i + j < WIDTH; i++) { + uint64_t n = carry + pn[i + j] + (uint64_t)a.pn[j] * b.pn[i]; + pn[i + j] = n & 0xffffffff; + carry = n >> 32; + } + } + return *this; +} + +template +base_uint& base_uint::operator/=(const base_uint& b) +{ + base_uint div = b; // make a copy, so we can shift. + base_uint num = *this; // make a copy, so we can subtract. + *this = 0; // the quotient. + int num_bits = num.bits(); + int div_bits = div.bits(); + if (div_bits == 0) + throw uint_error("Division by zero"); + if (div_bits > num_bits) // the result is certainly 0. + return *this; + int shift = num_bits - div_bits; + div <<= shift; // shift so that div and num align. + while (shift >= 0) { + if (num >= div) { + num -= div; + pn[shift / 32] |= (1 << (shift & 31)); // set a bit of the result. + } + div >>= 1; // shift back. + shift--; + } + // num now contains the remainder of the division. + return *this; +} + +template +int base_uint::CompareTo(const base_uint& b) const +{ + for (int i = WIDTH - 1; i >= 0; i--) { + if (pn[i] < b.pn[i]) + return -1; + if (pn[i] > b.pn[i]) + return 1; + } + return 0; +} + +template +bool base_uint::EqualTo(uint64_t b) const +{ + for (int i = WIDTH - 1; i >= 2; i--) { + if (pn[i]) + return false; + } + if (pn[1] != (b >> 32)) + return false; + if (pn[0] != (b & 0xfffffffful)) + return false; + return true; +} + +template +double base_uint::getdouble() const +{ + double ret = 0.0; + double fact = 1.0; + for (int i = 0; i < WIDTH; i++) { + ret += fact * pn[i]; + fact *= 4294967296.0; + } + return ret; +} + +template +std::string base_uint::GetHex() const +{ + return ArithToUint256(*this).GetHex(); +} + +template +void base_uint::SetHex(const char* psz) +{ + *this = UintToArith256(uint256S(psz)); +} + +template +void base_uint::SetHex(const std::string& str) +{ + SetHex(str.c_str()); +} + +template +std::string base_uint::ToString() const +{ + return (GetHex()); +} + +template +unsigned int base_uint::bits() const +{ + for (int pos = WIDTH - 1; pos >= 0; pos--) { + if (pn[pos]) { + for (int bits = 31; bits > 0; bits--) { + if (pn[pos] & 1 << bits) + return 32 * pos + bits + 1; + } + return 32 * pos + 1; + } + } + return 0; +} + +// Explicit instantiations for base_uint<256> +template base_uint<256>::base_uint(const std::string&); +template base_uint<256>& base_uint<256>::operator<<=(unsigned int); +template base_uint<256>& base_uint<256>::operator>>=(unsigned int); +template base_uint<256>& base_uint<256>::operator*=(uint32_t b32); +template base_uint<256>& base_uint<256>::operator*=(const base_uint<256>& b); +template base_uint<256>& base_uint<256>::operator/=(const base_uint<256>& b); +template int base_uint<256>::CompareTo(const base_uint<256>&) const; +template bool base_uint<256>::EqualTo(uint64_t) const; +template double base_uint<256>::getdouble() const; +template std::string base_uint<256>::GetHex() const; +template std::string base_uint<256>::ToString() const; +template void base_uint<256>::SetHex(const char*); +template void base_uint<256>::SetHex(const std::string&); +template unsigned int base_uint<256>::bits() const; + +// This implementation directly uses shifts instead of going +// through an intermediate MPI representation. +arith_uint256& arith_uint256::SetCompact(uint32_t nCompact, bool* pfNegative, bool* pfOverflow) +{ + int nSize = nCompact >> 24; + uint32_t nWord = nCompact & 0x007fffff; + if (nSize <= 3) { + nWord >>= 8 * (3 - nSize); + *this = nWord; + } else { + *this = nWord; + *this <<= 8 * (nSize - 3); + } + if (pfNegative) + *pfNegative = nWord != 0 && (nCompact & 0x00800000) != 0; + if (pfOverflow) + *pfOverflow = nWord != 0 && ((nSize > 34) || + (nWord > 0xff && nSize > 33) || + (nWord > 0xffff && nSize > 32)); + return *this; +} + +uint32_t arith_uint256::GetCompact(bool fNegative) const +{ + int nSize = (bits() + 7) / 8; + uint32_t nCompact = 0; + if (nSize <= 3) { + nCompact = GetLow64() << 8 * (3 - nSize); + } else { + arith_uint256 bn = *this >> 8 * (nSize - 3); + nCompact = bn.GetLow64(); + } + // The 0x00800000 bit denotes the sign. + // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. + if (nCompact & 0x00800000) { + nCompact >>= 8; + nSize++; + } + assert((nCompact & ~0x007fffff) == 0); + assert(nSize < 256); + nCompact |= nSize << 24; + nCompact |= (fNegative && (nCompact & 0x007fffff) ? 0x00800000 : 0); + return nCompact; +} + +uint256 ArithToUint256(const arith_uint256 &a) +{ + uint256 b; + for(int x=0; x -#include -#include -#include -#include -#include - -class uint256; - -class uint_error : public std::runtime_error { -public: - explicit uint_error(const std::string& str) : std::runtime_error(str) {} -}; - -/** Template base class for unsigned big integers. */ -template -class base_uint -{ -protected: - enum { WIDTH=BITS/32 }; - uint32_t pn[WIDTH]; -public: - - base_uint() - { - for (int i = 0; i < WIDTH; i++) - pn[i] = 0; - } - - base_uint(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - } - - base_uint& operator=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - return *this; - } - - base_uint(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - } - - explicit base_uint(const std::string& str); - - bool operator!() const - { - for (int i = 0; i < WIDTH; i++) - if (pn[i] != 0) - return false; - return true; - } - - const base_uint operator~() const - { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - return ret; - } - - const base_uint operator-() const - { - base_uint ret; - for (int i = 0; i < WIDTH; i++) - ret.pn[i] = ~pn[i]; - ret++; - return ret; - } - - double getdouble() const; - - base_uint& operator=(uint64_t b) - { - pn[0] = (unsigned int)b; - pn[1] = (unsigned int)(b >> 32); - for (int i = 2; i < WIDTH; i++) - pn[i] = 0; - return *this; - } - - base_uint& operator^=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] ^= b.pn[i]; - return *this; - } - - base_uint& operator&=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] &= b.pn[i]; - return *this; - } - - base_uint& operator|=(const base_uint& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] |= b.pn[i]; - return *this; - } - - base_uint& operator^=(uint64_t b) - { - pn[0] ^= (unsigned int)b; - pn[1] ^= (unsigned int)(b >> 32); - return *this; - } - - base_uint& operator|=(uint64_t b) - { - pn[0] |= (unsigned int)b; - pn[1] |= (unsigned int)(b >> 32); - return *this; - } - - base_uint& operator<<=(unsigned int shift); - base_uint& operator>>=(unsigned int shift); - - base_uint& operator+=(const base_uint& b) - { - uint64_t carry = 0; - for (int i = 0; i < WIDTH; i++) - { - uint64_t n = carry + pn[i] + b.pn[i]; - pn[i] = n & 0xffffffff; - carry = n >> 32; - } - return *this; - } - - base_uint& operator-=(const base_uint& b) - { - *this += -b; - return *this; - } - - base_uint& operator+=(uint64_t b64) - { - base_uint b; - b = b64; - *this += b; - return *this; - } - - base_uint& operator-=(uint64_t b64) - { - base_uint b; - b = b64; - *this += -b; - return *this; - } - - base_uint& operator*=(uint32_t b32); - base_uint& operator*=(const base_uint& b); - base_uint& operator/=(const base_uint& b); - - base_uint& operator++() - { - // prefix operator - int i = 0; - while (++pn[i] == 0 && i < WIDTH-1) - i++; - return *this; - } - - const base_uint operator++(int) - { - // postfix operator - const base_uint ret = *this; - ++(*this); - return ret; - } - - base_uint& operator--() - { - // prefix operator - int i = 0; - while (--pn[i] == (uint32_t)-1 && i < WIDTH-1) - i++; - return *this; - } - - const base_uint operator--(int) - { - // postfix operator - const base_uint ret = *this; - --(*this); - return ret; - } - - int CompareTo(const base_uint& b) const; - bool EqualTo(uint64_t b) const; - - friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } - friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } - friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } - friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } - friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } - friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } - friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } - friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } - friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } - friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } - friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } - friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } - friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } - friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } - friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } - friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } - friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } - friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } - - std::string GetHex() const; - void SetHex(const char* psz); - void SetHex(const std::string& str); - std::string ToString() const; - - unsigned int size() const - { - return sizeof(pn); - } - - /** - * Returns the position of the highest bit set plus one, or zero if the - * value is zero. - */ - unsigned int bits() const; - - uint64_t GetLow64() const - { - assert(WIDTH >= 2); - return pn[0] | (uint64_t)pn[1] << 32; - } -}; - -/** 256-bit unsigned big integer. */ -class arith_uint256 : public base_uint<256> { -public: - arith_uint256() {} - arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} - arith_uint256(uint64_t b) : base_uint<256>(b) {} - explicit arith_uint256(const std::string& str) : base_uint<256>(str) {} - - /** - * The "compact" format is a representation of a whole - * number N using an unsigned 32bit number similar to a - * floating point format. - * The most significant 8 bits are the unsigned exponent of base 256. - * This exponent can be thought of as "number of bytes of N". - * The lower 23 bits are the mantissa. - * Bit number 24 (0x800000) represents the sign of N. - * N = (-1^sign) * mantissa * 256^(exponent-3) - * - * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). - * MPI uses the most significant bit of the first byte as sign. - * Thus 0x1234560000 is compact (0x05123456) - * and 0xc0de000000 is compact (0x0600c0de) - * - * Bitcoin only uses this "compact" format for encoding difficulty - * targets, which are unsigned 256bit quantities. Thus, all the - * complexities of the sign bit and using base 256 are probably an - * implementation accident. - */ - arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); - uint32_t GetCompact(bool fNegative = false) const; - - friend uint256 ArithToUint256(const arith_uint256 &); - friend arith_uint256 UintToArith256(const uint256 &); -}; - -uint256 ArithToUint256(const arith_uint256 &); -arith_uint256 UintToArith256(const uint256 &); - -#endif // BITCOIN_ARITH_UINT256_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_ARITH_UINT256_H +#define BITCOIN_ARITH_UINT256_H + +#include +#include +#include +#include +#include +#include + +class uint256; + +class uint_error : public std::runtime_error { +public: + explicit uint_error(const std::string& str) : std::runtime_error(str) {} +}; + +/** Template base class for unsigned big integers. */ +template +class base_uint +{ +protected: + enum { WIDTH=BITS/32 }; + uint32_t pn[WIDTH]; +public: + + base_uint() + { + for (int i = 0; i < WIDTH; i++) + pn[i] = 0; + } + + base_uint(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + } + + base_uint& operator=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + return *this; + } + + base_uint(uint64_t b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + } + + explicit base_uint(const std::string& str); + + bool operator!() const + { + for (int i = 0; i < WIDTH; i++) + if (pn[i] != 0) + return false; + return true; + } + + const base_uint operator~() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + return ret; + } + + const base_uint operator-() const + { + base_uint ret; + for (int i = 0; i < WIDTH; i++) + ret.pn[i] = ~pn[i]; + ret++; + return ret; + } + + double getdouble() const; + + base_uint& operator=(uint64_t b) + { + pn[0] = (unsigned int)b; + pn[1] = (unsigned int)(b >> 32); + for (int i = 2; i < WIDTH; i++) + pn[i] = 0; + return *this; + } + + base_uint& operator^=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] ^= b.pn[i]; + return *this; + } + + base_uint& operator&=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] &= b.pn[i]; + return *this; + } + + base_uint& operator|=(const base_uint& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] |= b.pn[i]; + return *this; + } + + base_uint& operator^=(uint64_t b) + { + pn[0] ^= (unsigned int)b; + pn[1] ^= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator|=(uint64_t b) + { + pn[0] |= (unsigned int)b; + pn[1] |= (unsigned int)(b >> 32); + return *this; + } + + base_uint& operator<<=(unsigned int shift); + base_uint& operator>>=(unsigned int shift); + + base_uint& operator+=(const base_uint& b) + { + uint64_t carry = 0; + for (int i = 0; i < WIDTH; i++) + { + uint64_t n = carry + pn[i] + b.pn[i]; + pn[i] = n & 0xffffffff; + carry = n >> 32; + } + return *this; + } + + base_uint& operator-=(const base_uint& b) + { + *this += -b; + return *this; + } + + base_uint& operator+=(uint64_t b64) + { + base_uint b; + b = b64; + *this += b; + return *this; + } + + base_uint& operator-=(uint64_t b64) + { + base_uint b; + b = b64; + *this += -b; + return *this; + } + + base_uint& operator*=(uint32_t b32); + base_uint& operator*=(const base_uint& b); + base_uint& operator/=(const base_uint& b); + + base_uint& operator++() + { + // prefix operator + int i = 0; + while (++pn[i] == 0 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator++(int) + { + // postfix operator + const base_uint ret = *this; + ++(*this); + return ret; + } + + base_uint& operator--() + { + // prefix operator + int i = 0; + while (--pn[i] == (uint32_t)-1 && i < WIDTH-1) + i++; + return *this; + } + + const base_uint operator--(int) + { + // postfix operator + const base_uint ret = *this; + --(*this); + return ret; + } + + int CompareTo(const base_uint& b) const; + bool EqualTo(uint64_t b) const; + + friend inline const base_uint operator+(const base_uint& a, const base_uint& b) { return base_uint(a) += b; } + friend inline const base_uint operator-(const base_uint& a, const base_uint& b) { return base_uint(a) -= b; } + friend inline const base_uint operator*(const base_uint& a, const base_uint& b) { return base_uint(a) *= b; } + friend inline const base_uint operator/(const base_uint& a, const base_uint& b) { return base_uint(a) /= b; } + friend inline const base_uint operator|(const base_uint& a, const base_uint& b) { return base_uint(a) |= b; } + friend inline const base_uint operator&(const base_uint& a, const base_uint& b) { return base_uint(a) &= b; } + friend inline const base_uint operator^(const base_uint& a, const base_uint& b) { return base_uint(a) ^= b; } + friend inline const base_uint operator>>(const base_uint& a, int shift) { return base_uint(a) >>= shift; } + friend inline const base_uint operator<<(const base_uint& a, int shift) { return base_uint(a) <<= shift; } + friend inline const base_uint operator*(const base_uint& a, uint32_t b) { return base_uint(a) *= b; } + friend inline bool operator==(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) == 0; } + friend inline bool operator!=(const base_uint& a, const base_uint& b) { return memcmp(a.pn, b.pn, sizeof(a.pn)) != 0; } + friend inline bool operator>(const base_uint& a, const base_uint& b) { return a.CompareTo(b) > 0; } + friend inline bool operator<(const base_uint& a, const base_uint& b) { return a.CompareTo(b) < 0; } + friend inline bool operator>=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) >= 0; } + friend inline bool operator<=(const base_uint& a, const base_uint& b) { return a.CompareTo(b) <= 0; } + friend inline bool operator==(const base_uint& a, uint64_t b) { return a.EqualTo(b); } + friend inline bool operator!=(const base_uint& a, uint64_t b) { return !a.EqualTo(b); } + + std::string GetHex() const; + void SetHex(const char* psz); + void SetHex(const std::string& str); + std::string ToString() const; + + unsigned int size() const + { + return sizeof(pn); + } + + /** + * Returns the position of the highest bit set plus one, or zero if the + * value is zero. + */ + unsigned int bits() const; + + uint64_t GetLow64() const + { + assert(WIDTH >= 2); + return pn[0] | (uint64_t)pn[1] << 32; + } +}; + +/** 256-bit unsigned big integer. */ +class arith_uint256 : public base_uint<256> { +public: + arith_uint256() {} + arith_uint256(const base_uint<256>& b) : base_uint<256>(b) {} + arith_uint256(uint64_t b) : base_uint<256>(b) {} + explicit arith_uint256(const std::string& str) : base_uint<256>(str) {} + + /** + * The "compact" format is a representation of a whole + * number N using an unsigned 32bit number similar to a + * floating point format. + * The most significant 8 bits are the unsigned exponent of base 256. + * This exponent can be thought of as "number of bytes of N". + * The lower 23 bits are the mantissa. + * Bit number 24 (0x800000) represents the sign of N. + * N = (-1^sign) * mantissa * 256^(exponent-3) + * + * Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). + * MPI uses the most significant bit of the first byte as sign. + * Thus 0x1234560000 is compact (0x05123456) + * and 0xc0de000000 is compact (0x0600c0de) + * + * Bitcoin only uses this "compact" format for encoding difficulty + * targets, which are unsigned 256bit quantities. Thus, all the + * complexities of the sign bit and using base 256 are probably an + * implementation accident. + */ + arith_uint256& SetCompact(uint32_t nCompact, bool *pfNegative = NULL, bool *pfOverflow = NULL); + uint32_t GetCompact(bool fNegative = false) const; + + friend uint256 ArithToUint256(const arith_uint256 &); + friend arith_uint256 UintToArith256(const uint256 &); +}; + +uint256 ArithToUint256(const arith_uint256 &); +arith_uint256 UintToArith256(const uint256 &); + +/*popchain ghost*/ +// This calculater the number divide by max uint256 +arith_uint256 maxUint256Div(const uint256 &a); +/*popchain ghost*/ + +#endif // BITCOIN_ARITH_UINT256_H diff --git a/src/chain.h b/src/chain.h index 798a40e..6cbef0f 100644 --- a/src/chain.h +++ b/src/chain.h @@ -138,6 +138,7 @@ class CBlockIndex /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 coinbaseAddress;//the autor address of this block header + uint256 difficulty;//the difficulty of this block header unsigned int number;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; @@ -168,6 +169,7 @@ class CBlockIndex /*popchain ghost*/ hashUncles = uint256(); coinbaseAddress = uint160(); + difficulty = uint256(); number = 0; /*popchain ghost*/ hashMerkleRoot = uint256(); @@ -190,6 +192,7 @@ class CBlockIndex /*popchain ghost*/ hashUncles = block.hashUncles; coinbaseAddress = block.coinbaseAddress; + difficulty = block.difficulty; number = block.number; /*popchain ghost*/ hashMerkleRoot = block.hashMerkleRoot; @@ -226,6 +229,7 @@ class CBlockIndex /*popchain ghost*/ block.hashUncles = hashUncles; block.coinbaseAddress = coinbaseAddress; + block.difficulty = difficulty; block.number = number; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; @@ -265,10 +269,11 @@ class CBlockIndex std::string ToString() const { /*popchain ghost*/ - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, number=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, difficulty=%s, number=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", pprev, nHeight, hashUncles.ToString(), coinbaseAddress.ToString(), + difficulty.ToString(), number, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), @@ -349,6 +354,7 @@ class CDiskBlockIndex : public CBlockIndex /*popchain ghost*/ READWRITE(hashUncles); READWRITE(coinbaseAddress); + READWRITE(difficulty); READWRITE(number); /*popchain ghost*/ READWRITE(hashMerkleRoot); @@ -368,6 +374,7 @@ class CDiskBlockIndex : public CBlockIndex /*popchain ghost*/ block.hashUncles = hashUncles; block.coinbaseAddress = coinbaseAddress; + block.difficulty = difficulty; block.number = number; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a46279d..410f454 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1,550 +1,552 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "base58.h" -#include "chainparams.h" -#include "consensus/merkle.h" - -#include "tinyformat.h" -#include "util.h" -#include "utilstrencodings.h" - -#include - -#include -#include "arith_uint256.h" -#include "chainparamsseeds.h" - -//#define GENESIS_GENERATION - -#ifdef GENESIS_GENERATION -#include -#include -#include -#include -#include -#include "utiltime.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "random.h" - -#include - -typedef uint32_t uint; -typedef CBlockHeader ch; -typedef long long ll; - -static std::mutex mtx; - -//test cnt 1000 times time -int64_t getCurrentTime() -{ - struct timeval tv; - gettimeofday(&tv,NULL); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -} - -// find a genesis in about 10-20 mins -void _get(const ch * const pblock, const arith_uint256 hashTarget) -{ - uint256 hash; - ch *pb = new ch(*pblock); - - for (int cnt = 0, tcnt=0; true; ++cnt,++tcnt) - { - uint256 hash = pb->GetHash(); - - //std::cout<<"hex hash = "<nNonce = ArithToUint256(UintToArith256(pb->nNonce) + 1); - if (cnt > 1e3) - { - pb->nTime = GetTime(); - cnt = 0; - } - if (tcnt !=0 and tcnt % 1000 == 0) - { - std::cout<<"cryptopop tcnt = "< guard(mtx); - std::cout << "\n\t\t----------------------------------------\t" << std::endl; - std::cout << "\t" << pb->ToString() << std::endl; - std::cout << "\n\t\t----------------------------------------\t" << std::endl; - delete pb; - - // stop while found one - assert(0); -} - -static void findGenesis(CBlockHeader *pb, const std::string &net) -{ - arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); - std::cout << " finding genesis using target " << hashTarget.ToString() - << ", " << net << std::endl; - - std::vector threads; - - for (int i = 0; i < std::min(GetNumCores(), 100); ++i) - //for (int i = 0; i < 1; ++i) - { - if (i >= 0) - { - // Randomise nonce - arith_uint256 nonce = UintToArith256(GetRandHash()); - // Clear the top and bottom 16 bits (for local use as thread flags and counters) - nonce <<= 32; - nonce >>= 16; - pb->nNonce = ArithToUint256(nonce); - //std::cout<<"i = "< printscript(genesisOutputScript.begin(),genesisOutputScript.end); - //std::cout<< StrHex(printscript)< 2 x fork detection time, was 24 * 60 * 60 in bitcoin - nPruneAfterHeight = 100000; - arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); -#ifdef GENESIS_GENERATION - arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); - std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; - //findGenesis(&genesis, "main"); -#endif - consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); - assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); - - // Pop addresses start with 'P' - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,56); - // Pop script addresses start with 'S' - base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,63); - // Pop private keys start with '5' or 'K' or 'L'(as in Bitcoin) - base58Prefixes[SECRET_KEY] = std::vector(1,0x80); - // Pop BIP32 pubkeys start with 'xpub' (Bitcoin defaults) - base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); - // Pop BIP32 prvkeys start with 'xprv' (Bitcoin defaults) - base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); - // Pop BIP44 coin type is '247' - base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0xf7).convert_to_container >(); - - //vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); - vFixedSeeds.clear(); - vSeeds.clear(); - vSeeds.push_back(CDNSSeedData("pop.xxx", "seed1.pop.xxx")); - - fMiningRequiresPeers = true; - fDefaultConsistencyChecks = false; - fRequireStandard = true; - fMineBlocksOnDemand = false; - fTestnetToBeDeprecatedFieldRPC = false; - - nPoolMaxTransactions = 3; - nFulfilledRequestExpireTime = 60*60; // fulfilled requests expire in 1 hour - strSporkPubKey = "03dc480bc3e569ea1ceed5ab8ed5904abd3e938e0f7e594ebf82397e7830fa56a5"; - - checkpointData = (CCheckpointData) { - boost::assign::map_list_of - ( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), - 1529900309, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint - }; - - // Founders reward script expects a vector of 2-of-3 multisig addresses - vFoundersRewardAddress = { - "USu35JzWCXSvgvDL1utfFzb52zR1fdkfZ9", /* main-index: 0*/ - "US2b9XyE5fCu8DNXhC4xwU7wo7b4uMNy4q", /* main-index: 1*/ - }; - } -}; -static CMainParams mainParams; - -/** - * Testnet (v3) - * Popchain DevTeam - */ -class CTestNetParams : public CChainParams { -public: - CTestNetParams() { - strNetworkID = "test"; - - // reward setting - consensus.premine = int64_t(1e7 * COIN); // premine - consensus.genesisReward = int64_t(1 * COIN); // genesis - consensus.minerReward4 = int64_t(300 * COIN); // miners - consensus.minerReward5 = int64_t(535.103 * COIN); - consensus.foundersReward = int64_t(200000 * COIN); // founders - - consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - - consensus.nSubsidyHalvingInterval = 840960; - consensus.nInstantSendKeepLock = 6; - consensus.nSuperblockStartBlock = 30; - consensus.nSuperblockCycle = 50; // Superblocks can be issued hourly on testnet - consensus.nPopnodeMinimumConfirmations = 2; - consensus.nMajorityEnforceBlockUpgrade = 51; - consensus.nMajorityRejectBlockOutdated = 75; - consensus.nMajorityWindow = 100; - consensus.BIP34Height = 0; - consensus.BIP34Hash = uint256S("00065185c3ffa77ff797ea3141fba9b1ab76a0f336863dec1199042ca5560fc4"); - consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); - consensus.nPowAveragingWindow = 17; - consensus.nPowMaxAdjustDown = 32; // 32% adjustment down - //consensus.nPowMaxAdjustUp = 16; // 16% adjustment up - consensus.nPowMaxAdjustUp = 48; // 48% adjustment up - consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day - consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes - consensus.fPowAllowMinDifficultyBlocks = true; - consensus.fPowNoRetargeting = false; - consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains - consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 123076799; // December 31, 2008 - - // Deployment of BIP68, BIP112, and BIP113. - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1524057440; // 2018/4/18 20:57:16 - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1555592236; // 2019/4/18 20:57:16 - - pchMessageStart[0] = 0xc2; - pchMessageStart[1] = 0xe6; - pchMessageStart[2] = 0xce; - pchMessageStart[3] = 0xf3; - vAlertPubKey = ParseHex("0244a0bb22e931bf59cc8a434d9d22bd2fa493f579bd2659bc9188361d78bdc45f"); - nDefaultPort = 19888; - nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet - nPruneAfterHeight = 1000; - - arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); -#ifdef GENESIS_GENERATION - arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); - std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; - //findGenesis(&genesis, "testnet"); -#endif - consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); - assert(genesis.hashMerkleRoot == uint256S("6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); - - vFixedSeeds.clear(); - vSeeds.clear(); - //vSeeds.push_back(CDNSSeedData("pop.xxx","testnet-seed1.pop.xxx")); - - // Testnet Pop addresses start with 'p' - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,118); - // Testnet Pop script addresses start with 's' - base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,125); - // Testnet private keys start with '9' or 'c'(as in Bitcoin) - base58Prefixes[SECRET_KEY] = std::vector(1,0xef); - // Testnet Pop BIP32 pubkeys start with 'tpub' (Bitcoin defaults) - base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); - // Testnet Pop BIP32 prvkeys start with 'tprv' (Bitcoin defaults) - base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); - // Testnet Pop BIP44 coin type is '1' (All coin's testnet default) - base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); - - //vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); - - fMiningRequiresPeers = true; - fDefaultConsistencyChecks = false; - fRequireStandard = true; - fMineBlocksOnDemand = false; - fTestnetToBeDeprecatedFieldRPC = true; - - nPoolMaxTransactions = 3; - nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes - strSporkPubKey = "02284dd24544e031b1b575fc4bf720a57d57425157290a9882f4d0dd192b1a316c"; - - checkpointData = (CCheckpointData) { - boost::assign::map_list_of - (0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), - 1529894661, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint - }; - - // Founders reward script expects a vector of 2-of-3 multisig addresses - vFoundersRewardAddress = { - "uTZGwu5TsrswPUEb9QciyhH9xpmRy4Rfq6", - "ubwJhHMSVPVCHr3PNPgieNYpWvuWG5XvcQ" - }; - } -}; - -static CTestNetParams testNetParams; - -/** - * Regression test - * Popchain DevTeam - */ -class CRegTestParams : public CChainParams { -public: - CRegTestParams() { - strNetworkID = "regtest"; - // reward setting - consensus.premine = int64_t(1e8 * COIN); // premine - consensus.genesisReward = int64_t(1 * COIN); // genesis - consensus.minerReward4 = int64_t(112.966 * COIN); // miners - consensus.minerReward5 = int64_t(535.103 * COIN); - consensus.foundersReward = int64_t(4166666.667 * COIN); // founders - consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - consensus.nSubsidyHalvingInterval = 150; - consensus.nInstantSendKeepLock = 6; - consensus.nSuperblockStartBlock = 1500; - consensus.nSuperblockCycle = 10; - consensus.nPopnodeMinimumConfirmations = 1; - consensus.nMajorityEnforceBlockUpgrade = 750; - consensus.nMajorityRejectBlockOutdated = 950; - consensus.nMajorityWindow = 1000; - consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest - consensus.BIP34Hash = uint256(); - consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); - consensus.nPowAveragingWindow = 17; - consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down - consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up - consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day - consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes - consensus.fPowAllowMinDifficultyBlocks = true; - consensus.fPowNoRetargeting = true; - consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains - consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1000000000000ULL; - - pchMessageStart[0] = 0xf0; - pchMessageStart[1] = 0xc5; - pchMessageStart[2] = 0xbb; - pchMessageStart[3] = 0xd0; - nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin - nDefaultPort = 29888; - nPruneAfterHeight = 1000; - - genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); -#ifdef GENESIS_GENERATION - //findGenesis(&genesis, "regtest"); -#endif - consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); - assert(genesis.hashMerkleRoot == uint256S("69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); - - vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. - vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. - - fMiningRequiresPeers = false; - fDefaultConsistencyChecks = true; - fRequireStandard = false; - fMineBlocksOnDemand = true; - fTestnetToBeDeprecatedFieldRPC = false; - - nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes - - checkpointData = (CCheckpointData){ - boost::assign::map_list_of - (0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), - 0, - 0, - 0 - }; - // Regtest Pop addresses start with 'y' - base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,140); - // Regtest Pop script addresses start with 'q' - base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,120); - // Regtest private keys start with 'm' - base58Prefixes[SECRET_KEY] = std::vector(1,0xef); - // Regtest Pop BIP32 pubkeys start with 'tpub' (Bitcoin defaults) - base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); - // Regtest Pop BIP32 prvkeys start with 'tprv' (Bitcoin defaults) - base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); - // Regtest Pop BIP44 coin type is '1' (All coin's testnet default) - base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); - - // Founders reward script expects a vector of 2-of-3 multisig addresses - vFoundersRewardAddress = {"u2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg"}; - } -}; -static CRegTestParams regTestParams; - -static CChainParams *pCurrentParams = 0; - -const CChainParams &Params() { - assert(pCurrentParams); - return *pCurrentParams; -} - -CChainParams& Params(const std::string& chain) -{ - if (chain == CBaseChainParams::MAIN) - return mainParams; - else if (chain == CBaseChainParams::TESTNET) - return testNetParams; - else if (chain == CBaseChainParams::REGTEST) - return regTestParams; - else - throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); -} - -void SelectParams(const std::string& network) -{ - SelectBaseParams(network); - pCurrentParams = &Params(network); -} - -// Block height must be >1 and 1 && height < consensus.endOfFoundersReward()); - - height /= consensus.nSuperblockCycle; - size_t i = height % vFoundersRewardAddress.size(); - return vFoundersRewardAddress[i]; -} - -// Block height must be >1 and 1 && height < consensus.endOfFoundersReward()); - - CBitcoinAddress address(GetFoundersRewardAddressAtHeight(height).c_str()); - assert(address.IsValid()); - CScript scriptPubKey = GetScriptForDestination(address.Get()); - return scriptPubKey; -} - -std::string CChainParams::GetFoundersRewardAddressAtIndex(int i) const -{ - assert(i >= 0 && i < int(vFoundersRewardAddress.size())); - return vFoundersRewardAddress[i]; -} - +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "base58.h" +#include "chainparams.h" +#include "consensus/merkle.h" + +#include "tinyformat.h" +#include "util.h" +#include "utilstrencodings.h" + +#include + +#include +#include "arith_uint256.h" +#include "chainparamsseeds.h" + +//#define GENESIS_GENERATION + +#ifdef GENESIS_GENERATION +#include +#include +#include +#include +#include +#include "utiltime.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "random.h" + +#include + +typedef uint32_t uint; +typedef CBlockHeader ch; +typedef long long ll; + +static std::mutex mtx; + +//test cnt 1000 times time +int64_t getCurrentTime() +{ + struct timeval tv; + gettimeofday(&tv,NULL); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} + +// find a genesis in about 10-20 mins +void _get(const ch * const pblock, const arith_uint256 hashTarget) +{ + uint256 hash; + ch *pb = new ch(*pblock); + + for (int cnt = 0, tcnt=0; true; ++cnt,++tcnt) + { + uint256 hash = pb->GetHash(); + + //std::cout<<"hex hash = "<nNonce = ArithToUint256(UintToArith256(pb->nNonce) + 1); + if (cnt > 1e3) + { + pb->nTime = GetTime(); + cnt = 0; + } + if (tcnt !=0 and tcnt % 1000 == 0) + { + std::cout<<"cryptopop tcnt = "< guard(mtx); + std::cout << "\n\t\t----------------------------------------\t" << std::endl; + std::cout << "\t" << pb->ToString() << std::endl; + std::cout << "\n\t\t----------------------------------------\t" << std::endl; + delete pb; + + // stop while found one + assert(0); +} + +static void findGenesis(CBlockHeader *pb, const std::string &net) +{ + /*popchain ghost*/ + arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); + /*popchain ghost*/ + std::cout << " finding genesis using target " << hashTarget.ToString() + << ", " << net << std::endl; + + std::vector threads; + + for (int i = 0; i < std::min(GetNumCores(), 100); ++i) + //for (int i = 0; i < 1; ++i) + { + if (i >= 0) + { + // Randomise nonce + arith_uint256 nonce = UintToArith256(GetRandHash()); + // Clear the top and bottom 16 bits (for local use as thread flags and counters) + nonce <<= 32; + nonce >>= 16; + pb->nNonce = ArithToUint256(nonce); + //std::cout<<"i = "< printscript(genesisOutputScript.begin(),genesisOutputScript.end); + //std::cout<< StrHex(printscript)< 2 x fork detection time, was 24 * 60 * 60 in bitcoin + nPruneAfterHeight = 100000; + arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); +#ifdef GENESIS_GENERATION + arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); + std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; + //findGenesis(&genesis, "main"); +#endif + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); + assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); + + // Pop addresses start with 'P' + base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,56); + // Pop script addresses start with 'S' + base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,63); + // Pop private keys start with '5' or 'K' or 'L'(as in Bitcoin) + base58Prefixes[SECRET_KEY] = std::vector(1,0x80); + // Pop BIP32 pubkeys start with 'xpub' (Bitcoin defaults) + base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x88)(0xB2)(0x1E).convert_to_container >(); + // Pop BIP32 prvkeys start with 'xprv' (Bitcoin defaults) + base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x88)(0xAD)(0xE4).convert_to_container >(); + // Pop BIP44 coin type is '247' + base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0xf7).convert_to_container >(); + + //vFixedSeeds = std::vector(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main)); + vFixedSeeds.clear(); + vSeeds.clear(); + vSeeds.push_back(CDNSSeedData("pop.xxx", "seed1.pop.xxx")); + + fMiningRequiresPeers = true; + fDefaultConsistencyChecks = false; + fRequireStandard = true; + fMineBlocksOnDemand = false; + fTestnetToBeDeprecatedFieldRPC = false; + + nPoolMaxTransactions = 3; + nFulfilledRequestExpireTime = 60*60; // fulfilled requests expire in 1 hour + strSporkPubKey = "03dc480bc3e569ea1ceed5ab8ed5904abd3e938e0f7e594ebf82397e7830fa56a5"; + + checkpointData = (CCheckpointData) { + boost::assign::map_list_of + ( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), + 1529900309, // * UNIX timestamp of last checkpoint block + 0, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 0 // * estimated number of transactions per day after checkpoint + }; + + // Founders reward script expects a vector of 2-of-3 multisig addresses + vFoundersRewardAddress = { + "USu35JzWCXSvgvDL1utfFzb52zR1fdkfZ9", /* main-index: 0*/ + "US2b9XyE5fCu8DNXhC4xwU7wo7b4uMNy4q", /* main-index: 1*/ + }; + } +}; +static CMainParams mainParams; + +/** + * Testnet (v3) + * Popchain DevTeam + */ +class CTestNetParams : public CChainParams { +public: + CTestNetParams() { + strNetworkID = "test"; + + // reward setting + consensus.premine = int64_t(1e7 * COIN); // premine + consensus.genesisReward = int64_t(1 * COIN); // genesis + consensus.minerReward4 = int64_t(300 * COIN); // miners + consensus.minerReward5 = int64_t(535.103 * COIN); + consensus.foundersReward = int64_t(200000 * COIN); // founders + + consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral + + consensus.nSubsidyHalvingInterval = 840960; + consensus.nInstantSendKeepLock = 6; + consensus.nSuperblockStartBlock = 30; + consensus.nSuperblockCycle = 50; // Superblocks can be issued hourly on testnet + consensus.nPopnodeMinimumConfirmations = 2; + consensus.nMajorityEnforceBlockUpgrade = 51; + consensus.nMajorityRejectBlockOutdated = 75; + consensus.nMajorityWindow = 100; + consensus.BIP34Height = 0; + consensus.BIP34Hash = uint256S("00065185c3ffa77ff797ea3141fba9b1ab76a0f336863dec1199042ca5560fc4"); + consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); + consensus.nPowAveragingWindow = 17; + consensus.nPowMaxAdjustDown = 32; // 32% adjustment down + //consensus.nPowMaxAdjustUp = 16; // 16% adjustment up + consensus.nPowMaxAdjustUp = 48; // 48% adjustment up + consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day + consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + consensus.fPowAllowMinDifficultyBlocks = true; + consensus.fPowNoRetargeting = false; + consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains + consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008 + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 123076799; // December 31, 2008 + + // Deployment of BIP68, BIP112, and BIP113. + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1524057440; // 2018/4/18 20:57:16 + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1555592236; // 2019/4/18 20:57:16 + + pchMessageStart[0] = 0xc2; + pchMessageStart[1] = 0xe6; + pchMessageStart[2] = 0xce; + pchMessageStart[3] = 0xf3; + vAlertPubKey = ParseHex("0244a0bb22e931bf59cc8a434d9d22bd2fa493f579bd2659bc9188361d78bdc45f"); + nDefaultPort = 19888; + nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet + nPruneAfterHeight = 1000; + + arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); +#ifdef GENESIS_GENERATION + arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); + std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; + //findGenesis(&genesis, "testnet"); +#endif + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); + assert(genesis.hashMerkleRoot == uint256S("6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); + + vFixedSeeds.clear(); + vSeeds.clear(); + //vSeeds.push_back(CDNSSeedData("pop.xxx","testnet-seed1.pop.xxx")); + + // Testnet Pop addresses start with 'p' + base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,118); + // Testnet Pop script addresses start with 's' + base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,125); + // Testnet private keys start with '9' or 'c'(as in Bitcoin) + base58Prefixes[SECRET_KEY] = std::vector(1,0xef); + // Testnet Pop BIP32 pubkeys start with 'tpub' (Bitcoin defaults) + base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); + // Testnet Pop BIP32 prvkeys start with 'tprv' (Bitcoin defaults) + base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); + // Testnet Pop BIP44 coin type is '1' (All coin's testnet default) + base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); + + //vFixedSeeds = std::vector(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test)); + + fMiningRequiresPeers = true; + fDefaultConsistencyChecks = false; + fRequireStandard = true; + fMineBlocksOnDemand = false; + fTestnetToBeDeprecatedFieldRPC = true; + + nPoolMaxTransactions = 3; + nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes + strSporkPubKey = "02284dd24544e031b1b575fc4bf720a57d57425157290a9882f4d0dd192b1a316c"; + + checkpointData = (CCheckpointData) { + boost::assign::map_list_of + (0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), + 1529894661, // * UNIX timestamp of last checkpoint block + 0, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 0 // * estimated number of transactions per day after checkpoint + }; + + // Founders reward script expects a vector of 2-of-3 multisig addresses + vFoundersRewardAddress = { + "uTZGwu5TsrswPUEb9QciyhH9xpmRy4Rfq6", + "ubwJhHMSVPVCHr3PNPgieNYpWvuWG5XvcQ" + }; + } +}; + +static CTestNetParams testNetParams; + +/** + * Regression test + * Popchain DevTeam + */ +class CRegTestParams : public CChainParams { +public: + CRegTestParams() { + strNetworkID = "regtest"; + // reward setting + consensus.premine = int64_t(1e8 * COIN); // premine + consensus.genesisReward = int64_t(1 * COIN); // genesis + consensus.minerReward4 = int64_t(112.966 * COIN); // miners + consensus.minerReward5 = int64_t(535.103 * COIN); + consensus.foundersReward = int64_t(4166666.667 * COIN); // founders + consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral + consensus.nSubsidyHalvingInterval = 150; + consensus.nInstantSendKeepLock = 6; + consensus.nSuperblockStartBlock = 1500; + consensus.nSuperblockCycle = 10; + consensus.nPopnodeMinimumConfirmations = 1; + consensus.nMajorityEnforceBlockUpgrade = 750; + consensus.nMajorityRejectBlockOutdated = 950; + consensus.nMajorityWindow = 1000; + consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest + consensus.BIP34Hash = uint256(); + consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + consensus.nPowAveragingWindow = 17; + consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down + consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up + consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day + consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + consensus.fPowAllowMinDifficultyBlocks = true; + consensus.fPowNoRetargeting = true; + consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains + consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 999999999999ULL; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].bit = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; + consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1000000000000ULL; + + pchMessageStart[0] = 0xf0; + pchMessageStart[1] = 0xc5; + pchMessageStart[2] = 0xbb; + pchMessageStart[3] = 0xd0; + nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin + nDefaultPort = 29888; + nPruneAfterHeight = 1000; + + genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); +#ifdef GENESIS_GENERATION + //findGenesis(&genesis, "regtest"); +#endif + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); + assert(genesis.hashMerkleRoot == uint256S("69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); + + vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. + vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. + + fMiningRequiresPeers = false; + fDefaultConsistencyChecks = true; + fRequireStandard = false; + fMineBlocksOnDemand = true; + fTestnetToBeDeprecatedFieldRPC = false; + + nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes + + checkpointData = (CCheckpointData){ + boost::assign::map_list_of + (0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), + 0, + 0, + 0 + }; + // Regtest Pop addresses start with 'y' + base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,140); + // Regtest Pop script addresses start with 'q' + base58Prefixes[SCRIPT_ADDRESS] = std::vector(1,120); + // Regtest private keys start with 'm' + base58Prefixes[SECRET_KEY] = std::vector(1,0xef); + // Regtest Pop BIP32 pubkeys start with 'tpub' (Bitcoin defaults) + base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container >(); + // Regtest Pop BIP32 prvkeys start with 'tprv' (Bitcoin defaults) + base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container >(); + // Regtest Pop BIP44 coin type is '1' (All coin's testnet default) + base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); + + // Founders reward script expects a vector of 2-of-3 multisig addresses + vFoundersRewardAddress = {"u2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg"}; + } +}; +static CRegTestParams regTestParams; + +static CChainParams *pCurrentParams = 0; + +const CChainParams &Params() { + assert(pCurrentParams); + return *pCurrentParams; +} + +CChainParams& Params(const std::string& chain) +{ + if (chain == CBaseChainParams::MAIN) + return mainParams; + else if (chain == CBaseChainParams::TESTNET) + return testNetParams; + else if (chain == CBaseChainParams::REGTEST) + return regTestParams; + else + throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain)); +} + +void SelectParams(const std::string& network) +{ + SelectBaseParams(network); + pCurrentParams = &Params(network); +} + +// Block height must be >1 and 1 && height < consensus.endOfFoundersReward()); + + height /= consensus.nSuperblockCycle; + size_t i = height % vFoundersRewardAddress.size(); + return vFoundersRewardAddress[i]; +} + +// Block height must be >1 and 1 && height < consensus.endOfFoundersReward()); + + CBitcoinAddress address(GetFoundersRewardAddressAtHeight(height).c_str()); + assert(address.IsValid()); + CScript scriptPubKey = GetScriptForDestination(address.Get()); + return scriptPubKey; +} + +std::string CChainParams::GetFoundersRewardAddressAtIndex(int i) const +{ + assert(i >= 0 && i < int(vFoundersRewardAddress.size())); + return vFoundersRewardAddress[i]; +} + diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 87e37d2..8c9d1a7 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -11,8 +11,10 @@ uint256 CBlockHeader::GetHash() const { // return SerializeHash(*this); uint256 hash; - +/*popchain ghost*/ CryptoPop(this, (unsigned char *)&hash); +/*popchain ghost*/ + // view_data_u8("PoW 3", (unsigned char *)&hash, OUTPUT_LEN); // std::cout<<"gethex() ="< Date: Tue, 31 Jul 2018 10:10:10 +0800 Subject: [PATCH 011/120] change for insert difficulty to block header --- src/chain.h | 44 +- src/chainparams.cpp | 61 +- src/main.cpp | 10 +- src/pow.cpp | 269 ++--- src/pow.h | 58 +- src/primitives/block.cpp | 16 +- src/primitives/block.h | 24 +- src/rpcmining.cpp | 1669 ++++++++++++++-------------- src/test/claimtrie_tests.cpp | 2017 +++++++++++++++++----------------- src/test/test_pop.cpp | 374 +++---- src/txdb.cpp | 11 +- 11 files changed, 2305 insertions(+), 2248 deletions(-) diff --git a/src/chain.h b/src/chain.h index 6cbef0f..79962c0 100644 --- a/src/chain.h +++ b/src/chain.h @@ -137,9 +137,9 @@ class CBlockIndex int nVersion; /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header - uint160 coinbaseAddress;//the autor address of this block header - uint256 difficulty;//the difficulty of this block header - unsigned int number;//the height of this block header + uint160 nCoinbase;//the autor address of this block header + uint256 nDifficulty;//the difficulty of this block header + unsigned int nNumber;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; @@ -168,9 +168,9 @@ class CBlockIndex nVersion = 0; /*popchain ghost*/ hashUncles = uint256(); - coinbaseAddress = uint160(); - difficulty = uint256(); - number = 0; + nCoinbase = uint160(); + nDifficulty = uint256(); + nNumber = 0; /*popchain ghost*/ hashMerkleRoot = uint256(); hashClaimTrie = uint256(); @@ -191,9 +191,9 @@ class CBlockIndex nVersion = block.nVersion; /*popchain ghost*/ hashUncles = block.hashUncles; - coinbaseAddress = block.coinbaseAddress; - difficulty = block.difficulty; - number = block.number; + nCoinbase = block.nCoinbase; + nDifficulty = block.nDifficulty; + nNumber = block.nNumber; /*popchain ghost*/ hashMerkleRoot = block.hashMerkleRoot; hashClaimTrie = block.hashClaimTrie; @@ -228,9 +228,9 @@ class CBlockIndex block.hashPrevBlock = pprev->GetBlockHash(); /*popchain ghost*/ block.hashUncles = hashUncles; - block.coinbaseAddress = coinbaseAddress; - block.difficulty = difficulty; - block.number = number; + block.nCoinbase = nCoinbase; + block.nDifficulty = nDifficulty; + block.nNumber = nNumber; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; @@ -269,12 +269,12 @@ class CBlockIndex std::string ToString() const { /*popchain ghost*/ - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, coinbaseAddress=%s, difficulty=%s, number=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", pprev, nHeight, hashUncles.ToString(), - coinbaseAddress.ToString(), - difficulty.ToString(), - number, + nCoinbase.ToString(), + nDifficulty.ToString(), + nNumber, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), GetBlockHash().ToString()); @@ -353,9 +353,9 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(hashPrev); /*popchain ghost*/ READWRITE(hashUncles); - READWRITE(coinbaseAddress); - READWRITE(difficulty); - READWRITE(number); + READWRITE(nCoinbase); + READWRITE(nDifficulty); + READWRITE(nNumber); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); @@ -373,9 +373,9 @@ class CDiskBlockIndex : public CBlockIndex block.hashPrevBlock = hashPrev; /*popchain ghost*/ block.hashUncles = hashUncles; - block.coinbaseAddress = coinbaseAddress; - block.difficulty = difficulty; - block.number = number; + block.nCoinbase = nCoinbase; + block.nDifficulty = nDifficulty; + block.nNumber = nNumber; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 410f454..ce80221 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -88,7 +88,8 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) static void findGenesis(CBlockHeader *pb, const std::string &net) { /*popchain ghost*/ - arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); + //arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); + arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); /*popchain ghost*/ std::cout << " finding genesis using target " << hashTarget.ToString() << ", " << net << std::endl; @@ -117,8 +118,9 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) } } #endif - -static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) +/*popchain ghost*/ +//static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) +static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const CAmount &genesisReward) { CMutableTransaction txNew; txNew.nVersion = 1; @@ -130,7 +132,11 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi CBlock genesis; genesis.nTime = nTime; - genesis.nBits = nBits; + /*popchain ghost*/ + genesis.nDifficulty = nDifficulty; + genesis.nBits = maxUint256Div(nDifficulty).GetCompact(); + //genesis.nBits = nBits; + /*popchain ghost*/ genesis.nNonce = nNonce; genesis.nVersion = nVersion; genesis.vtx.push_back(txNew); @@ -139,7 +145,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.hashClaimTrie = uint256S("0x1"); return genesis; } - +/*popchain ghost*/ /** * Build the genesis block. Note that the output of its generation * transaction cannot be spent since it did not originally exist in the @@ -151,21 +157,27 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi * CTxOut(nValue=50.00000000, scriptPubKey=0xA9037BAC7050C479B121CF) * vMerkleTree: e0028e */ -static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) + /*popchain ghost*/ +//static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) +static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const int64_t& genesisReward) { const char* pszTimestamp = "pop hold value testnet."; const CScript genesisOutputScript = CScript() << ParseHex("034c73d75f59061a08032b68369e5034390abc5215b3df79be01fb4319173a88f8") << OP_CHECKSIG; //std::vector printscript(genesisOutputScript.begin(),genesisOutputScript.end); //std::cout<< StrHex(printscript)< 2 x fork detection time, was 24 * 60 * 60 in bitcoin nPruneAfterHeight = 100000; - arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); + /*popchain ghost*/ + //arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); + genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), consensus.powLimit, 1, consensus.genesisReward); + /*popchain ghost*/ #ifdef GENESIS_GENERATION arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); - std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; + /*popchain ghost*/ + //std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; + std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; + /*popchain ghost*/ //findGenesis(&genesis, "main"); #endif consensus.hashGenesisBlock = genesis.GetHash(); @@ -341,12 +359,17 @@ class CTestNetParams : public CChainParams { nDefaultPort = 19888; nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet nPruneAfterHeight = 1000; - - arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); + /*popchain ghost*/ + //arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), consensus.powLimit, 1, 1 * COIN); + /*popchain ghost*/ #ifdef GENESIS_GENERATION arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); - std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; + /*popchain ghost*/ + //std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; + std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; + /*popchain ghost*/ //findGenesis(&genesis, "testnet"); #endif consensus.hashGenesisBlock = genesis.GetHash(); @@ -450,8 +473,10 @@ class CRegTestParams : public CChainParams { nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin nDefaultPort = 29888; nPruneAfterHeight = 1000; - - genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); + /*popchain ghost*/ + //genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); + genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), consensus.powLimit, 1, 1 * COIN); + /*popchain ghost*/ #ifdef GENESIS_GENERATION //findGenesis(&genesis, "regtest"); #endif diff --git a/src/main.cpp b/src/main.cpp index 3cd5b34..c67028b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1704,9 +1704,11 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: //arith_uint256 k = UintToArith256(block.GetHash()); //LogPrintf("\t\t\tblock = %s\n\t\t\thash = %s\n\t\t\tarith hash = %s\n", block.ToString().c_str(), block.GetHash().ToString().c_str(), k.ToString().c_str()); - if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) + /*popchain ghost*/ + //if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) + if (!CheckProofOfWork(block.GetHash(), block.nDifficulty, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); - + /*popchain ghost*/ return true; } @@ -3861,7 +3863,9 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + /*popchain ghost*/ + //if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nDifficulty, Params().GetConsensus())) { LogPrintf("CheckBlockHeader(): \n--b-l-o-c-k---%s\n\n", block.ToString().c_str()); return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), diff --git a/src/pow.cpp b/src/pow.cpp index 9b72bfd..1222a1d 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,129 +1,140 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "pow.h" - -#include "arith_uint256.h" -#include "chain.h" -#include "chainparams.h" -#include "primitives/block.h" -#include "uint256.h" -#include "util.h" - -#include - -#include -#include - -// daa from zcash -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) -{ - unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - - // Genesis block - if (pindexLast == NULL) - return nProofOfWorkLimit; - - // Find the first block in the averaging interval - const CBlockIndex* pindexFirst = pindexLast; - arith_uint256 bnTot {0}; - for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) { - arith_uint256 bnTmp; - bnTmp.SetCompact(pindexFirst->nBits); - bnTot += bnTmp; - pindexFirst = pindexFirst->pprev; - } - - // Check we have enough blocks - if (pindexFirst == NULL) - return nProofOfWorkLimit; - - arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow}; - - return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params); -} - -unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, - int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params& params) -{ - // Limit adjustment step - // Use medians to prevent time-warp attacks - int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; - LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4; - LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); - - if (nActualTimespan < params.MinActualTimespan()) - nActualTimespan = params.MinActualTimespan(); - if (nActualTimespan > params.MaxActualTimespan()) - nActualTimespan = params.MaxActualTimespan(); - - // Retarget - const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); - arith_uint256 bnNew {bnAvg}; - bnNew /= params.AveragingWindowTimespan(); - bnNew *= nActualTimespan; - - if (bnNew > bnPowLimit) - bnNew = bnPowLimit; - - /// debug print - LogPrint("pow", "GetNextWorkRequired RETARGET\n"); - LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(), nActualTimespan); - LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); - LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); - - return bnNew.GetCompact(); -} - -bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) -{ - bool fNegative = false; - bool fOverflow = false; - arith_uint256 bnTarget; - - bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - - // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) - return error("CheckProofOfWork(): nBits below minimum work"); - - // Check proof of work matches claimed amount - if (UintToArith256(hash) > bnTarget) - { - return error("CheckProofOfWork(): hash doesn't match nBits"); - } - return true; -} - -arith_uint256 GetBlockProof(const CBlockIndex& block) -{ - arith_uint256 bnTarget; - bool fNegative; - bool fOverflow; - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a arith_uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; -} - -int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) -{ - arith_uint256 r; - int sign = 1; - if (to.nChainWork > from.nChainWork) { - r = to.nChainWork - from.nChainWork; - } else { - r = from.nChainWork - to.nChainWork; - sign = -1; - } - r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); - if (r.bits() > 63) { - return sign * std::numeric_limits::max(); - } - return sign * r.GetLow64(); -} +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "pow.h" + +#include "arith_uint256.h" +#include "chain.h" +#include "chainparams.h" +#include "primitives/block.h" +#include "uint256.h" +#include "util.h" + +#include + +#include +#include + +// daa from zcash +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +{ + unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); + + // Genesis block + if (pindexLast == NULL) + return nProofOfWorkLimit; + + // Find the first block in the averaging interval + const CBlockIndex* pindexFirst = pindexLast; + arith_uint256 bnTot {0}; + for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) { + arith_uint256 bnTmp; + bnTmp.SetCompact(pindexFirst->nBits); + bnTot += bnTmp; + pindexFirst = pindexFirst->pprev; + } + + // Check we have enough blocks + if (pindexFirst == NULL) + return nProofOfWorkLimit; + + arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow}; + + return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params); +} + +unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, + int64_t nLastBlockTime, int64_t nFirstBlockTime, + const Consensus::Params& params) +{ + // Limit adjustment step + // Use medians to prevent time-warp attacks + int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; + LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); + nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4; + LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); + + if (nActualTimespan < params.MinActualTimespan()) + nActualTimespan = params.MinActualTimespan(); + if (nActualTimespan > params.MaxActualTimespan()) + nActualTimespan = params.MaxActualTimespan(); + + // Retarget + const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); + arith_uint256 bnNew {bnAvg}; + bnNew /= params.AveragingWindowTimespan(); + bnNew *= nActualTimespan; + + if (bnNew > bnPowLimit) + bnNew = bnPowLimit; + + /// debug print + LogPrint("pow", "GetNextWorkRequired RETARGET\n"); + LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(), nActualTimespan); + LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); + LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); + + return bnNew.GetCompact(); +} +/*popchain ghost*/ +//bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) +bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) +{ + bool fNegative = false; + bool fOverflow = false; + arith_uint256 bnTarget; + + //bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + bnTarget = maxUint256Div(nDifficulty); + + // Check range + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) + return error("CheckProofOfWork(): nBits below minimum work"); + + // Check proof of work matches claimed amount + if (UintToArith256(hash) > bnTarget) + { + return error("CheckProofOfWork(): hash doesn't match nBits"); + } + return true; +} + +/*popchain ghost*/ + +/*popchain ghost*/ +arith_uint256 GetBlockProof(const CBlockIndex& block) +{ + arith_uint256 bnTarget; + bool fNegative; + bool fOverflow; + /* + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); + if (fNegative || fOverflow || bnTarget == 0) + return 0; + // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 + // as it's too large for a arith_uint256. However, as 2**256 is at least as large + // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, + // or ~bnTarget / (nTarget+1) + 1. + return (~bnTarget / (bnTarget + 1)) + 1; + */ + bnTarget = maxUint256Div(block.nDifficulty); + return bnTarget; +} + +/*popchain ghost*/ + +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params) +{ + arith_uint256 r; + int sign = 1; + if (to.nChainWork > from.nChainWork) { + r = to.nChainWork - from.nChainWork; + } else { + r = from.nChainWork - to.nChainWork; + sign = -1; + } + r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); + if (r.bits() > 63) { + return sign * std::numeric_limits::max(); + } + return sign * r.GetLow64(); +} diff --git a/src/pow.h b/src/pow.h index 11988eb..bef5b71 100644 --- a/src/pow.h +++ b/src/pow.h @@ -1,27 +1,31 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#ifndef BITCOIN_POW_H -#define BITCOIN_POW_H - -#include "consensus/params.h" - -#include - -class CBlockHeader; -class CBlockIndex; -class uint256; -class arith_uint256; - -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); -unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, - int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params&); - -/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); -arith_uint256 GetBlockProof(const CBlockIndex& block); - -/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */ -int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); - -#endif // BITCOIN_POW_H +// Copyright (c) 2017-2018 The Popchain Core Developers + +#ifndef BITCOIN_POW_H +#define BITCOIN_POW_H + +#include "consensus/params.h" + +#include + +class CBlockHeader; +class CBlockIndex; +class uint256; +class arith_uint256; +/*popchain ghost*/ +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); +/*popchain ghost*/ +unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, + int64_t nLastBlockTime, int64_t nFirstBlockTime, + const Consensus::Params&); + +/** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ +/*popchain ghost*/ +//bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params&); +/*popchain ghost*/ +arith_uint256 GetBlockProof(const CBlockIndex& block); + +/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */ +int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); + +#endif // BITCOIN_POW_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 8c9d1a7..5bf7ff2 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -25,14 +25,14 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, coinbaseAddress=%s, difficulty=%s, number=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(), - coinbaseAddress.ToString(),/*change by base58 ?*/ - difficulty.ToString(), - number, + nCoinbase.ToString(),/*change by base58 ?*/ + nDifficulty.ToString(), + nNumber, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, nBits, nNonce.ToString()); @@ -43,14 +43,14 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, coinbaseAddress=%s, difficulty=%s, number=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, nCoinbaseAddress=%s, nDifficulty=%s, nNumber=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(),/*popchain ghost*/ - coinbaseAddress.ToString(),/*popchain ghost*/ - difficulty.ToString(),/*popchain ghost*/ - number,/*popchain ghost*/ + nCoinbase.ToString(),/*popchain ghost*/ + nDifficulty.ToString(),/*popchain ghost*/ + nNumber,/*popchain ghost*/ hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, nBits, nNonce.ToString(), diff --git a/src/primitives/block.h b/src/primitives/block.h index 59f244e..f19f49a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -23,9 +23,9 @@ class CBlockHeader uint256 hashPrevBlock; /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header - uint160 coinbaseAddress;//the autor address of this block header - uint256 difficulty;//the difficulty of this block - uint32_t number;//the height of this block header + uint160 nCoinbase;//the autor address of this block header + uint256 nDifficulty;//the difficulty of this block + uint32_t nNumber;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; // for claim operation @@ -47,9 +47,9 @@ class CBlockHeader READWRITE(hashPrevBlock); /*popchain ghost*/ READWRITE(hashUncles); - READWRITE(coinbaseAddress); - READWRITE(difficulty); - READWRITE(number); + READWRITE(nCoinbase); + READWRITE(nDifficulty); + READWRITE(nNumber); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); @@ -64,9 +64,9 @@ class CBlockHeader hashPrevBlock.SetNull(); /*popchain ghost*/ hashUncles.SetNull(); - coinbaseAddress.SetNull(); - difficulty.SetNull(); - number=0; + nCoinbase.SetNull(); + nDifficulty.SetNull(); + nNumber=0; /*popchain ghost*/ hashMerkleRoot.SetNull(); hashClaimTrie.SetNull(); @@ -144,9 +144,9 @@ class CBlock : public CBlockHeader block.hashPrevBlock = hashPrevBlock; /*popchain ghost*/ block.hashUncles = hashUncles; - block.coinbaseAddress = coinbaseAddress; - block.difficulty = difficulty; - block.number = number; + block.nCoinbase = nCoinbase; + block.nDifficulty = nDifficulty; + block.nNumber = nNumber; /*popchian ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index a659ed4..5e074cd 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -1,834 +1,835 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#include "amount.h" -#include "rpcserver.h" -#include "base58.h" -#include "amount.h" -#include "chain.h" -#include "chainparams.h" -#include "consensus/consensus.h" -#include "consensus/validation.h" -#include "core_io.h" -#include "init.h" -#include "main.h" -#include "miner.h" -#include "net.h" -#include "pow.h" -#include "rpcserver.h" -#include "spork.h" -#include "txmempool.h" -#include "util.h" -#ifdef ENABLE_WALLET -#include "popnode-sync.h" -#endif -#include "utilstrencodings.h" -#include "validationinterface.h" - -#include - -#include -#include - -#include - -using namespace std; - -/** - * Return average network hashes per second based on the last 'lookup' blocks, - * or from the last difficulty change if 'lookup' is nonpositive. - * If 'height' is nonnegative, compute the estimate at the time when a given block was found. - */ -UniValue GetNetworkHashPS(int lookup, int height) { - CBlockIndex *pb = chainActive.Tip(); - - if (height >= 0 && height < chainActive.Height()) - pb = chainActive[height]; - - if (pb == NULL || !pb->nHeight) - return 0; - - // If lookup is -1, then use blocks since last difficulty change. - if (lookup <= 0) - { - lookup = Params().GetConsensus().nPowAveragingWindow; - } - // If lookup is larger than chain, then set it to chain length. - if (lookup > pb->nHeight) - lookup = pb->nHeight; - - CBlockIndex *pb0 = pb; - int64_t minTime = pb0->GetBlockTime(); - int64_t maxTime = minTime; - for (int i = 0; i < lookup; i++) { - pb0 = pb0->pprev; - int64_t time = pb0->GetBlockTime(); - minTime = std::min(time, minTime); - maxTime = std::max(time, maxTime); - } - - // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception. - if (minTime == maxTime) - return 0; - - arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; - int64_t timeDiff = maxTime - minTime; - - return workDiff.getdouble() / timeDiff; -} - -UniValue getnetworkhashps(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "getnetworkhashps ( blocks height )\n" - "\nReturns the estimated network hashes per second based on the last n blocks.\n" - "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" - "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" - "\nArguments:\n" - "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" - "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" - "\nResult:\n" - "x (numeric) Hashes per second estimated\n" - "\nExamples:\n" - + HelpExampleCli("getnetworkhashps", "") - + HelpExampleRpc("getnetworkhashps", "") - ); - - LOCK(cs_main); - return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); -} - -UniValue getgenerate(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getgenerate\n" - "\nReturn if the server is set to generate coins or not. The default is false.\n" - "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n" - "It can also be set with the setgenerate call.\n" - "\nResult\n" - "true|false (boolean) If the server is set to generate coins or not\n" - "\nExamples:\n" - + HelpExampleCli("getgenerate", "") - + HelpExampleRpc("getgenerate", "") - ); - - LOCK(cs_main); - return GetBoolArg("-gen", DEFAULT_GENERATE); -} - -UniValue generate(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 1) - throw runtime_error( - "generate numblocks\n" - "\nMine blocks immediately (before the RPC call returns)\n" - "\nNote: this function can only be used on the regtest network\n" - "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array) hashes of blocks generated\n" - "\nExamples:\n" - "\nGenerate 11 blocks\n" - + HelpExampleCli("generate", "11") - ); - - if (!Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); - - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - int nGenerate = params[0].get_int(); - - boost::shared_ptr coinbaseScript; - GetMainSignals().ScriptForMining(coinbaseScript); - - // If the keypool is exhausted, no script is returned at all. Catch this. - if (!coinbaseScript) - throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); - - //throw an error if no script was provided - if (coinbaseScript->reserveScript.empty()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); - - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart+nGenerate; - } - unsigned int nExtraNonce = 0; - UniValue blockHashes(UniValue::VARR); - while (nHeight < nHeightEnd) - { - unique_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - CBlock *pblock = &pblocktemplate->block; - { - LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); - } - - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { - // Yes, there is a chance every nonce could fail to satisfy the -regtest - // target -- 1 in 2^(2^32). That ain't gonna happen - pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); - } - CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); - ++nHeight; - blockHashes.push_back(pblock->GetHash().GetHex()); - - //mark script as important because it was used at least for one coinbase output - coinbaseScript->KeepScript(); - } - return blockHashes; -} - -UniValue setgenerate(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "setgenerate generate ( genproclimit )\n" - "\nSet 'generate' true or false to turn generation on or off.\n" - "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" - "See the getgenerate call for the current setting.\n" - "\nArguments:\n" - "1. generate (boolean, required) Set to true to turn on generation, false to turn off.\n" - "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" - "\nExamples:\n" - "\nSet the generation on with a limit of one processor\n" - + HelpExampleCli("setgenerate", "true 1") + - "\nCheck the setting\n" - + HelpExampleCli("getgenerate", "") + - "\nTurn off generation\n" - + HelpExampleCli("setgenerate", "false") + - "\nUsing json rpc\n" - + HelpExampleRpc("setgenerate", "true, 1") - ); - - if (Params().MineBlocksOnDemand()) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); - - bool fGenerate = true; - if (params.size() > 0) - fGenerate = params[0].get_bool(); - - int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); - if (params.size() > 1) - { - nGenProcLimit = params[1].get_int(); - if (nGenProcLimit == 0) - fGenerate = false; - } - - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, nGenProcLimit, Params()); - - return NullUniValue; -} - -UniValue getmininginfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getmininginfo\n" - "\nReturns a json object containing mining-related information." - "\nResult:\n" - "{\n" - " \"blocks\": nnn, (numeric) The current block\n" - " \"currentblocksize\": nnn, (numeric) The last block size\n" - " \"currentblocktx\": nnn, (numeric) The last block transaction\n" - " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" - " \"errors\": \"...\" (string) Current errors\n" - " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" - " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" - " \"pooledtx\": n (numeric) The size of the mem pool\n" - " \"testnet\": true|false (boolean) If using testnet or not\n" - " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getmininginfo", "") - + HelpExampleRpc("getmininginfo", "") - ); - - - LOCK(cs_main); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); - obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); - obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); - obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); - obj.push_back(Pair("chain", Params().NetworkIDString())); - obj.push_back(Pair("generate", getgenerate(params, false))); - return obj; -} - - -// NOTE: Unlike wallet RPC (which use PCH values), mining RPCs follow GBT (BIP 22) in using satoshi amounts -UniValue prioritisetransaction(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 3) - throw runtime_error( - "prioritisetransaction \n" - "Accepts the transaction into mined blocks at a higher (or lower) priority\n" - "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id.\n" - "2. priority delta (numeric, required) The priority to add or subtract.\n" - " The transaction selection algorithm considers the tx as it would have a higher priority.\n" - " (priority of a transaction is calculated: coinage * value_in_duffs / txsize) \n" - "3. fee delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n" - " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" - " considers the transaction as it would have paid a higher (or lower) fee.\n" - "\nResult\n" - "true (boolean) Returns true\n" - "\nExamples:\n" - + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") - + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") - ); - - LOCK(cs_main); - uint256 hash = ParseHashStr(params[0].get_str(), "txid"); - CAmount nAmount = params[2].get_int64(); - - mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); - return true; -} - - -// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller -static UniValue BIP22ValidationResult(const CValidationState& state) -{ - if (state.IsValid()) - return NullUniValue; - - std::string strRejectReason = state.GetRejectReason(); - if (state.IsError()) - throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); - if (state.IsInvalid()) - { - if (strRejectReason.empty()) - return "rejected"; - return strRejectReason; - } - // Should be impossible - return "valid?"; -} - -// Popchain DevTeam -UniValue getblocktemplate(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getblocktemplate ( \"jsonrequestobject\" )\n" - "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" - "It returns data needed to construct a block to work on.\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - - "\nArguments:\n" - "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" - " {\n" - " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" - " \"capabilities\":[ (array, optional) A list of strings\n" - " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" - " ,...\n" - " ]\n" - " }\n" - "\n" - - "\nResult:\n" - "{\n" - " \"version\" : n, (numeric) The block version\n" - " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" - " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" - " {\n" - " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" - " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" - " \"depends\" : [ (array) array of numbers \n" - " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" - " ,...\n" - " ],\n" - " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" - " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" - " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" - " }\n" - " ,...\n" - " ],\n" - " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" - " \"flags\" : \"flags\" (string) \n" - " },\n" - " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" - " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" - " \"target\" : \"xxxx\", (string) The hash target\n" - " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" - " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" - " ,...\n" - " ],\n" - " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" - " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" - " \"sizelimit\" : n, (numeric) limit of block size\n" - " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" - " \"bits\" : \"xxx\", (string) compressed target of next block\n" - " \"height\" : n (numeric) The height of the next block\n" - " \"popnode\" : { (json object) \n" - " \"amount\": n (numeric) required amount to pay\n" - " },\n" - " \"superblock\" : [ (array) required superblock payees that must be included in the next block\n" - " {\n" - " \"payee\" : \"xxxx\", (string) payee address\n" - " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" - " \"amount\": n (numeric) required amount to pay\n" - " }\n" - " ,...\n" - " ],\n" - " \"superblocks_started\" : true|false, (boolean) true, if superblock payments started\n" - " \"superblocks_enabled\" : true|false (boolean) true, if superblock payments are enabled\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("getblocktemplate", "") - + HelpExampleRpc("getblocktemplate", "") - ); - - LOCK(cs_main); - - std::string strMode = "template"; - UniValue lpval = NullUniValue; - if (params.size() > 0) - { - const UniValue& oparam = params[0].get_obj(); - const UniValue& modeval = find_value(oparam, "mode"); - if (modeval.isStr()) - strMode = modeval.get_str(); - else if (modeval.isNull()) - { - /* Do nothing */ - } - else - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - lpval = find_value(oparam, "longpollid"); - - if (strMode == "proposal") - { - const UniValue& dataval = find_value(oparam, "data"); - if (!dataval.isStr()) - throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); - - CBlock block; - if (!DecodeHexBlk(block, dataval.get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); - - uint256 hash = block.GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { - CBlockIndex *pindex = mi->second; - if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) - return "duplicate"; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return "duplicate-invalid"; - return "duplicate-inconclusive"; - } - - CBlockIndex* const pindexPrev = chainActive.Tip(); - // TestBlockValidity only supports blocks built on the current Tip - if (block.hashPrevBlock != pindexPrev->GetBlockHash()) - return "inconclusive-not-best-prevblk"; - CValidationState state; - TestBlockValidity(state, Params(), block, pindexPrev, false, true); - return BIP22ValidationResult(state); - } - } - - if (strMode != "template") - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); - - if (vNodes.empty()) - throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Pop Core is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Pop Core is downloading blocks..."); - - if (!popnodeSync.IsSynced()) - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Pop Core is syncing with network..."); - - static unsigned int nTransactionsUpdatedLast; - - if (!lpval.isNull()) - { - // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions - uint256 hashWatchedChain; - boost::system_time checktxtime; - unsigned int nTransactionsUpdatedLastLP; - - if (lpval.isStr()) - { - // Format: - std::string lpstr = lpval.get_str(); - - hashWatchedChain.SetHex(lpstr.substr(0, 64)); - nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); - } - else - { - // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier - hashWatchedChain = chainActive.Tip()->GetBlockHash(); - nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; - } - - // Release the wallet and main lock while waiting - LEAVE_CRITICAL_SECTION(cs_main); - { - checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); - - boost::unique_lock lock(csBestBlock); - while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) - { - if (!cvBlockChange.timed_wait(lock, checktxtime)) - { - // Timeout: Check transactions for update - if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) - break; - checktxtime += boost::posix_time::seconds(10); - } - } - } - ENTER_CRITICAL_SECTION(cs_main); - - if (!IsRPCRunning()) - throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); - // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? - } - - // Update block - static CBlockIndex* pindexPrev; - static int64_t nStart; - static CBlockTemplate* pblocktemplate; - if (pindexPrev != chainActive.Tip() || - (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) - { - // Clear pindexPrev so future calls make a new block, despite any failures from here on - pindexPrev = NULL; - - // Store the chainActive.Tip() used before CreateNewBlock, to avoid races - nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); - CBlockIndex* pindexPrevNew = chainActive.Tip(); - nStart = GetTime(); - - // Create new block - if(pblocktemplate) - { - delete pblocktemplate; - pblocktemplate = NULL; - } - CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(Params(), scriptDummy); - if (!pblocktemplate) - throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); - - // Need to update only after we know CreateNewBlock succeeded - pindexPrev = pindexPrevNew; - } - CBlock* pblock = &pblocktemplate->block; // pointer for convenience - - // Update nTime - UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nNonce.SetNull(); - - UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); - - UniValue transactions(UniValue::VARR); - map setTxIndex; - int i = 0; - BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { - uint256 txHash = tx.GetHash(); - setTxIndex[txHash] = i++; - - if (tx.IsCoinBase()) - continue; - - UniValue entry(UniValue::VOBJ); - - entry.push_back(Pair("data", EncodeHexTx(tx))); - - entry.push_back(Pair("hash", txHash.GetHex())); - - UniValue deps(UniValue::VARR); - BOOST_FOREACH (const CTxIn &in, tx.vin) - { - if (setTxIndex.count(in.prevout.hash)) - deps.push_back(setTxIndex[in.prevout.hash]); - } - entry.push_back(Pair("depends", deps)); - - int index_in_template = i - 1; - entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); - entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); - - transactions.push_back(entry); - } - - UniValue aux(UniValue::VOBJ); - aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - - static UniValue aMutable(UniValue::VARR); - if (aMutable.empty()) - { - aMutable.push_back("time"); - aMutable.push_back("transactions"); - aMutable.push_back("prevblock"); - } - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("capabilities", aCaps)); - result.push_back(Pair("version", pblock->nVersion)); - result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); - result.push_back(Pair("transactions", transactions)); - result.push_back(Pair("coinbaseaux", aux)); - result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut())); - result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); - result.push_back(Pair("target", hashTarget.GetHex())); - result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); - result.push_back(Pair("mutable", aMutable)); - result.push_back(Pair("noncerange", "00000000ffffffff")); - result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); - result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); - result.push_back(Pair("curtime", pblock->GetBlockTime())); - result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); - result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); - result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); - - UniValue FoundnodeObj(UniValue::VOBJ); - if(pblock->txoutFound != CTxOut()) { - CTxDestination address1; - ExtractDestination(pblock->txoutFound.scriptPubKey, address1); - CBitcoinAddress address2(address1); - FoundnodeObj.push_back(Pair("foundpayee", address2.ToString().c_str())); - FoundnodeObj.push_back(Pair("foundscript", HexStr(pblock->txoutFound.scriptPubKey.begin(), pblock->txoutFound.scriptPubKey.end()))); - FoundnodeObj.push_back(Pair("foundamount", pblock->txoutFound.nValue)); - } - result.push_back(Pair("Foundnode", FoundnodeObj)); - - return result; -} - -class submitblock_StateCatcher : public CValidationInterface -{ -public: - uint256 hash; - bool found; - CValidationState state; - - submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {} - -protected: - virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { - if (block.GetHash() != hash) - return; - found = true; - state = stateIn; - }; -}; - -UniValue submitblock(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n" - "\nAttempts to submit new block to network.\n" - "The 'jsonparametersobject' parameter is currently ignored.\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - - "\nArguments\n" - "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" - "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n" - " {\n" - " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n" - " }\n" - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("submitblock", "\"mydata\"") - + HelpExampleRpc("submitblock", "\"mydata\"") - ); - - CBlock block; - if (!DecodeHexBlk(block, params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); - - uint256 hash = block.GetHash(); - bool fBlockPresent = false; - { - LOCK(cs_main); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { - CBlockIndex *pindex = mi->second; - if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) - return "duplicate"; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return "duplicate-invalid"; - // Otherwise, we might only have the header - process the block before returning - fBlockPresent = true; - } - } - - CValidationState state; - submitblock_StateCatcher sc(block.GetHash()); - RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); - UnregisterValidationInterface(&sc); - if (fBlockPresent) - { - if (fAccepted && !sc.found) - return "duplicate-inconclusive"; - return "duplicate"; - } - if (fAccepted) - { - if (!sc.found) - return "inconclusive"; - state = sc.state; - } - return BIP22ValidationResult(state); -} - -UniValue estimatefee(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatefee nblocks\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within nblocks blocks.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "n (numeric) estimated fee-per-kilobyte\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate.\n" - "\nExample:\n" - + HelpExampleCli("estimatefee", "6") - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); - - int nBlocks = params[0].get_int(); - if (nBlocks < 1) - nBlocks = 1; - - CFeeRate feeRate = mempool.estimateFee(nBlocks); - if (feeRate == CFeeRate(0)) - return -1.0; - - return ValueFromAmount(feeRate.GetFeePerK()); -} - -UniValue estimatepriority(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatepriority nblocks\n" - "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" - "confirmation within nblocks blocks.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "n (numeric) estimated priority\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate.\n" - "\nExample:\n" - + HelpExampleCli("estimatepriority", "6") - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); - - int nBlocks = params[0].get_int(); - if (nBlocks < 1) - nBlocks = 1; - - return mempool.estimatePriority(nBlocks); -} - -UniValue estimatesmartfee(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatesmartfee nblocks\n" - "\nWARNING: This interface is unstable and may disappear or change!\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within nblocks blocks if possible and return the number of blocks\n" - "for which the estimate is valid.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "{\n" - " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in UC)\n" - " \"blocks\" : n (numeric) block number where estimate was found\n" - "}\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate for any number of blocks.\n" - "However it will not return a value below the mempool reject fee.\n" - "\nExample:\n" - + HelpExampleCli("estimatesmartfee", "6") - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); - - int nBlocks = params[0].get_int(); - - UniValue result(UniValue::VOBJ); - int answerFound; - CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound); - result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); - result.push_back(Pair("blocks", answerFound)); - return result; -} - -UniValue estimatesmartpriority(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatesmartpriority nblocks\n" - "\nWARNING: This interface is unstable and may disappear or change!\n" - "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" - "confirmation within nblocks blocks if possible and return the number of blocks\n" - "for which the estimate is valid.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "{\n" - " \"priority\" : x.x, (numeric) estimated priority\n" - " \"blocks\" : n (numeric) block number where estimate was found\n" - "}\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate for any number of blocks.\n" - "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n" - "\nExample:\n" - + HelpExampleCli("estimatesmartpriority", "6") - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); - - int nBlocks = params[0].get_int(); - - UniValue result(UniValue::VOBJ); - int answerFound; - double priority = mempool.estimateSmartPriority(nBlocks, &answerFound); - result.push_back(Pair("priority", priority)); - result.push_back(Pair("blocks", answerFound)); - return result; -} +// Copyright (c) 2017-2018 The Popchain Core Developers + +#include "amount.h" +#include "rpcserver.h" +#include "base58.h" +#include "amount.h" +#include "chain.h" +#include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "core_io.h" +#include "init.h" +#include "main.h" +#include "miner.h" +#include "net.h" +#include "pow.h" +#include "rpcserver.h" +#include "spork.h" +#include "txmempool.h" +#include "util.h" +#ifdef ENABLE_WALLET +#include "popnode-sync.h" +#endif +#include "utilstrencodings.h" +#include "validationinterface.h" + +#include + +#include +#include + +#include + +using namespace std; + +/** + * Return average network hashes per second based on the last 'lookup' blocks, + * or from the last difficulty change if 'lookup' is nonpositive. + * If 'height' is nonnegative, compute the estimate at the time when a given block was found. + */ +UniValue GetNetworkHashPS(int lookup, int height) { + CBlockIndex *pb = chainActive.Tip(); + + if (height >= 0 && height < chainActive.Height()) + pb = chainActive[height]; + + if (pb == NULL || !pb->nHeight) + return 0; + + // If lookup is -1, then use blocks since last difficulty change. + if (lookup <= 0) + { + lookup = Params().GetConsensus().nPowAveragingWindow; + } + // If lookup is larger than chain, then set it to chain length. + if (lookup > pb->nHeight) + lookup = pb->nHeight; + + CBlockIndex *pb0 = pb; + int64_t minTime = pb0->GetBlockTime(); + int64_t maxTime = minTime; + for (int i = 0; i < lookup; i++) { + pb0 = pb0->pprev; + int64_t time = pb0->GetBlockTime(); + minTime = std::min(time, minTime); + maxTime = std::max(time, maxTime); + } + + // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception. + if (minTime == maxTime) + return 0; + + arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; + int64_t timeDiff = maxTime - minTime; + + return workDiff.getdouble() / timeDiff; +} + +UniValue getnetworkhashps(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 2) + throw runtime_error( + "getnetworkhashps ( blocks height )\n" + "\nReturns the estimated network hashes per second based on the last n blocks.\n" + "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" + "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" + "\nArguments:\n" + "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" + "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" + "\nResult:\n" + "x (numeric) Hashes per second estimated\n" + "\nExamples:\n" + + HelpExampleCli("getnetworkhashps", "") + + HelpExampleRpc("getnetworkhashps", "") + ); + + LOCK(cs_main); + return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); +} + +UniValue getgenerate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getgenerate\n" + "\nReturn if the server is set to generate coins or not. The default is false.\n" + "It is set with the command line argument -gen (or " + std::string(BITCOIN_CONF_FILENAME) + " setting gen)\n" + "It can also be set with the setgenerate call.\n" + "\nResult\n" + "true|false (boolean) If the server is set to generate coins or not\n" + "\nExamples:\n" + + HelpExampleCli("getgenerate", "") + + HelpExampleRpc("getgenerate", "") + ); + + LOCK(cs_main); + return GetBoolArg("-gen", DEFAULT_GENERATE); +} + +UniValue generate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "generate numblocks\n" + "\nMine blocks immediately (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" + "\nArguments:\n" + "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = params[0].get_int(); + + boost::shared_ptr coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + // If the keypool is exhausted, no script is returned at all. Catch this. + if (!coinbaseScript) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first"); + + //throw an error if no script was provided + if (coinbaseScript->reserveScript.empty()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart+nGenerate; + } + unsigned int nExtraNonce = 0; + UniValue blockHashes(UniValue::VARR); + while (nHeight < nHeightEnd) + { + unique_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); + CBlock *pblock = &pblocktemplate->block; + { + LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + /*popchain ghost*/ + //while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, Params().GetConsensus())) { + // Yes, there is a chance every nonce could fail to satisfy the -regtest + // target -- 1 in 2^(2^32). That ain't gonna happen + pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); + } + CValidationState state; + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + ++nHeight; + blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); + } + return blockHashes; +} + +UniValue setgenerate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "setgenerate generate ( genproclimit )\n" + "\nSet 'generate' true or false to turn generation on or off.\n" + "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" + "See the getgenerate call for the current setting.\n" + "\nArguments:\n" + "1. generate (boolean, required) Set to true to turn on generation, false to turn off.\n" + "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" + "\nExamples:\n" + "\nSet the generation on with a limit of one processor\n" + + HelpExampleCli("setgenerate", "true 1") + + "\nCheck the setting\n" + + HelpExampleCli("getgenerate", "") + + "\nTurn off generation\n" + + HelpExampleCli("setgenerate", "false") + + "\nUsing json rpc\n" + + HelpExampleRpc("setgenerate", "true, 1") + ); + + if (Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); + + bool fGenerate = true; + if (params.size() > 0) + fGenerate = params[0].get_bool(); + + int nGenProcLimit = GetArg("-genproclimit", DEFAULT_GENERATE_THREADS); + if (params.size() > 1) + { + nGenProcLimit = params[1].get_int(); + if (nGenProcLimit == 0) + fGenerate = false; + } + + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + mapArgs ["-genproclimit"] = itostr(nGenProcLimit); + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); + + return NullUniValue; +} + +UniValue getmininginfo(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "getmininginfo\n" + "\nReturns a json object containing mining-related information." + "\nResult:\n" + "{\n" + " \"blocks\": nnn, (numeric) The current block\n" + " \"currentblocksize\": nnn, (numeric) The last block size\n" + " \"currentblocktx\": nnn, (numeric) The last block transaction\n" + " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" + " \"errors\": \"...\" (string) Current errors\n" + " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" + " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" + " \"pooledtx\": n (numeric) The size of the mem pool\n" + " \"testnet\": true|false (boolean) If using testnet or not\n" + " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getmininginfo", "") + + HelpExampleRpc("getmininginfo", "") + ); + + + LOCK(cs_main); + + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("blocks", (int)chainActive.Height())); + obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); + obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); + obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); + obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); + obj.push_back(Pair("chain", Params().NetworkIDString())); + obj.push_back(Pair("generate", getgenerate(params, false))); + return obj; +} + + +// NOTE: Unlike wallet RPC (which use PCH values), mining RPCs follow GBT (BIP 22) in using satoshi amounts +UniValue prioritisetransaction(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 3) + throw runtime_error( + "prioritisetransaction \n" + "Accepts the transaction into mined blocks at a higher (or lower) priority\n" + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id.\n" + "2. priority delta (numeric, required) The priority to add or subtract.\n" + " The transaction selection algorithm considers the tx as it would have a higher priority.\n" + " (priority of a transaction is calculated: coinage * value_in_duffs / txsize) \n" + "3. fee delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n" + " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" + " considers the transaction as it would have paid a higher (or lower) fee.\n" + "\nResult\n" + "true (boolean) Returns true\n" + "\nExamples:\n" + + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") + ); + + LOCK(cs_main); + uint256 hash = ParseHashStr(params[0].get_str(), "txid"); + CAmount nAmount = params[2].get_int64(); + + mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); + return true; +} + + +// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller +static UniValue BIP22ValidationResult(const CValidationState& state) +{ + if (state.IsValid()) + return NullUniValue; + + std::string strRejectReason = state.GetRejectReason(); + if (state.IsError()) + throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); + if (state.IsInvalid()) + { + if (strRejectReason.empty()) + return "rejected"; + return strRejectReason; + } + // Should be impossible + return "valid?"; +} + +// Popchain DevTeam +UniValue getblocktemplate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getblocktemplate ( \"jsonrequestobject\" )\n" + "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" + "It returns data needed to construct a block to work on.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" + + "\nArguments:\n" + "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" + " {\n" + " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" + " \"capabilities\":[ (array, optional) A list of strings\n" + " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" + " ,...\n" + " ]\n" + " }\n" + "\n" + + "\nResult:\n" + "{\n" + " \"version\" : n, (numeric) The block version\n" + " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" + " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" + " {\n" + " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" + " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" + " \"depends\" : [ (array) array of numbers \n" + " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" + " ,...\n" + " ],\n" + " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" + " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" + " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" + " }\n" + " ,...\n" + " ],\n" + " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" + " \"flags\" : \"flags\" (string) \n" + " },\n" + " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" + " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" + " \"target\" : \"xxxx\", (string) The hash target\n" + " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" + " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" + " ,...\n" + " ],\n" + " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" + " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" + " \"sizelimit\" : n, (numeric) limit of block size\n" + " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" + " \"bits\" : \"xxx\", (string) compressed target of next block\n" + " \"height\" : n (numeric) The height of the next block\n" + " \"popnode\" : { (json object) \n" + " \"amount\": n (numeric) required amount to pay\n" + " },\n" + " \"superblock\" : [ (array) required superblock payees that must be included in the next block\n" + " {\n" + " \"payee\" : \"xxxx\", (string) payee address\n" + " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" + " \"amount\": n (numeric) required amount to pay\n" + " }\n" + " ,...\n" + " ],\n" + " \"superblocks_started\" : true|false, (boolean) true, if superblock payments started\n" + " \"superblocks_enabled\" : true|false (boolean) true, if superblock payments are enabled\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("getblocktemplate", "") + + HelpExampleRpc("getblocktemplate", "") + ); + + LOCK(cs_main); + + std::string strMode = "template"; + UniValue lpval = NullUniValue; + if (params.size() > 0) + { + const UniValue& oparam = params[0].get_obj(); + const UniValue& modeval = find_value(oparam, "mode"); + if (modeval.isStr()) + strMode = modeval.get_str(); + else if (modeval.isNull()) + { + /* Do nothing */ + } + else + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + lpval = find_value(oparam, "longpollid"); + + if (strMode == "proposal") + { + const UniValue& dataval = find_value(oparam, "data"); + if (!dataval.isStr()) + throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); + + CBlock block; + if (!DecodeHexBlk(block, dataval.get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + uint256 hash = block.GetHash(); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + return "duplicate-inconclusive"; + } + + CBlockIndex* const pindexPrev = chainActive.Tip(); + // TestBlockValidity only supports blocks built on the current Tip + if (block.hashPrevBlock != pindexPrev->GetBlockHash()) + return "inconclusive-not-best-prevblk"; + CValidationState state; + TestBlockValidity(state, Params(), block, pindexPrev, false, true); + return BIP22ValidationResult(state); + } + } + + if (strMode != "template") + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); + + if (vNodes.empty()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Pop Core is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Pop Core is downloading blocks..."); + + if (!popnodeSync.IsSynced()) + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Pop Core is syncing with network..."); + + static unsigned int nTransactionsUpdatedLast; + + if (!lpval.isNull()) + { + // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions + uint256 hashWatchedChain; + boost::system_time checktxtime; + unsigned int nTransactionsUpdatedLastLP; + + if (lpval.isStr()) + { + // Format: + std::string lpstr = lpval.get_str(); + + hashWatchedChain.SetHex(lpstr.substr(0, 64)); + nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); + } + else + { + // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier + hashWatchedChain = chainActive.Tip()->GetBlockHash(); + nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; + } + + // Release the wallet and main lock while waiting + LEAVE_CRITICAL_SECTION(cs_main); + { + checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); + + boost::unique_lock lock(csBestBlock); + while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) + { + if (!cvBlockChange.timed_wait(lock, checktxtime)) + { + // Timeout: Check transactions for update + if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) + break; + checktxtime += boost::posix_time::seconds(10); + } + } + } + ENTER_CRITICAL_SECTION(cs_main); + + if (!IsRPCRunning()) + throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); + // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? + } + + // Update block + static CBlockIndex* pindexPrev; + static int64_t nStart; + static CBlockTemplate* pblocktemplate; + if (pindexPrev != chainActive.Tip() || + (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) + { + // Clear pindexPrev so future calls make a new block, despite any failures from here on + pindexPrev = NULL; + + // Store the chainActive.Tip() used before CreateNewBlock, to avoid races + nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); + CBlockIndex* pindexPrevNew = chainActive.Tip(); + nStart = GetTime(); + + // Create new block + if(pblocktemplate) + { + delete pblocktemplate; + pblocktemplate = NULL; + } + CScript scriptDummy = CScript() << OP_TRUE; + pblocktemplate = CreateNewBlock(Params(), scriptDummy); + if (!pblocktemplate) + throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); + + // Need to update only after we know CreateNewBlock succeeded + pindexPrev = pindexPrevNew; + } + CBlock* pblock = &pblocktemplate->block; // pointer for convenience + + // Update nTime + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); + pblock->nNonce.SetNull(); + + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); + + UniValue transactions(UniValue::VARR); + map setTxIndex; + int i = 0; + BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { + uint256 txHash = tx.GetHash(); + setTxIndex[txHash] = i++; + + if (tx.IsCoinBase()) + continue; + + UniValue entry(UniValue::VOBJ); + + entry.push_back(Pair("data", EncodeHexTx(tx))); + + entry.push_back(Pair("hash", txHash.GetHex())); + + UniValue deps(UniValue::VARR); + BOOST_FOREACH (const CTxIn &in, tx.vin) + { + if (setTxIndex.count(in.prevout.hash)) + deps.push_back(setTxIndex[in.prevout.hash]); + } + entry.push_back(Pair("depends", deps)); + + int index_in_template = i - 1; + entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); + entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); + + transactions.push_back(entry); + } + + UniValue aux(UniValue::VOBJ); + aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); + + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + + static UniValue aMutable(UniValue::VARR); + if (aMutable.empty()) + { + aMutable.push_back("time"); + aMutable.push_back("transactions"); + aMutable.push_back("prevblock"); + } + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("capabilities", aCaps)); + result.push_back(Pair("version", pblock->nVersion)); + result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("coinbaseaux", aux)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut())); + result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); + result.push_back(Pair("target", hashTarget.GetHex())); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); + result.push_back(Pair("mutable", aMutable)); + result.push_back(Pair("noncerange", "00000000ffffffff")); + result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); + result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); + result.push_back(Pair("curtime", pblock->GetBlockTime())); + result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); + result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); + result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); + + UniValue FoundnodeObj(UniValue::VOBJ); + if(pblock->txoutFound != CTxOut()) { + CTxDestination address1; + ExtractDestination(pblock->txoutFound.scriptPubKey, address1); + CBitcoinAddress address2(address1); + FoundnodeObj.push_back(Pair("foundpayee", address2.ToString().c_str())); + FoundnodeObj.push_back(Pair("foundscript", HexStr(pblock->txoutFound.scriptPubKey.begin(), pblock->txoutFound.scriptPubKey.end()))); + FoundnodeObj.push_back(Pair("foundamount", pblock->txoutFound.nValue)); + } + result.push_back(Pair("Foundnode", FoundnodeObj)); + + return result; +} + +class submitblock_StateCatcher : public CValidationInterface +{ +public: + uint256 hash; + bool found; + CValidationState state; + + submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {} + +protected: + virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { + if (block.GetHash() != hash) + return; + found = true; + state = stateIn; + }; +}; + +UniValue submitblock(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n" + "\nAttempts to submit new block to network.\n" + "The 'jsonparametersobject' parameter is currently ignored.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" + + "\nArguments\n" + "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" + "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n" + " {\n" + " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n" + " }\n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("submitblock", "\"mydata\"") + + HelpExampleRpc("submitblock", "\"mydata\"") + ); + + CBlock block; + if (!DecodeHexBlk(block, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); + + uint256 hash = block.GetHash(); + bool fBlockPresent = false; + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + // Otherwise, we might only have the header - process the block before returning + fBlockPresent = true; + } + } + + CValidationState state; + submitblock_StateCatcher sc(block.GetHash()); + RegisterValidationInterface(&sc); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); + UnregisterValidationInterface(&sc); + if (fBlockPresent) + { + if (fAccepted && !sc.found) + return "duplicate-inconclusive"; + return "duplicate"; + } + if (fAccepted) + { + if (!sc.found) + return "inconclusive"; + state = sc.state; + } + return BIP22ValidationResult(state); +} + +UniValue estimatefee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatefee nblocks\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "n (numeric) estimated fee-per-kilobyte\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" + "\nExample:\n" + + HelpExampleCli("estimatefee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + if (nBlocks < 1) + nBlocks = 1; + + CFeeRate feeRate = mempool.estimateFee(nBlocks); + if (feeRate == CFeeRate(0)) + return -1.0; + + return ValueFromAmount(feeRate.GetFeePerK()); +} + +UniValue estimatepriority(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatepriority nblocks\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "n (numeric) estimated priority\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate.\n" + "\nExample:\n" + + HelpExampleCli("estimatepriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + if (nBlocks < 1) + nBlocks = 1; + + return mempool.estimatePriority(nBlocks); +} + +UniValue estimatesmartfee(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartfee nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in UC)\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However it will not return a value below the mempool reject fee.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartfee", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + CFeeRate feeRate = mempool.estimateSmartFee(nBlocks, &answerFound); + result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); + result.push_back(Pair("blocks", answerFound)); + return result; +} + +UniValue estimatesmartpriority(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "estimatesmartpriority nblocks\n" + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nEstimates the approximate priority a zero-fee transaction needs to begin\n" + "confirmation within nblocks blocks if possible and return the number of blocks\n" + "for which the estimate is valid.\n" + "\nArguments:\n" + "1. nblocks (numeric)\n" + "\nResult:\n" + "{\n" + " \"priority\" : x.x, (numeric) estimated priority\n" + " \"blocks\" : n (numeric) block number where estimate was found\n" + "}\n" + "\n" + "A negative value is returned if not enough transactions and blocks\n" + "have been observed to make an estimate for any number of blocks.\n" + "However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n" + "\nExample:\n" + + HelpExampleCli("estimatesmartpriority", "6") + ); + + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); + + int nBlocks = params[0].get_int(); + + UniValue result(UniValue::VOBJ); + int answerFound; + double priority = mempool.estimateSmartPriority(nBlocks, &answerFound); + result.push_back(Pair("priority", priority)); + result.push_back(Pair("blocks", answerFound)); + return result; +} diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 1309638..2cd8620 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -1,1007 +1,1010 @@ -// Copyright (c) 2015 The LBRY Foundation -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://opensource.org/licenses/mit-license.php - -#include "main.h" -#include "consensus/validation.h" -#include "consensus/merkle.h" -#include "primitives/transaction.h" -#include "miner.h" -#include "txmempool.h" -#include "claimtrie.h" -#include "nameclaim.h" -#include "arith_uint256.h" -#include "coins.h" -#include "streams.h" -#include "chainparams.h" -#include "policy/policy.h" -#include "pow.h" -#include -#include -#include "test/test_pop.h" - -using namespace std; - -CScript scriptPubKey = CScript() << OP_TRUE; - -BOOST_FIXTURE_TEST_SUITE(claimtrie_tests, RegTestingSetup) - -CMutableTransaction BuildTransaction(const uint256& prevhash) -{ - CMutableTransaction tx; - tx.nVersion = 1; - tx.nLockTime = 0; - tx.vin.resize(1); - tx.vout.resize(1); - tx.vin[0].prevout.hash = prevhash; - tx.vin[0].prevout.n = 0; - tx.vin[0].scriptSig = CScript(); - tx.vin[0].nSequence = std::numeric_limits::max(); - tx.vout[0].scriptPubKey = CScript(); - tx.vout[0].nValue = 0; - - return tx; -} - -CMutableTransaction BuildTransaction(const CMutableTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1) -{ - CMutableTransaction tx; - tx.nVersion = 1; - tx.nLockTime = 0; - tx.vin.resize(1); - tx.vout.resize(numOutputs); - tx.vin[0].prevout.hash = prev.GetHash(); - tx.vin[0].prevout.n = prevout; - tx.vin[0].scriptSig = CScript(); - tx.vin[0].nSequence = std::numeric_limits::max(); - CAmount valuePerOutput = prev.vout[prevout].nValue; - unsigned int numOutputsCopy = numOutputs; - while ((numOutputsCopy = numOutputsCopy >> 1) > 0) - { - valuePerOutput = valuePerOutput >> 1; - } - for (unsigned int i = 0; i < numOutputs; ++i) - { - tx.vout[i].scriptPubKey = CScript(); - tx.vout[i].nValue = valuePerOutput; - } - - return tx; -} - -CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1) -{ - return BuildTransaction(CMutableTransaction(prev), prevout, numOutputs); -} - -void AddToMempool(CMutableTransaction& tx) -{ - //CCoinsView dummy; - //CCoinsViewCache view(&dummy); - //CAmount inChainInputValue; - //double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); - //unsigned int nSigOps = GetLegacySigOpCount(tx); - //nSigOps += GetP2SHSigOpCount(tx, view); - //LockPoints lp; - //BOOST_CHECK(CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)); - //mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.1, chainActive.Height(), mempool.HasNoInputsOf(tx), 10000000000, false, nSigOps, lp)); - CValidationState state; - - BOOST_CHECK(AcceptToMemoryPool(mempool, state, tx, false, NULL)); - //TestMemPoolEntryHelper entry; - //entry.nFee = 11; - //entry.dPriority = 111.0; - //entry.nHeight = 11; - //mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).Time(GetTime()).FromTx(tx)); -} - -bool CreateBlock(CBlockTemplate* pblocktemplate) -{ - static int unique_block_counter = 0; - const CChainParams& chainparams = Params(CBaseChainParams::REGTEST); - CBlock* pblock = &pblocktemplate->block; - pblock->nVersion = 1; - pblock->nTime = chainActive.Tip()->GetBlockTime()+Params().GetConsensus().nPowTargetSpacing; - CMutableTransaction txCoinbase(pblock->vtx[0]); - txCoinbase.vin[0].scriptSig = CScript() << CScriptNum(unique_block_counter++) << CScriptNum(chainActive.Height()); - txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, chainparams.GetConsensus()); - pblock->vtx[0] = CTransaction(txCoinbase); - pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); - for (arith_uint256 i = 0; ; ++i) - { - pblock->nNonce = ArithToUint256(i); - if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) - { - break; - } - } - CValidationState state; - bool success = (ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL) && state.IsValid() && pblock->GetHash() == chainActive.Tip()->GetBlockHash()); - - pblock->hashPrevBlock = pblock->GetHash(); - return success; -} - -bool RemoveBlock(uint256& blockhash) -{ - CValidationState state; - if (mapBlockIndex.count(blockhash) == 0) - return false; - CBlockIndex* pblockindex = mapBlockIndex[blockhash]; - InvalidateBlock(state, Params().GetConsensus(), pblockindex); - if (state.IsValid()) - { - ActivateBestChain(state, Params()); - } - mempool.clear(); - return state.IsValid(); - -} - -bool CreateCoinbases(unsigned int num_coinbases, std::vector& coinbases) -{ - CBlockTemplate *pblocktemplate; - coinbases.clear(); - BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); - BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); - pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); - for (unsigned int i = 0; i < 100 + num_coinbases; ++i) - { - BOOST_CHECK(CreateBlock(pblocktemplate)); - if (coinbases.size() < num_coinbases) - coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0])); - } - delete pblocktemplate; - return true; -} - -bool CreateBlocks(unsigned int num_blocks, unsigned int num_txs) -{ - CBlockTemplate *pblocktemplate; - BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); - BOOST_CHECK(pblocktemplate->block.vtx.size() == num_txs); - pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); - for (unsigned int i = 0; i nCurrentHeight == chainActive.Height() + 1); - LOCK(cs_main); - - std::string sName1("atest"); - std::string sName2("btest"); - std::string sName3("atest123"); - std::string sValue1("testa"); - std::string sValue2("testb"); - std::string sValue3("123testa"); - - std::vector vchName1(sName1.begin(), sName1.end()); - std::vector vchName2(sName2.begin(), sName2.end()); - std::vector vchName3(sName3.begin(), sName3.end()); - std::vector vchValue1(sValue1.begin(), sValue1.end()); - std::vector vchValue2(sValue2.begin(), sValue2.end()); - std::vector vchValue3(sValue3.begin(), sValue3.end()); - - std::vector coinbases; - - BOOST_CHECK(CreateCoinbases(6, coinbases)); - - uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); - //BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0); - - CMutableTransaction tx1 = BuildTransaction(coinbases[1]); - tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue1 << OP_2DROP << OP_DROP << OP_TRUE; - uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); - std::vector vchTx1ClaimId(tx1ClaimId.begin(), tx1ClaimId.end()); - COutPoint tx1OutPoint(tx1.GetHash(), 0); - - CMutableTransaction tx2 = BuildTransaction(coinbases[1]); - tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; - tx2.vout[0].nValue = tx1.vout[0].nValue - 1; - COutPoint tx2OutPoint(tx2.GetHash(), 0); - - CMutableTransaction tx3 = BuildTransaction(tx1); - tx3.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; - tx3.vout[0].nValue -= 10000; - COutPoint tx3OutPoint(tx3.GetHash(), 0); - - CMutableTransaction tx4 = BuildTransaction(tx2); - tx4.vout[0].scriptPubKey = CScript() << OP_TRUE; - COutPoint tx4OutPoint(tx4.GetHash(), 0); - - CMutableTransaction tx5 = BuildTransaction(coinbases[2]); - tx5.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; - COutPoint tx5OutPoint(tx5.GetHash(), 0); - - CMutableTransaction tx6 = BuildTransaction(tx3); - tx6.vout[0].scriptPubKey = CScript() << OP_TRUE; - COutPoint tx6OutPoint(tx6.GetHash(), 0); - - CMutableTransaction tx7 = BuildTransaction(coinbases[3]); - tx7.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; - tx7.vout[0].nValue = tx1.vout[0].nValue - 10001; - uint160 tx7ClaimId = ClaimIdHash(tx7.GetHash(), 0); - std::vector vchTx7ClaimId(tx7ClaimId.begin(), tx7ClaimId.end()); - COutPoint tx7OutPoint(tx7.GetHash(), 0); - - CMutableTransaction tx8 = BuildTransaction(tx3, 0, 2); - tx8.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; - tx8.vout[0].nValue = tx8.vout[0].nValue - 1; - tx8.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; - COutPoint tx8OutPoint0(tx8.GetHash(), 0); - COutPoint tx8OutPoint1(tx8.GetHash(), 1); - - CMutableTransaction tx9 = BuildTransaction(tx7); - tx9.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx7ClaimId << vchValue2 << OP_2DROP << OP_2DROP << OP_TRUE; - tx9.vout[0].nValue -= 10000; - COutPoint tx9OutPoint(tx9.GetHash(), 0); - - CMutableTransaction tx10 = BuildTransaction(coinbases[4]); - tx10.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; - COutPoint tx10OutPoint(tx10.GetHash(), 0); - - CMutableTransaction tx11 = BuildTransaction(tx10); - tx11.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; - COutPoint tx11OutPoint(tx11.GetHash(), 0); - - CMutableTransaction tx12 = BuildTransaction(tx10); - tx12.vout[0].scriptPubKey = CScript() << OP_TRUE; - COutPoint tx12OutPoint(tx12.GetHash(), 0); - - CMutableTransaction tx13 = BuildTransaction(coinbases[5]); - tx13.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName3 << vchValue3 << OP_2DROP << OP_DROP << OP_TRUE; - COutPoint tx13OutPoint(tx13.GetHash(), 0); - - CClaimValue val; - - int nThrowaway; - - std::vector blocks_to_invalidate; - - // Verify claims for uncontrolled names go in immediately - - AddToMempool(tx7); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx7OutPoint); - - // Verify claims for controlled names are delayed, and that the bigger claim wins when inserted - - BOOST_CHECK(CreateBlocks(5, 1)); - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(5, 1)); - - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(1, 1)); - - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx1OutPoint); - - // Verify updates to the best claim get inserted immediately, and others don't. - - AddToMempool(tx3); - AddToMempool(tx9); - - BOOST_CHECK(CreateBlocks(1, 3)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx1OutPoint)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx7OutPoint)); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx3OutPoint); - BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx9OutPoint, nThrowaway)); - - // Disconnect all blocks until the first block, and then reattach them, in memory only - - //FlushStateToDisk(); - - CCoinsViewCache coins(pcoinsTip); - CClaimTrieCache trieCache(pclaimTrie); - CBlockIndex* pindexState = chainActive.Tip(); - CValidationState state; - CBlockIndex* pindex; - for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex=pindex->pprev) - { - CBlock block; - BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); - if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) - { - bool fClean = true; - BOOST_CHECK(DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)); - pindexState = pindex->pprev; - } - } - while (pindex != chainActive.Tip()) - { - pindex = chainActive.Next(pindex); - CBlock block; - BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); - BOOST_CHECK(ConnectBlock(block, state, pindex, coins, trieCache)); - } - - // Roll back the last block, make sure tx1 and tx7 are put back in the trie - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx1OutPoint); - BOOST_CHECK(pclaimTrie->haveClaim(sName1, tx7OutPoint)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->empty()); - - // Roll all the way back, make sure all txs are out of the trie - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(!pclaimTrie->getInfoForName(sName1, val)); - - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Test undoing a claim before the claim gets into the trie - - // Put tx1 in the chain, then advance a few blocks. - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(10, 1)); - - // Put tx7 in the chain, verify it goes into the queue - - AddToMempool(tx7); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - // Undo that block and make sure it's not in the queue - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - // Make sure it's not in the queue - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Go back to the beginning - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Test spend a claim which was just inserted into the trie - - // Immediately spend tx2 with tx4, verify nothing gets put in the trie - - AddToMempool(tx2); - AddToMempool(tx4); - - BOOST_CHECK(CreateBlocks(1, 3)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Verify that if a claim in the queue is spent, it does not get into the trie - - // Put tx5 into the chain, advance until it's in the trie for a few blocks - - AddToMempool(tx5); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(CreateBlocks(5, 1)); - - // Put tx2 into the chain, and then advance a few blocks but not far enough for it to get into the trie - - AddToMempool(tx2); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName2, tx2OutPoint, nThrowaway)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(3, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - // Spend tx2 with tx4, and then advance to where tx2 would be inserted into the trie and verify it hasn't happened - - AddToMempool(tx4); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(5, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->haveClaim(sName2, tx2OutPoint)); - - // Undo spending tx2 with tx4, and then advance and verify tx2 is inserted into the trie when it should be - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - BOOST_CHECK(CreateBlocks(1, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName2, tx2OutPoint, nThrowaway)); - - BOOST_CHECK(CreateBlocks(2, 1)); - - BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName2, val)); - BOOST_CHECK(val.outPoint == tx5OutPoint); - BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); - - // Test undoing a spend which involves a claim in the trie - - // spend tx2, which is in the trie, with tx4 - - AddToMempool(tx4); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->haveClaim(sName2, tx2OutPoint)); - - // undo spending tx2 with tx4, and verify tx2 is back in the trie - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName2, val)); - BOOST_CHECK(val.outPoint == tx5OutPoint); - BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); - - // roll back to the beginning - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Test undoing a spent update which updated a claim still in the queue - - // Create the claim that will cause the others to be in the queue - - AddToMempool(tx7); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(CreateBlocks(5, 1)); - - // Create the original claim (tx1) - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - //blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx1OutPoint, nThrowaway)); - - // move forward some, but not far enough for the claim to get into the trie - - BOOST_CHECK(CreateBlocks(2, 1)); - - // update the original claim (tx3 spends tx1) - - AddToMempool(tx3); - - BOOST_CHECK(CreateBlocks(1, 2)); - //blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx1OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx1OutPoint)); - BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx3OutPoint, nThrowaway)); - - // spend the update (tx6 spends tx3) - - AddToMempool(tx6); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx3OutPoint)); - - // undo spending the update (undo tx6 spending tx3) - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - // make sure the update (tx3) still goes into effect when it's supposed to - - BOOST_CHECK(CreateBlocks(8, 1)); - BOOST_CHECK(CreateBlocks(1, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx3OutPoint); - - BOOST_CHECK(CreateBlocks(1, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->haveClaim(sName1, tx3OutPoint)); - - // roll all the way back - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // Test undoing an spent update which updated the best claim to a name - - // move forward until the original claim is inserted into the trie - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(5, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx1OutPoint); - - // update the original claim (tx3 spends tx1) - - AddToMempool(tx3); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx3OutPoint); - - // spend the update (tx6 spends tx3) - - AddToMempool(tx6); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // undo spending the update (undo tx6 spending tx3) - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx3OutPoint); - - // Test having two updates to a claim in the same transaction - - // Add both txouts (tx8 spends tx3) - - AddToMempool(tx8); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - // ensure txout 0 made it into the trie and txout 1 did not - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx8OutPoint0); - - // roll forward until tx8 output 1 gets into the trie - - BOOST_CHECK(CreateBlocks(6, 1)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(!pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(1, 1)); - - // ensure txout 1 made it into the trie and is now in control - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx8OutPoint1); - - // roll back to before tx8 - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - // roll all the way back - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // make sure invalid updates don't wreak any havoc - - // put tx1 into the trie - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); - BOOST_CHECK(val.outPoint == tx1OutPoint); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // advance a few blocks - - BOOST_CHECK(CreateBlocks(5, 1)); - - // put in bad tx10 - - AddToMempool(tx10); - - BOOST_CHECK(CreateBlocks(1, 2)); - - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll back, make sure nothing bad happens - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - // put it back in - - AddToMempool(tx10); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // update it - - AddToMempool(tx11); - - BOOST_CHECK(CreateBlocks(1, 2)); - - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - BOOST_CHECK(CreateBlocks(10, 1)); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll back to before the update - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // make sure tx10 would have gotten into the trie, then run tests again - - BOOST_CHECK(CreateBlocks(10, 1)); - - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // update it - - AddToMempool(tx11); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // make sure tx11 would have gotten into the trie - - BOOST_CHECK(CreateBlocks(20, 1)); - - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); - BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); - BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll all the way back - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - // Put tx10 and tx11 in without tx1 in - - AddToMempool(tx10); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // update with tx11 - - AddToMempool(tx11); - - BOOST_CHECK(CreateBlocks(1, 2)); - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll back to before tx11 - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - - // spent tx10 with tx12 instead which is not a claim operation of any kind - - AddToMempool(tx12); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll all the way back - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); - // make sure all claim for names which exist in the trie but have no - // values get inserted immediately - - blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); - - AddToMempool(tx13); - - BOOST_CHECK(CreateBlocks(1, 2)); - - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - AddToMempool(tx1); - - BOOST_CHECK(CreateBlocks(1, 2)); - BOOST_CHECK(!pclaimTrie->empty()); - BOOST_CHECK(pclaimTrie->queueEmpty()); - - // roll back - - BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); - blocks_to_invalidate.pop_back(); -} - -BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize) -{ - fRequireStandard = false; - CDataStream ss(SER_DISK, 0); - - uint160 hash160; - - CClaimTrieNode n1; - CClaimTrieNode n2; - CClaimValue throwaway; - - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - n1.hash.SetHex("0000000000000000000000000000000000000000000000000000000000000001"); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - n1.hash.SetHex("a79e8a5b28f7fa5e8836a4b48da9988bdf56ce749f81f413cb754f963a516200"); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100); - CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101); - - n1.insertClaim(v1); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - n1.insertClaim(v2); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - n1.removeClaim(v1.outPoint, throwaway); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); - - n1.removeClaim(v2.outPoint, throwaway); - BOOST_CHECK(n1 != n2); - ss << n1; - ss >> n2; - BOOST_CHECK(n1 == n2); -} - -bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name) -{ - uint256 previousComputedHash; - std::string computedReverseName; - bool verifiedValue = false; - - for (std::vector::const_reverse_iterator itNodes = proof.nodes.rbegin(); itNodes != proof.nodes.rend(); ++itNodes) - { - bool foundChildInChain = false; - std::vector vchToHash; - for (std::vector >::const_iterator itChildren = itNodes->children.begin(); itChildren != itNodes->children.end(); ++itChildren) - { - vchToHash.push_back(itChildren->first); - uint256 childHash; - if (itChildren->second.IsNull()) - { - if (previousComputedHash.IsNull()) - { - return false; - } - if (foundChildInChain) - { - return false; - } - foundChildInChain = true; - computedReverseName += itChildren->first; - childHash = previousComputedHash; - } - else - { - childHash = itChildren->second; - } - vchToHash.insert(vchToHash.end(), childHash.begin(), childHash.end()); - } - if (itNodes != proof.nodes.rbegin() && !foundChildInChain) - { - return false; - } - if (itNodes->hasValue) - { - uint256 valHash; - if (itNodes->valHash.IsNull()) - { - if (itNodes != proof.nodes.rbegin()) - { - return false; - } - if (!proof.hasValue) - { - return false; - } - valHash = getValueHash(proof.outPoint, - proof.nHeightOfLastTakeover); - - verifiedValue = true; - } - else - { - valHash = itNodes->valHash; - } - vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end()); - } - else if (proof.hasValue && itNodes == proof.nodes.rbegin()) - { - return false; - } - CHash256 hasher; - std::vector vchHash(hasher.OUTPUT_SIZE); - hasher.Write(vchToHash.data(), vchToHash.size()); - hasher.Finalize(&(vchHash[0])); - uint256 calculatedHash(vchHash); - previousComputedHash = calculatedHash; - } - if (previousComputedHash != rootHash) - { - return false; - } - if (proof.hasValue && !verifiedValue) - { - return false; - } - std::string::reverse_iterator itComputedName = computedReverseName.rbegin(); - std::string::const_iterator itName = name.begin(); - for (; itName != name.end() && itComputedName != computedReverseName.rend(); ++itName, ++itComputedName) - { - if (*itName != *itComputedName) - { - return false; - } - } - return (!proof.hasValue || itName == name.end()); -} - - -BOOST_AUTO_TEST_SUITE_END() +// Copyright (c) 2015 The LBRY Foundation +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://opensource.org/licenses/mit-license.php + +#include "main.h" +#include "consensus/validation.h" +#include "consensus/merkle.h" +#include "primitives/transaction.h" +#include "miner.h" +#include "txmempool.h" +#include "claimtrie.h" +#include "nameclaim.h" +#include "arith_uint256.h" +#include "coins.h" +#include "streams.h" +#include "chainparams.h" +#include "policy/policy.h" +#include "pow.h" +#include +#include +#include "test/test_pop.h" + +using namespace std; + +CScript scriptPubKey = CScript() << OP_TRUE; + +BOOST_FIXTURE_TEST_SUITE(claimtrie_tests, RegTestingSetup) + +CMutableTransaction BuildTransaction(const uint256& prevhash) +{ + CMutableTransaction tx; + tx.nVersion = 1; + tx.nLockTime = 0; + tx.vin.resize(1); + tx.vout.resize(1); + tx.vin[0].prevout.hash = prevhash; + tx.vin[0].prevout.n = 0; + tx.vin[0].scriptSig = CScript(); + tx.vin[0].nSequence = std::numeric_limits::max(); + tx.vout[0].scriptPubKey = CScript(); + tx.vout[0].nValue = 0; + + return tx; +} + +CMutableTransaction BuildTransaction(const CMutableTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1) +{ + CMutableTransaction tx; + tx.nVersion = 1; + tx.nLockTime = 0; + tx.vin.resize(1); + tx.vout.resize(numOutputs); + tx.vin[0].prevout.hash = prev.GetHash(); + tx.vin[0].prevout.n = prevout; + tx.vin[0].scriptSig = CScript(); + tx.vin[0].nSequence = std::numeric_limits::max(); + CAmount valuePerOutput = prev.vout[prevout].nValue; + unsigned int numOutputsCopy = numOutputs; + while ((numOutputsCopy = numOutputsCopy >> 1) > 0) + { + valuePerOutput = valuePerOutput >> 1; + } + for (unsigned int i = 0; i < numOutputs; ++i) + { + tx.vout[i].scriptPubKey = CScript(); + tx.vout[i].nValue = valuePerOutput; + } + + return tx; +} + +CMutableTransaction BuildTransaction(const CTransaction& prev, uint32_t prevout=0, unsigned int numOutputs=1) +{ + return BuildTransaction(CMutableTransaction(prev), prevout, numOutputs); +} + +void AddToMempool(CMutableTransaction& tx) +{ + //CCoinsView dummy; + //CCoinsViewCache view(&dummy); + //CAmount inChainInputValue; + //double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + //unsigned int nSigOps = GetLegacySigOpCount(tx); + //nSigOps += GetP2SHSigOpCount(tx, view); + //LockPoints lp; + //BOOST_CHECK(CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)); + //mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, GetTime(), 111.1, chainActive.Height(), mempool.HasNoInputsOf(tx), 10000000000, false, nSigOps, lp)); + CValidationState state; + + BOOST_CHECK(AcceptToMemoryPool(mempool, state, tx, false, NULL)); + //TestMemPoolEntryHelper entry; + //entry.nFee = 11; + //entry.dPriority = 111.0; + //entry.nHeight = 11; + //mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).Time(GetTime()).FromTx(tx)); +} + +bool CreateBlock(CBlockTemplate* pblocktemplate) +{ + static int unique_block_counter = 0; + const CChainParams& chainparams = Params(CBaseChainParams::REGTEST); + CBlock* pblock = &pblocktemplate->block; + pblock->nVersion = 1; + pblock->nTime = chainActive.Tip()->GetBlockTime()+Params().GetConsensus().nPowTargetSpacing; + CMutableTransaction txCoinbase(pblock->vtx[0]); + txCoinbase.vin[0].scriptSig = CScript() << CScriptNum(unique_block_counter++) << CScriptNum(chainActive.Height()); + txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, chainparams.GetConsensus()); + pblock->vtx[0] = CTransaction(txCoinbase); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); + pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); + for (arith_uint256 i = 0; ; ++i) + { + pblock->nNonce = ArithToUint256(i); + /*popchain ghost*/ + //if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) + if (CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, chainparams.GetConsensus())) + { + break; + } + /*popchain ghost*/ + } + CValidationState state; + bool success = (ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL) && state.IsValid() && pblock->GetHash() == chainActive.Tip()->GetBlockHash()); + + pblock->hashPrevBlock = pblock->GetHash(); + return success; +} + +bool RemoveBlock(uint256& blockhash) +{ + CValidationState state; + if (mapBlockIndex.count(blockhash) == 0) + return false; + CBlockIndex* pblockindex = mapBlockIndex[blockhash]; + InvalidateBlock(state, Params().GetConsensus(), pblockindex); + if (state.IsValid()) + { + ActivateBestChain(state, Params()); + } + mempool.clear(); + return state.IsValid(); + +} + +bool CreateCoinbases(unsigned int num_coinbases, std::vector& coinbases) +{ + CBlockTemplate *pblocktemplate; + coinbases.clear(); + BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); + BOOST_CHECK(pblocktemplate->block.vtx.size() == 1); + pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); + for (unsigned int i = 0; i < 100 + num_coinbases; ++i) + { + BOOST_CHECK(CreateBlock(pblocktemplate)); + if (coinbases.size() < num_coinbases) + coinbases.push_back(CTransaction(pblocktemplate->block.vtx[0])); + } + delete pblocktemplate; + return true; +} + +bool CreateBlocks(unsigned int num_blocks, unsigned int num_txs) +{ + CBlockTemplate *pblocktemplate; + BOOST_CHECK(pblocktemplate = CreateNewBlock(Params(), scriptPubKey)); + BOOST_CHECK(pblocktemplate->block.vtx.size() == num_txs); + pblocktemplate->block.hashPrevBlock = chainActive.Tip()->GetBlockHash(); + for (unsigned int i = 0; i nCurrentHeight == chainActive.Height() + 1); + LOCK(cs_main); + + std::string sName1("atest"); + std::string sName2("btest"); + std::string sName3("atest123"); + std::string sValue1("testa"); + std::string sValue2("testb"); + std::string sValue3("123testa"); + + std::vector vchName1(sName1.begin(), sName1.end()); + std::vector vchName2(sName2.begin(), sName2.end()); + std::vector vchName3(sName3.begin(), sName3.end()); + std::vector vchValue1(sValue1.begin(), sValue1.end()); + std::vector vchValue2(sValue2.begin(), sValue2.end()); + std::vector vchValue3(sValue3.begin(), sValue3.end()); + + std::vector coinbases; + + BOOST_CHECK(CreateCoinbases(6, coinbases)); + + uint256 hash0(uint256S("0000000000000000000000000000000000000000000000000000000000000001")); + //BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0); + + CMutableTransaction tx1 = BuildTransaction(coinbases[1]); + tx1.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue1 << OP_2DROP << OP_DROP << OP_TRUE; + uint160 tx1ClaimId = ClaimIdHash(tx1.GetHash(), 0); + std::vector vchTx1ClaimId(tx1ClaimId.begin(), tx1ClaimId.end()); + COutPoint tx1OutPoint(tx1.GetHash(), 0); + + CMutableTransaction tx2 = BuildTransaction(coinbases[1]); + tx2.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; + tx2.vout[0].nValue = tx1.vout[0].nValue - 1; + COutPoint tx2OutPoint(tx2.GetHash(), 0); + + CMutableTransaction tx3 = BuildTransaction(tx1); + tx3.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; + tx3.vout[0].nValue -= 10000; + COutPoint tx3OutPoint(tx3.GetHash(), 0); + + CMutableTransaction tx4 = BuildTransaction(tx2); + tx4.vout[0].scriptPubKey = CScript() << OP_TRUE; + COutPoint tx4OutPoint(tx4.GetHash(), 0); + + CMutableTransaction tx5 = BuildTransaction(coinbases[2]); + tx5.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName2 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; + COutPoint tx5OutPoint(tx5.GetHash(), 0); + + CMutableTransaction tx6 = BuildTransaction(tx3); + tx6.vout[0].scriptPubKey = CScript() << OP_TRUE; + COutPoint tx6OutPoint(tx6.GetHash(), 0); + + CMutableTransaction tx7 = BuildTransaction(coinbases[3]); + tx7.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; + tx7.vout[0].nValue = tx1.vout[0].nValue - 10001; + uint160 tx7ClaimId = ClaimIdHash(tx7.GetHash(), 0); + std::vector vchTx7ClaimId(tx7ClaimId.begin(), tx7ClaimId.end()); + COutPoint tx7OutPoint(tx7.GetHash(), 0); + + CMutableTransaction tx8 = BuildTransaction(tx3, 0, 2); + tx8.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; + tx8.vout[0].nValue = tx8.vout[0].nValue - 1; + tx8.vout[1].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName1 << vchValue2 << OP_2DROP << OP_DROP << OP_TRUE; + COutPoint tx8OutPoint0(tx8.GetHash(), 0); + COutPoint tx8OutPoint1(tx8.GetHash(), 1); + + CMutableTransaction tx9 = BuildTransaction(tx7); + tx9.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx7ClaimId << vchValue2 << OP_2DROP << OP_2DROP << OP_TRUE; + tx9.vout[0].nValue -= 10000; + COutPoint tx9OutPoint(tx9.GetHash(), 0); + + CMutableTransaction tx10 = BuildTransaction(coinbases[4]); + tx10.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; + COutPoint tx10OutPoint(tx10.GetHash(), 0); + + CMutableTransaction tx11 = BuildTransaction(tx10); + tx11.vout[0].scriptPubKey = CScript() << OP_UPDATE_CLAIM << vchName1 << vchTx1ClaimId << vchValue1 << OP_2DROP << OP_2DROP << OP_TRUE; + COutPoint tx11OutPoint(tx11.GetHash(), 0); + + CMutableTransaction tx12 = BuildTransaction(tx10); + tx12.vout[0].scriptPubKey = CScript() << OP_TRUE; + COutPoint tx12OutPoint(tx12.GetHash(), 0); + + CMutableTransaction tx13 = BuildTransaction(coinbases[5]); + tx13.vout[0].scriptPubKey = CScript() << OP_CLAIM_NAME << vchName3 << vchValue3 << OP_2DROP << OP_DROP << OP_TRUE; + COutPoint tx13OutPoint(tx13.GetHash(), 0); + + CClaimValue val; + + int nThrowaway; + + std::vector blocks_to_invalidate; + + // Verify claims for uncontrolled names go in immediately + + AddToMempool(tx7); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx7OutPoint); + + // Verify claims for controlled names are delayed, and that the bigger claim wins when inserted + + BOOST_CHECK(CreateBlocks(5, 1)); + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(5, 1)); + + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx1OutPoint); + + // Verify updates to the best claim get inserted immediately, and others don't. + + AddToMempool(tx3); + AddToMempool(tx9); + + BOOST_CHECK(CreateBlocks(1, 3)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx1OutPoint)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx7OutPoint)); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx3OutPoint); + BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx9OutPoint, nThrowaway)); + + // Disconnect all blocks until the first block, and then reattach them, in memory only + + //FlushStateToDisk(); + + CCoinsViewCache coins(pcoinsTip); + CClaimTrieCache trieCache(pclaimTrie); + CBlockIndex* pindexState = chainActive.Tip(); + CValidationState state; + CBlockIndex* pindex; + for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex=pindex->pprev) + { + CBlock block; + BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); + if (pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) + { + bool fClean = true; + BOOST_CHECK(DisconnectBlock(block, state, pindex, coins, trieCache, &fClean)); + pindexState = pindex->pprev; + } + } + while (pindex != chainActive.Tip()) + { + pindex = chainActive.Next(pindex); + CBlock block; + BOOST_CHECK(ReadBlockFromDisk(block, pindex, Params().GetConsensus())); + BOOST_CHECK(ConnectBlock(block, state, pindex, coins, trieCache)); + } + + // Roll back the last block, make sure tx1 and tx7 are put back in the trie + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx1OutPoint); + BOOST_CHECK(pclaimTrie->haveClaim(sName1, tx7OutPoint)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->empty()); + + // Roll all the way back, make sure all txs are out of the trie + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(!pclaimTrie->getInfoForName(sName1, val)); + + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->getMerkleHash() == hash0); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Test undoing a claim before the claim gets into the trie + + // Put tx1 in the chain, then advance a few blocks. + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(10, 1)); + + // Put tx7 in the chain, verify it goes into the queue + + AddToMempool(tx7); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + // Undo that block and make sure it's not in the queue + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + // Make sure it's not in the queue + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Go back to the beginning + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Test spend a claim which was just inserted into the trie + + // Immediately spend tx2 with tx4, verify nothing gets put in the trie + + AddToMempool(tx2); + AddToMempool(tx4); + + BOOST_CHECK(CreateBlocks(1, 3)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Verify that if a claim in the queue is spent, it does not get into the trie + + // Put tx5 into the chain, advance until it's in the trie for a few blocks + + AddToMempool(tx5); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(CreateBlocks(5, 1)); + + // Put tx2 into the chain, and then advance a few blocks but not far enough for it to get into the trie + + AddToMempool(tx2); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName2, tx2OutPoint, nThrowaway)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(3, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + // Spend tx2 with tx4, and then advance to where tx2 would be inserted into the trie and verify it hasn't happened + + AddToMempool(tx4); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(5, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->haveClaim(sName2, tx2OutPoint)); + + // Undo spending tx2 with tx4, and then advance and verify tx2 is inserted into the trie when it should be + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName2, tx2OutPoint, nThrowaway)); + + BOOST_CHECK(CreateBlocks(2, 1)); + + BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName2, val)); + BOOST_CHECK(val.outPoint == tx5OutPoint); + BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); + + // Test undoing a spend which involves a claim in the trie + + // spend tx2, which is in the trie, with tx4 + + AddToMempool(tx4); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->haveClaim(sName2, tx2OutPoint)); + + // undo spending tx2 with tx4, and verify tx2 is back in the trie + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName2, val)); + BOOST_CHECK(val.outPoint == tx5OutPoint); + BOOST_CHECK(pclaimTrie->haveClaim(sName2, tx2OutPoint)); + + // roll back to the beginning + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Test undoing a spent update which updated a claim still in the queue + + // Create the claim that will cause the others to be in the queue + + AddToMempool(tx7); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(CreateBlocks(5, 1)); + + // Create the original claim (tx1) + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + //blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx1OutPoint, nThrowaway)); + + // move forward some, but not far enough for the claim to get into the trie + + BOOST_CHECK(CreateBlocks(2, 1)); + + // update the original claim (tx3 spends tx1) + + AddToMempool(tx3); + + BOOST_CHECK(CreateBlocks(1, 2)); + //blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx1OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx1OutPoint)); + BOOST_CHECK(pclaimTrie->haveClaimInQueue(sName1, tx3OutPoint, nThrowaway)); + + // spend the update (tx6 spends tx3) + + AddToMempool(tx6); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx3OutPoint)); + + // undo spending the update (undo tx6 spending tx3) + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + // make sure the update (tx3) still goes into effect when it's supposed to + + BOOST_CHECK(CreateBlocks(8, 1)); + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx3OutPoint); + + BOOST_CHECK(CreateBlocks(1, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->haveClaim(sName1, tx3OutPoint)); + + // roll all the way back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // Test undoing an spent update which updated the best claim to a name + + // move forward until the original claim is inserted into the trie + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(5, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx1OutPoint); + + // update the original claim (tx3 spends tx1) + + AddToMempool(tx3); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx3OutPoint); + + // spend the update (tx6 spends tx3) + + AddToMempool(tx6); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // undo spending the update (undo tx6 spending tx3) + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx3OutPoint); + + // Test having two updates to a claim in the same transaction + + // Add both txouts (tx8 spends tx3) + + AddToMempool(tx8); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + // ensure txout 0 made it into the trie and txout 1 did not + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx8OutPoint0); + + // roll forward until tx8 output 1 gets into the trie + + BOOST_CHECK(CreateBlocks(6, 1)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(!pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(1, 1)); + + // ensure txout 1 made it into the trie and is now in control + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx8OutPoint1); + + // roll back to before tx8 + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + // roll all the way back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // make sure invalid updates don't wreak any havoc + + // put tx1 into the trie + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->getInfoForName(sName1, val)); + BOOST_CHECK(val.outPoint == tx1OutPoint); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // advance a few blocks + + BOOST_CHECK(CreateBlocks(5, 1)); + + // put in bad tx10 + + AddToMempool(tx10); + + BOOST_CHECK(CreateBlocks(1, 2)); + + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll back, make sure nothing bad happens + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + // put it back in + + AddToMempool(tx10); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // update it + + AddToMempool(tx11); + + BOOST_CHECK(CreateBlocks(1, 2)); + + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + BOOST_CHECK(CreateBlocks(10, 1)); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll back to before the update + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // make sure tx10 would have gotten into the trie, then run tests again + + BOOST_CHECK(CreateBlocks(10, 1)); + + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // update it + + AddToMempool(tx11); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // make sure tx11 would have gotten into the trie + + BOOST_CHECK(CreateBlocks(20, 1)); + + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx11OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx11OutPoint)); + BOOST_CHECK(!pclaimTrie->haveClaimInQueue(sName1, tx10OutPoint, nThrowaway)); + BOOST_CHECK(!pclaimTrie->haveClaim(sName1, tx10OutPoint)); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll all the way back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + // Put tx10 and tx11 in without tx1 in + + AddToMempool(tx10); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // update with tx11 + + AddToMempool(tx11); + + BOOST_CHECK(CreateBlocks(1, 2)); + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll back to before tx11 + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + + // spent tx10 with tx12 instead which is not a claim operation of any kind + + AddToMempool(tx12); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll all the way back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); + // make sure all claim for names which exist in the trie but have no + // values get inserted immediately + + blocks_to_invalidate.push_back(chainActive.Tip()->GetBlockHash()); + + AddToMempool(tx13); + + BOOST_CHECK(CreateBlocks(1, 2)); + + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + AddToMempool(tx1); + + BOOST_CHECK(CreateBlocks(1, 2)); + BOOST_CHECK(!pclaimTrie->empty()); + BOOST_CHECK(pclaimTrie->queueEmpty()); + + // roll back + + BOOST_CHECK(RemoveBlock(blocks_to_invalidate.back())); + blocks_to_invalidate.pop_back(); +} + +BOOST_AUTO_TEST_CASE(claimtrienode_serialize_unserialize) +{ + fRequireStandard = false; + CDataStream ss(SER_DISK, 0); + + uint160 hash160; + + CClaimTrieNode n1; + CClaimTrieNode n2; + CClaimValue throwaway; + + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + n1.hash.SetHex("0000000000000000000000000000000000000000000000000000000000000001"); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + n1.hash.SetHex("a79e8a5b28f7fa5e8836a4b48da9988bdf56ce749f81f413cb754f963a516200"); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + CClaimValue v1(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000001"), 0), hash160, 50, 0, 100); + CClaimValue v2(COutPoint(uint256S("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 1), hash160, 100, 1, 101); + + n1.insertClaim(v1); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + n1.insertClaim(v2); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + n1.removeClaim(v1.outPoint, throwaway); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); + + n1.removeClaim(v2.outPoint, throwaway); + BOOST_CHECK(n1 != n2); + ss << n1; + ss >> n2; + BOOST_CHECK(n1 == n2); +} + +bool verify_proof(const CClaimTrieProof proof, uint256 rootHash, const std::string& name) +{ + uint256 previousComputedHash; + std::string computedReverseName; + bool verifiedValue = false; + + for (std::vector::const_reverse_iterator itNodes = proof.nodes.rbegin(); itNodes != proof.nodes.rend(); ++itNodes) + { + bool foundChildInChain = false; + std::vector vchToHash; + for (std::vector >::const_iterator itChildren = itNodes->children.begin(); itChildren != itNodes->children.end(); ++itChildren) + { + vchToHash.push_back(itChildren->first); + uint256 childHash; + if (itChildren->second.IsNull()) + { + if (previousComputedHash.IsNull()) + { + return false; + } + if (foundChildInChain) + { + return false; + } + foundChildInChain = true; + computedReverseName += itChildren->first; + childHash = previousComputedHash; + } + else + { + childHash = itChildren->second; + } + vchToHash.insert(vchToHash.end(), childHash.begin(), childHash.end()); + } + if (itNodes != proof.nodes.rbegin() && !foundChildInChain) + { + return false; + } + if (itNodes->hasValue) + { + uint256 valHash; + if (itNodes->valHash.IsNull()) + { + if (itNodes != proof.nodes.rbegin()) + { + return false; + } + if (!proof.hasValue) + { + return false; + } + valHash = getValueHash(proof.outPoint, + proof.nHeightOfLastTakeover); + + verifiedValue = true; + } + else + { + valHash = itNodes->valHash; + } + vchToHash.insert(vchToHash.end(), valHash.begin(), valHash.end()); + } + else if (proof.hasValue && itNodes == proof.nodes.rbegin()) + { + return false; + } + CHash256 hasher; + std::vector vchHash(hasher.OUTPUT_SIZE); + hasher.Write(vchToHash.data(), vchToHash.size()); + hasher.Finalize(&(vchHash[0])); + uint256 calculatedHash(vchHash); + previousComputedHash = calculatedHash; + } + if (previousComputedHash != rootHash) + { + return false; + } + if (proof.hasValue && !verifiedValue) + { + return false; + } + std::string::reverse_iterator itComputedName = computedReverseName.rbegin(); + std::string::const_iterator itName = name.begin(); + for (; itName != name.end() && itComputedName != computedReverseName.rend(); ++itName, ++itComputedName) + { + if (*itName != *itComputedName) + { + return false; + } + } + return (!proof.hasValue || itName == name.end()); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_pop.cpp b/src/test/test_pop.cpp index a7847ec..5e3227a 100644 --- a/src/test/test_pop.cpp +++ b/src/test/test_pop.cpp @@ -1,186 +1,188 @@ -// Copyright (c) 2017-2018 The Popchain Core Developers - -#define BOOST_TEST_MODULE Pop Test Suite - -#include "test_pop.h" - -#include "chainparams.h" -#include "consensus/consensus.h" -#include "consensus/validation.h" -#include "key.h" -#include "main.h" -#include "miner.h" -#include "pubkey.h" -#include "random.h" -#include "txdb.h" -#include "txmempool.h" -#include "ui_interface.h" -#include "rpcserver.h" -#include "util.h" -#ifdef ENABLE_WALLET -#include "wallet/db.h" -#include "wallet/wallet.h" -#endif - -#include -#include -#include - -CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h -CWallet* pwalletMain; - -extern bool fPrintToConsole; -extern void noui_connect(); - -BasicTestingSetup::BasicTestingSetup(const std::string& chainName) -{ - ECC_Start(); - SetupEnvironment(); - SetupNetworking(); - fPrintToDebugLog = false; // don't want to write to debug.log file - fCheckBlockIndex = true; - SelectParams(chainName); - noui_connect(); -} - -BasicTestingSetup::~BasicTestingSetup() -{ - ECC_Stop(); -} - -TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) -{ - const CChainParams& chainparams = Params(); -#ifdef ENABLE_WALLET - bitdb.MakeMock(); -#endif - ClearDatadirCache(); - pathTemp = GetTempPath() / strprintf("test_pop_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - pblocktree = new CBlockTreeDB(1 << 20, true); - pcoinsdbview = new CCoinsViewDB(1 << 23, true); - pcoinsTip = new CCoinsViewCache(pcoinsdbview); - pclaimTrie = new CClaimTrie(true, false, 1); - InitBlockIndex(chainparams); -#ifdef ENABLE_WALLET - bool fFirstRun; - pwalletMain = new CWallet("wallet.dat"); - pwalletMain->LoadWallet(fFirstRun); - RegisterValidationInterface(pwalletMain); -#endif - nScriptCheckThreads = 3; - for (int i=0; i < nScriptCheckThreads-1; i++) - threadGroup.create_thread(&ThreadScriptCheck); - RegisterNodeSignals(GetNodeSignals()); -} - -TestingSetup::~TestingSetup() -{ - UnregisterNodeSignals(GetNodeSignals()); - threadGroup.interrupt_all(); - threadGroup.join_all(); -#ifdef ENABLE_WALLET - UnregisterValidationInterface(pwalletMain); - delete pwalletMain; - pwalletMain = NULL; -#endif - UnloadBlockIndex(); - delete pclaimTrie; - delete pcoinsTip; - delete pcoinsdbview; - delete pblocktree; -#ifdef ENABLE_WALLET - bitdb.Flush(true); - bitdb.Reset(); -#endif - boost::filesystem::remove_all(pathTemp); -} - -TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) -{ - // Generate a 100-block chain: - coinbaseKey.MakeNewKey(true); - CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - for (int i = 0; i < COINBASE_MATURITY; i++) - { - std::vector noTxns; - CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); - coinbaseTxns.push_back(b.vtx[0]); - } -} - -// -// Create a new block with just given transactions, coinbase paying to -// scriptPubKey, and try to add it to the current chain. -// -CBlock -TestChain100Setup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey) -{ - const CChainParams& chainparams = Params(); - CBlockTemplate *pblocktemplate = CreateNewBlock(chainparams, scriptPubKey); - CBlock& block = pblocktemplate->block; - - // Replace mempool-selected txns with just coinbase plus passed-in txns: - block.vtx.resize(1); - BOOST_FOREACH(const CMutableTransaction& tx, txns) - block.vtx.push_back(tx); - // IncrementExtraNonce creates a valid coinbase and merkleRoot - unsigned int extraNonce = 0; - IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - - for(arith_uint256 i = 0; ; ++i) - { - block.nNonce = ArithToUint256(i); - if (CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) - { - break; - } - } - - CValidationState state; - ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); - - CBlock result = block; - delete pblocktemplate; - return result; -} - -TestChain100Setup::~TestChain100Setup() -{ -} - -RegTestingSetup::RegTestingSetup() : TestingSetup(CBaseChainParams::REGTEST) -{ - minRelayTxFee = CFeeRate(0); -} - -RegTestingSetup::~RegTestingSetup() -{ - minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); -} - -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { - CTransaction txn(tx); - bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies; - // Hack to assume either its completely dependent on other mempool txs or not at all - CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; - - return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, - hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); -} - -void Shutdown(void* parg) -{ - exit(0); -} - -void StartShutdown() -{ - exit(0); -} - -bool ShutdownRequested() -{ - return false; -} +// Copyright (c) 2017-2018 The Popchain Core Developers + +#define BOOST_TEST_MODULE Pop Test Suite + +#include "test_pop.h" + +#include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "key.h" +#include "main.h" +#include "miner.h" +#include "pubkey.h" +#include "random.h" +#include "txdb.h" +#include "txmempool.h" +#include "ui_interface.h" +#include "rpcserver.h" +#include "util.h" +#ifdef ENABLE_WALLET +#include "wallet/db.h" +#include "wallet/wallet.h" +#endif + +#include +#include +#include + +CClientUIInterface uiInterface; // Declared but not defined in ui_interface.h +CWallet* pwalletMain; + +extern bool fPrintToConsole; +extern void noui_connect(); + +BasicTestingSetup::BasicTestingSetup(const std::string& chainName) +{ + ECC_Start(); + SetupEnvironment(); + SetupNetworking(); + fPrintToDebugLog = false; // don't want to write to debug.log file + fCheckBlockIndex = true; + SelectParams(chainName); + noui_connect(); +} + +BasicTestingSetup::~BasicTestingSetup() +{ + ECC_Stop(); +} + +TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(chainName) +{ + const CChainParams& chainparams = Params(); +#ifdef ENABLE_WALLET + bitdb.MakeMock(); +#endif + ClearDatadirCache(); + pathTemp = GetTempPath() / strprintf("test_pop_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); + pblocktree = new CBlockTreeDB(1 << 20, true); + pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); + pclaimTrie = new CClaimTrie(true, false, 1); + InitBlockIndex(chainparams); +#ifdef ENABLE_WALLET + bool fFirstRun; + pwalletMain = new CWallet("wallet.dat"); + pwalletMain->LoadWallet(fFirstRun); + RegisterValidationInterface(pwalletMain); +#endif + nScriptCheckThreads = 3; + for (int i=0; i < nScriptCheckThreads-1; i++) + threadGroup.create_thread(&ThreadScriptCheck); + RegisterNodeSignals(GetNodeSignals()); +} + +TestingSetup::~TestingSetup() +{ + UnregisterNodeSignals(GetNodeSignals()); + threadGroup.interrupt_all(); + threadGroup.join_all(); +#ifdef ENABLE_WALLET + UnregisterValidationInterface(pwalletMain); + delete pwalletMain; + pwalletMain = NULL; +#endif + UnloadBlockIndex(); + delete pclaimTrie; + delete pcoinsTip; + delete pcoinsdbview; + delete pblocktree; +#ifdef ENABLE_WALLET + bitdb.Flush(true); + bitdb.Reset(); +#endif + boost::filesystem::remove_all(pathTemp); +} + +TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) +{ + // Generate a 100-block chain: + coinbaseKey.MakeNewKey(true); + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + for (int i = 0; i < COINBASE_MATURITY; i++) + { + std::vector noTxns; + CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); + coinbaseTxns.push_back(b.vtx[0]); + } +} + +// +// Create a new block with just given transactions, coinbase paying to +// scriptPubKey, and try to add it to the current chain. +// +CBlock +TestChain100Setup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey) +{ + const CChainParams& chainparams = Params(); + CBlockTemplate *pblocktemplate = CreateNewBlock(chainparams, scriptPubKey); + CBlock& block = pblocktemplate->block; + + // Replace mempool-selected txns with just coinbase plus passed-in txns: + block.vtx.resize(1); + BOOST_FOREACH(const CMutableTransaction& tx, txns) + block.vtx.push_back(tx); + // IncrementExtraNonce creates a valid coinbase and merkleRoot + unsigned int extraNonce = 0; + IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); + + for(arith_uint256 i = 0; ; ++i) + { + block.nNonce = ArithToUint256(i); + /*popchain ghost*/ + //if (CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) + if (CheckProofOfWork(block.GetHash(), block.nDifficulty, chainparams.GetConsensus())) + { + break; + } + } + + CValidationState state; + ProcessNewBlock(state, chainparams, NULL, &block, true, NULL); + + CBlock result = block; + delete pblocktemplate; + return result; +} + +TestChain100Setup::~TestChain100Setup() +{ +} + +RegTestingSetup::RegTestingSetup() : TestingSetup(CBaseChainParams::REGTEST) +{ + minRelayTxFee = CFeeRate(0); +} + +RegTestingSetup::~RegTestingSetup() +{ + minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); +} + +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { + CTransaction txn(tx); + bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies; + // Hack to assume either its completely dependent on other mempool txs or not at all + CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; + + return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight, + hasNoDependencies, inChainValue, spendsCoinbase, sigOpCount, lp); +} + +void Shutdown(void* parg) +{ + exit(0); +} + +void StartShutdown() +{ + exit(0); +} + +bool ShutdownRequested() +{ + return false; +} diff --git a/src/txdb.cpp b/src/txdb.cpp index 4dc96b9..163fef2 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -328,6 +328,12 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nDataPos = diskindex.nDataPos; pindexNew->nUndoPos = diskindex.nUndoPos; pindexNew->nVersion = diskindex.nVersion; + /*popchain ghost*/ + pindexNew->hashUncles = diskindex.hashUncles; + pindexNew->nCoinbase = diskindex.nCoinbase; + pindexNew->nDifficulty = diskindex.nDifficulty; + pindexNew->nNumber = diskindex.nNumber; + /*popchain ghost*/ pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->hashClaimTrie = diskindex.hashClaimTrie; pindexNew->nTime = diskindex.nTime; @@ -335,8 +341,9 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nNonce = diskindex.nNonce; pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) + /*popchain ghost*/ + //if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nDifficulty, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); pcursor->Next(); From bc42e6b965fe839f7b0d2c0047000da96805889c Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Thu, 2 Aug 2018 14:30:19 +0800 Subject: [PATCH 012/120] update founder address --- src/chainparams.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ce80221..a6eaaf1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -296,8 +296,8 @@ class CMainParams : public CChainParams { // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { - "USu35JzWCXSvgvDL1utfFzb52zR1fdkfZ9", /* main-index: 0*/ - "US2b9XyE5fCu8DNXhC4xwU7wo7b4uMNy4q", /* main-index: 1*/ + "PoWvpLL3iDxm2GJSZQRspzRawEFEs3BbG8", /* main-index: 0*/ + "PcjJdnb9Fp35TRTAz61vp6MPXTv3ApcMhj", /* main-index: 1*/ }; } }; @@ -416,8 +416,8 @@ class CTestNetParams : public CChainParams { // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { - "uTZGwu5TsrswPUEb9QciyhH9xpmRy4Rfq6", - "ubwJhHMSVPVCHr3PNPgieNYpWvuWG5XvcQ" + "pbFyUjHfZB8BBivQS1LXh8EaJNH5jjGbzk", + "pbvTm479A2XTp2nCa8Z9qwAhindNbKarrX" }; } }; @@ -516,7 +516,7 @@ class CRegTestParams : public CChainParams { base58Prefixes[EXT_COIN_TYPE] = boost::assign::list_of(0x80)(0x00)(0x00)(0x01).convert_to_container >(); // Founders reward script expects a vector of 2-of-3 multisig addresses - vFoundersRewardAddress = {"u2FwcEhFdNXuFMv1tcYwaBJtYVtMj8b1uTg"}; + vFoundersRewardAddress = {"pbFyUjHfZB8BBivQS1LXh8EaJNH5jjGbzk"}; } }; static CRegTestParams regTestParams; From 5418c5890b634b9edeebeecb12a2a1a34759d7d6 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 6 Aug 2018 11:16:47 +0800 Subject: [PATCH 013/120] check the chain --- src/chainparams.cpp | 77 ++++++++++++++++++++++++------------ src/consensus/consensus.h | 6 ++- src/cryptopop/PoW.c | 5 ++- src/cryptopop/common.h | 5 ++- src/hash.h | 8 ++-- src/main.cpp | 37 +++++++++++++++-- src/miner.cpp | 11 +++++- src/pow.cpp | 15 +++---- src/pow.h | 4 +- src/primitives/block.cpp | 40 +++++++++++++++++-- src/primitives/block.h | 11 +++++- src/rpcmining.cpp | 4 +- src/test/claimtrie_tests.cpp | 4 +- src/test/test_pop.cpp | 4 +- src/txdb.cpp | 4 +- 15 files changed, 176 insertions(+), 59 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a6eaaf1..70d8971 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -88,8 +88,8 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) static void findGenesis(CBlockHeader *pb, const std::string &net) { /*popchain ghost*/ - //arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); - arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); + arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); + //arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); /*popchain ghost*/ std::cout << " finding genesis using target " << hashTarget.ToString() << ", " << net << std::endl; @@ -119,8 +119,8 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) } #endif /*popchain ghost*/ -//static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) -static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const CAmount &genesisReward) +//static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const CAmount &genesisReward) +static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) { CMutableTransaction txNew; txNew.nVersion = 1; @@ -133,14 +133,22 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi CBlock genesis; genesis.nTime = nTime; /*popchain ghost*/ - genesis.nDifficulty = nDifficulty; - genesis.nBits = maxUint256Div(nDifficulty).GetCompact(); - //genesis.nBits = nBits; + //genesis.nDifficulty = nDifficulty; + //genesis.nBits = maxUint256Div(nDifficulty).GetCompact(); + genesis.nBits = nBits; /*popchain ghost*/ genesis.nNonce = nNonce; genesis.nVersion = nVersion; genesis.vtx.push_back(txNew); genesis.hashPrevBlock.SetNull(); + /*popchain ghost*/ + genesis.hashUncles.SetNull(); + genesis.nCoinbase.SetNull(); + genesis.nDifficulty.SetNull(); + genesis.nNumber = 0; + genesis.vuh.clear(); + genesis.hashUncles = BlockUncleRoot(genesis); + /*popchain ghost*/ genesis.hashMerkleRoot = BlockMerkleRoot(genesis); genesis.hashClaimTrie = uint256S("0x1"); return genesis; @@ -158,24 +166,27 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi * vMerkleTree: e0028e */ /*popchain ghost*/ -//static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) -static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const int64_t& genesisReward) + +//static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const int64_t& genesisReward) +static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) { const char* pszTimestamp = "pop hold value testnet."; const CScript genesisOutputScript = CScript() << ParseHex("034c73d75f59061a08032b68369e5034390abc5215b3df79be01fb4319173a88f8") << OP_CHECKSIG; //std::vector printscript(genesisOutputScript.begin(),genesisOutputScript.end); //std::cout<< StrHex(printscript)< 2 x fork detection time, was 24 * 60 * 60 in bitcoin nPruneAfterHeight = 100000; /*popchain ghost*/ - //arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); - genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), consensus.powLimit, 1, consensus.genesisReward); + //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), consensus.powLimit, 1, consensus.genesisReward); + genesis = CreateGenesisBlock1(1529900309, uint256S("00002ff377441449fc998797055b4a553d9f855c587431e3aa2bd5892ea400ea"), 0x1f0fffff, 1, consensus.genesisReward); /*popchain ghost*/ #ifdef GENESIS_GENERATION - arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); + //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); + arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); /*popchain ghost*/ //std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; @@ -254,7 +270,8 @@ class CMainParams : public CChainParams { //findGenesis(&genesis, "main"); #endif consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); + //assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); + assert(consensus.hashGenesisBlock == uint256S("0x0008c4249ce438419b225a0a0332f107ada1fa9eb18b4572fde08de4ecc3fcbf")); assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); // Pop addresses start with 'P' @@ -287,7 +304,8 @@ class CMainParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), + ( 0, uint256S("0x0008c4249ce438419b225a0a0332f107ada1fa9eb18b4572fde08de4ecc3fcbf")), + //( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), 1529900309, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) @@ -360,9 +378,10 @@ class CTestNetParams : public CChainParams { nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet nPruneAfterHeight = 1000; /*popchain ghost*/ - //arith_uint256 nTempBit = UintToArith256( consensus.powLimit); + arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); - genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), consensus.powLimit, 1, 1 * COIN); + //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), consensus.powLimit, 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0000577da6294991bd9e1891b7f1e5fbc7e23943341e56e8e005db4358a6001e"), 0x1f0fffff, 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); @@ -373,7 +392,8 @@ class CTestNetParams : public CChainParams { //findGenesis(&genesis, "testnet"); #endif consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); + //assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); + assert(consensus.hashGenesisBlock == uint256S("000b826ae49848958a81d388d4007a59d7836697a8d2c52a21244245b23ca9c3")); assert(genesis.hashMerkleRoot == uint256S("6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); vFixedSeeds.clear(); @@ -407,7 +427,8 @@ class CTestNetParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), + (0, uint256S("000b826ae49848958a81d388d4007a59d7836697a8d2c52a21244245b23ca9c3")), + //(0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), 1529894661, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) @@ -474,14 +495,17 @@ class CRegTestParams : public CChainParams { nDefaultPort = 29888; nPruneAfterHeight = 1000; /*popchain ghost*/ + arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); - genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), consensus.powLimit, 1, 1 * COIN); + //genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), consensus.powLimit, 1, 1 * COIN); + genesis = CreateGenesisBlock1(1529894661, uint256S("0x0000e1f169e639906e0e50622879c4fcf429d559b154002d32d3c250d2500001"), 0x200f0f0f, 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION //findGenesis(&genesis, "regtest"); #endif consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); + //assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); + assert(consensus.hashGenesisBlock == uint256S("017b05f2adc6491e3fa200b72069b44daa6e83af1b5824a921427dcae8c08050")); assert(genesis.hashMerkleRoot == uint256S("69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. @@ -497,7 +521,8 @@ class CRegTestParams : public CChainParams { checkpointData = (CCheckpointData){ boost::assign::map_list_of - (0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), + (0, uint256S("017b05f2adc6491e3fa200b72069b44daa6e83af1b5824a921427dcae8c08050")), + //(0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), 0, 0, 0 diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index ea0b192..61c94e7 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -8,8 +8,10 @@ static const unsigned int MAX_BLOCK_SIZE = 4000000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ -static const int COINBASE_MATURITY = 100; - +/*popchain ghost*/ +//100 to 10 +static const int COINBASE_MATURITY = 10; +/*popchain ghost*/ /** Flags for nSequence and nLockTime locks */ enum { /* Interpret sequence numbers as relative lock-time constraints. */ diff --git a/src/cryptopop/PoW.c b/src/cryptopop/PoW.c index 52baf0d..8e29842 100644 --- a/src/cryptopop/PoW.c +++ b/src/cryptopop/PoW.c @@ -278,7 +278,10 @@ void testPowFunction(uint8_t *mess, uint32_t messLen, const int64_t iterNum) { #define OUTPUT_BUFFER_SIZE (32 * 1024UL * 1024UL) -#define MAX_TEST_INPUT_LEN 140 +/*popchain ghost*/ +//140 to 228 +#define MAX_TEST_INPUT_LEN 228 +/*popchain ghost*/ #define MAX_OUT_FILE_NAME_LEN 25 const char testInputCase[][MAX_TEST_INPUT_LEN] = { diff --git a/src/cryptopop/common.h b/src/cryptopop/common.h index 03b50a3..524a045 100644 --- a/src/cryptopop/common.h +++ b/src/cryptopop/common.h @@ -10,7 +10,10 @@ #include #endif -#define INPUT_LEN 140 +/*popchain ghost*/ +//114 to 228 +#define INPUT_LEN 228 +/*popchain ghsot*/ #define OUTPUT_LEN 32 // Least common multiple diff --git a/src/hash.h b/src/hash.h index 37643f4..633a6b2 100644 --- a/src/hash.h +++ b/src/hash.h @@ -73,9 +73,11 @@ class CryptoPop { { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *pblock; - assert(ss.size() == 140); - write((uchar *)&ss[0], 140).finalize(hash); - + /*popchain ghost*/ + //140 to 228 + assert(ss.size() == 228); + write((uchar *)&ss[0], 228).finalize(hash); + /*popchain ghost*/ //view_data_u8("PoW 2", hash, OUTPUT_LEN); } diff --git a/src/main.cpp b/src/main.cpp index c67028b..2f8a06c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1705,8 +1705,8 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: //arith_uint256 k = UintToArith256(block.GetHash()); //LogPrintf("\t\t\tblock = %s\n\t\t\thash = %s\n\t\t\tarith hash = %s\n", block.ToString().c_str(), block.GetHash().ToString().c_str(), k.ToString().c_str()); /*popchain ghost*/ - //if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) - if (!CheckProofOfWork(block.GetHash(), block.nDifficulty, consensusParams)) + //if (!CheckProofOfWork(block.GetHash(), block.nDifficulty, consensusParams)) + if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); /*popchain ghost*/ return true; @@ -3864,13 +3864,14 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f { // Check proof of work matches claimed amount /*popchain ghost*/ - //if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nDifficulty, Params().GetConsensus())) + //if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nDifficulty, Params().GetConsensus())) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) { LogPrintf("CheckBlockHeader(): \n--b-l-o-c-k---%s\n\n", block.ToString().c_str()); return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); } + /*popchain ghost*/ // Check timestamp if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), @@ -3907,6 +3908,16 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo REJECT_INVALID, "bad-txns-duplicate", true); } + /*popchain ghost*/ + if(true){ + uint256 hashUncleRoot = BlockUncleRoot(block); + if(block.hashUncles != hashUncleRoot){ + return state.DoS(100, error("CheckBlock(): hashUncles mismatch"), + REJECT_INVALID, "bad-uncleshash", true); + } + } + /*popchain ghost*/ + // All potential-corruption validation must be done before we do any // transaction validation, as otherwise we may mark the header as invalid // because we receive the wrong transactions for it. @@ -4002,6 +4013,14 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta int nHeight = pindexPrev->nHeight + 1; LogPrintf("check block header height %d \n", nHeight); + + /*popchain ghost*/ + // check nNumber against prev + if (block.nNumber != (pindexPrev->nNumber+ 1)) + return state.DoS(100, error("%s : incorrect nNumber at %d", __func__, nHeight), + REJECT_INVALID, "bad-nNumber"); + /*popchain ghost*/ + // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) return state.DoS(100, error("%s : incorrect proof of work at %d", __func__, nHeight), @@ -6155,6 +6174,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, for (unsigned int n = 0; n < nCount; n++) { vRecv >> headers[n]; ReadCompactSize(vRecv); // ignore tx count; assume it is 0. + /*popchain ghost*/ + ReadCompactSize(vRecv); // ignore uncles count; assume it is 0. + /*popchain ghost*/ } LOCK(cs_main); @@ -6189,6 +6211,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 20); return error("non-continuous headers sequence"); } + + /*popchain ghost*/ + if (pindexLast != NULL && header.nNumber != (pindexLast->nNumber + 1)) { + Misbehaving(pfrom->GetId(), 20); + return error("non-continuous headers number"); + } + if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { diff --git a/src/miner.cpp b/src/miner.cpp index 3974a8d..e04c255 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -446,6 +446,9 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + /*popchain ghost*/ + pblock->nNumber = pindexPrev->nNumber + 1; + /*popchain ghost*/ UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); @@ -485,12 +488,18 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 + /*popchain ghost*/ + //pblock->nNumber = pindexPrev->nNumber + 1; + /*popchain ghost*/ CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); + /*popchain ghost*/ + pblock->hashUncles = BlockUncleRoot(*pblock); + /*popchain ghost*/ } static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) @@ -606,7 +615,7 @@ void static BitcoinMiner(const CChainParams& chainparams) pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); /*popchain ghost*/ //change parameter 0xFF to 0xffff to support the ghost protol - if ((UintToArith256(pblock->nNonce) & 0xffff) == 0) + if ((UintToArith256(pblock->nNonce) & 0xff) == 0) { //LogPrintf("PopMiner: %d nExtraNonce: %d\n", pblock->nNonce, nExtraNonce); break; diff --git a/src/pow.cpp b/src/pow.cpp index 1222a1d..be7aaca 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -76,15 +76,15 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, return bnNew.GetCompact(); } /*popchain ghost*/ -//bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) +bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative = false; bool fOverflow = false; arith_uint256 bnTarget; - //bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - bnTarget = maxUint256Div(nDifficulty); + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); + //bnTarget = maxUint256Div(nDifficulty); // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) @@ -106,7 +106,7 @@ arith_uint256 GetBlockProof(const CBlockIndex& block) arith_uint256 bnTarget; bool fNegative; bool fOverflow; - /* + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); if (fNegative || fOverflow || bnTarget == 0) return 0; @@ -115,9 +115,10 @@ arith_uint256 GetBlockProof(const CBlockIndex& block) // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, // or ~bnTarget / (nTarget+1) + 1. return (~bnTarget / (bnTarget + 1)) + 1; - */ - bnTarget = maxUint256Div(block.nDifficulty); - return bnTarget; + /*popchain ghost*/ + //bnTarget = maxUint256Div(block.nDifficulty); + //return bnTarget; + /*popchain ghost*/ } /*popchain ghost*/ diff --git a/src/pow.h b/src/pow.h index bef5b71..c185496 100644 --- a/src/pow.h +++ b/src/pow.h @@ -20,8 +20,8 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ /*popchain ghost*/ -//bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); -bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params&); +bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); +//bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params&); /*popchain ghost*/ arith_uint256 GetBlockProof(const CBlockIndex& block); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 5bf7ff2..c51e1f1 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -25,12 +25,12 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(), - nCoinbase.ToString(),/*change by base58 ?*/ + nCoinbase.ToString(),/*need change by base58 ?*/ nDifficulty.ToString(), nNumber, hashMerkleRoot.ToString(), @@ -43,7 +43,7 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashUncles=%s, nCoinbaseAddress=%s, nDifficulty=%s, nNumber=%u, hashPrevBlock=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), @@ -60,5 +60,39 @@ std::string CBlock::ToString() const { s << " " << vtx[i].ToString() << "\n"; } + + /*popchain ghost*/ + + for (unsigned int i = 0; i < vuh.size(); i++) + { + s << " " << vuh[i].ToString() << "\n"; + } + + /*popchain ghost*/ + return s.str(); } + +/*popchain ghost*/ + +uint256 BlockUncleRoot(const CBlock& block) +{ + uint256 hashUncles = uint256(); + std::vector uncles; + uncles.resize(block.vuh.size()); + for (size_t s = 0; s < block.vuh.size(); s++) { + uncles[s] = block.vuh[s].GetHash(); + } + + if(uncles.size() == 1){ + CHash256().Write(uncles[0].begin(), 32).Write(uncles[0].begin(), 32).Finalize(hashUncles.begin()); + } + else if(uncles.size() == 2){ + CHash256().Write(uncles[0].begin(), 32).Write(uncles[1].begin(), 32).Finalize(hashUncles.begin()); + } + + return hashUncles; +} + +/*popchain ghost*/ + diff --git a/src/primitives/block.h b/src/primitives/block.h index f19f49a..3395952 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -126,7 +126,7 @@ class CBlock : public CBlockHeader READWRITE(vtx); /*popchain ghost*/ READWRITE(vuh); - READWRITE(td); + //READWRITE(td); /*popchain ghost*/ } @@ -134,6 +134,9 @@ class CBlock : public CBlockHeader { CBlockHeader::SetNull(); vtx.clear(); + /*popchain ghost*/ + vuh.clear(); + /*popchain ghost*/ fChecked = false; } @@ -194,4 +197,10 @@ struct CBlockLocator } }; +/*popchain ghost*/ +uint256 BlockUncleRoot(const CBlock& block); + +/*popchain ghost*/ + + #endif // BITCOIN_PRIMITIVES_BLOCK_H diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 5e074cd..c2cc428 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -171,8 +171,8 @@ UniValue generate(const UniValue& params, bool fHelp) IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } /*popchain ghost*/ - //while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { - while (!CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, Params().GetConsensus())) { + //while (!CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 2cd8620..20c8034 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -112,8 +112,8 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) { pblock->nNonce = ArithToUint256(i); /*popchain ghost*/ - //if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) - if (CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, chainparams.GetConsensus())) + //if (CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, chainparams.GetConsensus())) + if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) { break; } diff --git a/src/test/test_pop.cpp b/src/test/test_pop.cpp index 5e3227a..118403a 100644 --- a/src/test/test_pop.cpp +++ b/src/test/test_pop.cpp @@ -133,8 +133,8 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& { block.nNonce = ArithToUint256(i); /*popchain ghost*/ - //if (CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) - if (CheckProofOfWork(block.GetHash(), block.nDifficulty, chainparams.GetConsensus())) + //if (CheckProofOfWork(block.GetHash(), block.nDifficulty, chainparams.GetConsensus())) + if (CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) { break; } diff --git a/src/txdb.cpp b/src/txdb.cpp index 163fef2..6de4fee 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -342,8 +342,8 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; /*popchain ghost*/ - //if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nDifficulty, Params().GetConsensus())) + //if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nDifficulty, Params().GetConsensus())) + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); pcursor->Next(); From e4843ad9bef75b481baf1f814b3e25133d067fdc Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 6 Aug 2018 11:25:19 +0800 Subject: [PATCH 014/120] change the checkproofofwork --- src/pow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pow.cpp b/src/pow.cpp index be7aaca..264f5b3 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -76,7 +76,7 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, return bnNew.GetCompact(); } /*popchain ghost*/ -bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) +//bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative = false; From 10d4bc180f553e54cb91e61ea058efb30eabb3d7 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 6 Aug 2018 11:55:29 +0800 Subject: [PATCH 015/120] change genesis block --- src/chainparams.cpp | 8 ++++---- src/miner.cpp | 2 +- src/primitives/block.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 70d8971..51f4c1e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -264,8 +264,8 @@ class CMainParams : public CChainParams { //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); /*popchain ghost*/ - //std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; - std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; + std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; + //std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; /*popchain ghost*/ //findGenesis(&genesis, "main"); #endif @@ -386,8 +386,8 @@ class CTestNetParams : public CChainParams { #ifdef GENESIS_GENERATION arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); /*popchain ghost*/ - //std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; - std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; + std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; + //std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; /*popchain ghost*/ //findGenesis(&genesis, "testnet"); #endif diff --git a/src/miner.cpp b/src/miner.cpp index e04c255..78644d0 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -615,7 +615,7 @@ void static BitcoinMiner(const CChainParams& chainparams) pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); /*popchain ghost*/ //change parameter 0xFF to 0xffff to support the ghost protol - if ((UintToArith256(pblock->nNonce) & 0xff) == 0) + if ((UintToArith256(pblock->nNonce) & 0xFF) == 0) { //LogPrintf("PopMiner: %d nExtraNonce: %d\n", pblock->nNonce, nExtraNonce); break; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index c51e1f1..df270ec 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -43,7 +43,7 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), From f71d134fa70e5374f93dd802fce2d556f53c0b7d Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 7 Aug 2018 16:56:30 +0800 Subject: [PATCH 016/120] add the check of is have uncle or not --- src/primitives/block.cpp | 10 ++++++++++ src/primitives/block.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index df270ec..55620c3 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -94,5 +94,15 @@ uint256 BlockUncleRoot(const CBlock& block) return hashUncles; } +bool hasUncles(uint256& hash) +{ + arith_uint256 d = UintToArith256(hash); + if(d == 0){ + return false; + } + + return true; +} + /*popchain ghost*/ diff --git a/src/primitives/block.h b/src/primitives/block.h index 3395952..59b96f3 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -200,6 +200,7 @@ struct CBlockLocator /*popchain ghost*/ uint256 BlockUncleRoot(const CBlock& block); +bool hasUncles(uint256& hash); /*popchain ghost*/ From 3bab79a25b447c7f67ad69c4e1649bbff15e692d Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 7 Aug 2018 17:00:16 +0800 Subject: [PATCH 017/120] change the check --- src/arith_uint256.cpp | 12 ++++++++++++ src/arith_uint256.h | 3 +++ src/primitives/block.cpp | 8 -------- src/primitives/block.h | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 8d8a3b6..e1a778a 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -268,4 +268,16 @@ arith_uint256 maxUint256Div(const uint256 &a) return t; } + +bool hasUncles(uint256& hash) +{ + arith_uint256 d = UintToArith256(hash); + if(d == 0){ + return false; + } + + return true; +} + + /*popchain ghost*/ diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 997191a..66877a5 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -287,6 +287,9 @@ arith_uint256 UintToArith256(const uint256 &); /*popchain ghost*/ // This calculater the number divide by max uint256 arith_uint256 maxUint256Div(const uint256 &a); + +bool hasUncles(uint256& hash); + /*popchain ghost*/ #endif // BITCOIN_ARITH_UINT256_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 55620c3..6a58c2f 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -94,15 +94,7 @@ uint256 BlockUncleRoot(const CBlock& block) return hashUncles; } -bool hasUncles(uint256& hash) -{ - arith_uint256 d = UintToArith256(hash); - if(d == 0){ - return false; - } - return true; -} /*popchain ghost*/ diff --git a/src/primitives/block.h b/src/primitives/block.h index 59b96f3..7413366 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -200,7 +200,7 @@ struct CBlockLocator /*popchain ghost*/ uint256 BlockUncleRoot(const CBlock& block); -bool hasUncles(uint256& hash); + /*popchain ghost*/ From 052e89494fbf29592c7e9476ff084415d50f6dd2 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 7 Aug 2018 17:02:18 +0800 Subject: [PATCH 018/120] change the check --- src/arith_uint256.cpp | 1 - src/arith_uint256.h | 1 - src/primitives/block.cpp | 1 - src/primitives/block.h | 1 - 4 files changed, 4 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index e1a778a..d9c17da 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -268,7 +268,6 @@ arith_uint256 maxUint256Div(const uint256 &a) return t; } - bool hasUncles(uint256& hash) { arith_uint256 d = UintToArith256(hash); diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 66877a5..85da264 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -289,7 +289,6 @@ arith_uint256 UintToArith256(const uint256 &); arith_uint256 maxUint256Div(const uint256 &a); bool hasUncles(uint256& hash); - /*popchain ghost*/ #endif // BITCOIN_ARITH_UINT256_H diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 6a58c2f..578dac4 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -95,6 +95,5 @@ uint256 BlockUncleRoot(const CBlock& block) } - /*popchain ghost*/ diff --git a/src/primitives/block.h b/src/primitives/block.h index 7413366..3395952 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -200,7 +200,6 @@ struct CBlockLocator /*popchain ghost*/ uint256 BlockUncleRoot(const CBlock& block); - /*popchain ghost*/ From ab6776313697a0fa97bf59d38dbe78d76ec79c16 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 7 Aug 2018 17:28:19 +0800 Subject: [PATCH 019/120] change the check --- src/arith_uint256.cpp | 8 -------- src/arith_uint256.h | 2 +- src/chain.h | 10 ++++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index d9c17da..0dd9738 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -268,15 +268,7 @@ arith_uint256 maxUint256Div(const uint256 &a) return t; } -bool hasUncles(uint256& hash) -{ - arith_uint256 d = UintToArith256(hash); - if(d == 0){ - return false; - } - return true; -} /*popchain ghost*/ diff --git a/src/arith_uint256.h b/src/arith_uint256.h index 85da264..b8ece4a 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -288,7 +288,7 @@ arith_uint256 UintToArith256(const uint256 &); // This calculater the number divide by max uint256 arith_uint256 maxUint256Div(const uint256 &a); -bool hasUncles(uint256& hash); + /*popchain ghost*/ #endif // BITCOIN_ARITH_UINT256_H diff --git a/src/chain.h b/src/chain.h index 79962c0..04e419c 100644 --- a/src/chain.h +++ b/src/chain.h @@ -310,6 +310,16 @@ class CBlockIndex //! Efficiently find an ancestor of this block. CBlockIndex* GetAncestor(int height); const CBlockIndex* GetAncestor(int height) const; + /*popchain ghost*/ + bool hasUncles(uint256& hash) + { + arith_uint256 d = UintToArith256(hash); + if(d == 0){ + return false; + } + return true; + } + /*popchain ghost*/ }; /** Used to marshal pointers into hashes for db storage. */ From 2c3bff3b2e94d7b57715bec801903238ef6459a0 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 7 Aug 2018 23:14:08 +0800 Subject: [PATCH 020/120] modify difficulty params --- src/arith_uint256.cpp | 16 ++++++++-------- src/arith_uint256.h | 2 +- src/chainparams.cpp | 22 +++++++++++----------- src/miner.cpp | 1 + src/pow.cpp | 5 +++-- src/pow.h | 12 +++++++++--- src/primitives/block.cpp | 17 ++++++++++------- src/rpcblockchain.cpp | 7 ++++++- src/rpcmining.cpp | 2 ++ 9 files changed, 51 insertions(+), 33 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 0dd9738..8ed6cea 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -259,14 +259,14 @@ arith_uint256 UintToArith256(const uint256 &a) /*popchain ghost*/ // This calculater the number divide by max uint256 -arith_uint256 maxUint256Div(const uint256 &a) -{ - arith_uint256 maxUint256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - arith_uint256 d = UintToArith256(a); - assert(d == 0); - arith_uint256 t= maxUint256 / d; - return t; -} +//arith_uint256 maxUint256Div(const uint256 &a) +//{ +// arith_uint256 maxUint256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); +// arith_uint256 d = UintToArith256(a); +// assert(d == 0); +// arith_uint256 t= maxUint256 / d; +// return t; +//} diff --git a/src/arith_uint256.h b/src/arith_uint256.h index b8ece4a..e5ca9bf 100644 --- a/src/arith_uint256.h +++ b/src/arith_uint256.h @@ -286,7 +286,7 @@ arith_uint256 UintToArith256(const uint256 &); /*popchain ghost*/ // This calculater the number divide by max uint256 -arith_uint256 maxUint256Div(const uint256 &a); +//arith_uint256 maxUint256Div(const uint256 &a); /*popchain ghost*/ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 51f4c1e..6d344a7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -14,7 +14,7 @@ #include "arith_uint256.h" #include "chainparamsseeds.h" -//#define GENESIS_GENERATION +#define GENESIS_GENERATION #ifdef GENESIS_GENERATION #include @@ -90,6 +90,7 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) /*popchain ghost*/ arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); //arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); + /*popchain ghost*/ std::cout << " finding genesis using target " << hashTarget.ToString() << ", " << net << std::endl; @@ -119,8 +120,8 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) } #endif /*popchain ghost*/ -//static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const CAmount &genesisReward) -static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) +static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint256 nDifficulty, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) +//static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward) { CMutableTransaction txNew; txNew.nVersion = 1; @@ -133,8 +134,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi CBlock genesis; genesis.nTime = nTime; /*popchain ghost*/ - //genesis.nDifficulty = nDifficulty; - //genesis.nBits = maxUint256Div(nDifficulty).GetCompact(); + genesis.nDifficulty = nDifficulty; genesis.nBits = nBits; /*popchain ghost*/ genesis.nNonce = nNonce; @@ -144,7 +144,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi /*popchain ghost*/ genesis.hashUncles.SetNull(); genesis.nCoinbase.SetNull(); - genesis.nDifficulty.SetNull(); + //genesis.nDifficulty.SetNull(); genesis.nNumber = 0; genesis.vuh.clear(); genesis.hashUncles = BlockUncleRoot(genesis); @@ -168,25 +168,25 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi /*popchain ghost*/ //static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint256 nDifficulty, int32_t nVersion, const int64_t& genesisReward) -static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) +static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint256 nDifficulty, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) { const char* pszTimestamp = "pop hold value testnet."; const CScript genesisOutputScript = CScript() << ParseHex("034c73d75f59061a08032b68369e5034390abc5215b3df79be01fb4319173a88f8") << OP_CHECKSIG; //std::vector printscript(genesisOutputScript.begin(),genesisOutputScript.end); //std::cout<< StrHex(printscript)<GetHash(); if (UintToArith256(hash) <= hashTarget) { diff --git a/src/pow.cpp b/src/pow.cpp index 264f5b3..d4bd41c 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -14,12 +14,13 @@ #include #include -// daa from zcash +// popchain ghost unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { + // get genesis nBits unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - // Genesis block + // Genesis block get minimum difficulty if (pindexLast == NULL) return nProofOfWorkLimit; diff --git a/src/pow.h b/src/pow.h index c185496..95cf294 100644 --- a/src/pow.h +++ b/src/pow.h @@ -11,12 +11,18 @@ class CBlockHeader; class CBlockIndex; class uint256; class arith_uint256; + /*popchain ghost*/ +uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); +arith_uint256 getHashTraget (uint256 difficulty); +uint32_t getNBits(arith_uint256 hashTarget); + unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); /*popchain ghost*/ -unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, - int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params&); + +//unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, +// int64_t nLastBlockTime, int64_t nFirstBlockTime, +// const Consensus::Params&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ /*popchain ghost*/ diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 578dac4..dd61cd8 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -7,6 +7,7 @@ #include "utilstrencodings.h" //#include "crypto/common.h" +// popchain ghost calc blockheader hash uint256 CBlockHeader::GetHash() const { // return SerializeHash(*this); @@ -25,17 +26,18 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%s, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(), - nCoinbase.ToString(),/*need change by base58 ?*/ - nDifficulty.ToString(), + nCoinbase.ToString(),/*need change by base58 ?*/ nNumber, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), - nTime, nBits, nNonce.ToString()); + nTime, + nDifficulty.ToString(), + nBits, nNonce.ToString()); /*popchain ghost*/ return s.str(); } @@ -43,17 +45,18 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nDifficulty=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%s, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(),/*popchain ghost*/ nCoinbase.ToString(),/*popchain ghost*/ - nDifficulty.ToString(),/*popchain ghost*/ nNumber,/*popchain ghost*/ hashMerkleRoot.ToString(), hashClaimTrie.ToString(), - nTime, nBits, nNonce.ToString(), + nTime, + nDifficulty.ToString(),/*popchain ghost*/ + nBits, nNonce.ToString(), vtx.size(), vuh.size()/*popchain ghost*/); for (unsigned int i = 0; i < vtx.size(); i++) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 223fc70..f16db6d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -25,10 +25,12 @@ using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); +//popchain ghost double GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. + /* if (blockindex == NULL) { if (chainActive.Tip() == NULL) @@ -54,6 +56,8 @@ double GetDifficulty(const CBlockIndex* blockindex) } return dDiff; + */ + return double(blockindex->nDifficulty); } UniValue blockheaderToJSON(const CBlockIndex* blockindex) @@ -72,8 +76,9 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); + result.push_back(Pair("difficulty", blockindex->nDifficulty); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + //result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index c2cc428..39a95c1 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -607,6 +607,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); + // ghost + result.push_back(Pair("difficulty", pblock->nDifficulty); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); From 825bc453efd8f3421ad678a7721e5d2e76958fac Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Wed, 8 Aug 2018 00:02:51 +0800 Subject: [PATCH 021/120] modify difficulty algorithm --- src/chainparams.cpp | 26 +++++++++++++++++++----- src/consensus/params.h | 5 +++++ src/pow.cpp | 46 +++++++++++++++++++++++++++++++++++++++--- src/pow.h | 1 + 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6d344a7..b3b191b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -221,7 +221,10 @@ class CMainParams : public CChainParams { consensus.BIP34Hash = uint256S("0x0000083331b8aa57aaae020d79aabe4136ebea6ce29be3a50fcaa2a55777e79c"); /*popchain ghost*/ //consensus.powLimit = uint256S("0x000009b173000000000000000000000000000000000000000000000000000000"); - consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); + consensus.powLimit = uint256S("0x000009b173149ff8b40000000000000000000000000000000000000000000000"); + consensus.difficultyBoundDivisor = 2048; + //consensus.durationLimit = 13; + consensus.minimumDifficulty = 1730830; // minidifficulty for target /*popchain ghost*/ consensus.nPowAveragingWindow = 17; consensus.nPowMaxAdjustDown = 32; // 32% adjustment down @@ -262,7 +265,7 @@ class CMainParams : public CChainParams { /*popchain ghost*/ #ifdef GENESIS_GENERATION //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); - arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); + arith_uint256 a("0x000009b173149ff8b40000000000000000000000000000000000000000000000"); /*popchain ghost*/ std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; //std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; @@ -349,7 +352,13 @@ class CTestNetParams : public CChainParams { consensus.nMajorityWindow = 100; consensus.BIP34Height = 0; consensus.BIP34Hash = uint256S("00065185c3ffa77ff797ea3141fba9b1ab76a0f336863dec1199042ca5560fc4"); - consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); + /* popchain ghost */ + //consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); + consensus.powLimit = uint256S("0x0010000000000001000000000000000000000000000000000000000000000000"); + consensus.difficultyBoundDivisor = 2048; + //consensus.durationLimit = 13; + consensus.minimumDifficulty = 4096; + /* popchain ghost */ consensus.nPowAveragingWindow = 17; consensus.nPowMaxAdjustDown = 32; // 32% adjustment down //consensus.nPowMaxAdjustUp = 16; // 16% adjustment up @@ -384,7 +393,7 @@ class CTestNetParams : public CChainParams { genesis = CreateGenesisBlock(1529894661, uint256S("0000577da6294991bd9e1891b7f1e5fbc7e23943341e56e8e005db4358a6001e"), 0x1f0fffff, 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION - arith_uint256 a("0x000fffffff000000000000000000000000000000000000000000000000000000"); + arith_uint256 a("0x0010000000000001000000000000000000000000000000000000000000000000"); /*popchain ghost*/ std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; //std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; @@ -470,7 +479,9 @@ class CRegTestParams : public CChainParams { consensus.nMajorityWindow = 1000; consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest consensus.BIP34Hash = uint256(); - consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + // ghost + //consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); + consensus.powLimit = uint256S("0f0f0f0f0f0f0f80000000000000000000000000000000000000000000000000"); consensus.nPowAveragingWindow = 17; consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up @@ -478,6 +489,11 @@ class CRegTestParams : public CChainParams { consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; + /*popchain ghost*/ + consensus.difficultyBoundDivisor = 2048; + //consensus.durationLimit = 13; + consensus.minimumDifficulty = 17; + /*popchain ghost*/ consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; diff --git a/src/consensus/params.h b/src/consensus/params.h index f4e734d..5de0c8c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -76,7 +76,12 @@ struct Params { uint32_t nMinerConfirmationWindow; BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS]; /** Proof of work parameters */ + /* popchain ghost */ uint256 powLimit; + uint32_t difficultyBoundDivisor; + //uint32_t durationLimit; + uint256 minimumDifficulty; + /* popchain ghost */ bool fPowAllowMinDifficultyBlocks; int64_t nPowAveragingWindow; bool fPowNoRetargeting; diff --git a/src/pow.cpp b/src/pow.cpp index d4bd41c..e45d018 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -14,13 +14,50 @@ #include #include -// popchain ghost +// ghost new difficulty algorithm +uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +{ + // Genesis block get minimum difficulty + if (pindexLast == NULL) + return params.minimumDifficulty; + + uint256 difficulty; + + // timestampDiff = _bi.timestamp() - _parent.timestamp() + const CBlockIndex* pindexParent = pindexLast->pprev; + if (pindexParent == NULL) + return params.minimumDifficulty; + + int64_t const timestampDiff = pindexLast->nTime - pindexParent->nTime; + int64_t const adjFactor = max((hasUncles(pindexParent.hashUncles) ? 2 : 1) - timestampDiff / 10, -99); + + difficulty = pindexParent->nDifficulty + pindexParent->nDifficulty / params.difficultyBoundDivisor * adjFactor; + difficulty = max(params.minimumDifficulty,difficulty); + return min(difficulty, std::numeric_limits::max()); +} + +arith_uint256 getHashTraget (uint256 difficulty) +{ + arith_uint256 hashTarget = std::numeric_limits::max()/UintToArith256(difficulty); + return hashTarget; +} + +uint32_t getNBits(arith_uint256 hashTarget) +{ + return hashTarget.GetCompact(); +} + +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +{ + return getNBits(getHashTraget(calculateDifficulty(pindexLast, *pblock, params))); +} + +/* unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - // get genesis nBits unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - // Genesis block get minimum difficulty + // Genesis block if (pindexLast == NULL) return nProofOfWorkLimit; @@ -76,6 +113,9 @@ unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, return bnNew.GetCompact(); } +*/ + + /*popchain ghost*/ //bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) diff --git a/src/pow.h b/src/pow.h index 95cf294..f82961c 100644 --- a/src/pow.h +++ b/src/pow.h @@ -24,6 +24,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // int64_t nLastBlockTime, int64_t nFirstBlockTime, // const Consensus::Params&); + /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ /*popchain ghost*/ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); From add9f180c5f42a1226281751555659a1d1b5f33d Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Wed, 8 Aug 2018 15:03:25 +0800 Subject: [PATCH 022/120] merge difficuly algorithm and cal genesis (#3) * repair bug * repair bug * repair bug * modify * modify * modify * modify * modify * merge for modify difficulty algorithm (#2) * repair bug * repair bug * repair bug * modify * modify * modify * modify * cal genesis block --- src/chain.h | 7 ++++--- src/chainparams.cpp | 44 +++++++++++++++++++++---------------------- src/pow.cpp | 15 +++++++-------- src/rpcblockchain.cpp | 4 ++-- src/rpcmining.cpp | 2 +- 5 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/chain.h b/src/chain.h index 04e419c..fad7010 100644 --- a/src/chain.h +++ b/src/chain.h @@ -310,10 +310,11 @@ class CBlockIndex //! Efficiently find an ancestor of this block. CBlockIndex* GetAncestor(int height); const CBlockIndex* GetAncestor(int height) const; + /*popchain ghost*/ - bool hasUncles(uint256& hash) + bool hasUncles() const { - arith_uint256 d = UintToArith256(hash); + arith_uint256 d = UintToArith256(hashUncles); if(d == 0){ return false; } @@ -363,7 +364,7 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(hashPrev); /*popchain ghost*/ READWRITE(hashUncles); - READWRITE(nCoinbase); + READWRITE(nCoinbase); READWRITE(nDifficulty); READWRITE(nNumber); /*popchain ghost*/ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b3b191b..2772821 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -3,6 +3,7 @@ #include "base58.h" #include "chainparams.h" #include "consensus/merkle.h" +#include "pow.h" #include "tinyformat.h" #include "util.h" @@ -88,8 +89,9 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) static void findGenesis(CBlockHeader *pb, const std::string &net) { /*popchain ghost*/ - arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); + //arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); //arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); + arith_uint256 hashTarget = getHashTraget(pb->nDifficulty); /*popchain ghost*/ std::cout << " finding genesis using target " << hashTarget.ToString() @@ -224,7 +226,7 @@ class CMainParams : public CChainParams { consensus.powLimit = uint256S("0x000009b173149ff8b40000000000000000000000000000000000000000000000"); consensus.difficultyBoundDivisor = 2048; //consensus.durationLimit = 13; - consensus.minimumDifficulty = 1730830; // minidifficulty for target + consensus.minimumDifficulty = uint256S("1730830"); // minidifficulty for target /*popchain ghost*/ consensus.nPowAveragingWindow = 17; consensus.nPowMaxAdjustDown = 32; // 32% adjustment down @@ -260,8 +262,7 @@ class CMainParams : public CChainParams { /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); - //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), consensus.powLimit, 1, consensus.genesisReward); - genesis = CreateGenesisBlock1(1529900309, uint256S("00002ff377441449fc998797055b4a553d9f855c587431e3aa2bd5892ea400ea"), 0x1f0fffff, 1, consensus.genesisReward); + genesis = CreateGenesisBlock1(1529900309, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, consensus.genesisReward); /*popchain ghost*/ #ifdef GENESIS_GENERATION //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); @@ -270,12 +271,12 @@ class CMainParams : public CChainParams { std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; //std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; /*popchain ghost*/ - //findGenesis(&genesis, "main"); + findGenesis(&genesis, "main"); #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); - assert(consensus.hashGenesisBlock == uint256S("0x0008c4249ce438419b225a0a0332f107ada1fa9eb18b4572fde08de4ecc3fcbf")); - assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); + assert(consensus.hashGenesisBlock == uint256S("0x01")); + assert(genesis.hashMerkleRoot == uint256S("0x01")); // Pop addresses start with 'P' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,56); @@ -307,9 +308,9 @@ class CMainParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x0008c4249ce438419b225a0a0332f107ada1fa9eb18b4572fde08de4ecc3fcbf")), + ( 0, uint256S("0x01")), //( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), - 1529900309, // * UNIX timestamp of last checkpoint block + 0, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint @@ -357,7 +358,7 @@ class CTestNetParams : public CChainParams { consensus.powLimit = uint256S("0x0010000000000001000000000000000000000000000000000000000000000000"); consensus.difficultyBoundDivisor = 2048; //consensus.durationLimit = 13; - consensus.minimumDifficulty = 4096; + consensus.minimumDifficulty = uint256S("4096"); /* popchain ghost */ consensus.nPowAveragingWindow = 17; consensus.nPowMaxAdjustDown = 32; // 32% adjustment down @@ -389,8 +390,7 @@ class CTestNetParams : public CChainParams { /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); - //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), consensus.powLimit, 1, 1 * COIN); - genesis = CreateGenesisBlock(1529894661, uint256S("0000577da6294991bd9e1891b7f1e5fbc7e23943341e56e8e005db4358a6001e"), 0x1f0fffff, 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION arith_uint256 a("0x0010000000000001000000000000000000000000000000000000000000000000"); @@ -398,12 +398,12 @@ class CTestNetParams : public CChainParams { std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; //std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; /*popchain ghost*/ - //findGenesis(&genesis, "testnet"); + findGenesis(&genesis, "testnet"); #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); - assert(consensus.hashGenesisBlock == uint256S("000b826ae49848958a81d388d4007a59d7836697a8d2c52a21244245b23ca9c3")); - assert(genesis.hashMerkleRoot == uint256S("6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); + assert(consensus.hashGenesisBlock == uint256S("0x01")); + assert(genesis.hashMerkleRoot == uint256S("0x01")); vFixedSeeds.clear(); vSeeds.clear(); @@ -436,9 +436,9 @@ class CTestNetParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("000b826ae49848958a81d388d4007a59d7836697a8d2c52a21244245b23ca9c3")), + (0, uint256S("0x01")), //(0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), - 1529894661, // * UNIX timestamp of last checkpoint block + 0, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) 0 // * estimated number of transactions per day after checkpoint @@ -492,7 +492,7 @@ class CRegTestParams : public CChainParams { /*popchain ghost*/ consensus.difficultyBoundDivisor = 2048; //consensus.durationLimit = 13; - consensus.minimumDifficulty = 17; + consensus.minimumDifficulty = uint256S("17"); /*popchain ghost*/ consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) @@ -512,12 +512,10 @@ class CRegTestParams : public CChainParams { nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - //genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), 0x200f0f0f, 1, 1 * COIN); - //genesis = CreateGenesisBlock1(1529894661, uint256S("0x000088c293aca9524f1c4e4de0dfcc3bf4aa6d9ec2e4338d59368242d8950000"), consensus.powLimit, 1, 1 * COIN); - genesis = CreateGenesisBlock1(1529894661, uint256S("0x0000e1f169e639906e0e50622879c4fcf429d559b154002d32d3c250d2500001"), 0x200f0f0f, 1, 1 * COIN); + genesis = CreateGenesisBlock1(1529894661, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION - //findGenesis(&genesis, "regtest"); + findGenesis(&genesis, "regtest"); #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); @@ -537,7 +535,7 @@ class CRegTestParams : public CChainParams { checkpointData = (CCheckpointData){ boost::assign::map_list_of - (0, uint256S("017b05f2adc6491e3fa200b72069b44daa6e83af1b5824a921427dcae8c08050")), + (0, uint256S("0x01")), //(0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), 0, 0, diff --git a/src/pow.cpp b/src/pow.cpp index e45d018..43da376 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -10,7 +10,6 @@ #include "util.h" #include - #include #include @@ -28,17 +27,17 @@ uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *p if (pindexParent == NULL) return params.minimumDifficulty; - int64_t const timestampDiff = pindexLast->nTime - pindexParent->nTime; - int64_t const adjFactor = max((hasUncles(pindexParent.hashUncles) ? 2 : 1) - timestampDiff / 10, -99); + int32_t const timestampDiff = pindexLast->nTime - pindexParent->nTime; + int64_t const adjFactor = std::max((pindexParent->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); - difficulty = pindexParent->nDifficulty + pindexParent->nDifficulty / params.difficultyBoundDivisor * adjFactor; - difficulty = max(params.minimumDifficulty,difficulty); - return min(difficulty, std::numeric_limits::max()); + difficulty = ArithToUint256(UintToArith256(pindexParent->nDifficulty) + UintToArith256(pindexParent->nDifficulty) / params.difficultyBoundDivisor * adjFactor); + difficulty = std::max(params.minimumDifficulty,difficulty); + return std::min(difficulty, std::numeric_limits::max()); } arith_uint256 getHashTraget (uint256 difficulty) { - arith_uint256 hashTarget = std::numeric_limits::max()/UintToArith256(difficulty); + arith_uint256 hashTarget = UintToArith256(std::numeric_limits::max())/UintToArith256(difficulty); return hashTarget; } @@ -49,7 +48,7 @@ uint32_t getNBits(arith_uint256 hashTarget) unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - return getNBits(getHashTraget(calculateDifficulty(pindexLast, *pblock, params))); + return getNBits(getHashTraget(calculateDifficulty(pindexLast, pblock, params))); } /* diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f16db6d..f546d66 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -57,7 +57,7 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; */ - return double(blockindex->nDifficulty); + return stod(blockindex->nDifficulty.ToString()); } UniValue blockheaderToJSON(const CBlockIndex* blockindex) @@ -76,7 +76,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); - result.push_back(Pair("difficulty", blockindex->nDifficulty); + result.push_back(Pair("difficulty", blockindex->nDifficulty.ToString())); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); //result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 39a95c1..cd1bb59 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -608,7 +608,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); // ghost - result.push_back(Pair("difficulty", pblock->nDifficulty); + result.push_back(Pair("difficulty", pblock->nDifficulty.ToString())); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); From f0a9a83b374036cc48b3ff9d7aa3caed5e8e4776 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Fri, 10 Aug 2018 17:04:44 +0800 Subject: [PATCH 023/120] add difficulty to adjust the block speed (#4) --- src/arith_uint256.cpp | 17 +++--- src/arith_uint256.h | 2 +- src/chainparams.cpp | 103 +++++++++++++++++------------------ src/consensus/params.h | 14 ++--- src/main.cpp | 3 + src/miner.cpp | 11 +++- src/pow.cpp | 28 +++++++--- src/rpcblockchain.cpp | 17 ++++-- src/rpcmining.cpp | 8 +-- src/rpcmisc.cpp | 2 +- src/rpcserver.h | 2 +- src/test/claimtrie_tests.cpp | 4 +- src/uint256.h | 2 + 13 files changed, 121 insertions(+), 92 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 8ed6cea..7ef9443 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -8,6 +8,7 @@ #include #include +#include template base_uint::base_uint(const std::string& str) @@ -259,14 +260,14 @@ arith_uint256 UintToArith256(const uint256 &a) /*popchain ghost*/ // This calculater the number divide by max uint256 -//arith_uint256 maxUint256Div(const uint256 &a) -//{ -// arith_uint256 maxUint256("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); -// arith_uint256 d = UintToArith256(a); -// assert(d == 0); -// arith_uint256 t= maxUint256 / d; -// return t; -//} +arith_uint256 maxUint256Div(const uint256 &a) +{ + arith_uint256 d = UintToArith256(a); + std::cout<<"difficulty: "< @@ -90,8 +90,7 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) { /*popchain ghost*/ //arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); - //arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); - arith_uint256 hashTarget = getHashTraget(pb->nDifficulty); + arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); /*popchain ghost*/ std::cout << " finding genesis using target " << hashTarget.ToString() @@ -223,15 +222,15 @@ class CMainParams : public CChainParams { consensus.BIP34Hash = uint256S("0x0000083331b8aa57aaae020d79aabe4136ebea6ce29be3a50fcaa2a55777e79c"); /*popchain ghost*/ //consensus.powLimit = uint256S("0x000009b173000000000000000000000000000000000000000000000000000000"); - consensus.powLimit = uint256S("0x000009b173149ff8b40000000000000000000000000000000000000000000000"); - consensus.difficultyBoundDivisor = 2048; + consensus.powLimit = uint256S("0x000009b173149ff8b3a49a388d7ebdd0e1eb76d294f9e5f648f254d81ad0938a"); + consensus.difficultyBoundDivisor = uint256S("0x800"); //consensus.durationLimit = 13; - consensus.minimumDifficulty = uint256S("1730830"); // minidifficulty for target + consensus.minimumDifficulty = uint256S("0x1a690e"); // minidifficulty for target /*popchain ghost*/ consensus.nPowAveragingWindow = 17; - consensus.nPowMaxAdjustDown = 32; // 32% adjustment down - consensus.nPowMaxAdjustUp = 48; // 48% adjustment up - consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day + //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down + //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up + //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; @@ -261,12 +260,11 @@ class CMainParams : public CChainParams { nPruneAfterHeight = 100000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - //genesis = CreateGenesisBlock1(1529900309, uint256S("00000e2ab47d1cbc2447109cf47e5a20153f9e6038f375cc956a1574c245d5df"), nTempBit.GetCompact(), 1, consensus.genesisReward); - genesis = CreateGenesisBlock1(1529900309, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, consensus.genesisReward); + genesis = CreateGenesisBlock1(1533741060, uint256S("0x000060125fa20d8bde277afa2e6b1f2d0e2bae1fb0fbfdc0a7e6e4df2cfd7e93"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, consensus.genesisReward); /*popchain ghost*/ #ifdef GENESIS_GENERATION //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); - arith_uint256 a("0x000009b173149ff8b40000000000000000000000000000000000000000000000"); + arith_uint256 a("0x000009b173149ff8b3a49a388d7ebdd0e1eb76d294f9e5f648f254d81ad0938aL"); /*popchain ghost*/ std::cout << "\tpow:\t" << a.GetCompact() << " "<< nTempBit.GetCompact() << std::endl; //std::cout << "\tpow:\t" << a.GetCompact() << " "<< ArithToUint256(a) << std::endl; @@ -275,8 +273,8 @@ class CMainParams : public CChainParams { #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); - assert(consensus.hashGenesisBlock == uint256S("0x01")); - assert(genesis.hashMerkleRoot == uint256S("0x01")); + assert(consensus.hashGenesisBlock == uint256S("0x000002c0aedad63473cac50ccb89bab94e325b11cc996947f7879cecb2676982")); + assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); // Pop addresses start with 'P' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,56); @@ -308,12 +306,11 @@ class CMainParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - ( 0, uint256S("0x01")), - //( 0, uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")), - 0, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint + (0, uint256S("0x000002c0aedad63473cac50ccb89bab94e325b11cc996947f7879cecb2676982")), + 0, // * UNIX timestamp of last checkpoint block + 0, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 0 // * estimated number of transactions per day after checkpoint }; // Founders reward script expects a vector of 2-of-3 multisig addresses @@ -355,19 +352,21 @@ class CTestNetParams : public CChainParams { consensus.BIP34Hash = uint256S("00065185c3ffa77ff797ea3141fba9b1ab76a0f336863dec1199042ca5560fc4"); /* popchain ghost */ //consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); - consensus.powLimit = uint256S("0x0010000000000001000000000000000000000000000000000000000000000000"); - consensus.difficultyBoundDivisor = 2048; + consensus.powLimit = uint256S("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + consensus.difficultyBoundDivisor = uint256S("0x800"); //consensus.durationLimit = 13; - consensus.minimumDifficulty = uint256S("4096"); + consensus.minimumDifficulty = uint256S("0x1000"); + /* popchain ghost */ consensus.nPowAveragingWindow = 17; - consensus.nPowMaxAdjustDown = 32; // 32% adjustment down + //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down //consensus.nPowMaxAdjustUp = 16; // 16% adjustment up - consensus.nPowMaxAdjustUp = 48; // 48% adjustment up - consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day - consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up + //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day + //consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + consensus.nPowTargetSpacing = 15; consensus.fPowAllowMinDifficultyBlocks = true; - consensus.fPowNoRetargeting = false; + //consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28; @@ -390,10 +389,11 @@ class CTestNetParams : public CChainParams { /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); - genesis = CreateGenesisBlock(1529894661, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0x00003dc6b0dfef31bdaff67e5cb66b60ea6b8b4e8e9dd2dd30dca8d2fb890081"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + /*popchain ghost*/ #ifdef GENESIS_GENERATION - arith_uint256 a("0x0010000000000001000000000000000000000000000000000000000000000000"); + arith_uint256 a("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); /*popchain ghost*/ std::cout << "pow limit : " << a.GetCompact()<< " "<< nTempBit.GetCompact() << std::endl; //std::cout << "pow limit : " << a.GetCompact()<< " "<< ArithToUint256(a) << std::endl; @@ -402,8 +402,8 @@ class CTestNetParams : public CChainParams { #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); - assert(consensus.hashGenesisBlock == uint256S("0x01")); - assert(genesis.hashMerkleRoot == uint256S("0x01")); + assert(consensus.hashGenesisBlock == uint256S("0x000304cef61d8345673c4455da35bcd46cdc0742ddad2f916bbc739ec7d53a3c")); + assert(genesis.hashMerkleRoot == uint256S("0x6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); vFixedSeeds.clear(); vSeeds.clear(); @@ -436,12 +436,11 @@ class CTestNetParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("0x01")), - //(0, uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")), - 0, // * UNIX timestamp of last checkpoint block - 0, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 0 // * estimated number of transactions per day after checkpoint + (0, uint256S("0x000304cef61d8345673c4455da35bcd46cdc0742ddad2f916bbc739ec7d53a3c")), + 0, // * UNIX timestamp of last checkpoint block + 0, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 0 // * estimated number of transactions per day after checkpoint }; // Founders reward script expects a vector of 2-of-3 multisig addresses @@ -480,19 +479,18 @@ class CRegTestParams : public CChainParams { consensus.BIP34Height = -1; // BIP34 has not necessarily activated on regtest consensus.BIP34Hash = uint256(); // ghost - //consensus.powLimit = uint256S("0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); - consensus.powLimit = uint256S("0f0f0f0f0f0f0f80000000000000000000000000000000000000000000000000"); + consensus.powLimit = uint256S("0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); consensus.nPowAveragingWindow = 17; - consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down - consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up - consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day + //consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down + //consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up + //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; /*popchain ghost*/ - consensus.difficultyBoundDivisor = 2048; + consensus.difficultyBoundDivisor = uint256S("0x800"); //consensus.durationLimit = 13; - consensus.minimumDifficulty = uint256S("17"); + consensus.minimumDifficulty = uint256S("0x11"); /*popchain ghost*/ consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016) @@ -512,15 +510,15 @@ class CRegTestParams : public CChainParams { nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock1(1529894661, uint256S("0x01"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock1(1529894661, uint256S("0x0000d655023ab53aa769b911f448c7d3cff831e25c83d5918b78d8f0a40c0000"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION findGenesis(&genesis, "regtest"); #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); - assert(consensus.hashGenesisBlock == uint256S("017b05f2adc6491e3fa200b72069b44daa6e83af1b5824a921427dcae8c08050")); - assert(genesis.hashMerkleRoot == uint256S("69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); + assert(consensus.hashGenesisBlock == uint256S("0x08ae39c71de8f9ea8ed0dff77572b37bc7b03f4d39a2332388bc5117f0e5d2c9")); + assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. @@ -535,11 +533,10 @@ class CRegTestParams : public CChainParams { checkpointData = (CCheckpointData){ boost::assign::map_list_of - (0, uint256S("0x01")), - //(0, uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")), - 0, - 0, - 0 + (0, uint256S("0x08ae39c71de8f9ea8ed0dff77572b37bc7b03f4d39a2332388bc5117f0e5d2c9")), + 0, + 0, + 0 }; // Regtest Pop addresses start with 'y' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,140); diff --git a/src/consensus/params.h b/src/consensus/params.h index 5de0c8c..c38663a 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -78,7 +78,7 @@ struct Params { /** Proof of work parameters */ /* popchain ghost */ uint256 powLimit; - uint32_t difficultyBoundDivisor; + uint256 difficultyBoundDivisor; //uint32_t durationLimit; uint256 minimumDifficulty; /* popchain ghost */ @@ -86,12 +86,12 @@ struct Params { int64_t nPowAveragingWindow; bool fPowNoRetargeting; int64_t nPowTargetSpacing; - int64_t nPowTargetTimespan; - int64_t nPowMaxAdjustDown; - int64_t nPowMaxAdjustUp; - int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } - int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } - int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } + //int64_t nPowTargetTimespan; + //int64_t nPowMaxAdjustDown; + //int64_t nPowMaxAdjustUp; + //int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } // 17*2.5*60 + //int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } + //int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } }; } // namespace Consensus diff --git a/src/main.cpp b/src/main.cpp index 2f8a06c..72cf11c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4023,8 +4023,11 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta // Check proof of work if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + { + std::cout<<"just for test"<GetMedianTimePast()) diff --git a/src/miner.cpp b/src/miner.cpp index d563142..c643c99 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -70,7 +70,11 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam // Updating time can change work required on testnet: if (consensusParams.fPowAllowMinDifficultyBlocks) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); + { + std::cout<<"update time: nOldTime"<nDifficulty = calculateDifficulty(pindexPrev, pblock, consensusParams); + pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); + } return nNewTime - nOldTime; } @@ -450,7 +454,10 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->nNumber = pindexPrev->nNumber + 1; /*popchain ghost*/ UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); + std::cout<<"create new block : nBits "<nBits<nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); + pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); + pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); diff --git a/src/pow.cpp b/src/pow.cpp index 43da376..ef10601 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -20,24 +20,32 @@ uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *p if (pindexLast == NULL) return params.minimumDifficulty; - uint256 difficulty; - // timestampDiff = _bi.timestamp() - _parent.timestamp() const CBlockIndex* pindexParent = pindexLast->pprev; if (pindexParent == NULL) return params.minimumDifficulty; + + if (UintToArith256(pindexParent->GetBlockHash()) == UintToArith256(params.hashGenesisBlock)) + return params.minimumDifficulty; + + uint256 difficulty; + std::cout<<"pindexLast ndifficulty: "<nDifficulty.ToString()<nTime - pindexParent->nTime; int64_t const adjFactor = std::max((pindexParent->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); - - difficulty = ArithToUint256(UintToArith256(pindexParent->nDifficulty) + UintToArith256(pindexParent->nDifficulty) / params.difficultyBoundDivisor * adjFactor); - difficulty = std::max(params.minimumDifficulty,difficulty); - return std::min(difficulty, std::numeric_limits::max()); + difficulty = ArithToUint256(UintToArith256(pindexParent->nDifficulty) + UintToArith256(pindexParent->nDifficulty) / UintToArith256(params.difficultyBoundDivisor) * arith_uint256(adjFactor)); + std::cout<<"test calculateDifficulty: timestampDiff: "< UintToArith256(difficulty)) + difficulty = params.minimumDifficulty; + + if (UintToArith256(difficulty) > UintToArith256(maxUint256)) + return maxUint256; + return difficulty; } arith_uint256 getHashTraget (uint256 difficulty) { - arith_uint256 hashTarget = UintToArith256(std::numeric_limits::max())/UintToArith256(difficulty); + arith_uint256 hashTarget = UintToArith256(maxUint256)/UintToArith256(difficulty); return hashTarget; } @@ -48,9 +56,11 @@ uint32_t getNBits(arith_uint256 hashTarget) unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - return getNBits(getHashTraget(calculateDifficulty(pindexLast, pblock, params))); + uint32_t nBits = getNBits(getHashTraget(calculateDifficulty(pindexLast, pblock, params))); + return nBits; } + /* unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { @@ -63,7 +73,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // Find the first block in the averaging interval const CBlockIndex* pindexFirst = pindexLast; arith_uint256 bnTot {0}; - for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) { + for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) { // 17 arith_uint256 bnTmp; bnTmp.SetCompact(pindexFirst->nBits); bnTot += bnTmp; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f546d66..6a8c436 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -26,7 +26,7 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); //popchain ghost -double GetDifficulty(const CBlockIndex* blockindex) +std::string GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. @@ -57,7 +57,15 @@ double GetDifficulty(const CBlockIndex* blockindex) return dDiff; */ - return stod(blockindex->nDifficulty.ToString()); + + if (blockindex == NULL) + { + if (chainActive.Tip() == NULL) + return std::string("unknown difficulty."); + else + blockindex = chainActive.Tip(); + } + return blockindex->nDifficulty.ToString(); } UniValue blockheaderToJSON(const CBlockIndex* blockindex) @@ -76,9 +84,8 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("time", (int64_t)blockindex->nTime)); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); - result.push_back(Pair("difficulty", blockindex->nDifficulty.ToString())); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); - //result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) @@ -796,7 +803,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("difficulty", GetDifficulty())); obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index cd1bb59..6986496 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -49,9 +49,9 @@ UniValue GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - { - lookup = Params().GetConsensus().nPowAveragingWindow; - } + { + lookup = Params().GetConsensus().nPowAveragingWindow; + } // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) lookup = pb->nHeight; @@ -264,7 +264,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("difficulty", GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 4c664e7..4bf92f3 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -96,7 +96,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("difficulty", GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); #ifdef ENABLE_WALLET if (pwalletMain) { diff --git a/src/rpcserver.h b/src/rpcserver.h index a0ea5d6..822aed6 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -166,7 +166,7 @@ extern std::vector ParseHexO(const UniValue& o, std::string strKe extern int64_t nWalletUnlockTime; extern CAmount AmountFromValue(const UniValue& value); extern UniValue ValueFromAmount(const CAmount& amount); -extern double GetDifficulty(const CBlockIndex* blockindex = NULL); +extern std::string GetDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 20c8034..7635c88 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -107,7 +107,9 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, chainparams.GetConsensus()); pblock->vtx[0] = CTransaction(txCoinbase); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); + //pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); + pblock->nDifficulty = calculateDifficulty(chainActive.Tip(),pblock,chainparams.GetConsensus()); + pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); for (arith_uint256 i = 0; ; ++i) { pblock->nNonce = ArithToUint256(i); diff --git a/src/uint256.h b/src/uint256.h index 901e2fb..a43da7c 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -150,6 +150,8 @@ inline uint256 uint256S(const std::string& str) return rv; } +static const uint256 maxUint256 = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + /** 512-bit unsigned big integer. */ class uint512 : public base_blob<512> { public: From 0361edb97f652db06243651edb17f9db5a3ba055 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Sat, 11 Aug 2018 08:57:59 +0800 Subject: [PATCH 024/120] change the difficulty data type (#5) --- src/arith_uint256.cpp | 9 ++++----- src/arith_uint256.h | 2 +- src/chain.h | 8 ++++---- src/chainparams.cpp | 43 ++++++++++++++++++++-------------------- src/consensus/params.h | 4 ++-- src/cryptopop/PoW.c | 4 ++-- src/cryptopop/common.h | 4 ++-- src/hash.h | 6 +++--- src/pow.cpp | 22 ++++++++++---------- src/pow.h | 4 ++-- src/primitives/block.cpp | 8 ++++---- src/primitives/block.h | 4 ++-- src/rpcblockchain.cpp | 6 +++--- src/rpcmining.cpp | 2 +- src/rpcserver.h | 2 +- 15 files changed, 63 insertions(+), 65 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 7ef9443..5deb05b 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -260,12 +260,11 @@ arith_uint256 UintToArith256(const uint256 &a) /*popchain ghost*/ // This calculater the number divide by max uint256 -arith_uint256 maxUint256Div(const uint256 &a) +arith_uint256 maxUint256Div(uint64_t &a) { - arith_uint256 d = UintToArith256(a); - std::cout<<"difficulty: "< // ghost new difficulty algorithm -uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +uint64_t calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { // Genesis block get minimum difficulty if (pindexLast == NULL) @@ -28,24 +28,24 @@ uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *p if (UintToArith256(pindexParent->GetBlockHash()) == UintToArith256(params.hashGenesisBlock)) return params.minimumDifficulty; - uint256 difficulty; - std::cout<<"pindexLast ndifficulty: "<nDifficulty.ToString()<nDifficulty<nTime - pindexParent->nTime; int64_t const adjFactor = std::max((pindexParent->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); - difficulty = ArithToUint256(UintToArith256(pindexParent->nDifficulty) + UintToArith256(pindexParent->nDifficulty) / UintToArith256(params.difficultyBoundDivisor) * arith_uint256(adjFactor)); - std::cout<<"test calculateDifficulty: timestampDiff: "< UintToArith256(difficulty)) - difficulty = params.minimumDifficulty; - if (UintToArith256(difficulty) > UintToArith256(maxUint256)) - return maxUint256; + difficulty = pindexParent->nDifficulty + pindexParent->nDifficulty / params.difficultyBoundDivisor * adjFactor; + std::cout<<"test calculateDifficulty: timestampDiff: "< 0); + if (params.minimumDifficulty > difficulty) + difficulty = params.minimumDifficulty; + assert (difficulty < std::numeric_limits::max()); return difficulty; } -arith_uint256 getHashTraget (uint256 difficulty) +arith_uint256 getHashTraget (uint64_t difficulty) { - arith_uint256 hashTarget = UintToArith256(maxUint256)/UintToArith256(difficulty); + arith_uint256 hashTarget = UintToArith256(maxUint256)/arith_uint256(difficulty); return hashTarget; } diff --git a/src/pow.h b/src/pow.h index f82961c..b7fa8e7 100644 --- a/src/pow.h +++ b/src/pow.h @@ -13,8 +13,8 @@ class uint256; class arith_uint256; /*popchain ghost*/ -uint256 calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); -arith_uint256 getHashTraget (uint256 difficulty); +uint64_t calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); +arith_uint256 getHashTraget (uint64_t difficulty); uint32_t getNBits(arith_uint256 hashTarget); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index dd61cd8..241f6f4 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -26,7 +26,7 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%s, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), @@ -36,7 +36,7 @@ std::string CBlockHeader::ToString() const hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, - nDifficulty.ToString(), + nDifficulty, nBits, nNonce.ToString()); /*popchain ghost*/ return s.str(); @@ -45,7 +45,7 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%s, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), @@ -55,7 +55,7 @@ std::string CBlock::ToString() const hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, - nDifficulty.ToString(),/*popchain ghost*/ + nDifficulty,/*popchain ghost*/ nBits, nNonce.ToString(), vtx.size(), vuh.size()/*popchain ghost*/); diff --git a/src/primitives/block.h b/src/primitives/block.h index 3395952..1023738 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -24,7 +24,7 @@ class CBlockHeader /*popchain ghost*/ uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 nCoinbase;//the autor address of this block header - uint256 nDifficulty;//the difficulty of this block + uint64_t nDifficulty;//the difficulty of this block uint32_t nNumber;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; @@ -65,7 +65,7 @@ class CBlockHeader /*popchain ghost*/ hashUncles.SetNull(); nCoinbase.SetNull(); - nDifficulty.SetNull(); + nDifficulty = 0; nNumber=0; /*popchain ghost*/ hashMerkleRoot.SetNull(); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 6a8c436..b8b7fa0 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -26,7 +26,7 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); //popchain ghost -std::string GetDifficulty(const CBlockIndex* blockindex) +uint64_t GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. @@ -61,11 +61,11 @@ std::string GetDifficulty(const CBlockIndex* blockindex) if (blockindex == NULL) { if (chainActive.Tip() == NULL) - return std::string("unknown difficulty."); + return 19910728; else blockindex = chainActive.Tip(); } - return blockindex->nDifficulty.ToString(); + return blockindex->nDifficulty; } UniValue blockheaderToJSON(const CBlockIndex* blockindex) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6986496..f1178fb 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -608,7 +608,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); // ghost - result.push_back(Pair("difficulty", pblock->nDifficulty.ToString())); + result.push_back(Pair("difficulty", pblock->nDifficulty)); result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); diff --git a/src/rpcserver.h b/src/rpcserver.h index 822aed6..3bd9c83 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -166,7 +166,7 @@ extern std::vector ParseHexO(const UniValue& o, std::string strKe extern int64_t nWalletUnlockTime; extern CAmount AmountFromValue(const UniValue& value); extern UniValue ValueFromAmount(const CAmount& amount); -extern std::string GetDifficulty(const CBlockIndex* blockindex = NULL); +extern uint64_t GetDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); From 1c21e8bce56a3b7515265268f43085f7a7d561f8 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 11 Aug 2018 11:50:45 +0800 Subject: [PATCH 025/120] add the futureblock paramater --- src/main.cpp | 23 +++++++++++++++++++++++ src/main.h | 11 +++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 72cf11c..ddd8df9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,6 +63,11 @@ using namespace std; CCriticalSection cs_main; BlockMap mapBlockIndex; + +/*popchain ghost*/ +FutureBlockMap mapFutureBlock; +/*popchain ghost*/ + CChain chainActive; CBlockIndex *pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; @@ -3726,6 +3731,24 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) return pindexNew; } +/*popchain ghost*/ +CBlock* AddToFutureBlock(const CBlock& block) +{ + uint256 hash = block.GetHash(); + BlockMap::iterator it = mapFutureBlock.find(hash); + if (it != mapFutureBlock.end()) + return it->second; + // Construct new block index object + CBlock* pBlockNew = new CBlock(); + *pBlockNew = block; + assert(pBlockNew); + mapFutureBlock.insert(make_pair(hash, pBlockNew)); + return pBlockNew; +} + +/*popchain ghost*/ + + /** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos) { diff --git a/src/main.h b/src/main.h index b961a13..48bc48f 100644 --- a/src/main.h +++ b/src/main.h @@ -135,6 +135,17 @@ extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern CTxMemPool mempool; typedef boost::unordered_map BlockMap; +/*popchain ghost*/ +//5min +static const unsigned int DEFAULT_MAXTIMEFUTUREBLOCKS = 3000; +//2.5min +static const unsigned int DEFAULT_ALLOWEDFUTUREBLOCKTIME = 1500; +//max futureblocks size limit +static const unsigned int DEFAULT_MAXFUTUREBLOCKS =256; +typedef std::map FutureBlockMap; +extern FutureBlockMap mapFutureBlock; +/*popchain ghost*/ + extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; From 26ebf71c435041eea884d49490c5bf73dcf2581b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 11 Aug 2018 11:56:49 +0800 Subject: [PATCH 026/120] add AddToFutureBlock function --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ddd8df9..7ad4125 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3735,7 +3735,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) CBlock* AddToFutureBlock(const CBlock& block) { uint256 hash = block.GetHash(); - BlockMap::iterator it = mapFutureBlock.find(hash); + FutureBlockMap::iterator it = mapFutureBlock.find(hash); if (it != mapFutureBlock.end()) return it->second; // Construct new block index object From 4574e32c679691bbd34452e38719bc061f3c8851 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 11 Aug 2018 17:28:00 +0800 Subject: [PATCH 027/120] add lru cache type define --- src/main.h | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/main.h b/src/main.h index 48bc48f..517ccb3 100644 --- a/src/main.h +++ b/src/main.h @@ -136,6 +136,116 @@ extern CCriticalSection cs_main; extern CTxMemPool mempool; typedef boost::unordered_map BlockMap; /*popchain ghost*/ +// lru cache define +template +class LRUCache { +public: + // err is return value when find fail + LRUCache(int capacity, Value err) { + err_ = err; + capacity_ = capacity; + head_.next = &tail_; + tail_.prev = &head_; + } + + Value get(Key key) { + auto it = vmap_.find(key); + if(it == vmap_.end()) { + return err_; + } else { + Cache *c = it->second; + move_cache_to_head(c); + return c->value; + } + } + + Value peek(Key key) { + auto it = vmap_.find(key); + if(it == vmap_.end()) { + return err_; + } else { + Cache *c = it->second; + return c->value; + } + } + + bool contains(Key key) { + auto it = vmap_.find(key); + if(it == vmap_.end()) { + return false; + } else { + return true; + } + } + + + void add(Key key, Value value) { + auto it = vmap_.find(key); + if(it != vmap_.end()) { + Cache *c = it->second; + c->value = value; + move_cache_to_head(c); + } else { + if(capacity_ == vmap_.size()) { + Cache *c = remove_last_cache(); + vmap_.erase(c->key); + c->key = key; + c->value = value; + cache_push(c); + vmap_[key] = c; + } else { + Cache *c = new Cache(key, value); + cache_push(c); + vmap_[key] = c; + } + } + } + +private: + struct Cache { + Cache() = default; + Cache(Key key, Value value) : key(key), value(value) {} + Key key; + Value value; + Cache *prev; + Cache *next; + }; + + void cache_push(Cache *c) { + c->next = head_.next; + head_.next = c; + c->next->prev = c; + c->prev = &head_; + } + + void cache_push(Key key, Value value) { + Cache *c = new Cache(key, value); + cache_push(c); + } + + void move_cache_to_head(Cache *c) { + c->prev->next = c->next; + c->next->prev = c->prev; + cache_push(c); + } + + Cache *remove_last_cache() { + Cache *c = tail_.prev; + tail_.prev = c->prev; + c->prev->next = &tail_; + return c; + } + +private: + Cache head_; + Cache tail_; + Value err_; + int capacity_; + std::unordered_map vmap_; +}; + + + //5min static const unsigned int DEFAULT_MAXTIMEFUTUREBLOCKS = 3000; //2.5min @@ -788,6 +898,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin /** Context-independent validity checks */ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); + bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); /** Context-dependent validity checks */ From dc05559628153d7522121e32616033280c8728fa Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 11 Aug 2018 17:33:53 +0800 Subject: [PATCH 028/120] add the lru cache struct --- src/main.h | 81 +++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/src/main.h b/src/main.h index 517ccb3..5e4fdea 100644 --- a/src/main.h +++ b/src/main.h @@ -139,6 +139,49 @@ typedef boost::unordered_map BlockMap; // lru cache define template class LRUCache { +private: + struct Cache { + Cache() = default; + Cache(Key key, Value value) : key(key), value(value) {} + Key key; + Value value; + Cache *prev; + Cache *next; + }; + + void cache_push(Cache *c) { + c->next = head_.next; + head_.next = c; + c->next->prev = c; + c->prev = &head_; + } + + void cache_push(Key key, Value value) { + Cache *c = new Cache(key, value); + cache_push(c); + } + + void move_cache_to_head(Cache *c) { + c->prev->next = c->next; + c->next->prev = c->prev; + cache_push(c); + } + + Cache *remove_last_cache() { + Cache *c = tail_.prev; + tail_.prev = c->prev; + c->prev->next = &tail_; + return c; + } + +private: + Cache head_; + Cache tail_; + Value err_; + int capacity_; + typedef boost::unordered_map vmap_; + + public: // err is return value when find fail LRUCache(int capacity, Value err) { @@ -201,47 +244,9 @@ class LRUCache { } } -private: - struct Cache { - Cache() = default; - Cache(Key key, Value value) : key(key), value(value) {} - Key key; - Value value; - Cache *prev; - Cache *next; - }; - - void cache_push(Cache *c) { - c->next = head_.next; - head_.next = c; - c->next->prev = c; - c->prev = &head_; - } - - void cache_push(Key key, Value value) { - Cache *c = new Cache(key, value); - cache_push(c); - } - void move_cache_to_head(Cache *c) { - c->prev->next = c->next; - c->next->prev = c->prev; - cache_push(c); - } - Cache *remove_last_cache() { - Cache *c = tail_.prev; - tail_.prev = c->prev; - c->prev->next = &tail_; - return c; - } -private: - Cache head_; - Cache tail_; - Value err_; - int capacity_; - std::unordered_map vmap_; }; From aa1a8fb080a74d5f77b04cf2c9ccbea7a762cfe1 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 14 Aug 2018 14:38:52 +0800 Subject: [PATCH 029/120] add the lru cache for future block --- src/main.cpp | 1 + src/main.h | 173 ++++++++++++++++++++++++++++++--------------------- src/pow.cpp | 4 +- 3 files changed, 104 insertions(+), 74 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7ad4125..3ff5a54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -65,6 +65,7 @@ CCriticalSection cs_main; BlockMap mapBlockIndex; /*popchain ghost*/ +LRUCache lruFutureBlock(DEFAULT_MAXFUTUREBLOCKS, CBlock()); FutureBlockMap mapFutureBlock; /*popchain ghost*/ diff --git a/src/main.h b/src/main.h index 5e4fdea..dabf8d9 100644 --- a/src/main.h +++ b/src/main.h @@ -135,55 +135,25 @@ extern CScript COINBASE_FLAGS; extern CCriticalSection cs_main; extern CTxMemPool mempool; typedef boost::unordered_map BlockMap; +extern BlockMap mapBlockIndex; /*popchain ghost*/ -// lru cache define -template -class LRUCache { -private: - struct Cache { - Cache() = default; - Cache(Key key, Value value) : key(key), value(value) {} - Key key; - Value value; - Cache *prev; - Cache *next; - }; - - void cache_push(Cache *c) { - c->next = head_.next; - head_.next = c; - c->next->prev = c; - c->prev = &head_; - } - void cache_push(Key key, Value value) { - Cache *c = new Cache(key, value); - cache_push(c); - } - void move_cache_to_head(Cache *c) { - c->prev->next = c->next; - c->next->prev = c->prev; - cache_push(c); - } - - Cache *remove_last_cache() { - Cache *c = tail_.prev; - tail_.prev = c->prev; - c->prev->next = &tail_; - return c; - } -private: - Cache head_; - Cache tail_; - Value err_; - int capacity_; - typedef boost::unordered_map vmap_; +//5min +static const unsigned int DEFAULT_MAXTIMEFUTUREBLOCKS = 3000; +//2.5min +static const unsigned int DEFAULT_ALLOWEDFUTUREBLOCKTIME = 1500; +//max futureblocks size limit +static const unsigned int DEFAULT_MAXFUTUREBLOCKS =256; +typedef std::map FutureBlockMap; +extern FutureBlockMap mapFutureBlock; +template +class LRUCache { public: - // err is return value when find fail + // err is return find fail LRUCache(int capacity, Value err) { err_ = err; capacity_ = capacity; @@ -202,26 +172,6 @@ class LRUCache { } } - Value peek(Key key) { - auto it = vmap_.find(key); - if(it == vmap_.end()) { - return err_; - } else { - Cache *c = it->second; - return c->value; - } - } - - bool contains(Key key) { - auto it = vmap_.find(key); - if(it == vmap_.end()) { - return false; - } else { - return true; - } - } - - void add(Key key, Value value) { auto it = vmap_.find(key); if(it != vmap_.end()) { @@ -244,24 +194,103 @@ class LRUCache { } } + void purge(){ + head_.next = &tail_; + tail_.prev = &head_; + vmap_.clear(); + } + Value peek(Key key){ + auto it = vmap_.find(key); + if(it == vmap_.end()) { + return err_; + } else { + Cache *c = it->second; + return c->value; + } + } + bool remove(Key key){ + auto it = vmap_.find(key); + if(it == vmap_.end()) { + return false; + } else { + Cache *c = it->second; + cache_remove(c); + vmap_.erase(it); + return true; + } + } -}; + bool contains(Key key){ + auto it = vmap_.find(key); + if(it == vmap_.end()){ + return false; + }else{ + return true; + } + } + void keys(std::vector &keys){ + Cache *c = tail_.prev; + for(int i = vmap_.size(); i > 0; i--){ + keys.push_back(c->key); + c = c->prev; + } + } +private: + struct Cache { + Cache() = default; + Cache(Key key, Value value) : key(key), value(value) {} + Key key; + Value value; + Cache *prev; + Cache *next; + }; + + void cache_push(Cache *c) { + c->next = head_.next; + head_.next = c; + c->next->prev = c; + c->prev = &head_; + } + + void cache_push(Key key, Value value) { + Cache *c = new Cache(key, value); + cache_push(c); + } + + + void move_cache_to_head(Cache *c) { + c->prev->next = c->next; + c->next->prev = c->prev; + cache_push(c); + } + + Cache *remove_last_cache() { + Cache *c = tail_.prev; + tail_.prev = c->prev; + c->prev->next = &tail_; + return c; + } + + void cache_remove(Cache *c){ + c->prev->next = c->next; + c->next->prev = c->prev; + } + +private: + Cache head_; + Cache tail_; + Value err_; + int capacity_; + std::map vmap_; +}; -//5min -static const unsigned int DEFAULT_MAXTIMEFUTUREBLOCKS = 3000; -//2.5min -static const unsigned int DEFAULT_ALLOWEDFUTUREBLOCKTIME = 1500; -//max futureblocks size limit -static const unsigned int DEFAULT_MAXFUTUREBLOCKS =256; -typedef std::map FutureBlockMap; -extern FutureBlockMap mapFutureBlock; /*popchain ghost*/ -extern BlockMap mapBlockIndex; + extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; diff --git a/src/pow.cpp b/src/pow.cpp index 813c959..545d3ae 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -29,13 +29,13 @@ uint64_t calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader * return params.minimumDifficulty; uint64_t difficulty; - std::cout<<"pindexLast ndifficulty: "<nDifficulty<nDifficulty<nTime - pindexParent->nTime; int64_t const adjFactor = std::max((pindexParent->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); difficulty = pindexParent->nDifficulty + pindexParent->nDifficulty / params.difficultyBoundDivisor * adjFactor; - std::cout<<"test calculateDifficulty: timestampDiff: "< 0); if (params.minimumDifficulty > difficulty) difficulty = params.minimumDifficulty; From 42bdaee2c1dc5f931a8b3f5d6194cf7e4094ea48 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Sat, 18 Aug 2018 16:40:45 +0800 Subject: [PATCH 030/120] add difficulty rapid adjust progress and modify some bugs (#6) --- src/chainparams.cpp | 9 ++++++ src/consensus/params.h | 2 ++ src/main.cpp | 73 +++++++++++++++++++++++++++--------------- src/miner.cpp | 11 ++++--- src/pow.cpp | 57 ++++++++++++++++++++------------- src/pow.h | 4 +-- src/test/pow_tests.cpp | 2 +- 7 files changed, 102 insertions(+), 56 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index bb4f453..b781506 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -171,6 +171,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint64_t nDifficulty, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) { const char* pszTimestamp = "pop hold value testnet."; + //const char* pszTimestamp = "hope u happiness in canada gg by armin."; const CScript genesisOutputScript = CScript() << ParseHex("034c73d75f59061a08032b68369e5034390abc5215b3df79be01fb4319173a88f8") << OP_CHECKSIG; //std::vector printscript(genesisOutputScript.begin(),genesisOutputScript.end); //std::cout<< StrHex(printscript)< mapOrphanTransactions GUARDED_BY(cs_main);; -map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);; +map mapOrphanTransactions GUARDED_BY(cs_main); +map > mapOrphanTransactionsByPrev GUARDED_BY(cs_main); map mapRejectedBlocks GUARDED_BY(cs_main); void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main); @@ -118,28 +118,48 @@ static void CheckBlockIndex(const Consensus::Params& consensusParams); CScript COINBASE_FLAGS; const string strMessageMagic = "Pop Signed Message:\n"; +#define P 100 // Internal stuff namespace { + float_t getRandomNumber() + { + srand(time(NULL)); + float_t num = rand() % P / (float_t)P; + //std::cout<<"num:="<nChainWork "<nChainWork.ToString()<<" pb->nChainWork "<nChainWork.ToString()<nSequenceId "<nSequenceId<<" pb->nSequenceId "<nSequenceId<nChainWork > pb->nChainWork) return false; +// if (pa->nChainWork < pb->nChainWork) return true; + +// // ... then by earliest time received, ... +// if (pa->nSequenceId < pb->nSequenceId) return false; +// if (pa->nSequenceId > pb->nSequenceId) return true; + +// // Use pointer address as tie breaker (should only happen with blocks +// // loaded from disk, as those all have id 0). +// if (pa < pb) return false; +// if (pa > pb) return true; + +// // Identical blocks. +// return false; +// } + bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { // First sort by most total work, ... - if (pa->nChainWork > pb->nChainWork) return false; - if (pa->nChainWork < pb->nChainWork) return true; - - // ... then by earliest time received, ... - if (pa->nSequenceId < pb->nSequenceId) return false; - if (pa->nSequenceId > pb->nSequenceId) return true; - - // Use pointer address as tie breaker (should only happen with blocks - // loaded from disk, as those all have id 0). - if (pa < pb) return false; - if (pa > pb) return true; - - // Identical blocks. - return false; + bool reorg; + reorg = pa->nChainWork < pb->nChainWork; + if (!reorg && pa->nChainWork == pb->nChainWork){ + reorg = pa->nHeight > pb->nHeight || (pa->nHeight == pb->nHeight && getRandomNumber()<0.5?(pa>pb):(paGetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; + return chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - consensusParams.nPowTargetSpacing * 20; // tipTimeStamp > timenow-300 20个å—内为true } // Requires cs_main @@ -1820,7 +1840,7 @@ void CheckForkWarningConditions() if (pindexBestForkTip && chainActive.Height() - pindexBestForkTip->nHeight >= 72) pindexBestForkTip = NULL; - if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockProof(*chainActive.Tip()) * 6))) + if (pindexBestForkTip || (pindexBestInvalid && pindexBestInvalid->nChainWork > chainActive.Tip()->nChainWork + (GetBlockDifficulty(*chainActive.Tip()) * 6))) { if (!fLargeWorkForkFound && pindexBestForkBase) { @@ -1878,7 +1898,7 @@ void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip) // We define it this way because it allows us to only store the highest fork tip (+ base) which meets // the 7-block condition and from this always have the most-likely-to-cause-warning fork if (pfork && (!pindexBestForkTip || (pindexBestForkTip && pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && - pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockProof(*pfork) * 7) && + pindexNewForkTip->nChainWork - pfork->nChainWork > (GetBlockDifficulty(*pfork) * 7) && chainActive.Height() - pindexNewForkTip->nHeight < 72) { pindexBestForkTip = pindexNewForkTip; @@ -3464,7 +3484,7 @@ static void PruneBlockIndexCandidates() { setBlockIndexCandidates.erase(it++); } // Either the current tip or a successor of it we're working towards is left in setBlockIndexCandidates. - assert(!setBlockIndexCandidates.empty()); + assert(!setBlockIndexCandidates.empty()); //empty return failure } /** @@ -3562,7 +3582,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, { LOCK(cs_main); CBlockIndex *pindexOldTip = chainActive.Tip(); - pindexMostWork = FindMostWorkChain(); + pindexMostWork = FindMostWorkChain(); //popchain ghost // Whether we have anything to do at all. if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()) @@ -3722,7 +3742,7 @@ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) pindexNew->nHeight = pindexNew->pprev->nHeight + 1; pindexNew->BuildSkip(); } - pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew); + pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockDifficulty(*pindexNew); pindexNew->RaiseValidity(BLOCK_VALID_TREE); if (pindexBestHeader == NULL || pindexBestHeader->nChainWork < pindexNew->nChainWork) pindexBestHeader = pindexNew; @@ -4043,15 +4063,16 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta if (block.nNumber != (pindexPrev->nNumber+ 1)) return state.DoS(100, error("%s : incorrect nNumber at %d", __func__, nHeight), REJECT_INVALID, "bad-nNumber"); - /*popchain ghost*/ - + // Check proof of work - if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + //if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) + if (block.nDifficulty != calculateDifficulty(pindexPrev, &block, consensusParams)) { std::cout<<"just for test"<GetMedianTimePast()) @@ -4551,7 +4572,7 @@ bool static LoadBlockIndexDB() BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; - pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex); + pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockDifficulty(*pindex); // We can link the chain of blocks for which we've received transactions at some point. // Pruned nodes may have deleted the block. if (pindex->nTx > 0) { diff --git a/src/miner.cpp b/src/miner.cpp index c643c99..cda3420 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -71,7 +71,10 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam // Updating time can change work required on testnet: if (consensusParams.fPowAllowMinDifficultyBlocks) { - std::cout<<"update time: nOldTime"<nBits = getNBits(getHashTraget(calculateDifficulty(pindexPrev, pblock, consensusParams))); + //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); + pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, consensusParams); pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); } @@ -452,12 +455,11 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->hashPrevBlock = pindexPrev->GetBlockHash(); /*popchain ghost*/ pblock->nNumber = pindexPrev->nNumber + 1; - /*popchain ghost*/ UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - std::cout<<"create new block : nBits "<nBits<nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); + //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); + /*popchain ghost*/ // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); @@ -596,6 +598,7 @@ void static BitcoinMiner(const CChainParams& chainparams) // Search // int64_t nStart = GetTime(); + //pblock->nDifficulty = calculateDifficulty() arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); while (true) { diff --git a/src/pow.cpp b/src/pow.cpp index 545d3ae..86ef018 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -14,28 +14,33 @@ #include // ghost new difficulty algorithm -uint64_t calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +// pindex chainactivate tip, pblock ready to assembly +uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblock, const Consensus::Params& params) { // Genesis block get minimum difficulty - if (pindexLast == NULL) + if (pindex == NULL) return params.minimumDifficulty; - // timestampDiff = _bi.timestamp() - _parent.timestamp() - const CBlockIndex* pindexParent = pindexLast->pprev; - if (pindexParent == NULL) - return params.minimumDifficulty; +// const CBlockIndex* pindexParent = pindex->pprev; +// if (pindexParent == NULL) +// return params.minimumDifficulty; - if (UintToArith256(pindexParent->GetBlockHash()) == UintToArith256(params.hashGenesisBlock)) + if (UintToArith256(pindex->GetBlockHash()) == UintToArith256(params.hashGenesisBlock)) return params.minimumDifficulty; uint64_t difficulty; - //std::cout<<"pindexLast ndifficulty: "<nDifficulty<nTime - pindex->nTime; - int32_t const timestampDiff = pindexLast->nTime - pindexParent->nTime; - int64_t const adjFactor = std::max((pindexParent->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); + if (pindex->nHeight < params.nYolandaTime){ + if (timestampDiff < 15) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; + else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; + std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 10, -99); + difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; + std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nDifficulty + pindexParent->nDifficulty / params.difficultyBoundDivisor * adjFactor; - //std::cout<<"test calculateDifficulty: timestampDiff: "< 0); if (params.minimumDifficulty > difficulty) difficulty = params.minimumDifficulty; @@ -54,9 +59,10 @@ uint32_t getNBits(arith_uint256 hashTarget) return hashTarget.GetCompact(); } -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) +// GetNextWorkRequired called getNBits +unsigned int GetNextWorkRequired(const CBlockIndex* pindex, const CBlockHeader *pblock, const Consensus::Params& params) { - uint32_t nBits = getNBits(getHashTraget(calculateDifficulty(pindexLast, pblock, params))); + uint32_t nBits = getNBits(getHashTraget(calculateDifficulty(pindex, pblock, params))); return nBits; } @@ -151,20 +157,25 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& /*popchain ghost*/ /*popchain ghost*/ -arith_uint256 GetBlockProof(const CBlockIndex& block) +arith_uint256 GetBlockDifficulty(const CBlockIndex& block) { - arith_uint256 bnTarget; - bool fNegative; - bool fOverflow; +// arith_uint256 bnTarget; +// bool fNegative; +// bool fOverflow; - bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if (fNegative || fOverflow || bnTarget == 0) - return 0; +// bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); +// if (fNegative || fOverflow || bnTarget == 0) +// return 0; // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 // as it's too large for a arith_uint256. However, as 2**256 is at least as large // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, // or ~bnTarget / (nTarget+1) + 1. - return (~bnTarget / (bnTarget + 1)) + 1; + //return (~bnTarget / (bnTarget + 1)) + 1; + + if (block.nDifficulty > 0) + return block.nDifficulty; + return 0; + /*popchain ghost*/ //bnTarget = maxUint256Div(block.nDifficulty); //return bnTarget; @@ -183,7 +194,7 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr r = from.nChainWork - to.nChainWork; sign = -1; } - r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip); + r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockDifficulty(tip); if (r.bits() > 63) { return sign * std::numeric_limits::max(); } diff --git a/src/pow.h b/src/pow.h index b7fa8e7..bef88e7 100644 --- a/src/pow.h +++ b/src/pow.h @@ -13,7 +13,7 @@ class uint256; class arith_uint256; /*popchain ghost*/ -uint64_t calculateDifficulty(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); +uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblock, const Consensus::Params& params); arith_uint256 getHashTraget (uint64_t difficulty); uint32_t getNBits(arith_uint256 hashTarget); @@ -30,7 +30,7 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); //bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params&); /*popchain ghost*/ -arith_uint256 GetBlockProof(const CBlockIndex& block); +arith_uint256 GetBlockDifficulty(const CBlockIndex& block); /** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 1d2413f..84806cf 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) blocks[i].nHeight = i; blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ - blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0); + blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockDifficulty(blocks[i - 1]) : arith_uint256(0); } for (int j = 0; j < 1000; j++) { From 9eb364f16c5d25e13c93c206de97afb61ff950e2 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 18 Aug 2018 17:59:48 +0800 Subject: [PATCH 031/120] the process of possible uncles --- src/main.cpp | 215 +++++++++++++++++++++++++++++++++++++++++++++++++- src/main.h | 22 ++++++ src/miner.cpp | 18 ++++- 3 files changed, 252 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 50e67a1..546eb70 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -65,6 +65,11 @@ CCriticalSection cs_main; BlockMap mapBlockIndex; /*popchain ghost*/ +BlockMapGho mapPossibleUncles; +BlockSetGho setCurrentAncestor; +BlockSetGho setCurrentUncle; +BlockSetGho setCurrentFamily; +uint256 currentParenthash = uint256(); LRUCache lruFutureBlock(DEFAULT_MAXFUTUREBLOCKS, CBlock()); FutureBlockMap mapFutureBlock; /*popchain ghost*/ @@ -2582,6 +2587,158 @@ bool GetBlockHash(uint256& hashRet, int nBlockHeight) return true; } +/*popchain ghost*/ +bool GetBlockNumber(uint256 hash, uint32_t* number) +{ + LOCK(cs_main); + if (hash != uint256()) { + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end() && (*mi).second) { + CBlockIndex* pindex = (*mi).second; + *number = pindex->nNumber; + return true; + } + } + return false; +} +bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi) +{ + LOCK(cs_main); + LogPrintf("GetAncestorBlocksFromHash \n"); + //uint32_t number=0; + if(hash == uint256()) + return false; + BlockMap::iterator mi = mapBlockIndex.find(hash); + if(mi != mapBlockIndex.end() && (*mi).second){ + CBlockIndex* pblockindex =(*mi).second; + for(int i = 0; i < n; i++){ + if(pblockindex != NULL){ + vCbi.push_back(pblockindex); + pblockindex = pblockindex->pprev; + } + } + return true; + } + return false; +} + +bool MakeCurrentCycle(uint256 hash) +{ + LOCK(cs_main); + LogPrintf("MakeCurrentCycle \n"); + if(hash == uint256()) + return false; + if(currentParenthash == hash) + return true; + const CChainParams& chainparams = Params(); + std::vector ancestor; + if(!GetAncestorBlocksFromHash(hash,7,ancestor)){ + return false; + } + CBlock block; + CBlockIndex* pBlockIndex; + CBlockHeader blockheader; + for(std::vector::iterator it = ancestor.begin(); it != ancestor.end(); ++it){ + pBlockIndex = *it; + ReadBlockFromDisk(block, pBlockIndex, chainparams.GetConsensus()); + for(std::vector::iterator bi = block.vuh.begin(); bi != block.vuh.end(); ++bi){ + blockheader = *bi; + setCurrentFamily.insert(blockheader.GetHash()); + } + setCurrentFamily.insert(block.GetHash()); + setCurrentAncestor.insert(block.GetHash()); + } + currentParenthash = hash; + return true; +} + +bool CommitUncle(CBlockHeader uncle) +{ + LOCK(cs_main); + LogPrintf("CommitUncle \n"); + uint256 hash = uncle.GetHash(); + if(setCurrentUncle.count(hash) != 0){ + return false; + } + if(setCurrentAncestor.count(uncle.hashPrevBlock) ==0){ + return false; + } + if(setCurrentFamily.count(hash) !=0){ + return false; + } + setCurrentUncle.insert(hash); + return true; + +} + +void FindBlockUncles(uint256 parenthash,std::vector& vuncles) +{ + LOCK(cs_main); + LogPrintf("FindBlockUncles in \n"); + if(parenthash == uint256()){ + LogPrintf("FindBlockUncles out 1 \n"); + //std::cout<<"parenthash == uint256()"< badUncles; + //std::vector goodUncles; + for(BlockMapGho::iterator it= mapPossibleUncles.begin(); it != mapPossibleUncles.end(); ++it){ + if(vuncles.size() == 2){ + break; + } + block = (*it).second; + blockheader = block.GetBlockHeader(); + if(CommitUncle(blockheader)){ + vuncles.push_back(block); + } else{ + badUncles.push_back(blockheader.GetHash()); + } + } + + //std::cout<<"findblockuncle vunces size"<::iterator it = badUncles.begin(); it != badUncles.end(); ++it){ + BlockMapGho::iterator mi = mapPossibleUncles.find(*it); + mapPossibleUncles.erase(mi); + } + LogPrintf("FindBlockUncles mapPossibleUncles size %d\n",mapPossibleUncles.size()); + //std::cout<<"findblockuncle parenthash "<GetBlockHash(); + ReadBlockFromDisk(possibleBlock, pindexPossibleBlock, chainparams.GetConsensus()); + mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); + std::cout<<"ActivateBestChainStep add to possibleUncles block hash: "<GetHash() == pindexMostWork->GetBlockHash() ? pblock : NULL)) return false; @@ -3956,6 +4149,17 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if(true){ uint256 hashUncleRoot = BlockUncleRoot(block); if(block.hashUncles != hashUncleRoot){ + /*popchain ghost*/ + std::cout<<"bad-uncleshash block.hashUncles: "<::iterator it = dBlock.vuh.begin(); it != dBlock.vuh.end(); ++it){ + CBlockHeader blockheader = *it; + std::cout<<" bad-uncleshash block.vuh[]: "<hashUncles != uint256()){ + CBlock blockhasuncle = *pblock; + std::cout<<"ProcessNewBlock block have uncles: "< BlockMap; extern BlockMap mapBlockIndex; /*popchain ghost*/ +typedef std::map BlockMapGho; +extern BlockMapGho mapPossibleUncles; +extern uint256 currentParenthash; +typedef std::set BlockSetGho; +extern BlockSetGho setCurrentAncestor; +extern BlockSetGho setCurrentUncle; +extern BlockSetGho setCurrentFamily; //5min @@ -1044,6 +1051,21 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para */ bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); +/*popchain ghost*/ +bool GetBlockNumber(uint256 hash, uint32_t* number); +bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi); +bool MakeCurrentCycle(uint256 hash); +bool CommitUncle(CBlockHeader uncle); +void FindBlockUncles(uint256 parenthash,std::vector& vuncles); + + + + + + +/*popchain ghost*/ + + /** Reject codes greater or equal to this can be returned by AcceptToMemPool * for transactions, to signal internal conditions. They cannot and should not * be sent over the P2P network. diff --git a/src/miner.cpp b/src/miner.cpp index cda3420..dd06a44 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -461,6 +461,22 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); /*popchain ghost*/ + /*popchain ghost*/ + std::vector unclesBlock; + FindBlockUncles(pblock->hashPrevBlock,unclesBlock); + CBlock uncleBlock; + int uncleCount = 0; + for(std::vector::iterator it = unclesBlock.begin();it != unclesBlock.end(); ++it){ + uncleBlock = *it; + if(uncleCount < 2){ + pblock->vuh.push_back(uncleBlock.GetBlockHeader()); + } + uncleCount++; + } + + pblock->hashUncles = BlockUncleRoot(*pblock); + /*popchain ghost*/ + // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); // Clear the top and bottom 16 bits (for local use as thread flags and counters) @@ -507,7 +523,7 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); /*popchain ghost*/ - pblock->hashUncles = BlockUncleRoot(*pblock); + //pblock->hashUncles = BlockUncleRoot(*pblock); /*popchain ghost*/ } From 8174e49449031d8728403e562a1637ee927df58b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 20 Aug 2018 09:43:39 +0800 Subject: [PATCH 032/120] change the rpc command getblock --- src/rpcblockchain.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index b8b7fa0..5877e15 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -123,6 +123,15 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); + /*popchain ghost*/ + UniValue uhs(UniValue::VARR); + BOOST_FOREACH(const CBlockHeader&uh, block.vuh) + { + //UniValue objUh(UniValue::VOBJ); + uhs.push_back(uh.GetHash().GetHex()); + } + result.push_back(Pair("uh",uhs)); + /*popchain ghost*/ result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", block.nNonce.GetHex())); From a2ef5ff5517ff07330495f5aaeebd324231f2aba Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 20 Aug 2018 17:05:00 +0800 Subject: [PATCH 033/120] change the rpc command getuncleblockheader --- src/rpcblockchain.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 3 ++ src/rpcserver.h | 4 ++ 3 files changed, 126 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 5877e15..569b142 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -129,6 +129,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx { //UniValue objUh(UniValue::VOBJ); uhs.push_back(uh.GetHash().GetHex()); + //uhs.push_back(uh.ToString()); } result.push_back(Pair("uh",uhs)); /*popchain ghost*/ @@ -412,6 +413,7 @@ UniValue getblockheader(const UniValue& params, bool fHelp) return blockheaderToJSON(pblockindex); } + UniValue getblockheaders(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 3) @@ -500,6 +502,123 @@ UniValue getblockheaders(const UniValue& params, bool fHelp) return arrHeaders; } +/*popchain ghost*/ + +UniValue getuncleblockheader(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock \"hash\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" + "If verbose is true, returns an Object with information about block .\n" + "\nArguments:\n" + "1. \"hash\" (string, required) The block hash\n" + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "\nResult (for verbose = true):\n" + "{\n" + " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" + " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" + " \"size\" : n, (numeric) The block size\n" + " \"height\" : n, (numeric) The block height or index\n" + " \"version\" : n, (numeric) The block version\n" + " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" + " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" + " \"tx\" : [ (array of string) The transaction ids\n" + " \"transactionid\" (string) The transaction id\n" + " ,...\n" + " ],\n" + " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"nonce\" : n, (numeric) The nonce\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"difficulty\" : x.xxx, (numeric) The difficulty\n" + " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" + " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" + " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + "}\n" + "\nResult (for verbose=false):\n" + "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nExamples:\n" + + HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + ); + + LOCK(cs_main); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + + bool fVerbose = true; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + UniValue result(UniValue::VOBJ); + + const CChainParams& chainparams = Params(); + //std::vector containUncleBlockIndex; + bool bGetUncle = false; + UniValue ucb(UniValue::VARR); + for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ + CBlockIndex* blockindex = (*mi).second; + if(blockindex->hashUncles == uint256()){ + continue; + } + + CBlock block; + if(!ReadBlockFromDisk(block, blockindex, chainparams.GetConsensus())){ + LogPrintf("getuncleblockheader : OpenBlockFile failed for %s ,BlockStatus %d \n",blockindex->GetBlockHash().ToString(),\ + blockindex->nStatus); + LogPrintf("blockhash: %s,pprev: %s,nHeight: %d,nFile: %d,nDataPos: %d,nUndoPos: %d,nChainWork: %s,nTx: %d,nChainTx: %d,nStatus: %d \n",\ + blockindex->GetBlockHash().ToString(),\ + blockindex->pprev->GetBlockHash().ToString(),blockindex->nHeight,\ + blockindex->nFile,blockindex->nDataPos,blockindex->nUndoPos,\ + blockindex->nChainWork.ToString(),blockindex->nTx,blockindex->nChainTx,\ + blockindex->nStatus); + } else{ + //LogPrintf("getuncleblockheader : OpenBlockFile successfor %s ,BlockStatus %d \n",blockindex->GetBlockHash().ToString(),\ + // blockindex->nStatus); + } + std::vector vuh = block.vuh; + for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ + if(hash == (*bi).GetHash()){ + ucb.push_back(block.GetHash().GetHex()); + if(!bGetUncle){ + result.push_back(Pair("uncle", (*bi).ToString())); + bGetUncle = true; + } + } + } + } + result.push_back(Pair("block contain uncle give",ucb)); + + +/* + if (mapBlockIndex.count(hash) == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + + CBlock block; + CBlockIndex* pblockindex = mapBlockIndex[hash]; + + if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + if (!fVerbose) + { + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << block; + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + return strHex; + } +*/ + return result; + //return blockToJSON(block, pblockindex); +} + + +/*popchain ghost*/ UniValue getblock(const UniValue& params, bool fHelp) { diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index df7e70a..a79a6b9 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -277,6 +277,9 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, { "blockchain", "getbestblockhash", &getbestblockhash, true }, { "blockchain", "getblockcount", &getblockcount, true }, + /*popchain ghost*/ + { "blockchain", "getuncleblockheader", &getuncleblockheader, true }, + /*popchain ghost*/ { "blockchain", "getblock", &getblock, true }, { "blockchain", "getblockhashes", &getblockhashes, true }, { "blockchain", "getblockhash", &getblockhash, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 3bd9c83..df7b27e 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -285,6 +285,10 @@ extern UniValue getblockhashes(const UniValue& params, bool fHelp); extern UniValue getblockhash(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblockheaders(const UniValue& params, bool fHelp); +/*popchain ghost*/ +extern UniValue getuncleblockheader(const UniValue& params, bool fHelp); + +/*popchain ghost*/ extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); extern UniValue gettxout(const UniValue& params, bool fHelp); From adfb05febbd68b73a103a00d8ee14cb506e03031 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 20 Aug 2018 20:22:59 +0800 Subject: [PATCH 034/120] add rpc command getalluncleblockheader --- src/rpcblockchain.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 1 + src/rpcserver.h | 2 + 3 files changed, 94 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 569b142..98f2301 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -618,6 +618,97 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) } +UniValue getalluncleblockheader(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getblock \"hash\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" + "If verbose is true, returns an Object with information about block .\n" + "\nArguments:\n" + "1. \"hash\" (string, required) The block hash\n" + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "\nResult (for verbose = true):\n" + "{\n" + " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" + " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" + " \"size\" : n, (numeric) The block size\n" + " \"height\" : n, (numeric) The block height or index\n" + " \"version\" : n, (numeric) The block version\n" + " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" + " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" + " \"tx\" : [ (array of string) The transaction ids\n" + " \"transactionid\" (string) The transaction id\n" + " ,...\n" + " ],\n" + " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"nonce\" : n, (numeric) The nonce\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"difficulty\" : x.xxx, (numeric) The difficulty\n" + " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" + " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" + " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + "}\n" + "\nResult (for verbose=false):\n" + "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\nExamples:\n" + + HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + ); + + LOCK(cs_main); + + std::string strHash = params[0].get_str(); + uint256 hash(uint256S(strHash)); + + bool fVerbose = true; + if (params.size() > 1) + fVerbose = params[1].get_bool(); + + UniValue result(UniValue::VOBJ); + + const CChainParams& chainparams = Params(); + //std::vector containUncleBlockIndex; + bool bGetUncle = false; + UniValue ucb(UniValue::VARR); + int uncleCount =0; + for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ + CBlockIndex* blockindex = (*mi).second; + if(blockindex->hashUncles == uint256()){ + continue; + } + LogPrintf("block contain uncle: %s\n",blockindex->GetBlockHash().ToString()); + + CBlock block; + if(!ReadBlockFromDisk(block, blockindex, chainparams.GetConsensus())){ + LogPrintf("uncleheader : OpenBlockFile failed for %s \n",blockindex->GetBlockHash().ToString()); + /* + LogPrintf("blockhash: %s,pprev: %s,nHeight: %d,nFile: %d,nDataPos: %d,nUndoPos: %d,nChainWork: %s,nTx: %d,nChainTx: %d,nStatus: %d \n",\ + blockindex->GetBlockHash().ToString(),\ + blockindex->pprev->GetBlockHash().ToString(),blockindex->nHeight,\ + blockindex->nFile,blockindex->nDataPos,blockindex->nUndoPos,\ + blockindex->nChainWork.ToString(),blockindex->nTx,blockindex->nChainTx,\ + blockindex->nStatus); + */ + } else{ + //LogPrintf("uncleheader : OpenBlockFile success for %s \n",blockindex->GetBlockHash().ToString()); + } + std::vector vuh = block.vuh; + for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ + LogPrintf("uncleheader : %s \n",(*bi).ToString()); + //result.push_back(Pair("uncle", (*bi).ToString())); + uncleCount++; + + + } + } + result.push_back(Pair("unclesize",uncleCount)); + + return result; +} + + /*popchain ghost*/ UniValue getblock(const UniValue& params, bool fHelp) diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index a79a6b9..168fcec 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -279,6 +279,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockcount", &getblockcount, true }, /*popchain ghost*/ { "blockchain", "getuncleblockheader", &getuncleblockheader, true }, + { "blockchain", "getalluncleblockheader", &getalluncleblockheader, true }, /*popchain ghost*/ { "blockchain", "getblock", &getblock, true }, { "blockchain", "getblockhashes", &getblockhashes, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index df7b27e..61502c5 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -287,6 +287,8 @@ extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblockheaders(const UniValue& params, bool fHelp); /*popchain ghost*/ extern UniValue getuncleblockheader(const UniValue& params, bool fHelp); +extern UniValue getalluncleblockheader(const UniValue& params, bool fHelp); + /*popchain ghost*/ extern UniValue getblock(const UniValue& params, bool fHelp); From 6317379a27a49fd85a6c286504920522a7dccb75 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Tue, 21 Aug 2018 00:22:53 +0800 Subject: [PATCH 035/120] Armindev (#7) change port to 2888 and 12888, add rpc command getblockdifficulty and gettotaldifficulty --- contrib/debian/examples/pop.conf | 4 +-- contrib/qos/README.md | 2 +- contrib/qos/tc.sh | 6 ++-- contrib/seeds/generate-seeds.py | 4 +-- doc/guide-startmany.md | 4 +-- doc/popnode_conf.md | 4 +-- doc/tor.md | 8 ++--- src/chainparams.cpp | 7 ++-- src/popnodeconfig.cpp | 2 +- src/qt/locale/pop_bg.ts | 8 ++--- src/qt/locale/pop_de.ts | 8 ++--- src/qt/locale/pop_en.ts | 8 ++--- src/qt/locale/pop_es.ts | 8 ++--- src/qt/locale/pop_fi.ts | 8 ++--- src/qt/locale/pop_fr.ts | 8 ++--- src/qt/locale/pop_pl.ts | 8 ++--- src/qt/locale/pop_pt.ts | 8 ++--- src/qt/locale/pop_ru.ts | 8 ++--- src/qt/locale/pop_sk.ts | 8 ++--- src/qt/locale/pop_vi.ts | 8 ++--- src/qt/locale/pop_zh_CN.ts | 8 ++--- src/qt/popstrings.cpp | 4 +-- src/rpcblockchain.cpp | 55 ++++++++++++++++++++++++++++++++ src/rpcclient.cpp | 2 ++ src/rpcnet.cpp | 6 ++-- src/rpcserver.cpp | 4 ++- src/rpcserver.h | 2 ++ src/test/netbase_tests.cpp | 18 +++++------ 28 files changed, 144 insertions(+), 84 deletions(-) diff --git a/contrib/debian/examples/pop.conf b/contrib/debian/examples/pop.conf index 746a2aa..54d68e2 100644 --- a/contrib/debian/examples/pop.conf +++ b/contrib/debian/examples/pop.conf @@ -44,11 +44,11 @@ # Use as many addnode= settings as you like to connect to specific peers #addnode=69.164.218.197 -#addnode=10.0.0.2:9888 +#addnode=10.0.0.2:2888 # Alternatively use as many connect= settings as you like to connect ONLY to specific peers #connect=69.164.218.197 -#connect=10.0.0.1:9888 +#connect=10.0.0.1:2888 # Listening mode, enabled by default except when 'connect' is being used #listen=1 diff --git a/contrib/qos/README.md b/contrib/qos/README.md index 6706b97..890b679 100644 --- a/contrib/qos/README.md +++ b/contrib/qos/README.md @@ -1,5 +1,5 @@ ### Qos ### -This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Pop network. It limits outbound TCP traffic with a source or destination port of 9888, but not if the destination IP is within a LAN (defined as 192.168.x.x). +This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Pop network. It limits outbound TCP traffic with a source or destination port of 2888, but not if the destination IP is within a LAN (defined as 192.168.x.x). This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it. diff --git a/contrib/qos/tc.sh b/contrib/qos/tc.sh index 35e9a61..5e8dfe0 100644 --- a/contrib/qos/tc.sh +++ b/contrib/qos/tc.sh @@ -32,10 +32,10 @@ tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11 # ret=$? #done -#limit outgoing traffic to and from port 9888. but not when dealing with a host on the local network +#limit outgoing traffic to and from port 2888. but not when dealing with a host on the local network # (defined by $LOCALNET) # --set-mark marks packages matching these criteria with the number "2" # these packages are filtered by the tc filter with "handle 2" # this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT} -iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 9888 ! -d ${LOCALNET} -j MARK --set-mark 0x2 -iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 9888 ! -d ${LOCALNET} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 2888 ! -d ${LOCALNET} -j MARK --set-mark 0x2 +iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 2888 ! -d ${LOCALNET} -j MARK --set-mark 0x2 diff --git a/contrib/seeds/generate-seeds.py b/contrib/seeds/generate-seeds.py index b97fe5c..23ef89b 100644 --- a/contrib/seeds/generate-seeds.py +++ b/contrib/seeds/generate-seeds.py @@ -127,10 +127,10 @@ def main(): g.write(' * IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.\n') g.write(' */\n') with open(os.path.join(indir,'nodes_main.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_main', 9888) + process_nodes(g, f, 'pnSeed6_main', 2888) g.write('\n') with open(os.path.join(indir,'nodes_test.txt'),'r') as f: - process_nodes(g, f, 'pnSeed6_test', 19888) + process_nodes(g, f, 'pnSeed6_test', 12888) g.write('#endif // UC_CHAINPARAMSSEEDS_H\n') if __name__ == '__main__': diff --git a/doc/guide-startmany.md b/doc/guide-startmany.md index 5daa5d0..c3cf3f1 100644 --- a/doc/guide-startmany.md +++ b/doc/guide-startmany.md @@ -106,8 +106,8 @@ alias ipaddress:port popnode_private_key collateral_output collateral_output_ind Example: ``` -pn01 127.0.0.1:9888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0 -pn02 127.0.0.2:9888 93WaAb3htPJEV8E9aQcN23Jt97bPex7YvWfgMDTUdWJvzmrMqey aa9f1034d973377a5e733272c3d0eced1de22555ad45d6b24abadff8087948d4 0 +pn01 127.0.0.1:2888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0 +pn02 127.0.0.2:2888 93WaAb3htPJEV8E9aQcN23Jt97bPex7YvWfgMDTUdWJvzmrMqey aa9f1034d973377a5e733272c3d0eced1de22555ad45d6b24abadff8087948d4 0 ``` ## What about the pop.conf file? diff --git a/doc/popnode_conf.md b/doc/popnode_conf.md index 888c3f4..428bc80 100644 --- a/doc/popnode_conf.md +++ b/doc/popnode_conf.md @@ -9,8 +9,8 @@ Pop Core allows controlling multiple remote popnodes from a single wallet. The w `popnode.conf` is a space separated text file. Each line consists of an alias, IP address followed by port, popnode private key, collateral output transaction id and collateral output index. Example: -pn1 127.0.0.2:19888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 7603c20a05258c208b58b0a0d77603b9fc93d47cfa403035f87f3ce0af814566 0 -pn2 127.0.0.4:19888 92Da1aYg6sbenP6uwskJgEY2XWB5LwJ7bXRqc3UPeShtHWJDjDv 5d898e78244f3206e0105f421cdb071d95d111a51cd88eb5511fc0dbf4bfd95f 1 +pn1 127.0.0.2:12888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 7603c20a05258c208b58b0a0d77603b9fc93d47cfa403035f87f3ce0af814566 0 +pn2 127.0.0.4:12888 92Da1aYg6sbenP6uwskJgEY2XWB5LwJ7bXRqc3UPeShtHWJDjDv 5d898e78244f3206e0105f421cdb071d95d111a51cd88eb5511fc0dbf4bfd95f 1 ``` _Note: IPs like 127.0.0.* are not allowed actually, we are using them here for explanatory purposes only. Make sure you have real reachable remote IPs in you `popnode.conf`._ diff --git a/doc/tor.md b/doc/tor.md index cfc7778..f391e04 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -52,11 +52,11 @@ reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equiv config file): HiddenServiceDir /var/lib/tor/popcore-service/ - HiddenServicePort 9888 127.0.0.1:9888 - HiddenServicePort 19888 127.0.0.1:19888 + HiddenServicePort 2888 127.0.0.1:2888 + HiddenServicePort 12888 127.0.0.1:12888 The directory can be different of course, but (both) port numbers should be equal to -your popd's P2P listen port (9888 by default). +your popd's P2P listen port (2888 by default). -externalip=X You can tell Pop Core about its publicly reachable address using this option, and this can be a .onion address. Given the above @@ -91,7 +91,7 @@ as well, use `discover` instead: ./popd ... -discover -and open port 9888 on your firewall (or use -upnp). +and open port 2888 on your firewall (or use -upnp). If you only want to use Tor to reach onion addresses, but not use it as a proxy for normal IPv4/IPv6 communication, use: diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b781506..8d7363d 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -229,7 +229,6 @@ class CMainParams : public CChainParams { //consensus.durationLimit = 13; consensus.minimumDifficulty = 1730830; // minidifficulty for target consensus.nYolandaTime = 172800; - /*popchain ghost*/ consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down @@ -259,7 +258,7 @@ class CMainParams : public CChainParams { pchMessageStart[2] = 0x6f; pchMessageStart[3] = 0xb1; vAlertPubKey = ParseHex("028efd0f3c697689f8f1f6744edbbc1f85871b8c51218ddd89d90a3e435d1a8691"); - nDefaultPort = 9888; + nDefaultPort = 2888; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin nPruneAfterHeight = 100000; /*popchain ghost*/ @@ -362,7 +361,7 @@ class CTestNetParams : public CChainParams { //consensus.durationLimit = 13; consensus.minimumDifficulty = 4096; consensus.nYolandaTime = 200; - + /* popchain ghost */ consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down @@ -389,7 +388,7 @@ class CTestNetParams : public CChainParams { pchMessageStart[2] = 0xce; pchMessageStart[3] = 0xf3; vAlertPubKey = ParseHex("0244a0bb22e931bf59cc8a434d9d22bd2fa493f579bd2659bc9188361d78bdc45f"); - nDefaultPort = 19888; + nDefaultPort = 12888; nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet nPruneAfterHeight = 1000; /*popchain ghost*/ diff --git a/src/popnodeconfig.cpp b/src/popnodeconfig.cpp index 10917fa..ebcacde 100644 --- a/src/popnodeconfig.cpp +++ b/src/popnodeconfig.cpp @@ -24,7 +24,7 @@ bool CPopnodeConfig::read(std::string& strErr) { if (configFile != NULL) { std::string strHeader = "# Popnode config file\n" "# Format: alias IP:port popnodeprivkey collateral_output_txid collateral_output_index\n" - "# Example: mn1 127.0.0.2:19888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; + "# Example: mn1 127.0.0.2:12888 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; fwrite(strHeader.c_str(), std::strlen(strHeader.c_str()), 1, configFile); fclose(configFile); } diff --git a/src/qt/locale/pop_bg.ts b/src/qt/locale/pop_bg.ts index a5da58f..7070372 100644 --- a/src/qt/locale/pop_bg.ts +++ b/src/qt/locale/pop_bg.ts @@ -3745,8 +3745,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Whitelisted не могат да бъдат DoS забранени и техните транзакции ще бъдат винаги предадени, дори ако вече Ñа в mempool, полезно напр. за gateway - (9888 could be used only on mainnet) - (9888 може да бъде използван в оÑновната мрежа) + (2888 could be used only on mainnet) + (2888 може да бъде използван в оÑновната мрежа) (default: %s) @@ -4155,8 +4155,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Ðевалиден чаÑтен ключ на Popnode. ÐœÐ¾Ð»Ñ Ð²Ð¸Ð¶Ñ‚Ðµ документациÑта. - (must be 9888 for mainnet) - (трÑбва да е 9888 за оÑновната мрежа) + (must be 2888 for mainnet) + (трÑбва да е 2888 за оÑновната мрежа) Can't find random Popnode. diff --git a/src/qt/locale/pop_de.ts b/src/qt/locale/pop_de.ts index 308a81d..5da0b60 100644 --- a/src/qt/locale/pop_de.ts +++ b/src/qt/locale/pop_de.ts @@ -3753,8 +3753,8 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Pop Alert\" admin@foo.comErlaubte Gegenstellen können nicht wegen DoS ausgeschlossen werden und ihre Transaktionen werden immer weitergeleitet, sogar wenn sie schon im Memory-Pool sind. Dies ist z.B. für Gateways nützlich. - (9888 could be used only on mainnet) - (9888 kann nur im Standardnetz benutzt werden) + (2888 could be used only on mainnet) + (2888 kann nur im Standardnetz benutzt werden) (default: %s) @@ -4160,8 +4160,8 @@ Pop Core wird heruntergefahren. Popnode-Geheimschlüssel (popnodeprivkey) ist ungültig. Siehe Dokumentation. - (must be 9888 for mainnet) - (muss für Standardnetz 9888 sein) + (must be 2888 for mainnet) + (muss für Standardnetz 2888 sein) Can't find random Popnode. diff --git a/src/qt/locale/pop_en.ts b/src/qt/locale/pop_en.ts index d0ad01d..a7d7f98 100644 --- a/src/qt/locale/pop_en.ts +++ b/src/qt/locale/pop_en.ts @@ -4780,8 +4780,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com - (9888 could be used only on mainnet) - (9888 could be used only on mainnet) + (2888 could be used only on mainnet) + (2888 could be used only on mainnet) @@ -5292,8 +5292,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com - (must be 9888 for mainnet) - (must be 9888 for mainnet) + (must be 2888 for mainnet) + (must be 2888 for mainnet) diff --git a/src/qt/locale/pop_es.ts b/src/qt/locale/pop_es.ts index 4654d20..0f68b7f 100644 --- a/src/qt/locale/pop_es.ts +++ b/src/qt/locale/pop_es.ts @@ -3755,8 +3755,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Alerta de Pop" admin@foo.com Los pares de la lista blanca no pueden ser excluidos por DoS y sus transacciones siempre se transmitirán, incluso si ya se encuentran en el grupo de memoria, útil e.g. para una pasarela - (9888 could be used only on mainnet) - (9888 sólo se puede usar en la red principal) + (2888 could be used only on mainnet) + (2888 sólo se puede usar en la red principal) (default: %s) @@ -4165,8 +4165,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Alerta de Pop" admin@foo.com La clave prinvada del nodo maestro no es válida. Por favor, consulte la documentación. - (must be 9888 for mainnet) - (debe ser 9888 para la red principal) + (must be 2888 for mainnet) + (debe ser 2888 para la red principal) Can't find random Popnode. diff --git a/src/qt/locale/pop_fi.ts b/src/qt/locale/pop_fi.ts index 8e035b6..9cbc83e 100644 --- a/src/qt/locale/pop_fi.ts +++ b/src/qt/locale/pop_fi.ts @@ -3761,8 +3761,8 @@ esimerkiksi: alertnotify=echo %%s | mail -s "Pop Hälytys" admin@foo.com Luotettaviksi merkittyjä peers:ejä ei voida DoS estää, ja niiden siirtotapahtumat välitetään aina, vaikka ne olisvatkin jo muistivarannossa, käyttökelpoinen esim. yhdyskäytävään - (9888 could be used only on mainnet) - (9888 voidaan käyttää vain pääverkossa) + (2888 could be used only on mainnet) + (2888 voidaan käyttää vain pääverkossa) (default: %s) @@ -4171,8 +4171,8 @@ esimerkiksi: alertnotify=echo %%s | mail -s "Pop Hälytys" admin@foo.com Virheellinen popnoden yksityisavain (popnodeprivkey). Katso lisätietoja dokumentaatiosta. - (must be 9888 for mainnet) - (oltava 9888 pääverkossa) + (must be 2888 for mainnet) + (oltava 2888 pääverkossa) Can't find random Popnode. diff --git a/src/qt/locale/pop_fr.ts b/src/qt/locale/pop_fr.ts index 225deab..5cc13aa 100644 --- a/src/qt/locale/pop_fr.ts +++ b/src/qt/locale/pop_fr.ts @@ -3754,8 +3754,8 @@ Pour exemple: alertnotify=echo %%s | mail -s "Alerte Pop" admin@foo.com Pairs en liste blanche ne peuvent être bannis pour DoS et leurs transactions sont toujours relayées, même si elles sont déjà en mémoire, utile par ex. pour une passerelle - (9888 could be used only on mainnet) - (9888 n'est utilisable que sur mainnet) + (2888 could be used only on mainnet) + (2888 n'est utilisable que sur mainnet) (default: %s) @@ -4164,8 +4164,8 @@ Pour exemple: alertnotify=echo %%s | mail -s "Alerte Pop" admin@foo.com popnodeprivkey invalide. Veuillez vous référer à la documentation. - (must be 9888 for mainnet) - (doit être 9888 pour mainnet) + (must be 2888 for mainnet) + (doit être 2888 pour mainnet) Can't find random Popnode. diff --git a/src/qt/locale/pop_pl.ts b/src/qt/locale/pop_pl.ts index 4201364..7f07e62 100644 --- a/src/qt/locale/pop_pl.ts +++ b/src/qt/locale/pop_pl.ts @@ -3753,8 +3753,8 @@ Zaleca siÄ™ również aby ustawić alarm powiadomieÅ„ tzw. alertnotify, aby dać Peery z biaÅ‚ej listy nie mogÄ… zostać zbanowane a ich transakcje sÄ… zawsze retransmitowane, nawet jeÅ›li już sÄ… w pamiÄ™ci zbiorowej (mempool). Jest to przydatne np. dla bramek wyjÅ›ciowych - (9888 could be used only on mainnet) - (9888 może być użyte tylko dla głównej sieci) + (2888 could be used only on mainnet) + (2888 może być użyte tylko dla głównej sieci) (default: %s) @@ -4163,8 +4163,8 @@ Zaleca siÄ™ również aby ustawić alarm powiadomieÅ„ tzw. alertnotify, aby dać NieprawidÅ‚owy klucz prywatny popnoda. Przeczytaj dokumentacjÄ™. - (must be 9888 for mainnet) - (musi być 9888 dla głównej sieci) + (must be 2888 for mainnet) + (musi być 2888 dla głównej sieci) Can't find random Popnode. diff --git a/src/qt/locale/pop_pt.ts b/src/qt/locale/pop_pt.ts index 60b3230..9462982 100644 --- a/src/qt/locale/pop_pt.ts +++ b/src/qt/locale/pop_pt.ts @@ -3654,8 +3654,8 @@ https://www.transifex.com/projects/p/pop/ Aviso: Por favor verifique que a data e a hora do computador está correcta! Se o relógio estiver errado o Pop Core não vai funcionar correctamente. - (9888 could be used only on mainnet) - (9888 apenas pode ser usado para mainnet) + (2888 could be used only on mainnet) + (2888 apenas pode ser usado para mainnet) (default: %s) @@ -4056,8 +4056,8 @@ https://www.transifex.com/projects/p/pop/ popnodeprivkey inválida. Por favor reveja a documentação. - (must be 9888 for mainnet) - (deve ser 9888 para mainnet) + (must be 2888 for mainnet) + (deve ser 2888 para mainnet) Can't find random Popnode. diff --git a/src/qt/locale/pop_ru.ts b/src/qt/locale/pop_ru.ts index 5e360fc..66fbd1f 100644 --- a/src/qt/locale/pop_ru.ts +++ b/src/qt/locale/pop_ru.ts @@ -3754,8 +3754,8 @@ rpcpassword=%s Пиры, внеÑенные в белый ÑпиÑок, не будут подвергатьÑÑ DoS блокировкам и их транзакции будут ретранÑлироватьÑÑ, даже еÑли они уже еÑть в пуле памÑти, что полезно, например, Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ в качеÑтве шлюза - (9888 could be used only on mainnet) - (9888 можно иÑпользовать только в главной Ñети) + (2888 could be used only on mainnet) + (2888 можно иÑпользовать только в главной Ñети) (default: %s) @@ -4164,8 +4164,8 @@ rpcpassword=%s Ðеправильное значение popnodeprivkey. ПожалуйÑта, ознакомьтеÑÑŒ Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸ÐµÐ¹. - (must be 9888 for mainnet) - (должно быть 9888 в главной Ñети) + (must be 2888 for mainnet) + (должно быть 2888 в главной Ñети) Can't find random Popnode. diff --git a/src/qt/locale/pop_sk.ts b/src/qt/locale/pop_sk.ts index 2d1c41f..947ad69 100644 --- a/src/qt/locale/pop_sk.ts +++ b/src/qt/locale/pop_sk.ts @@ -3753,8 +3753,8 @@ napríklad: alertnotify=echo %%s | mail -s "Pop Upozornenie" admin@foo.com Uzle na zoznam povolených nemôžu byÅ¥ DoS zakázané a ich transakcie vždy postúpené Äalej, aj v prípade, ak sú už pamäťovej fronte. UžitoÄné napr. pre brány - (9888 could be used only on mainnet) - (9888 nemôže byÅ¥ použité pre hlavnú sieÅ¥) + (2888 could be used only on mainnet) + (2888 nemôže byÅ¥ použité pre hlavnú sieÅ¥) (default: %s) @@ -4163,8 +4163,8 @@ napríklad: alertnotify=echo %%s | mail -s "Pop Upozornenie" admin@foo.com Neplatný popnodeprivkey. Prosím pozrite do dokumentácie. - (must be 9888 for mainnet) - (pre hlavnú sieÅ¥ musí byÅ¥ 9888) + (must be 2888 for mainnet) + (pre hlavnú sieÅ¥ musí byÅ¥ 2888) Can't find random Popnode. diff --git a/src/qt/locale/pop_vi.ts b/src/qt/locale/pop_vi.ts index 90de313..5d21ef7 100644 --- a/src/qt/locale/pop_vi.ts +++ b/src/qt/locale/pop_vi.ts @@ -3754,8 +3754,8 @@ ví dụ: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Cái Ä‘iểm ngang hàng trong danh sách trắng không thể bị cấm DoS và các giao dịch cá»§a nó luôn được chuyển tiếp, thậm chí cả khi nó đã có trong mempool, hữu ích ví dụ như cho má»™t cá»­a ngõ - (9888 could be used only on mainnet) - (9888 chỉ được sá»­ dụng trên mạng chính thức) + (2888 could be used only on mainnet) + (2888 chỉ được sá»­ dụng trên mạng chính thức) (default: %s) @@ -4163,8 +4163,8 @@ ví dụ: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Popnodeprivkey không hợp lệ. Hãy xem lại tài liệu. - (must be 9888 for mainnet) - (phải là 9888 cho mạng chính thức) + (must be 2888 for mainnet) + (phải là 2888 cho mạng chính thức) Can't find random Popnode. diff --git a/src/qt/locale/pop_zh_CN.ts b/src/qt/locale/pop_zh_CN.ts index cd2d895..a249a2e 100644 --- a/src/qt/locale/pop_zh_CN.ts +++ b/src/qt/locale/pop_zh_CN.ts @@ -3860,8 +3860,8 @@ https://www.transifex.com/projects/p/pop/ 在白åå•中的节点ä¸ä¼šå› ä¸ºæ£€æµ‹åˆ°DoS攻击而被åœç”¨. æ¥è‡ªè¿™äº›èŠ‚ç‚¹çš„äº¤æ˜“ä¹Ÿä¸€å®šä¼šè¢«è½¬å‘, å³ä½¿è¯´äº¤æ˜“本神就æ¥è‡ªè®°å¿†æ± . 适用于网关 - (9888 could be used only on mainnet) - (9888 åªèƒ½è¢«ç”¨äºŽä¸»ç½‘) + (2888 could be used only on mainnet) + (2888 åªèƒ½è¢«ç”¨äºŽä¸»ç½‘) (default: %s) @@ -4196,8 +4196,8 @@ https://www.transifex.com/projects/p/pop/ 无效主节点ç§é’¥ã€‚è¯·æŸ¥é˜…æ–‡ä»¶ææ–™ã€‚ - (must be 9888 for mainnet) - (设置 9888 为主网) + (must be 2888 for mainnet) + (设置 2888 为主网) Can't find random Popnode. diff --git a/src/qt/popstrings.cpp b/src/qt/popstrings.cpp index 6de2f60..83f5695 100644 --- a/src/qt/popstrings.cpp +++ b/src/qt/popstrings.cpp @@ -202,10 +202,10 @@ QT_TRANSLATE_NOOP("pop-core", "" QT_TRANSLATE_NOOP("pop-core", "" "You must specify a popnodeprivkey in the configuration. Please see " "documentation for help."), -QT_TRANSLATE_NOOP("pop-core", "(9888 could be used only on mainnet)"), +QT_TRANSLATE_NOOP("pop-core", "(2888 could be used only on mainnet)"), QT_TRANSLATE_NOOP("pop-core", "(default: %s)"), QT_TRANSLATE_NOOP("pop-core", "(default: 1)"), -QT_TRANSLATE_NOOP("pop-core", "(must be 9888 for mainnet)"), +QT_TRANSLATE_NOOP("pop-core", "(must be 2888 for mainnet)"), QT_TRANSLATE_NOOP("pop-core", " can be:\n"), QT_TRANSLATE_NOOP("pop-core", "Accept command line and JSON-RPC commands"), QT_TRANSLATE_NOOP("pop-core", "Accept connections from outside (default: 1 if no -proxy or -connect)"), diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 98f2301..205523d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -355,6 +355,61 @@ UniValue getblockhash(const UniValue& params, bool fHelp) return pblockindex->GetBlockHash().GetHex(); } +UniValue getblockdifficulty(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "getblockdifficulty index\n" + "\nReturns difficulty of block in best-block-chain at index provided.\n" + "\nArguments:\n" + "1. index (numeric, required) The block index\n" + "\nResult:\n" + "\"difficulty\" (string) The block difficulty\n" + "\nExamples:\n" + + HelpExampleCli("getblockdifficulty", "1000") + + HelpExampleRpc("getblockdifficulty", "1000") + ); + + LOCK(cs_main); + + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > chainActive.Height()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + + CBlockIndex* pblockindex = chainActive[nHeight]; + return GetDifficulty(pblockindex); +} + +UniValue gettotaldifficulty(const UniValue& params, bool fHelp) +{ + if (fHelp || (params.size() != 0 && params.size() != 1)) + throw runtime_error( + "gettotaldifficulty index\n" + "\nReturns total difficulty of block in best-block-chain at index provided or tip.\n" + "\nArguments:\n" + "1. index (numeric, optional, default=chainactive tip) The block index\n" + "\nResult:\n" + "\"total difficulty\" (string) The block total difficulty\n" + "\nExamples:\n" + + HelpExampleCli("gettotaldifficulty", "1000") + + HelpExampleRpc("gettotaldifficulty", "1000") + ); + + LOCK(cs_main); + + CBlockIndex* pblockindex; + if (params.size() == 1){ + int nHeight = params[0].get_int(); + if (nHeight < 0 || nHeight > chainActive.Height()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + pblockindex = chainActive[nHeight]; + } + else { + pblockindex = chainActive.Tip(); + } + return pblockindex->nChainWork.ToString(); +} + UniValue getblockheader(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 69a1517..129ef27 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -50,6 +50,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getchaintips", 0 }, { "getchaintips", 1 }, { "getblockhash", 0 }, + { "getblockdifficulty", 0 }, + { "gettotaldifficulty", 0 }, { "move", 2 }, { "move", 3 }, { "sendfrom", 2 }, diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 4aa0a42..6172a53 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -184,8 +184,8 @@ UniValue addnode(const UniValue& params, bool fHelp) "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n" "2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n" "\nExamples:\n" - + HelpExampleCli("addnode", "\"192.168.0.6:9888\" \"onetry\"") - + HelpExampleRpc("addnode", "\"192.168.0.6:9888\", \"onetry\"") + + HelpExampleCli("addnode", "\"192.168.0.6:2888\" \"onetry\"") + + HelpExampleRpc("addnode", "\"192.168.0.6:2888\", \"onetry\"") ); string strNode = params[0].get_str(); @@ -260,7 +260,7 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp) " \"connected\" : true|false, (boolean) If connected\n" " \"addresses\" : [\n" " {\n" - " \"address\" : \"192.168.0.201:9888\", (string) The pop server host and port\n" + " \"address\" : \"192.168.0.201:2888\", (string) The pop server host and port\n" " \"connected\" : \"outbound\" (string) connection, inbound or outbound\n" " }\n" " ,...\n" diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 168fcec..7d0fce9 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -287,7 +287,9 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockheader", &getblockheader, true }, { "blockchain", "getblockheaders", &getblockheaders, true }, { "blockchain", "getchaintips", &getchaintips, true }, - { "blockchain", "getdifficulty", &getdifficulty, true }, + { "blockchain", "getdifficulty", &getdifficulty, true }, + { "blockchain", "getblockdifficulty", &getblockdifficulty, true }, + { "blockchain", "gettotaldifficulty", &gettotaldifficulty, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, { "blockchain", "getrawmempool", &getrawmempool, true }, { "blockchain", "gettxout", &gettxout, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 61502c5..773f8fc 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -278,6 +278,8 @@ extern UniValue mnsync(const UniValue& params, bool fHelp); extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); +extern UniValue getblockdifficulty(const UniValue& params, bool fHelp); +extern UniValue gettotaldifficulty(const UniValue& params, bool fHelp); extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); extern UniValue getrawmempool(const UniValue& params, bool fHelp); diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index d1a68f3..56944c6 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -59,15 +59,15 @@ BOOST_AUTO_TEST_CASE(netbase_splithost) BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80)); BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80)); BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("127.0.0.1:9888", "127.0.0.1", 9888)); + BOOST_CHECK(TestSplitHost("127.0.0.1:2888", "127.0.0.1", 2888)); BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("[127.0.0.1]:9888", "127.0.0.1", 9888)); + BOOST_CHECK(TestSplitHost("[127.0.0.1]:2888", "127.0.0.1", 2888)); BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1)); - BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:9888", "::ffff:127.0.0.1", 9888)); - BOOST_CHECK(TestSplitHost("[::]:9888", "::", 9888)); - BOOST_CHECK(TestSplitHost("::9888", "::9888", -1)); - BOOST_CHECK(TestSplitHost(":9888", "", 9888)); - BOOST_CHECK(TestSplitHost("[]:9888", "", 9888)); + BOOST_CHECK(TestSplitHost("[::ffff:127.0.0.1]:2888", "::ffff:127.0.0.1", 2888)); + BOOST_CHECK(TestSplitHost("[::]:2888", "::", 2888)); + BOOST_CHECK(TestSplitHost("::2888", "::2888", -1)); + BOOST_CHECK(TestSplitHost(":2888", "", 2888)); + BOOST_CHECK(TestSplitHost("[]:2888", "", 2888)); BOOST_CHECK(TestSplitHost("", "", -1)); } @@ -82,10 +82,10 @@ bool static TestParse(string src, string canon) BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) { BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535")); - BOOST_CHECK(TestParse("127.0.0.1:9888", "127.0.0.1:9888")); + BOOST_CHECK(TestParse("127.0.0.1:2888", "127.0.0.1:2888")); BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535")); BOOST_CHECK(TestParse("::", "[::]:65535")); - BOOST_CHECK(TestParse("[::]:9888", "[::]:9888")); + BOOST_CHECK(TestParse("[::]:2888", "[::]:2888")); BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535")); BOOST_CHECK(TestParse(":::", "")); } From 28a3d839c2e1cc794b21e8d4c0b7d3cef60c57e0 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Tue, 21 Aug 2018 17:56:51 +0800 Subject: [PATCH 036/120] Armindev (#8) fix some bug --- src/chainparams.cpp | 2 +- src/rpcclient.cpp | 2 +- src/rpcserver.cpp | 2 +- src/rpcserver.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8d7363d..8b3e176 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -513,7 +513,7 @@ class CRegTestParams : public CChainParams { pchMessageStart[2] = 0xbb; pchMessageStart[3] = 0xd0; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin - nDefaultPort = 29888; + nDefaultPort = 12888; nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 129ef27..24fc280 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -51,7 +51,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getchaintips", 1 }, { "getblockhash", 0 }, { "getblockdifficulty", 0 }, - { "gettotaldifficulty", 0 }, + { "getchainwork", 0 }, { "move", 2 }, { "move", 3 }, { "sendfrom", 2 }, diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 7d0fce9..fd2d6aa 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -289,7 +289,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getchaintips", &getchaintips, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, { "blockchain", "getblockdifficulty", &getblockdifficulty, true }, - { "blockchain", "gettotaldifficulty", &gettotaldifficulty, true }, + { "blockchain", "getchainwork", &getchainwork, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, { "blockchain", "getrawmempool", &getrawmempool, true }, { "blockchain", "gettxout", &gettxout, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 773f8fc..3e1595b 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -279,7 +279,7 @@ extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcbloc extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); extern UniValue getblockdifficulty(const UniValue& params, bool fHelp); -extern UniValue gettotaldifficulty(const UniValue& params, bool fHelp); +extern UniValue getchainwork(const UniValue& params, bool fHelp); extern UniValue settxfee(const UniValue& params, bool fHelp); extern UniValue getmempoolinfo(const UniValue& params, bool fHelp); extern UniValue getrawmempool(const UniValue& params, bool fHelp); From 62638738bc3fdb4526ec358d25d48fcfeaf9b8b3 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 21 Aug 2018 20:39:29 +0800 Subject: [PATCH 037/120] fix rpc bug --- src/rpcblockchain.cpp | 12 ++++++------ src/rpcserver.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 205523d..f8750e4 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -380,19 +380,19 @@ UniValue getblockdifficulty(const UniValue& params, bool fHelp) return GetDifficulty(pblockindex); } -UniValue gettotaldifficulty(const UniValue& params, bool fHelp) +UniValue getchainwork(const UniValue& params, bool fHelp) { if (fHelp || (params.size() != 0 && params.size() != 1)) throw runtime_error( - "gettotaldifficulty index\n" - "\nReturns total difficulty of block in best-block-chain at index provided or tip.\n" + "getchainwork index\n" + "\nReturns chain work of block in best-block-chain at index provided or tip.\n" "\nArguments:\n" "1. index (numeric, optional, default=chainactive tip) The block index\n" "\nResult:\n" - "\"total difficulty\" (string) The block total difficulty\n" + "\"chain work\" (string) The block total difficulty\n" "\nExamples:\n" - + HelpExampleCli("gettotaldifficulty", "1000") - + HelpExampleRpc("gettotaldifficulty", "1000") + + HelpExampleCli("getchainwork", "1000") + + HelpExampleRpc("getchainwork", "1000") ); LOCK(cs_main); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index fd2d6aa..43bd145 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -289,7 +289,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getchaintips", &getchaintips, true }, { "blockchain", "getdifficulty", &getdifficulty, true }, { "blockchain", "getblockdifficulty", &getblockdifficulty, true }, - { "blockchain", "getchainwork", &getchainwork, true }, + { "blockchain", "getchainwork", &getchainwork, true }, { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, { "blockchain", "getrawmempool", &getrawmempool, true }, { "blockchain", "gettxout", &gettxout, true }, From 8b714d49856956926898e55f516e871c98f0917c Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 21 Aug 2018 21:10:51 +0800 Subject: [PATCH 038/120] change the rpc command getblock,getuncleblockheader,getalluncleblock --- src/rest.cpp | 2 +- src/rpcblockchain.cpp | 179 +++++++++++++++++++++--------------------- src/rpcclient.cpp | 1 + src/rpcserver.cpp | 2 +- src/rpcserver.h | 3 +- 5 files changed, 96 insertions(+), 91 deletions(-) diff --git a/src/rest.cpp b/src/rest.cpp index bc6c911..3fc45cf 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -56,7 +56,7 @@ struct CCoin { }; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); -extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false); +extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false, bool uhDetails = false); extern UniValue mempoolInfoToJSON(); extern UniValue mempoolToJSON(bool fVerbose = false); extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f8750e4..2d66454 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -96,7 +96,27 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) return result; } -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) +/*popchain ghost*/ +void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry) +{ + entry.push_back(Pair("hash", blockheader.GetHash().GetHex())); + entry.push_back(Pair("CURRENT_VERSION", blockheader.CURRENT_VERSION)); + entry.push_back(Pair("nVersion", blockheader.nVersion)); + entry.push_back(Pair("hashPrevBlock", blockheader.hashPrevBlock.GetHex())); + entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); + entry.push_back(Pair("nCoinbase", blockheader.nCoinbase.GetHex())); + entry.push_back(Pair("nDifficulty", strprintf("%d", blockheader.nDifficulty))); + entry.push_back(Pair("nNumber", strprintf("%d", blockheader.nNumber))); + entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); + entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); + entry.push_back(Pair("nTime", strprintf("%d", blockheader.nTime))); + entry.push_back(Pair("nBits", strprintf("%08x", blockheader.nBits))); + entry.push_back(Pair("nNonce", blockheader.nNonce.GetHex())); +} + +/*popchain ghost*/ + +UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false, bool uhDetails = false) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); @@ -108,6 +128,11 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); + /*popchain ghost*/ + result.push_back(Pair("hashUncles",block.hashUncles.GetHex())); + result.push_back(Pair("coinbase",block.nCoinbase.GetHex())); + result.push_back(Pair("number",strprintf("%d", block.nNumber))); + /*popchain ghost*/ result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", block.hashClaimTrie.GetHex())); UniValue txs(UniValue::VARR); @@ -125,16 +150,25 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("tx", txs)); /*popchain ghost*/ UniValue uhs(UniValue::VARR); + //uhDetails =true; BOOST_FOREACH(const CBlockHeader&uh, block.vuh) { //UniValue objUh(UniValue::VOBJ); - uhs.push_back(uh.GetHash().GetHex()); + //uhs.push_back(uh.GetHash().GetHex()); //uhs.push_back(uh.ToString()); + if(uhDetails){ + UniValue objUh(UniValue::VOBJ); + uncleblockheaderToJSON(uh,objUh); + uhs.push_back(objUh); + } else{ + uhs.push_back(uh.GetHash().GetHex()); + } } result.push_back(Pair("uh",uhs)); /*popchain ghost*/ result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); + result.push_back(Pair("unclesize",block.vuh.size())); result.push_back(Pair("nonce", block.nNonce.GetHex())); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -148,6 +182,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx return result; } + UniValue getblockcount(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -559,19 +594,24 @@ UniValue getblockheaders(const UniValue& params, bool fHelp) } /*popchain ghost*/ + + UniValue getuncleblockheader(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( - "getblock \"hash\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" + "getuncleblockheader \"hash\" hashuncle\" ( verbose )\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block header 'hash'.\n" "If verbose is true, returns an Object with information about block .\n" "\nArguments:\n" "1. \"hash\" (string, required) The block hash\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "2. \"hashuncle\" (string, required) The uncle block header hash\n" + "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" - " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" + " \"hash\" : \"hash\", (string) the uncle block header hash (same as provided)\n" + " \"CURRENT_VERSION\" : \"CURRENT_VERSION\", (string) the uncle block header CURRENT_VERSION \n" + " \"nVersion\" : \"nVersion\", (string) the uncle block header nVersion \n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" @@ -582,6 +622,10 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) " \"transactionid\" (string) The transaction id\n" " ,...\n" " ],\n" + " \"uh\" : [ (array of string) The uncle block header hash\n" + " \"hash\" (string) The block header hash\n" + " ,...\n" + " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" @@ -603,51 +647,15 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) std::string strHash = params[0].get_str(); uint256 hash(uint256S(strHash)); + std::string strHashUncle = params[1].get_str(); + uint256 hashuncle(uint256S(strHashUncle)); + bool fVerbose = true; - if (params.size() > 1) - fVerbose = params[1].get_bool(); + if (params.size() > 2) + fVerbose = params[2].get_bool(); UniValue result(UniValue::VOBJ); - - const CChainParams& chainparams = Params(); - //std::vector containUncleBlockIndex; - bool bGetUncle = false; - UniValue ucb(UniValue::VARR); - for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ - CBlockIndex* blockindex = (*mi).second; - if(blockindex->hashUncles == uint256()){ - continue; - } - - CBlock block; - if(!ReadBlockFromDisk(block, blockindex, chainparams.GetConsensus())){ - LogPrintf("getuncleblockheader : OpenBlockFile failed for %s ,BlockStatus %d \n",blockindex->GetBlockHash().ToString(),\ - blockindex->nStatus); - LogPrintf("blockhash: %s,pprev: %s,nHeight: %d,nFile: %d,nDataPos: %d,nUndoPos: %d,nChainWork: %s,nTx: %d,nChainTx: %d,nStatus: %d \n",\ - blockindex->GetBlockHash().ToString(),\ - blockindex->pprev->GetBlockHash().ToString(),blockindex->nHeight,\ - blockindex->nFile,blockindex->nDataPos,blockindex->nUndoPos,\ - blockindex->nChainWork.ToString(),blockindex->nTx,blockindex->nChainTx,\ - blockindex->nStatus); - } else{ - //LogPrintf("getuncleblockheader : OpenBlockFile successfor %s ,BlockStatus %d \n",blockindex->GetBlockHash().ToString(),\ - // blockindex->nStatus); - } - std::vector vuh = block.vuh; - for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ - if(hash == (*bi).GetHash()){ - ucb.push_back(block.GetHash().GetHex()); - if(!bGetUncle){ - result.push_back(Pair("uncle", (*bi).ToString())); - bGetUncle = true; - } - } - } - } - result.push_back(Pair("block contain uncle give",ucb)); - -/* if (mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); @@ -660,22 +668,44 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + bool bGetUncle = false; + UniValue objUh(UniValue::VOBJ); + std::vector vuh = block.vuh; + CBlockHeader blockheader; + + for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ + blockheader = (*bi); + //std::cout<<"hashuncle: "< 2) + if (fHelp || params.size() != 0) throw runtime_error( "getblock \"hash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" @@ -714,51 +744,24 @@ UniValue getalluncleblockheader(const UniValue& params, bool fHelp) LOCK(cs_main); - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - - bool fVerbose = true; - if (params.size() > 1) - fVerbose = params[1].get_bool(); - UniValue result(UniValue::VOBJ); const CChainParams& chainparams = Params(); //std::vector containUncleBlockIndex; bool bGetUncle = false; - UniValue ucb(UniValue::VARR); - int uncleCount =0; + //UniValue ucb(UniValue::VARR); + //int uncleCount =0; + int blockcount = 0; for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ CBlockIndex* blockindex = (*mi).second; if(blockindex->hashUncles == uint256()){ continue; } - LogPrintf("block contain uncle: %s\n",blockindex->GetBlockHash().ToString()); - - CBlock block; - if(!ReadBlockFromDisk(block, blockindex, chainparams.GetConsensus())){ - LogPrintf("uncleheader : OpenBlockFile failed for %s \n",blockindex->GetBlockHash().ToString()); - /* - LogPrintf("blockhash: %s,pprev: %s,nHeight: %d,nFile: %d,nDataPos: %d,nUndoPos: %d,nChainWork: %s,nTx: %d,nChainTx: %d,nStatus: %d \n",\ - blockindex->GetBlockHash().ToString(),\ - blockindex->pprev->GetBlockHash().ToString(),blockindex->nHeight,\ - blockindex->nFile,blockindex->nDataPos,blockindex->nUndoPos,\ - blockindex->nChainWork.ToString(),blockindex->nTx,blockindex->nChainTx,\ - blockindex->nStatus); - */ - } else{ - //LogPrintf("uncleheader : OpenBlockFile success for %s \n",blockindex->GetBlockHash().ToString()); - } - std::vector vuh = block.vuh; - for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ - LogPrintf("uncleheader : %s \n",(*bi).ToString()); - //result.push_back(Pair("uncle", (*bi).ToString())); - uncleCount++; - - - } + //LogPrintf("block contain uncle: %s\n",blockindex->GetBlockHash().ToString()); + result.push_back(Pair("blockcotainuncle", blockindex->GetBlockHash().ToString())); + blockcount++; } - result.push_back(Pair("unclesize",uncleCount)); + result.push_back(Pair("blockcount",blockcount)); return result; } diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 24fc280..56a0196 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -123,6 +123,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddressdeltas", 0}, { "getaddressutxos", 0}, { "getaddressmempool", 0}, + { "getuncleblockheader",2}, }; class CRPCConvertTable diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 43bd145..791c1f9 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -279,7 +279,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "getblockcount", &getblockcount, true }, /*popchain ghost*/ { "blockchain", "getuncleblockheader", &getuncleblockheader, true }, - { "blockchain", "getalluncleblockheader", &getalluncleblockheader, true }, + { "blockchain", "getalluncleblock", &getalluncleblock, true }, /*popchain ghost*/ { "blockchain", "getblock", &getblock, true }, { "blockchain", "getblockhashes", &getblockhashes, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 3e1595b..4b2e3f1 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -288,8 +288,9 @@ extern UniValue getblockhash(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblockheaders(const UniValue& params, bool fHelp); /*popchain ghost*/ +extern void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry); extern UniValue getuncleblockheader(const UniValue& params, bool fHelp); -extern UniValue getalluncleblockheader(const UniValue& params, bool fHelp); +extern UniValue getalluncleblock(const UniValue& params, bool fHelp); /*popchain ghost*/ From 15c6fd70765e0c8c0b3f7a3cfbd87f7ee1692e04 Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Wed, 22 Aug 2018 10:24:41 +0800 Subject: [PATCH 039/120] fix a Segmentation fault (#9) --- src/arith_uint256.cpp | 1 - src/chainparams.cpp | 2 -- src/main.cpp | 43 ++++++++++++++++++++----------------------- src/pow.cpp | 4 ++-- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index 5deb05b..b5ebad2 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -262,7 +262,6 @@ arith_uint256 UintToArith256(const uint256 &a) // This calculater the number divide by max uint256 arith_uint256 maxUint256Div(uint64_t &a) { - std::cout<<"difficulty: "<GetBlockHash(); - ReadBlockFromDisk(possibleBlock, pindexPossibleBlock, chainparams.GetConsensus()); - mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); - std::cout<<"ActivateBestChainStep add to possibleUncles block hash: "<GetBlockHash(); + ReadBlockFromDisk(possibleBlock, pindexPossibleBlock, chainparams.GetConsensus()); + mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); +// std::cout<<"ActivateBestChainStep add to possibleUncles block hash: "<GetHash(),*pblock)); +// std::cout<<"ActivateBestChain add to possibleUncles block hash: "<nHeight < params.nYolandaTime){ if (timestampDiff < 15) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; - std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 10, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; - std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< 0); From c9863942b3555a8020f2ffcbf4bba1593a14010d Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Wed, 22 Aug 2018 11:56:10 +0800 Subject: [PATCH 040/120] modify rpc port --- src/chainparamsbase.cpp | 6 +++--- src/rpcserver.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index cbbcdb5..ebbaf88 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -29,7 +29,7 @@ class CBaseMainParams : public CBaseChainParams public: CBaseMainParams() { - nRPCPort = 9889; + nRPCPort = 2889; } }; static CBaseMainParams mainParams; @@ -42,7 +42,7 @@ class CBaseTestNetParams : public CBaseChainParams public: CBaseTestNetParams() { - nRPCPort = 19889; + nRPCPort = 12889; strDataDir = "testnet3"; } }; @@ -56,7 +56,7 @@ class CBaseRegTestParams : public CBaseChainParams public: CBaseRegTestParams() { - nRPCPort = 29889; + nRPCPort = 22889; strDataDir = "regtest"; } }; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 791c1f9..9d7edf3 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -601,7 +601,7 @@ std::string HelpExampleCli(const std::string& methodname, const std::string& arg std::string HelpExampleRpc(const std::string& methodname, const std::string& args) { return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", " - "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:9889/\n"; + "\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:2889/\n"; } void RPCRegisterTimerInterface(RPCTimerInterface *iface) From eda3285c195ff543e2dc81e0950cd88f2fa6b830 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 22 Aug 2018 15:16:20 +0800 Subject: [PATCH 041/120] add the help --- src/rpcblockchain.cpp | 125 ++++++++++++++++++------------------------ src/rpcclient.cpp | 1 + 2 files changed, 54 insertions(+), 72 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 2d66454..7f5dab1 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -609,37 +609,25 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" - " \"hash\" : \"hash\", (string) the uncle block header hash (same as provided)\n" - " \"CURRENT_VERSION\" : \"CURRENT_VERSION\", (string) the uncle block header CURRENT_VERSION \n" - " \"nVersion\" : \"nVersion\", (string) the uncle block header nVersion \n" - " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" - " \"size\" : n, (numeric) The block size\n" - " \"height\" : n, (numeric) The block height or index\n" - " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" - " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" - " \"tx\" : [ (array of string) The transaction ids\n" - " \"transactionid\" (string) The transaction id\n" - " ,...\n" - " ],\n" - " \"uh\" : [ (array of string) The uncle block header hash\n" - " \"hash\" (string) The block header hash\n" - " ,...\n" - " ],\n" - " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" - " \"difficulty\" : x.xxx, (numeric) The difficulty\n" - " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" - " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" - " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + " \"hash\" : \"hash\", (string) the uncle block header hash (same as provided)\n" + " \"CURRENT_VERSION\" : n, (numeric) the uncle block header CURRENT_VERSION \n" + " \"nVersion\" : n, (numeric) the uncle block header nVersion \n" + " \"hashPrevBlock\" : \"hash\", (string) the uncle block header hashPrevBlock \n" + " \"hashUncles\" : \"hash\", (string) the uncle block header hashUncles \n" + " \"nCoinbase\" : \"hash\", (string) the uncle block header nCoinbase \n" + " \"nDifficulty\" : n, (numeric) the uncle block header nDifficulty \n" + " \"nNumber\" : n, (numeric) the uncle block header nNumber \n" + " \"hashMerkleRoot\" : \"hash\", (string) the uncle block header hashMerkleRoot \n" + " \"hashClaimTrie\" : \"hash\", (string) the uncle block header hashClaimTrie \n" + " \"nTime\" : n, (numeric) the uncle block header nTime \n" + " \"nBits\" : n, (hex) the uncle block header nBits \n" + " \"nNonce\" : \"hash\", (string) the uncle block header nNonce \n" "}\n" "\nResult (for verbose=false):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" + "\"data\" (string) A string that is serialized, hex-encoded data for uncle block header 'hash'.\n" "\nExamples:\n" - + HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") - + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + + HelpExampleCli("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 00010cfa2058317dc1b39e64d1cc790d61859e188b6a342ef5e5494cb7ae8e5f") + + HelpExampleRpc("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 00010cfa2058317dc1b39e64d1cc790d61859e188b6a342ef5e5494cb7ae8e5f") ); LOCK(cs_main); @@ -705,64 +693,56 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) UniValue getalluncleblock(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) + if (fHelp || params.size() < 0 || params.size() > 1) throw runtime_error( - "getblock \"hash\" ( verbose )\n" + "getalluncleblock \n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbose is true, returns an Object with information about block .\n" "\nArguments:\n" - "1. \"hash\" (string, required) The block hash\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" - "\nResult (for verbose = true):\n" + "1. fGetAll (boolean, optional, default=true) true for get all block contain uncle, false for main chain block cotain uncle \n" + "\nResult :\n" "{\n" - " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" - " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" - " \"size\" : n, (numeric) The block size\n" - " \"height\" : n, (numeric) The block height or index\n" - " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" - " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" - " \"tx\" : [ (array of string) The transaction ids\n" - " \"transactionid\" (string) The transaction id\n" - " ,...\n" - " ],\n" - " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" - " \"difficulty\" : x.xxx, (numeric) The difficulty\n" - " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" - " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" - " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" + " \"blockcotainuncle\" : \"hash\", (string) the block hash\n" "}\n" - "\nResult (for verbose=false):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" "\nExamples:\n" - + HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") - + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + + HelpExampleCli("getalluncleblock", "") + + HelpExampleRpc("getalluncleblock", "") ); LOCK(cs_main); - + UniValue result(UniValue::VOBJ); + bool fGetAll = true; + if (params.size() > 0) + fGetAll = params[0].get_bool(); - const CChainParams& chainparams = Params(); - //std::vector containUncleBlockIndex; - bool bGetUncle = false; - //UniValue ucb(UniValue::VARR); - //int uncleCount =0; int blockcount = 0; - for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ - CBlockIndex* blockindex = (*mi).second; - if(blockindex->hashUncles == uint256()){ - continue; + CBlockIndex* blockindex; + if(fGetAll){ + for(BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi){ + blockindex = (*mi).second; + if(blockindex->hashUncles == uint256()){ + continue; + } + result.push_back(Pair("blockcotainuncle", blockindex->GetBlockHash().ToString())); + blockcount++; } - //LogPrintf("block contain uncle: %s\n",blockindex->GetBlockHash().ToString()); - result.push_back(Pair("blockcotainuncle", blockindex->GetBlockHash().ToString())); - blockcount++; + } else{ + blockindex = chainActive.Genesis(); + do{ + blockindex = chainActive.Next(blockindex); + + if(blockindex->hashUncles == uint256()){ + continue; + } + //std::cout<GetBlockHash().ToString()<GetBlockHash().ToString())); + blockcount++; + }while(blockindex != chainActive.Tip()); } + result.push_back(Pair("blockcount",blockcount)); - + return result; } @@ -786,14 +766,15 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" - " \"nameclaimroot\" : \"xxxx\", (string) The hash of the root of the name claim trie\n" + " \"merkleroot\" : \"hash\", (string) The merkle root\n" + " \"nameclaimroot\" : \"hash\", (string) The hash of the root of the name claim trie\n" " \"tx\" : [ (array of string) The transaction ids\n" " \"transactionid\" (string) The transaction id\n" " ,...\n" " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"unclesize\" : n, (numeric) The size of block uncle header\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 56a0196..8d7a9ca 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -124,6 +124,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddressutxos", 0}, { "getaddressmempool", 0}, { "getuncleblockheader",2}, + { "getalluncleblock",0}, }; class CRPCConvertTable From 01e450b655585f22d7dbccfa1464a021ca49d6a5 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Wed, 22 Aug 2018 15:56:50 +0800 Subject: [PATCH 042/120] add testnet dns seed --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index bcd2a8e..35f7bd0 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -410,7 +410,7 @@ class CTestNetParams : public CChainParams { vFixedSeeds.clear(); vSeeds.clear(); - //vSeeds.push_back(CDNSSeedData("pop.xxx","testnet-seed1.pop.xxx")); + vSeeds.push_back(CDNSSeedData("popchain.uosio.org","uosrguosio.org")); // Testnet Pop addresses start with 'p' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,118); From 450dc36c410e1b5275719091131472539937ba71 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Wed, 22 Aug 2018 16:11:53 +0800 Subject: [PATCH 043/120] debug --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 35f7bd0..66c8094 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -410,7 +410,7 @@ class CTestNetParams : public CChainParams { vFixedSeeds.clear(); vSeeds.clear(); - vSeeds.push_back(CDNSSeedData("popchain.uosio.org","uosrguosio.org")); + vSeeds.push_back(CDNSSeedData("uosrguosio.org","popchain.uosio.org")); // Testnet Pop addresses start with 'p' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,118); From c75bdacbe3f7c21c2c9aeb2e4360f6bbe11dab64 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Wed, 22 Aug 2018 17:23:48 +0800 Subject: [PATCH 044/120] debug --- src/main.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 9e4775c..820a2b6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4147,13 +4147,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo uint256 hashUncleRoot = BlockUncleRoot(block); if(block.hashUncles != hashUncleRoot){ /*popchain ghost*/ - std::cout<<"bad-uncleshash block.hashUncles: "<::iterator it = dBlock.vuh.begin(); it != dBlock.vuh.end(); ++it){ CBlockHeader blockheader = *it; - std::cout<<" bad-uncleshash block.vuh[]: "<hashUncles != uint256()){ CBlock blockhasuncle = *pblock; - std::cout<<"ProcessNewBlock block have uncles: "< Date: Thu, 23 Aug 2018 16:29:15 +0800 Subject: [PATCH 045/120] add the accept uncle block header function --- src/main.cpp | 92 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 820a2b6..772c8d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4333,48 +4333,79 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return true; } /*popchain ghost*/ -static bool AcceptUnclesHeader(const CBlock & block, CValidationState& state, const CChainParams& chainparams) +static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, const CChainParams& chainparams, bool fCheckPOW = true) { + std::vector blockUncles = block.vuh; + int tmpSize = blockUncles.size(); + if (tmpSize > 2 || tmpSize < 0){ + return false; + } - std::vector blockHeaders = block.vuh; - if (blockHeaders.size() > 2 || blockHeaders.size() < 0) - { - return false; - } - + if(tmpSize ==0 && block.hashUncles == uint256()){ + return true; + } + LogPrintf("AcceptUnclesHeader block:%s \n", block.GetHash().ToString()); + //LogPrintf("AcceptUnclesHeader uncles size: %d \n", tmpSize); - uint256 hashHeaders; - hashHeaders.SetNull(); + //const CChainParams& chainparams = Params(); + std::vector vecAncestor; + if(!GetAncestorBlocksFromHash(block.hashPrevBlock,7,vecAncestor)) + return false; + //LogPrintf("AcceptUnclesHeader vecAncestor size: %d \n", vecAncestor.size()); + + CBlock tmpBlock; + CBlockIndex* tmpBlockIndex; + CBlockHeader tmpBlockHeader; + std::set ancestorset; + std::set unclesset; - if(blockHeaders.size() > 0) - { - vector::iterator it = blockHeaders.begin(); - while( it != blockHeaders.end()) { - CBlockHeader tmpBH = *it; - uint256 tmpHash; - tmpHash.SetNull(); - if(!CheckBlockHeader(tmpBH, state, true)) - { - return false; - } - tmpHash = tmpBH.GetHash(); - CHash256().Write(tmpHash.begin(), 32).Write(hashHeaders.begin(), 32).Finalize(hashHeaders.begin()); - it++; + for(std::vector::iterator it = vecAncestor.begin(); it != vecAncestor.end(); ++it){ + tmpBlockIndex = *it; + if(ReadBlockFromDisk(tmpBlock, tmpBlockIndex, chainparams.GetConsensus())){ + for(std::vector::iterator bi = tmpBlock.vuh.begin(); bi != tmpBlock.vuh.end(); ++bi){ + tmpBlockHeader = *bi; + unclesset.insert(tmpBlockHeader.GetHash()); + //LogPrintf("AcceptUnclesHeader unclesset nNmber: %d , hash:%s \n",tmpBlockHeader.nNumber,tmpBlockHeader.GetHash().ToString()); } + ancestorset.insert(tmpBlockIndex->GetBlockHash()); + //LogPrintf("AcceptUnclesHeader ancestorset nNmber: %d , hash:%s \n",tmpBlockIndex->nNumber,tmpBlockIndex->GetBlockHash().ToString()); + } else{ + return false; } - else - { - return true; - } + } - if(block.hashUncles != hashHeaders) - { + LogPrintf("AcceptUnclesHeader ancestorset size: %d \n", ancestorset.size()); + //LogPrintf("AcceptUnclesHeader unclesset size: %d \n", unclesset.size()); + + for(std::vector::iterator it = blockUncles.begin(); it != blockUncles.end(); ++it){ + tmpBlockHeader = *it; + uint256 tmpHash = tmpBlockHeader.GetHash(); + if(unclesset.count(tmpHash) != 0){ + return false; + } + //LogPrintf("AcceptUnclesHeader unclesset check ok\n"); + if(ancestorset.count(tmpBlockHeader.hashPrevBlock) == 0){ + return false; + } + //LogPrintf("AcceptUnclesHeader ancestorset parent check ok\n"); + if(ancestorset.count(tmpHash) !=0){ return false; } + //LogPrintf("AcceptUnclesHeader ancestorset self check ok\n"); + if(fCheckPOW){ + if(!CheckBlockHeader(tmpBlockHeader,state,fCheckPOW)){ + return false; + } + } + //LogPrintf("AcceptUnclesHeader CheckBlockHeader check ok\n"); + } + + LogPrintf("AcceptUnclesHeader OK \n"); return true; } + /*popchain ghost*/ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex=NULL) @@ -4453,6 +4484,9 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha if (!AcceptBlockHeader(block, state, chainparams, &pindex)) return false; + if(!AcceptUnclesHeader(block, state, chainparams)) + return false; + // Try to process all requested blocks that we don't have, but only // process an unrequested block if it's new and has enough work to // advance our tip, and isn't too many blocks ahead. From ee66c7b18860c214a8efc42e7b926b9bfa0e7bcd Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 24 Aug 2018 16:38:52 +0800 Subject: [PATCH 046/120] add the data to coinbase --- src/main.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/miner.cpp | 49 ++++++++++++++++++++++++++++++++------------ 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 772c8d2..2b99e23 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1789,6 +1789,20 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) } } } +/* +CAmount GetMainMinerSubsidy(const int height, const Consensus::Params &cp, int uc) +{ + if(uc < 0 || uc > 2){ + return 0; + } + CAmount reward = GetMinerSubsidy(height,cp); + return (reward + (reward * uc / 32)); +} + +CAmount GetUncleMinerSubsidey() +*/ + + CAmount GetFoundersReward(const int height, const Consensus::Params &cp) { @@ -4176,6 +4190,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), REJECT_INVALID, "bad-cb-missing"); + /*popchain ghost*/ + uint160 coinBaseAddress; + int addressType; + CScript scriptPubKeyIn = block.vtx[0].vout[0].scriptPubKey; + if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ + if(!(block.nCoinbase == coinBaseAddress) && (block.nNumber!=0)){ + return state.DoS(100, error("CheckBlock(): first tx coinbase not match"), + REJECT_INVALID, "bad-cb-notmatch"); + } + LogPrintf("CheckBlock nNumber: %d nCoinBase match \n",block.nNumber); + } else{ + return state.DoS(100, error("CheckBlock(): first tx coinbase address error"), + REJECT_INVALID, "bad-cb-addresserror"); + } + + /*popchain ghost*/ for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i].IsCoinBase()) return state.DoS(100, error("CheckBlock(): more than one coinbase"), @@ -4318,7 +4348,33 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return state.DoS(10, error("%s: contains a non-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); } } + /*popchain ghost*/ + + uint160 coinBaseAddress; + int addressType; + CScript scriptPubKeyIn; + + if(block.vuh.size() != 0){ + for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ + scriptPubKeyIn = block.vtx[0].vout[uncleCount + 1].scriptPubKey; + if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ + if(!(block.vuh[uncleCount].nCoinbase == coinBaseAddress) && (block.vuh[uncleCount].nNumber!=0)){ + return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase not match"), + REJECT_INVALID, "bad-cb-notmatch"); + } + + LogPrintf("CheckBlock nNumber: %d uncle header %d nCoinBase match \n",block.nNumber,uncleCount); + } else{ + return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase address error"), + REJECT_INVALID, "bad-cb-addresserror"); + } + + } + + } + + /*popchain ghost*/ // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height // if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet): if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)) diff --git a/src/miner.cpp b/src/miner.cpp index dd06a44..1af7549 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -434,6 +434,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s // Compute regular coinbase transaction. txNew.vout[0].nValue = blockReward; + txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; // get some info back to pass to getblocktemplate @@ -447,21 +448,17 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); - // Update block coinbase - pblock->vtx[0] = txNew; - pblocktemplate->vTxFees[0] = -nFees; - - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - /*popchain ghost*/ - pblock->nNumber = pindexPrev->nNumber + 1; - UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); - pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); - //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); - pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); - /*popchain ghost*/ /*popchain ghost*/ + + uint160 coinBaseAddress; + int addressType; + if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ + pblock->nCoinbase = coinBaseAddress; + } else{ + return NULL; + } + std::vector unclesBlock; FindBlockUncles(pblock->hashPrevBlock,unclesBlock); CBlock uncleBlock; @@ -470,13 +467,39 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s uncleBlock = *it; if(uncleCount < 2){ pblock->vuh.push_back(uncleBlock.GetBlockHeader()); + CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); + CAmount nAmount = 1 ; + CTxOut outNew(nAmount,uncleScriptPubKeyIn); + txNew.vout.push_back(outNew); + LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); + } uncleCount++; } + txNew.vout[0].nValue = blockReward - uncleCount; + LogPrintf("createnewblock uncle reward %d \n",uncleCount); + pblock->hashUncles = BlockUncleRoot(*pblock); + /*popchain ghost*/ + // Update block coinbase + pblock->vtx[0] = txNew; + pblocktemplate->vTxFees[0] = -nFees; + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + /*popchain ghost*/ + pblock->nNumber = pindexPrev->nNumber + 1; + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); + //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); + pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); + /*popchain ghost*/ + + + // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); // Clear the top and bottom 16 bits (for local use as thread flags and counters) From 6e077d397afbe7dd8c984d84dfa26480249fa4fc Mon Sep 17 00:00:00 2001 From: arminsu7 <39320652+arminsu7@users.noreply.github.com> Date: Fri, 24 Aug 2018 16:55:10 +0800 Subject: [PATCH 047/120] change test chainparms for test (#10) --- src/chainparams.cpp | 4 ++-- src/pow.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 66c8094..bf4b98b 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -356,10 +356,10 @@ class CTestNetParams : public CChainParams { //consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); consensus.powLimit = uint256S("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); consensus.difficultyBoundDivisor = 2048; - consensus.difficultyRapidFitDivisor = 20; + consensus.difficultyRapidFitDivisor = 50; //consensus.durationLimit = 13; consensus.minimumDifficulty = 4096; - consensus.nYolandaTime = 200; + consensus.nYolandaTime = 500; /* popchain ghost */ consensus.nPowAveragingWindow = 17; diff --git a/src/pow.cpp b/src/pow.cpp index 2dd38ba..9d2ff05 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -32,13 +32,13 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo int32_t const timestampDiff = pblock->nTime - pindex->nTime; if (pindex->nHeight < params.nYolandaTime){ - if (timestampDiff < 15) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; + if (timestampDiff < 30) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; - //std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 10, -99); + int64_t const adjFactor = std::max((pindex->hasUncles() ? 2 : 1) - timestampDiff / 20, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; - //std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< 0); From 0ac9a064378c1c1055636a32f17e9c6f51cf2e51 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Fri, 24 Aug 2018 17:01:49 +0800 Subject: [PATCH 048/120] delete note --- src/pow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index 9d2ff05..b5ebe88 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -34,11 +34,11 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo if (pindex->nHeight < params.nYolandaTime){ if (timestampDiff < 30) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; - std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 20, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; - std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< 0); From 6f477f50c9e493e127e2864f97df4d9ce98fbce4 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 24 Aug 2018 17:52:38 +0800 Subject: [PATCH 049/120] repair some bug --- src/miner.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 1af7549..154abf5 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -448,6 +448,8 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOps); + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); /*popchain ghost*/ @@ -468,7 +470,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s if(uncleCount < 2){ pblock->vuh.push_back(uncleBlock.GetBlockHeader()); CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); - CAmount nAmount = 1 ; + CAmount nAmount = COIN ; CTxOut outNew(nAmount,uncleScriptPubKeyIn); txNew.vout.push_back(outNew); LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); @@ -477,7 +479,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s uncleCount++; } - txNew.vout[0].nValue = blockReward - uncleCount; + txNew.vout[0].nValue = blockReward - (uncleCount * COIN); LogPrintf("createnewblock uncle reward %d \n",uncleCount); pblock->hashUncles = BlockUncleRoot(*pblock); @@ -488,8 +490,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; - // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + /*popchain ghost*/ pblock->nNumber = pindexPrev->nNumber + 1; UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); From fa4234f3d00486d0cb4e4232fda452b15282962e Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sun, 26 Aug 2018 16:29:43 +0800 Subject: [PATCH 050/120] add the uncle reward --- src/main.cpp | 49 ++++++++++++++++++++++++++++++------ src/main.h | 12 ++++++++- src/miner.cpp | 5 ++-- src/popnode-payments.cpp | 5 ++-- src/superblock.cpp | 8 +++--- src/superblock.h | 5 +++- src/test/claimtrie_tests.cpp | 4 ++- 7 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2b99e23..6d7fa9e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1789,19 +1789,32 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) } } } -/* -CAmount GetMainMinerSubsidy(const int height, const Consensus::Params &cp, int uc) + +/*popchain ghost*/ +CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) { if(uc < 0 || uc > 2){ return 0; } CAmount reward = GetMinerSubsidy(height,cp); - return (reward + (reward * uc / 32)); + CAmount ret = (reward + (reward * uc / 32)); + LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d",height,uc,ret); + return ret; } -CAmount GetUncleMinerSubsidey() -*/ +CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) +{ + int diff = uh + 8 - height; + if(diff <= 0){ + return 0; + } + CAmount reward = GetMinerSubsidy(height,cp); + CAmount ret = ( diff * reward / 8); + LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d",height,uh,ret); + return ret; +} +/*popchain ghost*/ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) @@ -1816,10 +1829,27 @@ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) } // return all subsidy -CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp) -{ +/*popchain ghost*/ +//CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp) +CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBlock& block) +{ + /* return GetMinerSubsidy(height, cp) + GetFoundersReward(height, cp); + */ + CAmount ret = GetMainMinerSubsidy(height, cp, block.vuh.size()); + /* + for(std::vector::iterator it = block.vuh.begin(); it != block.vuh.end(); ++it){ + ret += GetUncleMinerSubsidy(height, cp, (*it).nNumber); + } + */ + for(int i = 0;i < block.vuh.size(); i++){ + ret += GetUncleMinerSubsidy(height, cp, block.vuh[i].nNumber); + } + + ret += GetFoundersReward(height, cp); + //LogPrintf("GetBlockSubsidy at height: %d ,hash: s%,amount: %d",height,(*block).GetHash(),ret); + return ret; } bool IsInitialBlockDownload() @@ -3161,7 +3191,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // the peer who sent us this block is missing some data and wasn't able // to recognize that block is actually invalid. // TODO: resync data (both ways?) and try to reprocess this block later. - CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); + /*popchain ghost*/ + //CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); + CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus(), block); + /*popchain ghost*/ std::string strError = ""; if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) { return state.DoS(0, error("ConnectBlock(PCH): %s", strError), REJECT_INVALID, "bad-cb-amount"); diff --git a/src/main.h b/src/main.h index c240a1d..3f052bf 100644 --- a/src/main.h +++ b/src/main.h @@ -413,10 +413,20 @@ bool GetProofForName(const CBlockIndex* pindexProof, const std::string& name, CC bool GetTransaction(const uint256 &hash, CTransaction &tx, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL); +/*popchain ghsot*/ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp); + +CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc); +CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh); + + + CAmount GetFoundersReward(const int height, const Consensus::Params &cp); -CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp); + +//CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp); +CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBlock& block); +/*popchain ghost*/ /** * Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target. diff --git a/src/miner.cpp b/src/miner.cpp index 154abf5..50f1e82 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -470,7 +470,8 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s if(uncleCount < 2){ pblock->vuh.push_back(uncleBlock.GetBlockHeader()); CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); - CAmount nAmount = COIN ; + //CAmount nAmount = COIN ; + CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), uncleBlock.nNumber); CTxOut outNew(nAmount,uncleScriptPubKeyIn); txNew.vout.push_back(outNew); LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); @@ -479,7 +480,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s uncleCount++; } - txNew.vout[0].nValue = blockReward - (uncleCount * COIN); + txNew.vout[0].nValue = nFees + GetMainMinerSubsidy(nHeight, Params().GetConsensus(),uncleCount); LogPrintf("createnewblock uncle reward %d \n",uncleCount); pblock->hashUncles = BlockUncleRoot(*pblock); diff --git a/src/popnode-payments.cpp b/src/popnode-payments.cpp index b6d22a8..2a22630 100644 --- a/src/popnode-payments.cpp +++ b/src/popnode-payments.cpp @@ -30,8 +30,9 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar } // superblocks started - - CAmount nSuperblockMaxValue = CSuperblock::GetPaymentsLimit(nBlockHeight); +/*popchain ghost*/ + CAmount nSuperblockMaxValue = CSuperblock::GetPaymentsLimit(nBlockHeight,block); +/*popchain ghost*/ bool isSuperblockMaxValueMet = (block.vtx[0].GetValueOut() <= nSuperblockMaxValue); if(CSuperblock::IsValidBlockHeight(nBlockHeight)) { diff --git a/src/superblock.cpp b/src/superblock.cpp index 2025036..6766767 100644 --- a/src/superblock.cpp +++ b/src/superblock.cpp @@ -104,15 +104,17 @@ bool CSuperblock::IsValidBlockHeight(int nBlockHeight) // Popchain DevTeam -CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) +/*popchain ghost*/ +//CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) +CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight, const CBlock& block) { const Consensus::Params& consensusParams = Params().GetConsensus(); if(!IsValidBlockHeight(nBlockHeight)) { return 0; } - CAmount nPaymentsLimit = GetBlockSubsidy(nBlockHeight, consensusParams); - LogPrint("gobject", "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); + CAmount nPaymentsLimit = GetBlockSubsidy(nBlockHeight, consensusParams, block); + LogPrintf("gobject", "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); LogPrintf("popchain CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); return nPaymentsLimit; } diff --git a/src/superblock.h b/src/superblock.h index cb21344..5dae330 100644 --- a/src/superblock.h +++ b/src/superblock.h @@ -46,7 +46,10 @@ class CSuperblock CSuperblock(uint256& nHash); static bool IsValidBlockHeight(int nBlockHeight); - static CAmount GetPaymentsLimit(int nBlockHeight); + /*popchain ghost*/ + //static CAmount GetPaymentsLimit(int nBlockHeight); + static CAmount GetPaymentsLimit(int nBlockHeight, const CBlock& block); + /*popchain ghost*/ static bool IsFounderValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward); // may use in the future diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index 7635c88..c6b78b3 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -104,7 +104,9 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) pblock->nTime = chainActive.Tip()->GetBlockTime()+Params().GetConsensus().nPowTargetSpacing; CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.vin[0].scriptSig = CScript() << CScriptNum(unique_block_counter++) << CScriptNum(chainActive.Height()); - txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, chainparams.GetConsensus()); + /*popchain ghost*/ + txCoinbase.vout[0].nValue = GetBlockSubsidy(chainActive.Height() + 1, chainparams.GetConsensus(), *pblock); + /*popchain ghost*/ pblock->vtx[0] = CTransaction(txCoinbase); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); //pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); From 5ae5e8c8eb1443ead4d53ae698c2b1d363571386 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Sun, 26 Aug 2018 16:42:14 +0800 Subject: [PATCH 051/120] debug for testing --- src/chainparams.cpp | 8 ++++---- src/consensus/consensus.h | 2 +- src/consensus/params.h | 2 +- src/pow.cpp | 4 ++-- src/rpcmining.cpp | 3 ++- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index bf4b98b..faa2458 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -230,7 +230,7 @@ class CMainParams : public CChainParams { consensus.minimumDifficulty = 1730830; // minidifficulty for target consensus.nYolandaTime = 172800; /*popchain ghost*/ - consensus.nPowAveragingWindow = 17; + //consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day @@ -345,7 +345,7 @@ class CTestNetParams : public CChainParams { consensus.nSubsidyHalvingInterval = 840960; consensus.nInstantSendKeepLock = 6; consensus.nSuperblockStartBlock = 30; - consensus.nSuperblockCycle = 50; // Superblocks can be issued hourly on testnet + consensus.nSuperblockCycle = 500; // Superblocks can be issued hourly on testnet consensus.nPopnodeMinimumConfirmations = 2; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; @@ -362,7 +362,7 @@ class CTestNetParams : public CChainParams { consensus.nYolandaTime = 500; /* popchain ghost */ - consensus.nPowAveragingWindow = 17; + //consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down //consensus.nPowMaxAdjustUp = 16; // 16% adjustment up //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up @@ -483,7 +483,7 @@ class CRegTestParams : public CChainParams { consensus.BIP34Hash = uint256(); // ghost consensus.powLimit = uint256S("0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"); - consensus.nPowAveragingWindow = 17; + //consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down //consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 61c94e7..226ef2a 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -10,7 +10,7 @@ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ /*popchain ghost*/ //100 to 10 -static const int COINBASE_MATURITY = 10; +static const int COINBASE_MATURITY = 100; /*popchain ghost*/ /** Flags for nSequence and nLockTime locks */ enum { diff --git a/src/consensus/params.h b/src/consensus/params.h index bb7c186..37425f4 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -84,7 +84,7 @@ struct Params { uint64_t minimumDifficulty; /* popchain ghost */ bool fPowAllowMinDifficultyBlocks; - int64_t nPowAveragingWindow; + //int64_t nPowAveragingWindow; bool fPowNoRetargeting; int64_t nPowTargetSpacing; uint32_t nYolandaTime; diff --git a/src/pow.cpp b/src/pow.cpp index b5ebe88..2dd38ba 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -32,11 +32,11 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo int32_t const timestampDiff = pblock->nTime - pindex->nTime; if (pindex->nHeight < params.nYolandaTime){ - if (timestampDiff < 30) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; + if (timestampDiff < 15) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; //std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 20, -99); + int64_t const adjFactor = std::max((pindex->hasUncles() ? 2 : 1) - timestampDiff / 10, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; //std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< pb->nHeight) From 3acdd01d851d16b4ddcd0cbf66f357047cd0841e Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 28 Aug 2018 09:35:58 +0800 Subject: [PATCH 052/120] add vseed --- src/chainparams.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index faa2458..8a949e7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -410,7 +410,10 @@ class CTestNetParams : public CChainParams { vFixedSeeds.clear(); vSeeds.clear(); - vSeeds.push_back(CDNSSeedData("uosrguosio.org","popchain.uosio.org")); + vSeeds.push_back(CDNSSeedData("uosio.org","popchain.uosio.org")); + vSeeds.push_back(CDNSSeedData("uosio.org","popchain2.uosio.org")); + vSeeds.push_back(CDNSSeedData("uosio.org","popchain3.uosio.org")); + vSeeds.push_back(CDNSSeedData("uosio.org","popchain4.uosio.org")); // Testnet Pop addresses start with 'p' base58Prefixes[PUBKEY_ADDRESS] = std::vector(1,118); From e4cfd974794827d0c824bd099fae66f2a45d05ac Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 28 Aug 2018 16:39:57 +0800 Subject: [PATCH 053/120] change the nNumber --- src/cryptopop/PoW.c | 4 ++-- src/hash.h | 6 +++--- src/main.cpp | 36 +++++++++++++----------------------- src/main.h | 3 ++- src/miner.cpp | 11 +++++------ src/primitives/block.cpp | 6 ++---- src/primitives/block.h | 3 --- src/rpcblockchain.cpp | 3 --- src/superblock.cpp | 2 +- src/txdb.cpp | 1 - 10 files changed, 28 insertions(+), 47 deletions(-) diff --git a/src/cryptopop/PoW.c b/src/cryptopop/PoW.c index a592b62..0a35eb8 100644 --- a/src/cryptopop/PoW.c +++ b/src/cryptopop/PoW.c @@ -279,8 +279,8 @@ void testPowFunction(uint8_t *mess, uint32_t messLen, const int64_t iterNum) { #define OUTPUT_BUFFER_SIZE (32 * 1024UL * 1024UL) /*popchain ghost*/ -//140 to 204 -#define MAX_TEST_INPUT_LEN 204 +//140 to 200 +#define MAX_TEST_INPUT_LEN 200 /*popchain ghost*/ #define MAX_OUT_FILE_NAME_LEN 25 diff --git a/src/hash.h b/src/hash.h index 38060f3..c27c57a 100644 --- a/src/hash.h +++ b/src/hash.h @@ -74,9 +74,9 @@ class CryptoPop { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << *pblock; /*popchain ghost*/ - //140 to 204 - assert(ss.size() == 204); - write((uchar *)&ss[0], 204).finalize(hash); + //140 to 200 + assert(ss.size() == 200); + write((uchar *)&ss[0], 200).finalize(hash); /*popchain ghost*/ //view_data_u8("PoW 2", hash, OUTPUT_LEN); } diff --git a/src/main.cpp b/src/main.cpp index 6d7fa9e..83232a8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1838,15 +1838,12 @@ CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBl GetFoundersReward(height, cp); */ CAmount ret = GetMainMinerSubsidy(height, cp, block.vuh.size()); - /* - for(std::vector::iterator it = block.vuh.begin(); it != block.vuh.end(); ++it){ - ret += GetUncleMinerSubsidy(height, cp, (*it).nNumber); - } - */ + int tmpBlockHeight = 0; for(int i = 0;i < block.vuh.size(); i++){ - ret += GetUncleMinerSubsidy(height, cp, block.vuh[i].nNumber); - } - + if(GetBlockHeight(block.vuh[i].hashPrevBlock,tmpBlockHeight)){ + ret += GetUncleMinerSubsidy(height, cp, (tmpBlockHeight + 1)); + } + } ret += GetFoundersReward(height, cp); //LogPrintf("GetBlockSubsidy at height: %d ,hash: s%,amount: %d",height,(*block).GetHash(),ret); return ret; @@ -2631,14 +2628,14 @@ bool GetBlockHash(uint256& hashRet, int nBlockHeight) } /*popchain ghost*/ -bool GetBlockNumber(uint256 hash, uint32_t* number) +bool GetBlockHeight(uint256 hash, int* hight) { LOCK(cs_main); if (hash != uint256()) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end() && (*mi).second) { CBlockIndex* pindex = (*mi).second; - *number = pindex->nNumber; + *hight = pindex->nHeight; return true; } } @@ -4227,12 +4224,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo uint160 coinBaseAddress; int addressType; CScript scriptPubKeyIn = block.vtx[0].vout[0].scriptPubKey; + const CChainParams& chainparams = Params(); if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ - if(!(block.nCoinbase == coinBaseAddress) && (block.nNumber!=0)){ + if(!(block.nCoinbase == coinBaseAddress) && (block.GetHash() != chainparams.hashGenesisBlock)){ return state.DoS(100, error("CheckBlock(): first tx coinbase not match"), REJECT_INVALID, "bad-cb-notmatch"); } - LogPrintf("CheckBlock nNumber: %d nCoinBase match \n",block.nNumber); + LogPrintf("CheckBlock hash: %s nCoinBase match \n",block.GetHash()); } else{ return state.DoS(100, error("CheckBlock(): first tx coinbase address error"), REJECT_INVALID, "bad-cb-addresserror"); @@ -4323,10 +4321,6 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta LogPrintf("check block header height %d \n", nHeight); /*popchain ghost*/ - // check nNumber against prev - if (block.nNumber != (pindexPrev->nNumber+ 1)) - return state.DoS(100, error("%s : incorrect nNumber at %d", __func__, nHeight), - REJECT_INVALID, "bad-nNumber"); // Check proof of work //if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams)) @@ -4391,12 +4385,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ scriptPubKeyIn = block.vtx[0].vout[uncleCount + 1].scriptPubKey; if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ - if(!(block.vuh[uncleCount].nCoinbase == coinBaseAddress) && (block.vuh[uncleCount].nNumber!=0)){ + const CChainParams& chainparams = Params(); + if(!(block.vuh[uncleCount].nCoinbase == coinBaseAddress) && (block.GetHash != chainparams.hashGenesisBlock)){ return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase not match"), REJECT_INVALID, "bad-cb-notmatch"); } - LogPrintf("CheckBlock nNumber: %d uncle header %d nCoinBase match \n",block.nNumber,uncleCount); + LogPrintf("CheckBlock hash: %d uncle header %d nCoinBase match \n",block.GetHash().ToString()); } else{ return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase address error"), @@ -6591,11 +6586,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } /*popchain ghost*/ - if (pindexLast != NULL && header.nNumber != (pindexLast->nNumber + 1)) { - Misbehaving(pfrom->GetId(), 20); - return error("non-continuous headers number"); - } - if (!AcceptBlockHeader(header, state, chainparams, &pindexLast)) { int nDoS; if (state.IsInvalid(nDoS)) { diff --git a/src/main.h b/src/main.h index 3f052bf..34bf5d4 100644 --- a/src/main.h +++ b/src/main.h @@ -1062,7 +1062,8 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para bool GetBlockHash(uint256& hashRet, int nBlockHeight = -1); /*popchain ghost*/ -bool GetBlockNumber(uint256 hash, uint32_t* number); +bool GetBlockHeight(uint256 hash, int* hight); + bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi); bool MakeCurrentCycle(uint256 hash); bool CommitUncle(CBlockHeader uncle); diff --git a/src/miner.cpp b/src/miner.cpp index 50f1e82..bbe026f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -470,8 +470,11 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s if(uncleCount < 2){ pblock->vuh.push_back(uncleBlock.GetBlockHeader()); CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); - //CAmount nAmount = COIN ; - CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), uncleBlock.nNumber); + int tmpBlockHeight = 0; + if(!GetBlockHeight(uncleBlock.hashPrevBlock,tmpBlockHeight)){ + return NULL; + } + CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); CTxOut outNew(nAmount,uncleScriptPubKeyIn); txNew.vout.push_back(outNew); LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); @@ -493,7 +496,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s /*popchain ghost*/ - pblock->nNumber = pindexPrev->nNumber + 1; UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); @@ -538,9 +540,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - /*popchain ghost*/ - //pblock->nNumber = pindexPrev->nNumber + 1; - /*popchain ghost*/ CMutableTransaction txCoinbase(pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 241f6f4..f77d207 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -26,13 +26,12 @@ std::string CBlockHeader::ToString() const { /*popchain ghost*/ std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(), nCoinbase.ToString(),/*need change by base58 ?*/ - nNumber, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, @@ -45,13 +44,12 @@ std::string CBlockHeader::ToString() const std::string CBlock::ToString() const { std::stringstream s; - s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, nNumber=%u, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", + s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashUncles=%s, nCoinbase=%s, hashMerkleRoot=%s, hashClaimTrie=%s, nTime=%u, nDifficulty=%u, nBits=%08x, nNonce=%s, vtx=%u, vuh=%u)\n", GetHash().ToString(), nVersion, hashPrevBlock.ToString(), hashUncles.ToString(),/*popchain ghost*/ nCoinbase.ToString(),/*popchain ghost*/ - nNumber,/*popchain ghost*/ hashMerkleRoot.ToString(), hashClaimTrie.ToString(), nTime, diff --git a/src/primitives/block.h b/src/primitives/block.h index 1023738..6157c2a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -25,7 +25,6 @@ class CBlockHeader uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 nCoinbase;//the autor address of this block header uint64_t nDifficulty;//the difficulty of this block - uint32_t nNumber;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; // for claim operation @@ -49,7 +48,6 @@ class CBlockHeader READWRITE(hashUncles); READWRITE(nCoinbase); READWRITE(nDifficulty); - READWRITE(nNumber); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); @@ -66,7 +64,6 @@ class CBlockHeader hashUncles.SetNull(); nCoinbase.SetNull(); nDifficulty = 0; - nNumber=0; /*popchain ghost*/ hashMerkleRoot.SetNull(); hashClaimTrie.SetNull(); diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 7f5dab1..77c9b3f 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -106,7 +106,6 @@ void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry) entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); entry.push_back(Pair("nCoinbase", blockheader.nCoinbase.GetHex())); entry.push_back(Pair("nDifficulty", strprintf("%d", blockheader.nDifficulty))); - entry.push_back(Pair("nNumber", strprintf("%d", blockheader.nNumber))); entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); entry.push_back(Pair("nTime", strprintf("%d", blockheader.nTime))); @@ -131,7 +130,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx /*popchain ghost*/ result.push_back(Pair("hashUncles",block.hashUncles.GetHex())); result.push_back(Pair("coinbase",block.nCoinbase.GetHex())); - result.push_back(Pair("number",strprintf("%d", block.nNumber))); /*popchain ghost*/ result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", block.hashClaimTrie.GetHex())); @@ -616,7 +614,6 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) " \"hashUncles\" : \"hash\", (string) the uncle block header hashUncles \n" " \"nCoinbase\" : \"hash\", (string) the uncle block header nCoinbase \n" " \"nDifficulty\" : n, (numeric) the uncle block header nDifficulty \n" - " \"nNumber\" : n, (numeric) the uncle block header nNumber \n" " \"hashMerkleRoot\" : \"hash\", (string) the uncle block header hashMerkleRoot \n" " \"hashClaimTrie\" : \"hash\", (string) the uncle block header hashClaimTrie \n" " \"nTime\" : n, (numeric) the uncle block header nTime \n" diff --git a/src/superblock.cpp b/src/superblock.cpp index 6766767..895b336 100644 --- a/src/superblock.cpp +++ b/src/superblock.cpp @@ -114,7 +114,7 @@ CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight, const CBlock& block) return 0; } CAmount nPaymentsLimit = GetBlockSubsidy(nBlockHeight, consensusParams, block); - LogPrintf("gobject", "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); + LogPrint("gobject", "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); LogPrintf("popchain CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); return nPaymentsLimit; } diff --git a/src/txdb.cpp b/src/txdb.cpp index 6de4fee..99b4a4a 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -332,7 +332,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->hashUncles = diskindex.hashUncles; pindexNew->nCoinbase = diskindex.nCoinbase; pindexNew->nDifficulty = diskindex.nDifficulty; - pindexNew->nNumber = diskindex.nNumber; /*popchain ghost*/ pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->hashClaimTrie = diskindex.hashClaimTrie; From 5292c906b612429361f5a42fbabb27cecd4d4844 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 28 Aug 2018 19:05:50 +0800 Subject: [PATCH 054/120] repair bug --- src/chain.h | 3 --- src/chainparams.cpp | 21 ++++++++++----------- src/cryptopop/common.h | 4 ++-- src/main.cpp | 9 +++++---- src/miner.cpp | 2 +- src/primitives/block.h | 1 - 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/chain.h b/src/chain.h index c819d00..a754c16 100644 --- a/src/chain.h +++ b/src/chain.h @@ -193,7 +193,6 @@ class CBlockIndex hashUncles = block.hashUncles; nCoinbase = block.nCoinbase; nDifficulty = block.nDifficulty; - nNumber = block.nNumber; /*popchain ghost*/ hashMerkleRoot = block.hashMerkleRoot; hashClaimTrie = block.hashClaimTrie; @@ -230,7 +229,6 @@ class CBlockIndex block.hashUncles = hashUncles; block.nCoinbase = nCoinbase; block.nDifficulty = nDifficulty; - block.nNumber = nNumber; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; @@ -386,7 +384,6 @@ class CDiskBlockIndex : public CBlockIndex block.hashUncles = hashUncles; block.nCoinbase = nCoinbase; block.nDifficulty = nDifficulty; - block.nNumber = nNumber; /*popchain ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8a949e7..be5da04 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -145,7 +145,6 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi /*popchain ghost*/ genesis.hashUncles.SetNull(); genesis.nCoinbase.SetNull(); - genesis.nNumber = 0; genesis.vuh.clear(); genesis.hashUncles = BlockUncleRoot(genesis); /*popchain ghost*/ @@ -263,7 +262,7 @@ class CMainParams : public CChainParams { nPruneAfterHeight = 100000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock1(1533916035, uint256S("0x0000bdefbb1cb97e50d2ac4c9cda0e61195d01d3441180448453fc484ce51ed5"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, consensus.genesisReward); + genesis = CreateGenesisBlock1(1535450353, uint256S("0x0000822e5bbe1008065a348e3d2e3e846076a26172ce25659b1e37f6ed1e699c"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, consensus.genesisReward); /*popchain ghost*/ #ifdef GENESIS_GENERATION //arith_uint256 a("0x000009b173000000000000000000000000000000000000000000000000000000"); @@ -275,7 +274,7 @@ class CMainParams : public CChainParams { #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); - assert(consensus.hashGenesisBlock == uint256S("0x000004cb6f548cb60b082d814aaf7172101f85b8fd5a0bf5a8677a358ce7a60d")); + assert(consensus.hashGenesisBlock == uint256S("0x00000405ea05415dea82707713f47fe9bb40f877602b32f8b9303369c6040705")); assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); // Pop addresses start with 'P' @@ -308,7 +307,7 @@ class CMainParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("0x000004cb6f548cb60b082d814aaf7172101f85b8fd5a0bf5a8677a358ce7a60d")), + (0, uint256S("0x00000405ea05415dea82707713f47fe9bb40f877602b32f8b9303369c6040705")), 0, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) @@ -393,7 +392,7 @@ class CTestNetParams : public CChainParams { /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); //genesis = CreateGenesisBlock(1529894661, uint256S("0000374f752799accf0ae43870b1764e17fc0e4a45ebd19adb80597bf0c30097"), nTempBit.GetCompact(), 1, 1 * COIN); - genesis = CreateGenesisBlock(1529894661, uint256S("0x00006410bb8e706a7f96be15cb4217e7f9b1a4fe1000b0f2bab3f03cdbc60047"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0x00005f1403ee998d921de9a0d0b5d53a9a37ef9f58d9cefb8ae1936ae07c00e8"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION @@ -405,7 +404,7 @@ class CTestNetParams : public CChainParams { #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("00077ade31e190b0dccd194c02c8e84bf77db7d037d8a8c3c2c82f89145e3e0a")); - assert(consensus.hashGenesisBlock == uint256S("0x0008247432537c397b0144615ee72ea2aca440079b749d288f1c47c387b71511")); + assert(consensus.hashGenesisBlock == uint256S("0x0009d363a3cb4f69655dc06f4fcd8f648b38e0b35ca545fb05f21f2e1f2ba92d")); assert(genesis.hashMerkleRoot == uint256S("0x6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); vFixedSeeds.clear(); @@ -442,7 +441,7 @@ class CTestNetParams : public CChainParams { checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("0x0008247432537c397b0144615ee72ea2aca440079b749d288f1c47c387b71511")), + (0, uint256S("0x0009d363a3cb4f69655dc06f4fcd8f648b38e0b35ca545fb05f21f2e1f2ba92d")), 0, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) @@ -518,14 +517,14 @@ class CRegTestParams : public CChainParams { nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock1(1529894661, uint256S("0x00009d7ffdffdfe3f6b2f57630e2ac492738972c1ae580e4faea92ff03e90001"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock1(1529894661, uint256S("0x0000ced7958e0eb78a0af58fde4dac17e48b249ff4f838cec072d47bbdf20000"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION - //findGenesis(&genesis, "regtest"); + findGenesis(&genesis, "regtest"); #endif consensus.hashGenesisBlock = genesis.GetHash(); //assert(consensus.hashGenesisBlock == uint256S("01bb1c4d83e5cd73ad4fe568fa2b50469d33def5703dca7e90e06f32f273b95d")); - assert(consensus.hashGenesisBlock == uint256S("0x00c7cf91fa452792f50bc2f15cb37e439174e1ee741888b8d12cd258d15f874c")); + assert(consensus.hashGenesisBlock == uint256S("0x09e79432d30ea2703e8e701d3d2885e56dd350c7e584a8cf4cc04998c1f99956")); assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. @@ -541,7 +540,7 @@ class CRegTestParams : public CChainParams { checkpointData = (CCheckpointData){ boost::assign::map_list_of - (0, uint256S("0x00c7cf91fa452792f50bc2f15cb37e439174e1ee741888b8d12cd258d15f874c")), + (0, uint256S("0x09e79432d30ea2703e8e701d3d2885e56dd350c7e584a8cf4cc04998c1f99956")), 0, 0, 0 diff --git a/src/cryptopop/common.h b/src/cryptopop/common.h index 6e36d6c..cd76e6a 100644 --- a/src/cryptopop/common.h +++ b/src/cryptopop/common.h @@ -11,8 +11,8 @@ #endif /*popchain ghost*/ -//114 to 204 -#define INPUT_LEN 204 +//114 to 200 +#define INPUT_LEN 200 /*popchain ghsot*/ #define OUTPUT_LEN 32 diff --git a/src/main.cpp b/src/main.cpp index 83232a8..0fd4053 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1840,7 +1840,7 @@ CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBl CAmount ret = GetMainMinerSubsidy(height, cp, block.vuh.size()); int tmpBlockHeight = 0; for(int i = 0;i < block.vuh.size(); i++){ - if(GetBlockHeight(block.vuh[i].hashPrevBlock,tmpBlockHeight)){ + if(GetBlockHeight(block.vuh[i].hashPrevBlock,&tmpBlockHeight)){ ret += GetUncleMinerSubsidy(height, cp, (tmpBlockHeight + 1)); } } @@ -4221,12 +4221,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return state.DoS(100, error("CheckBlock(): first tx is not coinbase"), REJECT_INVALID, "bad-cb-missing"); /*popchain ghost*/ + /* uint160 coinBaseAddress; int addressType; CScript scriptPubKeyIn = block.vtx[0].vout[0].scriptPubKey; const CChainParams& chainparams = Params(); if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ - if(!(block.nCoinbase == coinBaseAddress) && (block.GetHash() != chainparams.hashGenesisBlock)){ + if(!(block.nCoinbase == coinBaseAddress) && (block.GetHash() != chainparams.GetConsensus().hashGenesisBlock)){ return state.DoS(100, error("CheckBlock(): first tx coinbase not match"), REJECT_INVALID, "bad-cb-notmatch"); } @@ -4235,7 +4236,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return state.DoS(100, error("CheckBlock(): first tx coinbase address error"), REJECT_INVALID, "bad-cb-addresserror"); } - + */ /*popchain ghost*/ for (unsigned int i = 1; i < block.vtx.size(); i++) if (block.vtx[i].IsCoinBase()) @@ -4386,7 +4387,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn scriptPubKeyIn = block.vtx[0].vout[uncleCount + 1].scriptPubKey; if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ const CChainParams& chainparams = Params(); - if(!(block.vuh[uncleCount].nCoinbase == coinBaseAddress) && (block.GetHash != chainparams.hashGenesisBlock)){ + if(!(block.vuh[uncleCount].nCoinbase == coinBaseAddress) && (nHeight != 0)){ return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase not match"), REJECT_INVALID, "bad-cb-notmatch"); } diff --git a/src/miner.cpp b/src/miner.cpp index bbe026f..229eb1d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -471,7 +471,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->vuh.push_back(uncleBlock.GetBlockHeader()); CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); int tmpBlockHeight = 0; - if(!GetBlockHeight(uncleBlock.hashPrevBlock,tmpBlockHeight)){ + if(!GetBlockHeight(uncleBlock.hashPrevBlock,&tmpBlockHeight)){ return NULL; } CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); diff --git a/src/primitives/block.h b/src/primitives/block.h index 6157c2a..a80a0c2 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -146,7 +146,6 @@ class CBlock : public CBlockHeader block.hashUncles = hashUncles; block.nCoinbase = nCoinbase; block.nDifficulty = nDifficulty; - block.nNumber = nNumber; /*popchian ghost*/ block.hashMerkleRoot = hashMerkleRoot; block.hashClaimTrie = hashClaimTrie; From 04eb1d74019e2bce4c4c45b064185bc362a98d26 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 28 Aug 2018 20:52:14 +0800 Subject: [PATCH 055/120] add some log print --- src/main.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0fd4053..6830274 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1798,7 +1798,7 @@ CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) } CAmount reward = GetMinerSubsidy(height,cp); CAmount ret = (reward + (reward * uc / 32)); - LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d",height,uc,ret); + LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); return ret; } @@ -1810,7 +1810,7 @@ CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) } CAmount reward = GetMinerSubsidy(height,cp); CAmount ret = ( diff * reward / 8); - LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d",height,uh,ret); + LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); return ret; } @@ -1823,8 +1823,10 @@ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) const int end = cp.endOfFoundersReward(); if (height >= beg && height < end) // before super block starting { + LogPrintf("GetFoundersReward at height: %d, amount: %d \n",height,cp.foundersReward); return cp.foundersReward; } + LogPrintf("GetFoundersReward at height: %d, amount: 0 \n",height); return 0; } @@ -4392,7 +4394,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn REJECT_INVALID, "bad-cb-notmatch"); } - LogPrintf("CheckBlock hash: %d uncle header %d nCoinBase match \n",block.GetHash().ToString()); + LogPrintf("CheckBlock hash: %s nCoinBase match \n",block.GetHash().ToString()); } else{ return state.DoS(100, error("CheckBlock(): first tx uncle header coinbase address error"), From 6b28c9ba0c28edd314d86d23671ede0d78c31557 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 28 Aug 2018 21:31:35 +0800 Subject: [PATCH 056/120] remove the nNumber --- src/chain.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/chain.h b/src/chain.h index a754c16..25f5bff 100644 --- a/src/chain.h +++ b/src/chain.h @@ -139,7 +139,6 @@ class CBlockIndex uint256 hashUncles;//the hash256 of uncles or uncle block header uint160 nCoinbase;//the autor address of this block header uint64_t nDifficulty;//the difficulty of this block header - unsigned int nNumber;//the height of this block header /*popchain ghost*/ uint256 hashMerkleRoot; uint256 hashClaimTrie; @@ -170,7 +169,6 @@ class CBlockIndex hashUncles = uint256(); nCoinbase = uint160(); nDifficulty = 0; - nNumber = 0; /*popchain ghost*/ hashMerkleRoot = uint256(); hashClaimTrie = uint256(); @@ -267,12 +265,11 @@ class CBlockIndex std::string ToString() const { /*popchain ghost*/ - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, nCoinbase=%s, nDifficulty=%u, nNumber=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, hashUncles=%s, nCoinbase=%s, nDifficulty=%u, merkle=%s, claimtrie=%s, hashBlock=%s)", pprev, nHeight, hashUncles.ToString(), nCoinbase.ToString(), nDifficulty, - nNumber, hashMerkleRoot.ToString(), hashClaimTrie.ToString(), GetBlockHash().ToString()); @@ -364,7 +361,6 @@ class CDiskBlockIndex : public CBlockIndex READWRITE(hashUncles); READWRITE(nCoinbase); READWRITE(nDifficulty); - READWRITE(nNumber); /*popchain ghost*/ READWRITE(hashMerkleRoot); READWRITE(hashClaimTrie); From 0e914d2c60dcf1a723dadcda661f9482845e8908 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 29 Aug 2018 11:59:55 +0800 Subject: [PATCH 057/120] improve the the uncle block header coinbase check --- src/chainparams.cpp | 2 +- src/main.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index be5da04..5f5646e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -344,7 +344,7 @@ class CTestNetParams : public CChainParams { consensus.nSubsidyHalvingInterval = 840960; consensus.nInstantSendKeepLock = 6; consensus.nSuperblockStartBlock = 30; - consensus.nSuperblockCycle = 500; // Superblocks can be issued hourly on testnet + consensus.nSuperblockCycle = 30; // Superblocks can be issued hourly on testnet consensus.nPopnodeMinimumConfirmations = 2; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; diff --git a/src/main.cpp b/src/main.cpp index 6830274..c28323c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4381,9 +4381,46 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn /*popchain ghost*/ uint160 coinBaseAddress; + uint160 tmpAddress; int addressType; CScript scriptPubKeyIn; - + CAmount tmpAmount = 0; + int tmpBlockHeight = 0; + CAmount tmpSubAmount =0; + const CChainParams& chainparams = Params(); + + if(block.vuh.size() != 0 && nHeight != 0){ + for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ + coinBaseAddress = block.vuh[uncleCount].nCoinbase; + for (const CTxOut &out: block.vtx[0].vout){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ + if(coinBaseAddress == tmpAddress){ + tmpAmount += out.nValue; + } + } else{ + LogPrintf("CheckBlock():ERROR DecodeAddressHash uncle header %d error \n",uncleCount); + return false; + } + } + if(GetBlockHeight(block.vuh[uncleCount].hashPrevBlock,&tmpBlockHeight)){ + tmpSubAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); + } else{ + LogPrintf("CheckBlock():ERROR GetBlockHeight uncle header %d error \n",uncleCount); + return false; + } + if(tmpAmount >= tmpSubAmount){ + LogPrintf("CheckBlock(): %d uncle header coinbase match \n",uncleCount); + } else{ + LogPrintf("CheckBlock():ERROR %d uncle header coinbase not match \n",uncleCount); + return false; + } + tmpAmount = 0; + tmpBlockHeight = 0; + tmpSubAmount =0; + } + } + + /* if(block.vuh.size() != 0){ for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ scriptPubKeyIn = block.vtx[0].vout[uncleCount + 1].scriptPubKey; @@ -4404,6 +4441,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } } + + */ /*popchain ghost*/ // Enforce block.nVersion=2 rule that the coinbase starts with serialized block height From b7d16f47583913a6837938e1cc8751cb6a11a79c Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 1 Sep 2018 16:23:27 +0800 Subject: [PATCH 058/120] change super block payment check --- src/main.cpp | 2 +- src/popnode-payments.cpp | 4 ++-- src/popnode-payments.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c28323c..e3828ab 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3195,7 +3195,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus(), block); /*popchain ghost*/ std::string strError = ""; - if (!IsBlockValueValid(block, pindex->nHeight, blockReward, strError)) { + if (!IsBlockValueValid(block, pindex->nHeight,nFees, blockReward, strError)) { return state.DoS(0, error("ConnectBlock(PCH): %s", strError), REJECT_INVALID, "bad-cb-amount"); } diff --git a/src/popnode-payments.cpp b/src/popnode-payments.cpp index 2a22630..efbfda1 100644 --- a/src/popnode-payments.cpp +++ b/src/popnode-payments.cpp @@ -13,7 +13,7 @@ #include // Popchain DevTeam -bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string &strErrorRet) +bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount nFees,CAmount blockReward, std::string &strErrorRet) { strErrorRet = ""; bool isBlockRewardValueMet = (block.vtx[0].GetValueOut() <= blockReward); @@ -33,7 +33,7 @@ bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockRewar /*popchain ghost*/ CAmount nSuperblockMaxValue = CSuperblock::GetPaymentsLimit(nBlockHeight,block); /*popchain ghost*/ - bool isSuperblockMaxValueMet = (block.vtx[0].GetValueOut() <= nSuperblockMaxValue); + bool isSuperblockMaxValueMet = (block.vtx[0].GetValueOut() <= (nSuperblockMaxValue+nFees)); if(CSuperblock::IsValidBlockHeight(nBlockHeight)) { if(CSuperblock::IsFounderValid( block.vtx[0], nBlockHeight, blockReward )==false) diff --git a/src/popnode-payments.h b/src/popnode-payments.h index deef6d1..d2aef75 100644 --- a/src/popnode-payments.h +++ b/src/popnode-payments.h @@ -10,7 +10,7 @@ #include "popnode.h" #include "utilstrencodings.h" -bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount blockReward, std::string &strErrorRet); +bool IsBlockValueValid(const CBlock& block, int nBlockHeight, CAmount nFees, CAmount blockReward, std::string &strErrorRet); bool IsBlockPayeeValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward); void FillBlockPayments(CMutableTransaction& txNew, int nBlockHeight, CAmount blockReward, CTxOut& txoutFound); From fd272e8b41a03ddf6dde88c6bb624b0b7b3649a3 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 14:11:22 +0800 Subject: [PATCH 059/120] add some log print --- src/main.cpp | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e3828ab..f386adf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2621,7 +2621,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para bool GetBlockHash(uint256& hashRet, int nBlockHeight) { - LOCK(cs_main); + //LOCK(cs_main); if(chainActive.Tip() == NULL) return false; if(nBlockHeight < -1 || nBlockHeight > chainActive.Height()) return false; if(nBlockHeight == -1) nBlockHeight = chainActive.Height(); @@ -2632,7 +2632,7 @@ bool GetBlockHash(uint256& hashRet, int nBlockHeight) /*popchain ghost*/ bool GetBlockHeight(uint256 hash, int* hight) { - LOCK(cs_main); + //LOCK(cs_main); if (hash != uint256()) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end() && (*mi).second) { @@ -2645,7 +2645,7 @@ bool GetBlockHeight(uint256 hash, int* hight) } bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi) { - LOCK(cs_main); + //LOCK(cs_main); LogPrintf("GetAncestorBlocksFromHash \n"); //uint32_t number=0; if(hash == uint256()) @@ -2666,7 +2666,7 @@ bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vC bool MakeCurrentCycle(uint256 hash) { - LOCK(cs_main); + //LOCK(cs_main); LogPrintf("MakeCurrentCycle \n"); if(hash == uint256()) return false; @@ -2682,13 +2682,16 @@ bool MakeCurrentCycle(uint256 hash) CBlockHeader blockheader; for(std::vector::iterator it = ancestor.begin(); it != ancestor.end(); ++it){ pBlockIndex = *it; - ReadBlockFromDisk(block, pBlockIndex, chainparams.GetConsensus()); - for(std::vector::iterator bi = block.vuh.begin(); bi != block.vuh.end(); ++bi){ - blockheader = *bi; - setCurrentFamily.insert(blockheader.GetHash()); + LogPrintf("MakeCurrentCycle():ReadBlockFromDisk %s", pBlockIndex->GetBlockHash().ToString()); + if(ReadBlockFromDisk(block, pBlockIndex, chainparams.GetConsensus())){ + for(std::vector::iterator bi = block.vuh.begin(); bi != block.vuh.end(); ++bi){ + blockheader = *bi; + setCurrentFamily.insert(blockheader.GetHash()); + } + setCurrentFamily.insert(block.GetHash()); + setCurrentAncestor.insert(block.GetHash()); } - setCurrentFamily.insert(block.GetHash()); - setCurrentAncestor.insert(block.GetHash()); + return false; } currentParenthash = hash; return true; @@ -2696,7 +2699,7 @@ bool MakeCurrentCycle(uint256 hash) bool CommitUncle(CBlockHeader uncle) { - LOCK(cs_main); + //LOCK(cs_main); LogPrintf("CommitUncle \n"); uint256 hash = uncle.GetHash(); if(setCurrentUncle.count(hash) != 0){ @@ -4452,6 +4455,9 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn CScript expect = CScript() << nHeight; if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + /*popchain ghost*/ + LogPrintf("ContextualCheckBlock():nHeighet %d,vin[0].scriptSig %s,expect %s,\n", nHeight, HexStr(block.vtx[0].vin[0].scriptSig), HexStr(expect)); + /*popchain ghost*/ return state.DoS(100, error("%s: block height mismatch in coinbase", __func__), REJECT_INVALID, "bad-cb-height"); } } @@ -4474,6 +4480,7 @@ static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, co //LogPrintf("AcceptUnclesHeader uncles size: %d \n", tmpSize); //const CChainParams& chainparams = Params(); + LogPrintf("AcceptUnclesHeader() GetAncestorBlocksFromHash block.hashPrevBlock %s \n", block.hashPrevBlock.ToString()); std::vector vecAncestor; if(!GetAncestorBlocksFromHash(block.hashPrevBlock,7,vecAncestor)) return false; From 3f858efbcc5f1d18b48165065ef2e8077ad2712a Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 14:25:19 +0800 Subject: [PATCH 060/120] add some print --- src/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index f386adf..430ac2b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2645,7 +2645,7 @@ bool GetBlockHeight(uint256 hash, int* hight) } bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi) { - //LOCK(cs_main); + LOCK(cs_main); LogPrintf("GetAncestorBlocksFromHash \n"); //uint32_t number=0; if(hash == uint256()) @@ -2690,8 +2690,10 @@ bool MakeCurrentCycle(uint256 hash) } setCurrentFamily.insert(block.GetHash()); setCurrentAncestor.insert(block.GetHash()); + }else { + return false; } - return false; + } currentParenthash = hash; return true; @@ -4495,6 +4497,7 @@ static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, co for(std::vector::iterator it = vecAncestor.begin(); it != vecAncestor.end(); ++it){ tmpBlockIndex = *it; + LogPrintf("AcceptUnclesHeader():ReadBlockFromDisk %s", tmpBlockIndex->GetBlockHash().ToString()); if(ReadBlockFromDisk(tmpBlock, tmpBlockIndex, chainparams.GetConsensus())){ for(std::vector::iterator bi = tmpBlock.vuh.begin(); bi != tmpBlock.vuh.end(); ++bi){ tmpBlockHeader = *bi; From d4a1e6a1209007708048c2f6860497970ddb1e95 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 16:02:23 +0800 Subject: [PATCH 061/120] repair some bug --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 430ac2b..1b9ec10 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2682,7 +2682,7 @@ bool MakeCurrentCycle(uint256 hash) CBlockHeader blockheader; for(std::vector::iterator it = ancestor.begin(); it != ancestor.end(); ++it){ pBlockIndex = *it; - LogPrintf("MakeCurrentCycle():ReadBlockFromDisk %s", pBlockIndex->GetBlockHash().ToString()); + LogPrintf("MakeCurrentCycle():ReadBlockFromDisk %s \n", pBlockIndex->GetBlockHash().ToString()); if(ReadBlockFromDisk(block, pBlockIndex, chainparams.GetConsensus())){ for(std::vector::iterator bi = block.vuh.begin(); bi != block.vuh.end(); ++bi){ blockheader = *bi; @@ -4497,7 +4497,7 @@ static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, co for(std::vector::iterator it = vecAncestor.begin(); it != vecAncestor.end(); ++it){ tmpBlockIndex = *it; - LogPrintf("AcceptUnclesHeader():ReadBlockFromDisk %s", tmpBlockIndex->GetBlockHash().ToString()); + LogPrintf("AcceptUnclesHeader():ReadBlockFromDisk %s\n", tmpBlockIndex->GetBlockHash().ToString()); if(ReadBlockFromDisk(tmpBlock, tmpBlockIndex, chainparams.GetConsensus())){ for(std::vector::iterator bi = tmpBlock.vuh.begin(); bi != tmpBlock.vuh.end(); ++bi){ tmpBlockHeader = *bi; From f8d30ba544b424cc78bf9522f5c70d575017acd8 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 16:17:21 +0800 Subject: [PATCH 062/120] change the magic number --- src/chainparams.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5f5646e..8e2e53c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -252,10 +252,10 @@ class CMainParams : public CChainParams { * The characters are rarely used upper ASCII, not valid as UTF-8, and produce * a large 32-bit integer with any alignment. */ - pchMessageStart[0] = 0xb3; - pchMessageStart[1] = 0x01; - pchMessageStart[2] = 0x6f; - pchMessageStart[3] = 0xb1; + pchMessageStart[0] = 0xd6; + pchMessageStart[1] = 0xa5; + pchMessageStart[2] = 0x3f; + pchMessageStart[3] = 0xc9; vAlertPubKey = ParseHex("028efd0f3c697689f8f1f6744edbbc1f85871b8c51218ddd89d90a3e435d1a8691"); nDefaultPort = 2888; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin @@ -381,10 +381,10 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1524057440; // 2018/4/18 20:57:16 consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1555592236; // 2019/4/18 20:57:16 - pchMessageStart[0] = 0xc2; - pchMessageStart[1] = 0xe6; - pchMessageStart[2] = 0xce; - pchMessageStart[3] = 0xf3; + pchMessageStart[0] = 0xd3; + pchMessageStart[1] = 0x5a; + pchMessageStart[2] = 0xc8; + pchMessageStart[3] = 0x4f; vAlertPubKey = ParseHex("0244a0bb22e931bf59cc8a434d9d22bd2fa493f579bd2659bc9188361d78bdc45f"); nDefaultPort = 12888; nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet @@ -508,10 +508,10 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1000000000000ULL; - pchMessageStart[0] = 0xf0; - pchMessageStart[1] = 0xc5; - pchMessageStart[2] = 0xbb; - pchMessageStart[3] = 0xd0; + pchMessageStart[0] = 0xf7; + pchMessageStart[1] = 0x5b; + pchMessageStart[2] = 0xc9; + pchMessageStart[3] = 0xe3; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin nDefaultPort = 12888; nPruneAfterHeight = 1000; From cf27d01101852a9ca700c9a42f6fd5fe0a45eb6c Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 20:37:02 +0800 Subject: [PATCH 063/120] change the getblock rpc command --- src/rpcblockchain.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 77c9b3f..498ec16 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -148,7 +148,13 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("tx", txs)); /*popchain ghost*/ UniValue uhs(UniValue::VARR); + UniValue uhsr(UniValue::VARR); //uhDetails =true; + int uncleCount =0; + uint160 coinBaseAddress; + uint160 tmpAddress; + CAmount tmpAmount = 0; + int addressType; BOOST_FOREACH(const CBlockHeader&uh, block.vuh) { //UniValue objUh(UniValue::VOBJ); @@ -161,8 +167,20 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } else{ uhs.push_back(uh.GetHash().GetHex()); } + coinBaseAddress = block.vuh[uncleCount].nCoinbase; + for (const CTxOut &out: block.vtx[0].vout){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ + if(coinBaseAddress == tmpAddress){ + tmpAmount += out.nValue; + } + } + } + uhsr.push_back(ValueFromAmount(tmpAmount)); + tmpAmount = 0; + uncleCount++; } result.push_back(Pair("uh",uhs)); + result.push_back(Pair("uhr",uhsr)); /*popchain ghost*/ result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); @@ -763,12 +781,22 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" + " \"hashUncles\" : \"hash\",(string) the block hashUncles \n" + " \"coinbase\" : \"hash\",(string) the block coinbase \n" " \"merkleroot\" : \"hash\", (string) The merkle root\n" " \"nameclaimroot\" : \"hash\", (string) The hash of the root of the name claim trie\n" " \"tx\" : [ (array of string) The transaction ids\n" " \"transactionid\" (string) The transaction id\n" " ,...\n" " ],\n" + " \"uh\" : [ (array of string) The uncle block header hash \n" + " \"uncleheaderhash\" (string) The transaction id\n" + " ,...\n" + " ],\n" + " \"uhr\" : [ (array of string) The uncle block reward \n" + " \"uncleheaderhash\" (numeric) The value of uncle block reward in COIN \n" + " ,...\n" + " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"unclesize\" : n, (numeric) The size of block uncle header\n" From cc22073a94c740e07ad215dc0a2effd16bb4b8e4 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 3 Sep 2018 20:47:23 +0800 Subject: [PATCH 064/120] change the help of getblock rpc command --- src/rpcblockchain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 498ec16..98a878d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -793,8 +793,8 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"uncleheaderhash\" (string) The transaction id\n" " ,...\n" " ],\n" - " \"uhr\" : [ (array of string) The uncle block reward \n" - " \"uncleheaderhash\" (numeric) The value of uncle block reward in COIN \n" + " \"uhr\" : [ (array of numeric) The uncle block reward \n" + " \"uncleheaderreward\" (numeric) The value of uncle block reward in COIN \n" " ,...\n" " ],\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" From 7d9d8094463fbacba3513c1fc709ab7a73b1fb25 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 4 Sep 2018 10:36:19 +0800 Subject: [PATCH 065/120] change the getblockheader rpc command --- src/rpcblockchain.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 98a878d..facaf90 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -79,6 +79,10 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", blockindex->nVersion)); + /*popchain ghost*/ + result.push_back(Pair("hashUncles",blockindex->hashUncles.GetHex())); + result.push_back(Pair("coinbase",blockindex->nCoinbase.GetHex())); + /*popchain ghost*/ result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", blockindex->hashClaimTrie.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); From ae43597d6b9cf0324afd96ec18112e47c642e562 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 4 Sep 2018 15:03:38 +0800 Subject: [PATCH 066/120] change the getuncleblockheader rpc command --- src/rpcblockchain.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index facaf90..480081a 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -105,6 +105,11 @@ void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry) { entry.push_back(Pair("hash", blockheader.GetHash().GetHex())); entry.push_back(Pair("CURRENT_VERSION", blockheader.CURRENT_VERSION)); + CBlockIndex* pblockindex = mapBlockIndex[blockheader.hashPrevBlock]; + if (chainActive.Contains(pblockindex)){ + int hight = pblockindex->nHeight + 1; + entry.push_back(Pair("nHeight", strprintf("%d", hight))); + } entry.push_back(Pair("nVersion", blockheader.nVersion)); entry.push_back(Pair("hashPrevBlock", blockheader.hashPrevBlock.GetHex())); entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); From eed3e68d1efae25790637faa6348910c3fe51344 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 4 Sep 2018 17:37:54 +0800 Subject: [PATCH 067/120] change for block chain browser --- src/rpcblockchain.cpp | 64 ++++++++++++++++++++++++++----------------- src/rpcclient.cpp | 1 + src/rpcserver.h | 2 +- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 480081a..c135f05 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -101,25 +101,25 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) } /*popchain ghost*/ -void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry) +void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int blockhight) { + entry.push_back(Pair("blockhight", blockhight)); entry.push_back(Pair("hash", blockheader.GetHash().GetHex())); - entry.push_back(Pair("CURRENT_VERSION", blockheader.CURRENT_VERSION)); CBlockIndex* pblockindex = mapBlockIndex[blockheader.hashPrevBlock]; if (chainActive.Contains(pblockindex)){ int hight = pblockindex->nHeight + 1; - entry.push_back(Pair("nHeight", strprintf("%d", hight))); + entry.push_back(Pair("height", strprintf("%d", hight))); } - entry.push_back(Pair("nVersion", blockheader.nVersion)); + entry.push_back(Pair("version", blockheader.nVersion)); entry.push_back(Pair("hashPrevBlock", blockheader.hashPrevBlock.GetHex())); entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); - entry.push_back(Pair("nCoinbase", blockheader.nCoinbase.GetHex())); - entry.push_back(Pair("nDifficulty", strprintf("%d", blockheader.nDifficulty))); + entry.push_back(Pair("coinbase", blockheader.nCoinbase.GetHex())); + entry.push_back(Pair("difficulty", strprintf("%d", blockheader.nDifficulty))); entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); - entry.push_back(Pair("nTime", strprintf("%d", blockheader.nTime))); - entry.push_back(Pair("nBits", strprintf("%08x", blockheader.nBits))); - entry.push_back(Pair("nNonce", blockheader.nNonce.GetHex())); + entry.push_back(Pair("time", strprintf("%d", blockheader.nTime))); + entry.push_back(Pair("bits", strprintf("%08x", blockheader.nBits))); + entry.push_back(Pair("nonce", blockheader.nNonce.GetHex())); } /*popchain ghost*/ @@ -171,7 +171,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx //uhs.push_back(uh.ToString()); if(uhDetails){ UniValue objUh(UniValue::VOBJ); - uncleblockheaderToJSON(uh,objUh); + uncleblockheaderToJSON(uh,objUh,blockindex->nHeight); uhs.push_back(objUh); } else{ uhs.push_back(uh.GetHash().GetHex()); @@ -634,24 +634,25 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" - " \"hash\" : \"hash\", (string) the uncle block header hash (same as provided)\n" - " \"CURRENT_VERSION\" : n, (numeric) the uncle block header CURRENT_VERSION \n" - " \"nVersion\" : n, (numeric) the uncle block header nVersion \n" + " \"blockheight\" : n, (numeric)the block height \n" + " \"hash\" : \"hash\", (string) the uncle block header hash \n" + " \"height\" : n, (numeric) The uncle block height \n" + " \"version\" : n, (numeric) the uncle block header nVersion \n" " \"hashPrevBlock\" : \"hash\", (string) the uncle block header hashPrevBlock \n" " \"hashUncles\" : \"hash\", (string) the uncle block header hashUncles \n" - " \"nCoinbase\" : \"hash\", (string) the uncle block header nCoinbase \n" - " \"nDifficulty\" : n, (numeric) the uncle block header nDifficulty \n" + " \"coinbase\" : \"hash\", (string) the uncle block header nCoinbase \n" + " \"difficulty\" : n, (numeric) the uncle block header nDifficulty \n" " \"hashMerkleRoot\" : \"hash\", (string) the uncle block header hashMerkleRoot \n" " \"hashClaimTrie\" : \"hash\", (string) the uncle block header hashClaimTrie \n" - " \"nTime\" : n, (numeric) the uncle block header nTime \n" - " \"nBits\" : n, (hex) the uncle block header nBits \n" - " \"nNonce\" : \"hash\", (string) the uncle block header nNonce \n" + " \"time\" : n, (numeric) the uncle block header nTime \n" + " \"bits\" : n, (hex) the uncle block header nBits \n" + " \"nonce\" : \"hash\", (string) the uncle block header nNonce \n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for uncle block header 'hash'.\n" "\nExamples:\n" - + HelpExampleCli("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 00010cfa2058317dc1b39e64d1cc790d61859e188b6a342ef5e5494cb7ae8e5f") - + HelpExampleRpc("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 00010cfa2058317dc1b39e64d1cc790d61859e188b6a342ef5e5494cb7ae8e5f") + + HelpExampleCli("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 0") + + HelpExampleRpc("getuncleblockheader", "\"0001c608305b44804b7345f3032242981958e860d4c03ae632e05c45615920a9\" 0") ); LOCK(cs_main); @@ -659,8 +660,12 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) std::string strHash = params[0].get_str(); uint256 hash(uint256S(strHash)); - std::string strHashUncle = params[1].get_str(); - uint256 hashuncle(uint256S(strHashUncle)); + //std::string strHashUncle = params[1].get_str(); + //uint256 hashuncle(uint256S(strHashUncle)); + + int nIndex = 0; + if (params.size() > 1) + nIndex = params[1].get_int(); bool fVerbose = true; if (params.size() > 2) @@ -682,9 +687,18 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) bool bGetUncle = false; UniValue objUh(UniValue::VOBJ); - std::vector vuh = block.vuh; + //std::vector vuh = block.vuh; CBlockHeader blockheader; - + + if((nIndex >= 0)&&(nIndex < block.vuh.size())){ + bGetUncle = true; + blockheader = block.vuh[nIndex]; + const CBlockHeader& cblockheader = block.vuh[nIndex]; + //uncleblockheaderToJSON(cblockheader,objUh); + uncleblockheaderToJSON(cblockheader,objUh,pblockindex->nHeight); + } + + /* for(std::vector::iterator bi = vuh.begin(); bi != vuh.end(); ++bi){ blockheader = (*bi); //std::cout<<"hashuncle: "< Date: Tue, 4 Sep 2018 17:54:09 +0800 Subject: [PATCH 068/120] change for block chain browser --- src/rpcblockchain.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index c135f05..085ec13 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -81,7 +81,8 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("version", blockindex->nVersion)); /*popchain ghost*/ result.push_back(Pair("hashUncles",blockindex->hashUncles.GetHex())); - result.push_back(Pair("coinbase",blockindex->nCoinbase.GetHex())); + //result.push_back(Pair("coinbase",blockindex->nCoinbase.GetHex())); + result.push_back(Pair("coinbase",CBitcoinAddress(CKeyID(blockindex->nCoinbase)).ToString())); /*popchain ghost*/ result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", blockindex->hashClaimTrie.GetHex())); @@ -113,7 +114,8 @@ void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int entry.push_back(Pair("version", blockheader.nVersion)); entry.push_back(Pair("hashPrevBlock", blockheader.hashPrevBlock.GetHex())); entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); - entry.push_back(Pair("coinbase", blockheader.nCoinbase.GetHex())); + //entry.push_back(Pair("coinbase", blockheader.nCoinbase.GetHex())); + entry.push_back(Pair("coinbase",CBitcoinAddress(CKeyID(blockheader.nCoinbase)).ToString())); entry.push_back(Pair("difficulty", strprintf("%d", blockheader.nDifficulty))); entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); @@ -137,8 +139,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", block.nVersion)); /*popchain ghost*/ - result.push_back(Pair("hashUncles",block.hashUncles.GetHex())); - result.push_back(Pair("coinbase",block.nCoinbase.GetHex())); + result.push_back(Pair("hashUncles",block.hashUncles.GetHex())); + result.push_back(Pair("coinbase",CBitcoinAddress(CKeyID(block.nCoinbase)).ToString())); + //result.push_back(Pair("coinbase",block.nCoinbase.GetHex())); /*popchain ghost*/ result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", block.hashClaimTrie.GetHex())); From a53df00dc2451b92e04107d3260382096d25c7cd Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Fri, 7 Sep 2018 00:38:35 +0800 Subject: [PATCH 069/120] add new reward distribution --- src/chainparams.cpp | 52 ++++++++++++++++++++++-------------------- src/consensus/params.h | 3 ++- src/main.cpp | 6 ++--- src/pow.cpp | 4 ++-- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8e2e53c..e45ddd8 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -203,17 +203,18 @@ class CMainParams : public CChainParams { strNetworkID = "main"; // reward setting - consensus.premine = int64_t(1e8 * COIN); // premine + consensus.premine = int64_t(6e8 * COIN); // premine consensus.genesisReward = int64_t(1 * COIN); // genesis - consensus.minerReward4 = int64_t(112.966 * COIN); // miners - consensus.minerReward5 = int64_t(133.775 * COIN); - consensus.foundersReward = int64_t(4166666.667 * COIN); // founders + consensus.minerReward4 = int64_t(73.648 * COIN); // miners + //consensus.minerReward5 = int64_t(133.775 * COIN); + consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - consensus.nSubsidyHalvingInterval = 840960; // 4 years, 24 * 60 / 2.5 * 365 * 4 + consensus.nSubsidyHalvingInterval = 2803200; // 4 years, 24 * 60 * 60 * 365 * 4/ 45 consensus.nInstantSendKeepLock = 24; consensus.nSuperblockStartBlock = 100; - consensus.nSuperblockCycle = 576 * 30; // ~(60*24*30)/2.6, actual number of blocks per month is 200700 / 12 = 16725 + consensus.nSuperblockCycle = 57600; + consensus.nUncleblockRatio = 0.1; consensus.nPopnodeMinimumConfirmations = 15; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; @@ -224,16 +225,16 @@ class CMainParams : public CChainParams { //consensus.powLimit = uint256S("0x000009b173000000000000000000000000000000000000000000000000000000"); consensus.powLimit = uint256S("0x000009b173149ff8b3a49a388d7ebdd0e1eb76d294f9e5f648f254d81ad0938a"); consensus.difficultyBoundDivisor = 2048; - consensus.difficultyRapidFitDivisor = 200; + consensus.difficultyRapidFitDivisor = 1024; //consensus.durationLimit = 13; consensus.minimumDifficulty = 1730830; // minidifficulty for target - consensus.nYolandaTime = 172800; + consensus.nYolandaTime = 57600; /*popchain ghost*/ //consensus.nPowAveragingWindow = 17; //consensus.nPowMaxAdjustDown = 32; // 32% adjustment down //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day - consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + consensus.nPowTargetSpacing = 45; // Pop: 45 second consensus.fPowAllowMinDifficultyBlocks = false; consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1916; // 95% of 2016 @@ -333,18 +334,18 @@ class CTestNetParams : public CChainParams { strNetworkID = "test"; // reward setting - consensus.premine = int64_t(1e7 * COIN); // premine + consensus.premine = int64_t(6e8 * COIN); // premine consensus.genesisReward = int64_t(1 * COIN); // genesis - consensus.minerReward4 = int64_t(300 * COIN); // miners - consensus.minerReward5 = int64_t(535.103 * COIN); - consensus.foundersReward = int64_t(200000 * COIN); // founders - + consensus.minerReward4 = int64_t(73.648 * COIN); // miners + //consensus.minerReward5 = int64_t(535.103 * COIN); + consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - consensus.nSubsidyHalvingInterval = 840960; + consensus.nSubsidyHalvingInterval = 1920; //1 day consensus.nInstantSendKeepLock = 6; - consensus.nSuperblockStartBlock = 30; - consensus.nSuperblockCycle = 30; // Superblocks can be issued hourly on testnet + consensus.nSuperblockStartBlock = 40; + consensus.nSuperblockCycle = 40; //30 minutes + consensus.nUncleblockRatio = 0.1; consensus.nPopnodeMinimumConfirmations = 2; consensus.nMajorityEnforceBlockUpgrade = 51; consensus.nMajorityRejectBlockOutdated = 75; @@ -354,11 +355,11 @@ class CTestNetParams : public CChainParams { /* popchain ghost */ //consensus.powLimit = uint256S("0x000fffffff000000000000000000000000000000000000000000000000000000"); consensus.powLimit = uint256S("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.difficultyBoundDivisor = 2048; + consensus.difficultyBoundDivisor = 1024; consensus.difficultyRapidFitDivisor = 50; //consensus.durationLimit = 13; consensus.minimumDifficulty = 4096; - consensus.nYolandaTime = 500; + consensus.nYolandaTime = 960; /* popchain ghost */ //consensus.nPowAveragingWindow = 17; @@ -367,7 +368,7 @@ class CTestNetParams : public CChainParams { //consensus.nPowMaxAdjustUp = 48; // 48% adjustment up //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day //consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes - consensus.nPowTargetSpacing = 15; + consensus.nPowTargetSpacing = 45; consensus.fPowAllowMinDifficultyBlocks = true; //consensus.fPowNoRetargeting = false; consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains @@ -467,16 +468,17 @@ class CRegTestParams : public CChainParams { CRegTestParams() { strNetworkID = "regtest"; // reward setting - consensus.premine = int64_t(1e8 * COIN); // premine + consensus.premine = int64_t(6e8 * COIN); // premine consensus.genesisReward = int64_t(1 * COIN); // genesis - consensus.minerReward4 = int64_t(112.966 * COIN); // miners - consensus.minerReward5 = int64_t(535.103 * COIN); - consensus.foundersReward = int64_t(4166666.667 * COIN); // founders + consensus.minerReward4 = int64_t(73.648 * COIN); // miners + //consensus.minerReward5 = int64_t(535.103 * COIN); + consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral consensus.nSubsidyHalvingInterval = 150; consensus.nInstantSendKeepLock = 6; consensus.nSuperblockStartBlock = 1500; consensus.nSuperblockCycle = 10; + consensus.nUncleblockRatio = 0.1; consensus.nPopnodeMinimumConfirmations = 1; consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; @@ -489,7 +491,7 @@ class CRegTestParams : public CChainParams { //consensus.nPowMaxAdjustDown = 0; // Turn off adjustment down //consensus.nPowMaxAdjustUp = 0; // Turn off adjustment up //consensus.nPowTargetTimespan = 24 * 60 * 60; // Pop: 1 day - consensus.nPowTargetSpacing = 2.5 * 60; // Pop: 2.5 minutes + consensus.nPowTargetSpacing = 45; // Pop: 2.5 minutes consensus.fPowAllowMinDifficultyBlocks = true; consensus.fPowNoRetargeting = true; /*popchain ghost*/ diff --git a/src/consensus/params.h b/src/consensus/params.h index 37425f4..22a23bd 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -41,7 +41,7 @@ struct Params { i64 premine; // premine i64 genesisReward; // genesis reward i64 minerReward4; // block reward to miners per block in the 1st 4 years - i64 minerReward5; // block reward to miners per block in the 2nd 4 years + //i64 minerReward5; // block reward to miners per block in the 2nd 4 years // founders reward i64 foundersReward; // super block reward to founders in first 4 years @@ -59,6 +59,7 @@ struct Params { int nSuperblockStartBlock; int nSuperblockCycle; // in blocks + double nUncleblockRatio; int nPopnodeMinimumConfirmations; /** Used to check majorities for block version upgrade */ int nMajorityEnforceBlockUpgrade; diff --git a/src/main.cpp b/src/main.cpp index 1b9ec10..6db12aa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1772,18 +1772,18 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) // first 4 years if (height < intval) { - return cp.minerReward4; + return cp.minerReward4*(1-cp.nUncleblockRatio); } // from the 5th year on else { int halvings = (height - intval) / intval; // force subsidy to 0 when right shift 64 bit is undifined - if (halvings > 63) + if (halvings > 3) { return 0; } - CAmount subsidy(cp.minerReward5); + CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); subsidy >>= halvings; return subsidy; } diff --git a/src/pow.cpp b/src/pow.cpp index 2dd38ba..173cb63 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -32,11 +32,11 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo int32_t const timestampDiff = pblock->nTime - pindex->nTime; if (pindex->nHeight < params.nYolandaTime){ - if (timestampDiff < 15) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; + if (timestampDiff < 45) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; //std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 10, -99); + int64_t const adjFactor = std::max((pindex->hasUncles() ? 2 : 1) - timestampDiff / 29, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; //std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< Date: Fri, 7 Sep 2018 11:13:01 +0800 Subject: [PATCH 070/120] change max block size from 4m to 2m --- src/consensus/consensus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index 226ef2a..d1c1e6d 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -4,7 +4,7 @@ #define BITCOIN_CONSENSUS_CONSENSUS_H /** The maximum allowed size for a serialized block, in bytes (network rule) */ -static const unsigned int MAX_BLOCK_SIZE = 4000000; +static const unsigned int MAX_BLOCK_SIZE = 2000000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ From 4214d787b38b7576687e674805768bdf630e5639 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 7 Sep 2018 17:50:45 +0800 Subject: [PATCH 071/120] change the rpc command for block chain brower --- src/rpcblockchain.cpp | 44 ++++++++++++++++++++++++++++--------------- src/rpcserver.h | 2 +- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 085ec13..c1c63d8 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -102,26 +102,27 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) } /*popchain ghost*/ -void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int blockhight) +void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int blockhight,CAmount unclereward) { entry.push_back(Pair("blockhight", blockhight)); entry.push_back(Pair("hash", blockheader.GetHash().GetHex())); CBlockIndex* pblockindex = mapBlockIndex[blockheader.hashPrevBlock]; if (chainActive.Contains(pblockindex)){ int hight = pblockindex->nHeight + 1; - entry.push_back(Pair("height", strprintf("%d", hight))); + entry.push_back(Pair("height", hight)); } entry.push_back(Pair("version", blockheader.nVersion)); entry.push_back(Pair("hashPrevBlock", blockheader.hashPrevBlock.GetHex())); entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); //entry.push_back(Pair("coinbase", blockheader.nCoinbase.GetHex())); entry.push_back(Pair("coinbase",CBitcoinAddress(CKeyID(blockheader.nCoinbase)).ToString())); - entry.push_back(Pair("difficulty", strprintf("%d", blockheader.nDifficulty))); + entry.push_back(Pair("difficulty", blockheader.nDifficulty)); entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); - entry.push_back(Pair("time", strprintf("%d", blockheader.nTime))); + entry.push_back(Pair("time", (int64_t)blockheader.nTime)); entry.push_back(Pair("bits", strprintf("%08x", blockheader.nBits))); entry.push_back(Pair("nonce", blockheader.nNonce.GetHex())); + entry.push_back(Pair("unclereward", ValueFromAmount(unclereward))); } /*popchain ghost*/ @@ -169,16 +170,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx int addressType; BOOST_FOREACH(const CBlockHeader&uh, block.vuh) { - //UniValue objUh(UniValue::VOBJ); - //uhs.push_back(uh.GetHash().GetHex()); - //uhs.push_back(uh.ToString()); - if(uhDetails){ - UniValue objUh(UniValue::VOBJ); - uncleblockheaderToJSON(uh,objUh,blockindex->nHeight); - uhs.push_back(objUh); - } else{ - uhs.push_back(uh.GetHash().GetHex()); - } coinBaseAddress = block.vuh[uncleCount].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ @@ -188,6 +179,16 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } } uhsr.push_back(ValueFromAmount(tmpAmount)); + + + if(uhDetails){ + UniValue objUh(UniValue::VOBJ); + uncleblockheaderToJSON(uh,objUh,blockindex->nHeight,tmpAmount); + uhs.push_back(objUh); + } else{ + uhs.push_back(uh.GetHash().GetHex()); + } + tmpAmount = 0; uncleCount++; } @@ -698,7 +699,20 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) blockheader = block.vuh[nIndex]; const CBlockHeader& cblockheader = block.vuh[nIndex]; //uncleblockheaderToJSON(cblockheader,objUh); - uncleblockheaderToJSON(cblockheader,objUh,pblockindex->nHeight); + + uint160 coinBaseAddress; + uint160 tmpAddress; + CAmount tmpAmount = 0; + int addressType; + coinBaseAddress = block.vuh[nIndex].nCoinbase; + for (const CTxOut &out: block.vtx[0].vout){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ + if(coinBaseAddress == tmpAddress){ + tmpAmount += out.nValue; + } + } + } + uncleblockheaderToJSON(cblockheader,objUh,pblockindex->nHeight,tmpAmount); } /* diff --git a/src/rpcserver.h b/src/rpcserver.h index 8225f21..b462a21 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -288,7 +288,7 @@ extern UniValue getblockhash(const UniValue& params, bool fHelp); extern UniValue getblockheader(const UniValue& params, bool fHelp); extern UniValue getblockheaders(const UniValue& params, bool fHelp); /*popchain ghost*/ -extern void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int blockhight); +extern void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int blockhight,CAmount unclereward); extern UniValue getuncleblockheader(const UniValue& params, bool fHelp); extern UniValue getalluncleblock(const UniValue& params, bool fHelp); From c535f3c3b364f997e367f7613955b97722791e44 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 10 Sep 2018 20:40:33 +0800 Subject: [PATCH 072/120] change the rpc command for block chain brower --- src/rpcblockchain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index c1c63d8..8b589a5 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -168,11 +168,12 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx uint160 tmpAddress; CAmount tmpAmount = 0; int addressType; + const CChainParams& chainparams = Params(); BOOST_FOREACH(const CBlockHeader&uh, block.vuh) { coinBaseAddress = block.vuh[uncleCount].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue < GetMinerSubsidy(blockindex->nHeight,chainparams.GetConsensus()))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } @@ -694,6 +695,8 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) //std::vector vuh = block.vuh; CBlockHeader blockheader; + const CChainParams& chainparams = Params(); + if((nIndex >= 0)&&(nIndex < block.vuh.size())){ bGetUncle = true; blockheader = block.vuh[nIndex]; @@ -706,7 +709,7 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) int addressType; coinBaseAddress = block.vuh[nIndex].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue < GetMinerSubsidy(pblockindex->nHeight,chainparams.GetConsensus()))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } From eef8083cfed1600d317eb0645a0b165abeb47a9a Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 12 Sep 2018 15:15:30 +0800 Subject: [PATCH 073/120] change for block chain brower --- src/main.cpp | 20 ++++++++++++++++++++ src/rpcblockchain.cpp | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6db12aa..5745749 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4384,6 +4384,10 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn } } /*popchain ghost*/ + if(block.vuh.size() > 2){ + LogPrintf("CheckBlock():ERROR uncle header size %d error \n",block.vuh.size()); + return false; + } uint160 coinBaseAddress; uint160 tmpAddress; @@ -4393,6 +4397,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn int tmpBlockHeight = 0; CAmount tmpSubAmount =0; const CChainParams& chainparams = Params(); + uint160 preCoinBaseAddress = uint160(); + CAmount tmpPreAmount = 0; if(block.vuh.size() != 0 && nHeight != 0){ for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ @@ -4419,6 +4425,20 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn LogPrintf("CheckBlock():ERROR %d uncle header coinbase not match \n",uncleCount); return false; } + /*only work uncle header size 2*/ + if(preCoinBaseAddress == coinBaseAddress){ + tmpPreAmount += tmpSubAmount; + if(tmpAmount >= tmpPreAmount){ + LogPrintf("CheckBlock(): %s two same uncle miner uncle header coinbase match \n",CBitcoinAddress(CKeyID(coinBaseAddress)).ToString()); + } else{ + LogPrintf("CheckBlock():ERROR %s two same uncle miner uncle header coinbase not match \n",CBitcoinAddress(CKeyID(coinBaseAddress)).ToString()); + return false; + } + } else{ + tmpPreAmount = tmpSubAmount; + preCoinBaseAddress = coinBaseAddress; + } + tmpAmount = 0; tmpBlockHeight = 0; tmpSubAmount =0; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 8b589a5..dd5591e 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -173,7 +173,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx { coinBaseAddress = block.vuh[uncleCount].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue < GetMinerSubsidy(blockindex->nHeight,chainparams.GetConsensus()))){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= (7 * GetMinerSubsidy(blockindex->nHeight,chainparams.GetConsensus()) / 8))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } @@ -709,7 +709,7 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) int addressType; coinBaseAddress = block.vuh[nIndex].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue < GetMinerSubsidy(pblockindex->nHeight,chainparams.GetConsensus()))){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= (7 * GetMinerSubsidy(pblockindex->nHeight,chainparams.GetConsensus()) / 8))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } From 026b389de5f74fc68b6482e4d66974199dcce0b5 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 12 Sep 2018 17:32:45 +0800 Subject: [PATCH 074/120] change for test --- src/rpcblockchain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index dd5591e..0b48ae5 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -123,6 +123,8 @@ void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int entry.push_back(Pair("bits", strprintf("%08x", blockheader.nBits))); entry.push_back(Pair("nonce", blockheader.nNonce.GetHex())); entry.push_back(Pair("unclereward", ValueFromAmount(unclereward))); + entry.push_back(Pair("valueSat", unclereward)); + } /*popchain ghost*/ From 6cd68efd2442f80ffea3c3216ab01294fcba71fd Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 17 Sep 2018 15:19:24 +0800 Subject: [PATCH 075/120] add the atomic swap function --- src/base58.cpp | 12 + src/base58.h | 3 + src/pubkey.h | 5 + src/rpcrawtransaction.cpp | 885 ++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 7 + src/rpcserver.h | 10 + src/script/script.cpp | 6 +- src/script/script.h | 4 +- 8 files changed, 929 insertions(+), 3 deletions(-) diff --git a/src/base58.cpp b/src/base58.cpp index d0887d9..7ad4c2d 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -254,6 +254,18 @@ uint160 CBitcoinAddress::GetData()const return id; } +/*atomic swap*/ +uint160 CBitcoinAddress::GetUint160()const +{ + if (!IsValid()) + return uint160(); + uint160 id; + memcpy(&id, &vchData[0], 20); + if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) + return id; +} + +/*atomic swap*/ CTxDestination CBitcoinAddress::Get() const { if (!IsValid()) diff --git a/src/base58.h b/src/base58.h index 710e4ae..ddacdaf 100644 --- a/src/base58.h +++ b/src/base58.h @@ -111,6 +111,9 @@ class CBitcoinAddress : public CBase58Data { CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); } CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); } uint160 GetData()const; + /*popchain atomic swap*/ + uint160 GetUint160()const; + /*popchain atomic swap*/ CTxDestination Get() const; bool GetKeyID(CKeyID &keyID) const; bool GetIndexKey(uint160& hashBytes, int& type) const; diff --git a/src/pubkey.h b/src/pubkey.h index 2034df5..a215421 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -151,6 +151,11 @@ class CPubKey { return Hash(vch, vch + size()); } + //! Get the 160-bit hash of this public key. + uint160 GetHash160()const + { + return Hash160(vch, vch + size()); + } /* * Check syntactic correctness. diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 2e3b3f4..f18b995 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -888,3 +888,888 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) return hashTx.GetHex(); } +#ifdef ENABLE_WALLET + + + +UniValue atomicswapfirsttx(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() < 2 || params.size() > 3) + throw runtime_error( + "atomicswapfirsttx \"address1\" amount\" address2\n" + "\nCreate the start atomic swap transaction spending the given inputs.\n" + "\nArguments:\n" + "1. \"address1\" (string,required) The PopChain address to send .\n" + "2. \"amount\" (numeric,required) The amount in " + CURRENCY_UNIT + " to send. eg 0.01\n" + "3. \"address2\" (string,optional) The PopChain address to refund .\n" + "\nResult:\n" + "\"lockTime\" (string) The lock time\n" + "\"refundAddress\" (string) The refund address encode by base58\n" + "\"transactionhash\" (string) The transaction hash\n" + "\"transaction\" (string) hex string of the transaction\n" + "\"htlcHash\" (string) The hash of hash time lock contract encode by base58\n" + "\"htlc\" (string) The hash time lock contract in hex\n" + "\"rawhash\" (string) The raw data of hashlock in hex\n" + "\"lockhash\" (string) The lock hash encode by base58\n" + "\nExamples:\n" + + HelpExampleCli("atomicswapfirsttx", "\"pUwZn7LXgJTpkYdKQQj4L5b2vUJRPTYV4X\" 0.1") + ); + + + LOCK(cs_main); + + //check params size is zero or not + if ((params[0].get_str().size() <= 0)||(params[1].get_str().size() <= 0)){ + throw JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter size can't be zero"); + } + + // parse the parmater 0 to get receiver address + CBitcoinAddress recAdr(params[0].get_str()); + + // check the recevier address is valid popchain address or not + if (!recAdr.IsValid()){ + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid popchain address"); + } + + // parse the parmater 1 to get the value to send + CAmount nSdValue = AmountFromValue(params[1]); + + // check the value is valid or not + if (nSdValue <= 0){ + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value to send"); + } + + // get the raw data of lockhash for hash time lock contract + unsigned char uchR[32]; + memset(uchR, 0, sizeof(uchR)); + RandAddSeedPerfmon(); + GetRandBytes(uchR, sizeof(uchR)); + uint256 rawHash = Hash(uchR,uchR+sizeof(uchR)); + + // do hash256 to raw data to get the lock hash fo hash time lock contract + std::vector vLockHash; + + //format the vector type raw data to string type,prepare to do RIPMED160 hash calculation + std::string strLockHashRip = rawHash.ToString(); + vLockHash.clear(); + vLockHash.resize(20); + + // The raw data do the RIPMED160 hash calculation + std::vectorvLockHashRip = ParseHex(strLockHashRip); + CRIPEMD160().Write(begin_ptr(vLockHashRip),vLockHashRip.size()).Finalize(begin_ptr(vLockHash)); + + // get lock time for hash time lock contract + struct timeval tmpTimeval; + gettimeofday(&tmpTimeval,NULL); + // lock time equal current time add two day 172800 + int64_t lockTime = tmpTimeval.tv_sec + 172800; + char tempChar[100] = {0}; + sprintf(tempChar,"%lx",lockTime); + std::string strLockTime = tempChar; + + // get a refund address from paramter or key pool + CPubKey refPubKey; + uint160 uRefAdr; + if (params.size() == 3){ + CBitcoinAddress tmpRefAdr(params[2].get_str()); + if (!tmpRefAdr.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PopChain address"); + uRefAdr = tmpRefAdr.GetUint160(); + } + else{ + if (!pwalletMain->GetKeyFromPool(refPubKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT,"Error: Keypool ran out,please call keypoolrefill first"); + uRefAdr = refPubKey.GetHash160(); + } + + uint160 uRecAdr = recAdr.GetUint160(); + + // construct hash time lock contract script + CScript htlc = CScript() << OP_IF << OP_RIPEMD160 << ToByteVector(vLockHash) << OP_EQUALVERIFY << OP_DUP << OP_HASH160 \ + << ToByteVector(uRecAdr) << OP_ELSE << lockTime << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_DUP << OP_HASH160\ + << ToByteVector(uRefAdr) << OP_ENDIF << OP_EQUALVERIFY << OP_CHECKSIG; + + //get the hash of hash time lock contract + CScriptID htlcID = CScriptID(htlc); + CBitcoinAddress htlcHashAdr; + htlcHashAdr.Set(htlcID ); + + // set the lock script for transaction. + CScript htlcP2SHPkScript = GetScriptForDestination(CTxDestination(htlcID)); + + // set the vout of transaction + vector vSend; + int nChangePosRet = -1; + CRecipient tmpRecipient = {htlcP2SHPkScript,nSdValue,false}; + vSend.push_back(tmpRecipient); + + // Start building a deal + CReserveKey tmpReskey(pwalletMain); + CAmount nFeeNeed = 0; + std::string strError; + CWalletTx wtxNew; + if ( !pwalletMain->CreateTransaction(vSend,wtxNew,tmpReskey,nFeeNeed,nChangePosRet,strError)) + { + if ( nSdValue + nFeeNeed > pwalletMain->GetBalance() ) + { + strError = strprintf("Error: This transaction requires a transaction fee of at least %s !",FormatMoney(nFeeNeed)); + } + LogPrintf("%s() : %s\n",__func__,strError); + throw JSONRPCError(RPC_WALLET_ERROR,strError); + } + + if ( !pwalletMain->CommitTransaction(wtxNew,tmpReskey) ) + throw JSONRPCError(RPC_WALLET_ERROR,"Error: The transaction was rejected! ."); + + //declare the return data + UniValue result(UniValue::VOBJ); + + CBitcoinAddress refAdr; + refAdr.Set(CKeyID(uRefAdr)); + + // Base58 encoding the lock hash + std::string strLockHash = EncodeBase58(vLockHash); + + result.push_back(Pair("lockTime",strLockTime)); + result.push_back(Pair("refundAddress",refAdr.ToString())); + result.push_back(Pair("transactionHash",wtxNew.GetHash().GetHex())); + result.push_back(Pair("transaction",EncodeHexTx(wtxNew))); + result.push_back(Pair("htlcHash ",htlcHashAdr.ToString())); + result.push_back(Pair("htlc",HexStr(htlc.begin(),htlc.end()))); + result.push_back(Pair("rawHash",rawHash.ToString())); + result.push_back(Pair("lockHash",strLockHash)); + return result; +} + +UniValue atomicswapsecondtx(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() < 3 || params.size() > 4) + throw runtime_error( + "atomicswapsecondtx \"address\"amount \"lockhash \n" + "\nCreate reback atomic swap transaction spending the given inputs .\n" + "\nArguments:\n" + "1. \"address1\" (string,required) The PopChain address to send .\n" + "2. \"amount\" (numeric,required) The amount in " + CURRENCY_UNIT + " to send. eg 0.01\n" + "3. \"lockhash \" (string,required) The lock hash in hex. \n" + "4. \"address2\" (string,optional) The PopChain address to refund .\n" + "\nResult:\n" + "\"lockTime\" (string) The lock time\n" + "\"refundAddress\" (string) The refund address encode by base58\n" + "\"transactionhash\" (string) The transaction hash\n" + "\"transaction\" (string) hex string of the transaction\n" + "\"htlcHash\" (string) The hash of hash time lock contract encode by base58\n" + "\"htlc\" (string) The hash time lock contract in hex\n" + "\nExamples:\n" + + HelpExampleCli("atomicswapsecondtx", "\"pUwZn7LXgJTpkYdKQQj4L5b2vUJRPTYV4X\" 0.1\" rcdug3scZ3uVqMox6w3nLm9m8zE") + ); + + LOCK(cs_main); + + //check params size is zero or not + if ((params[0].get_str().size() <= 0)||(params[1].get_str().size() <= 0)||(params[2].get_str().size() <= 0)){ + throw JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter size can't be zero"); + } + + // parse the parmater 0 to get receiver address + CBitcoinAddress recAdr(params[0].get_str()); + + // check the recevier address is valid popchain address or not + if (!recAdr.IsValid()){ + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid popchain address"); + } + + // parse the parmater 1 to get the value to send + CAmount nSdValue = AmountFromValue(params[1]); + + // check the value is valid or not + if (nSdValue <= 0){ + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid value to send"); + } + + //get the lock hash from parmater 3 + std::vectorvLockHash; + string tmpStr = params[2].get_str(); + DecodeBase58(tmpStr, vLockHash); + + // get lock time for hash time lock contract + struct timeval tmpTimeval; + gettimeofday(&tmpTimeval,NULL); + // lock time equal current time add one day 86400 + int64_t lockTime = tmpTimeval.tv_sec + 86400; + char tempChar[100] = {0}; + sprintf(tempChar,"%lx",lockTime); + std::string strLockTime = tempChar; + + // get a refund address from paramter or key pool + CPubKey refPubKey; + uint160 uRefAdr; + if (params.size() == 4){ + CBitcoinAddress tmpRefAdr(params[3].get_str()); + if (!tmpRefAdr.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PopChain address"); + uRefAdr = tmpRefAdr.GetUint160(); + } + else{ + if (!pwalletMain->GetKeyFromPool(refPubKey)) + throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT,"Error: Keypool ran out,please call keypoolrefill first"); + uRefAdr = refPubKey.GetHash160(); + } + + uint160 uRecAdr = recAdr.GetUint160(); + + // construct hash time lock contract script + CScript htlc = CScript() << OP_IF << OP_RIPEMD160 << ToByteVector(vLockHash) << OP_EQUALVERIFY << OP_DUP << OP_HASH160 \ + << ToByteVector(uRecAdr) << OP_ELSE << lockTime << OP_CHECKLOCKTIMEVERIFY << OP_DROP << OP_DUP << OP_HASH160\ + << ToByteVector(uRefAdr) << OP_ENDIF << OP_EQUALVERIFY << OP_CHECKSIG; + + //get the hash of hash time lock contract + CScriptID htlcID = CScriptID(htlc); + CBitcoinAddress htlcHashAdr; + htlcHashAdr.Set(htlcID ); + + // set the lock script for transaction. + CScript htlcP2SHPkScript = GetScriptForDestination(CTxDestination(htlcID)); + + // set the vout of transaction + vector vSend; + int nChangePosRet = -1; + CRecipient tmpRecipient = {htlcP2SHPkScript,nSdValue,false}; + vSend.push_back(tmpRecipient); + + // Start building a deal + CReserveKey tmpReskey(pwalletMain); + CAmount nFeeNeed = 0; + std::string strError; + CWalletTx wtxNew; + if ( !pwalletMain->CreateTransaction(vSend,wtxNew,tmpReskey,nFeeNeed,nChangePosRet,strError)) + { + if ( nSdValue + nFeeNeed > pwalletMain->GetBalance() ) + { + strError = strprintf("Error: This transaction requires a transaction fee of at least %s !",FormatMoney(nFeeNeed)); + } + LogPrintf("%s() : %s\n",__func__,strError); + throw JSONRPCError(RPC_WALLET_ERROR,strError); + } + + if ( !pwalletMain->CommitTransaction(wtxNew,tmpReskey) ) + throw JSONRPCError(RPC_WALLET_ERROR,"Error: The transaction was rejected! ."); + + //declare the return data + UniValue result(UniValue::VOBJ); + + CBitcoinAddress refAdr; + refAdr.Set(CKeyID(uRefAdr)); + + // Base58 encoding the lock hash + std::string strLockHash = EncodeBase58(vLockHash); + + result.push_back(Pair("lockTime",strLockTime)); + result.push_back(Pair("refundAddress",refAdr.ToString())); + result.push_back(Pair("transactionHash",wtxNew.GetHash().GetHex())); + result.push_back(Pair("transaction",EncodeHexTx(wtxNew))); + result.push_back(Pair("htlcHash ",htlcHashAdr.ToString())); + result.push_back(Pair("htlc",HexStr(htlc.begin(),htlc.end()))); + return result; + + +} + +UniValue atomicswapredeemtx(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() !=3) + throw runtime_error( + "atomicswapredeemtx \"htlc\" \"transaction\" \"rawhash\" \n" + "\nCreate atomicswap redeem transaction spending the given inputs .\n" + "\nArguments:\n" + "1. \"htlc \" (string) The hash time lock contract in hex\n" + "2. \"transaction\" (string) hex string of the transaction\n" + "3. \"rawhash \" (string) The raw data of hashlock in hex\n" + "nResult:\n" + "\"txfee\" (string) The fee of transacton\n" + "\"transactionhash\" (string) The transaction hash in hex\n" + "\"transaction\" (string) The transaction in hex\n" + ); + + LOCK(cs_main); + + //check params type + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR)(UniValue::VSTR)); + + //check params size is zero or not + if ((params[0].get_str().size() <= 0)||(params[1].get_str().size() <= 0)||(params[2].get_str().size() <= 0)) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter size can't be zero"); + } + + //get the hash time lock contract from parameter 0 + string strHtlc = params[0].get_str(); + std::vectorvHtlc = ParseHex(strHtlc); + CScript htlc(vHtlc.begin(),vHtlc.end()); + + //split the hash time lock contract + std::string htlcString = ScriptToAsmStr(htlc); + std::vector htlcVStr; + boost::split( htlcVStr, htlcString, boost::is_any_of( " " ), boost::token_compress_on ); + + // check the hash time lock contract is valid contract or not + if(!htlc.IsAtomicSwapPaymentScript()) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter is no stander HTLC"); + } + + //get receiver address hash + std::vector vRecAdrHash = ParseHex(htlcVStr[6]); + uint160 recAdrHash(vRecAdrHash); + + //decode the input transaction + CTransaction inputTx; + if (!DecodeHexTx(inputTx, params[1].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + + //get lock hash from hash time lock contract + std::vector contractLockHash = ParseHex(htlcVStr[2]); + uint160 uContractLockHash(contractLockHash); + + //get htlc hash form parameter 2 the raw hash + std::vector rawHashVector =ParseHexV(params[2], "rawHash"); + + //check the htlc hash in parameter and in hash time lock contract + std::vector parameterLockHash(20); + CRIPEMD160().Write(begin_ptr(rawHashVector), rawHashVector.size()).Finalize(begin_ptr(parameterLockHash)); + uint160 uParameterLockHash(parameterLockHash); + if ( 0 != strcmp(uContractLockHash.ToString().c_str(),uParameterLockHash.ToString().c_str()) ) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the lock hash in parameter not match in in contract"); + } + + //declare transaction + CMutableTransaction txNew; + CAmount nFeePay = 3100; + + //the redeem amount is input amount - tx fee + CAmount preOutAmount = 0; + COutPoint preOutPoint; + uint256 preTxid = inputTx.GetHash(); + CTxOut preTxOut; + uint32_t preOutN =0; + std::vector vSolutions; + txnouttype addressType = TX_NONSTANDARD; + uint160 addrhash; + + //get the previous tx ouput + BOOST_FOREACH(const CTxOut& txout, inputTx.vout) + { + const CScript scriptPubkey = StripClaimScriptPrefix(txout.scriptPubKey); + if (Solver(scriptPubkey, addressType, vSolutions)) + { + if(addressType== TX_SCRIPTHASH ) + { + addrhash=uint160(vSolutions[0]); + preOutAmount = txout.nValue; + CTxIn tmptxin = CTxIn(preTxid,preOutN,CScript()); + tmptxin.prevPubKey = txout.scriptPubKey; + txNew.vin.push_back(tmptxin); + break; + } + } + preOutN++; + } + + //check the previous tx output type + if(addressType !=TX_SCRIPTHASH) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the transaction have none P2SH type tx out"); + } + + //check the hash time lock contract is match input transaction or not + if ( 0 != strcmp(addrhash.ToString().c_str(),Hash160(vHtlc).ToString().c_str()) ) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the HTLC in parameter can't match transaction"); + } + + //get the pubkey and key of recevier address + const CKeyStore& keystore = *pwalletMain; + CKeyID keyID(recAdrHash); + CPubKey pubKey; + CKey key; + if(!keystore.GetPubKey(keyID,pubKey)) + { + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error:Can't find the pubkey of receiver address"); + } + if(!keystore.GetKey(keyID,key)) + { + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error:Can't find the key of receiver address"); + } + + //declare the reserverkey for commit transaction + CReserveKey reservekey(pwalletMain); + + //build the output use the hash time lock contract receiver address + CBitcoinAddress outPutAddress(CTxDestination(pubKey.GetID())); + if (!outPutAddress.IsValid()) + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error:Invalid PopChain address"); + + // Start building the lock script for the p2pkh type. + CScript recP2PkHScript = GetScriptForDestination(CTxDestination(pubKey.GetID())); + CAmount nAmount = preOutAmount- nFeePay; + CTxOut outNew(nAmount,recP2PkHScript); + txNew.vout.push_back(outNew); + + txNew.nLockTime = chainActive.Height(); + txNew.nVersion = 1; + + // Sign the redeem transaction + CTransaction txNewConst(txNew); + std::vector vchSig; + CScript scriptSigRs; + uint256 hash = SignatureHash(htlc, txNew, 0, SIGHASH_ALL); + bool signSuccess = key.Sign(hash, vchSig); + bool verifySuccess = pubKey.Verify(hash,vchSig); + vchSig.push_back((unsigned char)SIGHASH_ALL); + + if(signSuccess) + { + CScript script1 =CScript() <= MAX_STANDARD_TX_SIZE) + { + return JSONRPCError(RPC_INTERNAL_ERROR, "ERROR:transaction too large"); + } + + //check transaction is Dust + if (txNew.vout[0].IsDust(::minRelayTxFee)) + { + return JSONRPCError(RPC_INTERNAL_ERROR, "ERROR:transaction is dust transaction"); + } + + //commit the redeem transaction + CWalletTx wtxNew; + wtxNew.fTimeReceivedIsTxTime = true; + wtxNew.BindWallet(pwalletMain); + wtxNew.fFromMe = true; + *static_cast(&wtxNew) = CTransaction(txNew); + if (!pwalletMain->CommitTransaction(wtxNew, reservekey,NetMsgType::TX)) + return JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + double fFeePay = (double)nFeePay; + string strRedeemFee = strprintf("tx fee: %.8f Pch(%.8f Pch/kB)\n", (fFeePay / COIN), ((fFeePay / COIN)/nBytes)); + + //declare return data + UniValue result(UniValue::VOBJ); + + result.push_back(Pair("txfee",strRedeemFee)); + result.push_back(Pair("transactionhash",CTransaction(txNew).GetHash().GetHex())); + result.push_back(Pair("transaction",EncodeHexTx(CTransaction(txNew)))); + return result; + +} + +UniValue atomicswaprefundtx(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() !=2) + throw runtime_error( + "atomicswaprefundtx \"htlc \"transaction \n" + "\nCreate atomic swap refund transaction spending the given inputs .\n" + "\nArguments:\n" + "1. \"htlc \" (string,required) (string) The hash time lock contract in hex\n" + "2. \"transaction \" (string,required) The transaction in hex\n" + "nResult:\n" + "\"txfee\" (string) The fee of transacton\n" + "\"transactionhash\" (string) The transaction hash in hex\n" + "\"transaction\" (string) The transaction in hex\n" + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR)); + + //check params size is zero or not + if (params[0].get_str().size() <= 0||(params[1].get_str().size() <= 0)) + { + return false; + } + + //get the hash time lock contract from parameter 0 + string strHtlc = params[0].get_str(); + std::vectorvHtlc = ParseHex(strHtlc); + CScript htlc(vHtlc.begin(),vHtlc.end()); + + //split the hash time lock contract + std::string htlcString = ScriptToAsmStr(htlc); + std::vector htlcVStr; + boost::split( htlcVStr, htlcString, boost::is_any_of( " " ), boost::token_compress_on ); + + // check the hash time lock contract is valid contract or not + if(!htlc.IsAtomicSwapPaymentScript()) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter is no stander HTLC"); + } + + //get lock time + int64_t lockTime = atoi64(htlcVStr[8]); + + //get refund address hash + std::vector vRefAdrHash = ParseHex(htlcVStr[13]); + uint160 refAdrHash(vRefAdrHash); + + //decode the input transaction + CTransaction inputTx; + if (!DecodeHexTx(inputTx, params[1].get_str())) + return JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + + //declare refund transaction + CMutableTransaction txNew; + CAmount nFeePay = 3100; + + //get the refund amount + CAmount preOutAmount = 0; + COutPoint preOutPoint; + uint256 preTxid = inputTx.GetHash(); + CTxOut preTxOut; + uint32_t preOutN =0; + std::vector vSolutions; + txnouttype addressType = TX_NONSTANDARD; + uint160 addrhash; + + BOOST_FOREACH(const CTxOut& txout, inputTx.vout) + { + const CScript scriptPubkey = StripClaimScriptPrefix(txout.scriptPubKey); + if (Solver(scriptPubkey, addressType, vSolutions)) + { + if(addressType== TX_SCRIPTHASH ) + { + addrhash=uint160(vSolutions[0]); + preOutAmount = txout.nValue; + CTxIn tmptxin = CTxIn(preTxid,preOutN,CScript(),(std::numeric_limits::max()-1)); + tmptxin.prevPubKey = txout.scriptPubKey; + txNew.vin.push_back(tmptxin); + break; + } + } + preOutN++; + } + + if(addressType !=TX_SCRIPTHASH) + { + throw JSONRPCError(RPC_INVALID_PARAMS, "Error:the transaction have none P2SH type tx out"); + } + + //check the hash time lock contract is match transaction or not + if ( 0 != strcmp(addrhash.ToString().c_str(),Hash160(vHtlc).ToString().c_str()) ) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the contract in parameter can't match transaction in parameter"); + } + + //get the pubkey and key of refund address + const CKeyStore& keystore = *pwalletMain; + CKeyID keyID(refAdrHash); + CPubKey pubKey; + CKey key; + if(!keystore.GetPubKey(keyID,pubKey)) + { + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error:Can't find the pubkey of refund address"); + } + if(!keystore.GetKey(keyID,key)) + { + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error:Can't find the key of refund address"); + } + + //get the out pubkey type p2pkh + CReserveKey reservekey(pwalletMain); + CBitcoinAddress outPutAddress(CTxDestination(pubKey.GetID())); + if (!outPutAddress.IsValid()) + return JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PopChain address"); + + + // Start building the lock script for the p2pkh type. + CScript refP2PkHScript = GetScriptForDestination(CTxDestination(pubKey.GetID())); + CAmount nAmount = preOutAmount- nFeePay; + CTxOut outNew(nAmount,refP2PkHScript); + txNew.vout.push_back(outNew); + + txNew.nLockTime = lockTime; + txNew.nVersion = 1; + + // Sign the refund transaction + CTransaction txNewConst(txNew); + std::vector vchSig; + CScript scriptSigRs; + uint256 hash = SignatureHash(htlc, txNew, 0, SIGHASH_ALL); + bool signSuccess = key.Sign(hash, vchSig); + bool verifySuccess = pubKey.Verify(hash,vchSig); + vchSig.push_back((unsigned char)SIGHASH_ALL); + if(!verifySuccess) + { + return JSONRPCError(RPC_INTERNAL_ERROR, "ERROR:verify the sign of transaction error"); + } + + if(signSuccess) + { + CScript script1 =CScript() <= MAX_STANDARD_TX_SIZE) + { + return JSONRPCError(RPC_INTERNAL_ERROR, "ERROR:transaction too large"); + } + + //check the refund transaction is Dust or not + if (txNew.vout[0].IsDust(::minRelayTxFee)) + { + return JSONRPCError(RPC_INTERNAL_ERROR, "ERROR:transaction is dust transaction"); + } + + + CWalletTx wtxNew; + wtxNew.fTimeReceivedIsTxTime = true; + wtxNew.BindWallet(pwalletMain); + wtxNew.fFromMe = true; + *static_cast(&wtxNew) = CTransaction(txNew); + if (!pwalletMain->CommitTransaction(wtxNew, reservekey,NetMsgType::TX)) + return JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + double fFeePay = (double)nFeePay; + string strRefundFee = strprintf("tx fee: %.8f Pch(%.8f Pch/kB)\n", (fFeePay / COIN), ((fFeePay / COIN)/nBytes)); + + //the return data + UniValue result(UniValue::VOBJ); + result.push_back(Pair("txfee",strRefundFee)); + result.push_back(Pair("transactionhash",CTransaction(txNew).GetHash().GetHex())); + result.push_back(Pair("transaction",EncodeHexTx(CTransaction(txNew)))); + return result; + +} + + + +UniValue atomicswapgetrawhash(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() !=1) + throw runtime_error( + "atomicswapgetsecret \"transaction \n" + "\nget raw data of lock hash from atomic redeem transaction spending the given inputs .\n" + "\nArguments:\n" + "1. \transaction \" (string,required) The transaction in hex\n" + "nResult:\n" + "\"rawhash\" (string) The transaction in hex\n" + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); + + //check params size is zero or not + if (params[0].get_str().size() <= 0) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter size can't be zero"); + } + + //decode the input transaction + CTransaction inputTx; + if (!DecodeHexTx(inputTx, params[0].get_str())) + return JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + CScript InputScriptSig = inputTx.vin[0].scriptSig; + + //split the scriptSig + std::string strInputScriptSig = ScriptToAsmStr(InputScriptSig); + std::vector vStrInpScrSig; + boost::split( vStrInpScrSig, strInputScriptSig, boost::is_any_of( " " ), boost::token_compress_on ); + + //get the hash time lock contract + std::vector vHtlc = ParseHex(vStrInpScrSig[4]); + CScript htlc(vHtlc.begin(),vHtlc.end()); + + //check the input hash time lock contract is standard HTLC or not + if(!htlc.IsAtomicSwapPaymentScript()) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the parameter is no stander contract"); + } + + //split the hash time lock contract + std::string strHtlc = ScriptToAsmStr(htlc); + std::vector vStrHtlc; + boost::split(vStrHtlc, strHtlc, boost::is_any_of( " " ), boost::token_compress_on ); + + //get secret hash from contract + std::vector htlcRawHash = ParseHex(vStrHtlc[2]); + uint160 uHtlcRawHash(htlcRawHash); + + //get secret form script sig + std::string strRawHash =vStrInpScrSig[2]; + std::vector vScrSigRawHash =ParseHex(vStrInpScrSig[2]); + + //check the secret in parameter and in contract + std::vector txRawHash(20); + CRIPEMD160().Write(begin_ptr(vScrSigRawHash), vScrSigRawHash.size()).Finalize(begin_ptr(txRawHash)); + uint160 uTxRawHash(txRawHash); + if ( 0 != strcmp(uHtlcRawHash.ToString().c_str(),uTxRawHash.ToString().c_str()) ) + { + return JSONRPCError(RPC_INVALID_PARAMS, "Error:the rawhash in parameter not match in in HTLC"); + } + + //declare the return data + UniValue result(UniValue::VOBJ); + + //return the raw data of lock hash + result.push_back(Pair("rawhash",strRawHash)); + return result; + +} + +char * timeReachCalc(int t,char *buf) +{ + int h = t / 3600; + int m_t = t - 3600 * h; + int m = m_t / 60; + int s = m_t - m * 60; + sprintf(buf,"%dh %dm %ds",h,m,s); + return buf; +} + + +UniValue atomicswapchecktx(const UniValue ¶ms, bool fHelp) +{ + if (fHelp || params.size() !=2) + throw runtime_error( + "atomicswapchecktx \"htlc\" transaction\n" + "\nCheck atomic swap transaction and atomic swap hash time lock contract spending the given inputs .\n" + "\nArguments:\n" + "1. \"htlc \" (string,required) (string) The hash time lock contract in hex\n" + "2. \"transaction \" (string,required) The contract raw transaction in hex\n" + "\nResult:\n" + "\"amount\" (amount) The transaction for amount \n" + "\"address1\" (string) The address of receiver by base58\n" + "\"address2\" (string) The address of refund by base58\n" + "\"lockhash\" (string) The lock hash in hex\n" + "\"locktime\" (string) The lock time \n" + ); + + + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR)); + + string strHtlc = params[0].get_str(); + std::vectorvHtlc = ParseHex(strHtlc); + CScript htlc(vHtlc.begin(),vHtlc.end()); + CScriptID htlcP2SH = CScriptID(htlc); + CBitcoinAddress htlcAdr; + + CTransaction tx; + if (!DecodeHexTx(tx, params[1].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + + std::vector vSolutions; + txnouttype addressType; + uint160 addrhash; + CAmount value; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + const CScript scriptPubkey = StripClaimScriptPrefix(txout.scriptPubKey); + if (Solver(scriptPubkey, addressType, vSolutions)) + { + if(addressType== TX_SCRIPTHASH ) + { + addrhash=uint160(vSolutions[0]); + value = txout.nValue; + break; + } + else if(addressType==TX_PUBKEYHASH ) + { + addrhash=uint160(vSolutions[0]); + continue; + } + else if(addressType== TX_PUBKEY) + { + addrhash= Hash160(vSolutions[0]); + continue; + } + } + } + + std::vector vHtlcStrV; + + if ( 0 == strcmp(htlcP2SH.ToString().c_str(),addrhash.ToString().c_str()) ) + { + htlcAdr.Set(htlcP2SH); + if (!htlc.IsAtomicSwapPaymentScript()) + { + LogPrintf("HTLC is not an standard contract"); + } + //split the contract + std::string htlcString = ScriptToAsmStr(htlc); + boost::split( vHtlcStrV, htlcString, boost::is_any_of( " " ), boost::token_compress_on ); + } + else + { + throw JSONRPCError(RPC_INVALID_PARAMS, "TX decode failed"); + } + + CBitcoinAddress recAdr; + CBitcoinAddress refAdr; + std::vector vRecAdr = ParseHex(vHtlcStrV[6]); + std::vector uRefAdr = ParseHex(vHtlcStrV[13]); + uint160 uRecKeyId(vRecAdr); + uint160 uRefKeyId(uRefAdr); + recAdr.Set((CKeyID&)uRecKeyId); + refAdr.Set((CKeyID&)uRefKeyId); + std::string strLockHash = EncodeBase58(ParseHex(vHtlcStrV[2])); + + int64_t iLocktime = atoi64(vHtlcStrV[8]); + + struct timeval tmpTime; + gettimeofday(&tmpTime,NULL); + int64_t currentTime = tmpTime.tv_sec; + int64_t remainTime = iLocktime - currentTime ; + string strTime; + char tmpBuf[100] = {0}; + timeReachCalc(remainTime,tmpBuf); + strTime = tmpBuf; + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("amount",ValueFromAmount(value))); + result.push_back(Pair("address1",recAdr.ToString())); + result.push_back(Pair("address2",refAdr.ToString())); + result.push_back(Pair("lockhash",strLockHash)); + result.push_back(Pair("Locktime:",asctime(localtime(&iLocktime)))); + + return result; + + + +} + + + +#endif + + diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 9d7edf3..54ee54f 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -419,6 +419,13 @@ static const CRPCCommand vRPCCommands[] = { "Claimtrie", "getclaimsfortx", &getclaimsfortx, true }, { "Claimtrie", "getnameproof", &getnameproof, true }, { "Claimtrie", "getclaimbyid", &getclaimbyid, true }, + /*atomic swap rpc interface*/ + { "atomicswap", "atomicswapfirsttx", &atomicswapfirsttx, true }, + { "atomicswap", "atomicswapsecondtx", &atomicswapsecondtx, true }, + { "atomicswap", "atomicswapredeemtx", &atomicswapredeemtx, true }, + { "atomicswap", "atomicswaprefundtx", &atomicswaprefundtx, true }, + { "atomicswap", "atomicswapgetrawhash", &atomicswapgetrawhash, true }, + { "atomicswap", "atomicswapchecktx", &atomicswapchecktx, true }, #endif // ENABLE_WALLET }; diff --git a/src/rpcserver.h b/src/rpcserver.h index b462a21..3ddd304 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -294,6 +294,16 @@ extern UniValue getalluncleblock(const UniValue& params, bool fHelp); /*popchain ghost*/ + +/*popchain atomic swap*/ +extern UniValue atomicswapfirsttx(const UniValue ¶ms, bool fHelp); +extern UniValue atomicswapsecondtx(const UniValue ¶ms, bool fHelp); +extern UniValue atomicswapredeemtx(const UniValue ¶ms, bool fHelp); +extern UniValue atomicswaprefundtx(const UniValue ¶ms, bool fHelp); +extern UniValue atomicswapgetrawhash(const UniValue ¶ms, bool fHelp); +extern UniValue atomicswapchecktx(const UniValue ¶ms, bool fHelp); +/*popchain atomic swap*/ + extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); extern UniValue gettxout(const UniValue& params, bool fHelp); diff --git a/src/script/script.cpp b/src/script/script.cpp index d5377dc..c9a3ee4 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -220,8 +220,8 @@ bool CScript::IsNormalPaymentScript() const return true; } - -bool CScript::IsCrossChainPaymentScript() const +/*popchain atomic swap*/ +bool CScript::IsAtomicSwapPaymentScript() const { if(this->size() != 81) return false; @@ -252,6 +252,8 @@ bool CScript::IsCrossChainPaymentScript() const return true; } +/*popchain atomic swap*/ + bool CScript::IsPayToPublicKeyHash() const { // Extra-fast test for pay-to-pubkey-hash CScripts: diff --git a/src/script/script.h b/src/script/script.h index d534b0d..e4c64e4 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -619,7 +619,9 @@ class CScript : public CScriptBase unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsNormalPaymentScript() const; - bool IsCrossChainPaymentScript()const; + /*popchain atomic swap*/ + bool IsAtomicSwapPaymentScript()const; + /*popchain atomic swap*/ bool IsPayToPublicKeyHash() const; bool IsPayToScriptHash() const; From 0e80bc2e0656a26521b0d00b5f6461405072b58d Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 17 Sep 2018 20:36:14 +0800 Subject: [PATCH 076/120] clean some no use print --- src/chainparams.cpp | 62 +++------------ src/claimtrie.cpp | 7 +- src/consensus/params.h | 13 +--- src/cryptopop/PoW.c | 51 ------------- src/cryptopop/common.h | 1 - src/hash.h | 2 - src/main.cpp | 143 ++--------------------------------- src/miner.cpp | 12 +-- src/pow.cpp | 89 ---------------------- src/pow.h | 5 +- src/primitives/block.cpp | 5 +- src/superblock.cpp | 7 +- src/test/claimtrie_tests.cpp | 17 +---- src/txdb.cpp | 1 - 14 files changed, 29 insertions(+), 386 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index e45ddd8..5f20ba1 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -89,7 +89,6 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) static void findGenesis(CBlockHeader *pb, const std::string &net) { /*popchain ghost*/ - //arith_uint256 hashTarget = arith_uint256().SetCompact(pb->nBits); arith_uint256 hashTarget = maxUint256Div(pb->nDifficulty); /*popchain ghost*/ @@ -99,7 +98,7 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) std::vector threads; for (int i = 0; i < std::min(GetNumCores(), 100); ++i) - //for (int i = 0; i < 1; ++i) + { if (i >= 0) { @@ -109,7 +108,7 @@ static void findGenesis(CBlockHeader *pb, const std::string &net) nonce <<= 32; nonce >>= 16; pb->nNonce = ArithToUint256(nonce); - //std::cout<<"i = "< printscript(genesisOutputScript.begin(),genesisOutputScript.end); - //std::cout<< StrHex(printscript)<nChainWork "<nChainWork.ToString()<<" pb->nChainWork "<nChainWork.ToString()<nSequenceId "<nSequenceId<<" pb->nSequenceId "<nSequenceId<nChainWork > pb->nChainWork) return false; -// if (pa->nChainWork < pb->nChainWork) return true; - -// // ... then by earliest time received, ... -// if (pa->nSequenceId < pb->nSequenceId) return false; -// if (pa->nSequenceId > pb->nSequenceId) return true; - -// // Use pointer address as tie breaker (should only happen with blocks -// // loaded from disk, as those all have id 0). -// if (pa < pb) return false; -// if (pa > pb) return true; - -// // Identical blocks. -// return false; -// } + bool operator()(CBlockIndex *pa, CBlockIndex *pb) const { // First sort by most total work, ... @@ -1731,11 +1713,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus: } // Check the header - -//arith_uint256 k = UintToArith256(block.GetHash()); -//LogPrintf("\t\t\tblock = %s\n\t\t\thash = %s\n\t\t\tarith hash = %s\n", block.ToString().c_str(), block.GetHash().ToString().c_str(), k.ToString().c_str()); /*popchain ghost*/ - //if (!CheckProofOfWork(block.GetHash(), block.nDifficulty, consensusParams)) if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); /*popchain ghost*/ @@ -1832,13 +1810,8 @@ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) // return all subsidy /*popchain ghost*/ -//CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp) CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBlock& block) { - /* - return GetMinerSubsidy(height, cp) + - GetFoundersReward(height, cp); - */ CAmount ret = GetMainMinerSubsidy(height, cp, block.vuh.size()); int tmpBlockHeight = 0; for(int i = 0;i < block.vuh.size(); i++){ @@ -1847,7 +1820,6 @@ CAmount GetBlockSubsidy(const int height, const Consensus::Params &cp, const CBl } } ret += GetFoundersReward(height, cp); - //LogPrintf("GetBlockSubsidy at height: %d ,hash: s%,amount: %d",height,(*block).GetHash(),ret); return ret; } @@ -2621,7 +2593,6 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para bool GetBlockHash(uint256& hashRet, int nBlockHeight) { - //LOCK(cs_main); if(chainActive.Tip() == NULL) return false; if(nBlockHeight < -1 || nBlockHeight > chainActive.Height()) return false; if(nBlockHeight == -1) nBlockHeight = chainActive.Height(); @@ -2632,7 +2603,6 @@ bool GetBlockHash(uint256& hashRet, int nBlockHeight) /*popchain ghost*/ bool GetBlockHeight(uint256 hash, int* hight) { - //LOCK(cs_main); if (hash != uint256()) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end() && (*mi).second) { @@ -2647,7 +2617,6 @@ bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vC { LOCK(cs_main); LogPrintf("GetAncestorBlocksFromHash \n"); - //uint32_t number=0; if(hash == uint256()) return false; BlockMap::iterator mi = mapBlockIndex.find(hash); @@ -2666,7 +2635,6 @@ bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vC bool MakeCurrentCycle(uint256 hash) { - //LOCK(cs_main); LogPrintf("MakeCurrentCycle \n"); if(hash == uint256()) return false; @@ -2701,7 +2669,6 @@ bool MakeCurrentCycle(uint256 hash) bool CommitUncle(CBlockHeader uncle) { - //LOCK(cs_main); LogPrintf("CommitUncle \n"); uint256 hash = uncle.GetHash(); if(setCurrentUncle.count(hash) != 0){ @@ -2724,13 +2691,11 @@ void FindBlockUncles(uint256 parenthash,std::vector& vuncles) LogPrintf("FindBlockUncles in \n"); if(parenthash == uint256()){ LogPrintf("FindBlockUncles out 1 \n"); - //std::cout<<"parenthash == uint256()"<& vuncles) if(!MakeCurrentCycle(parenthash)){ LogPrintf("FindBlockUncles out 3 \n"); - //std::cout<<"!MakeCurrentCycle(parenthash"< badUncles; - //std::vector goodUncles; for(BlockMapGho::iterator it= mapPossibleUncles.begin(); it != mapPossibleUncles.end(); ++it){ if(vuncles.size() == 2){ break; @@ -2766,23 +2729,15 @@ void FindBlockUncles(uint256 parenthash,std::vector& vuncles) } } - //std::cout<<"findblockuncle vunces size"<::iterator it = badUncles.begin(); it != badUncles.end(); ++it){ BlockMapGho::iterator mi = mapPossibleUncles.find(*it); mapPossibleUncles.erase(mi); } LogPrintf("FindBlockUncles mapPossibleUncles size %d\n",mapPossibleUncles.size()); - //std::cout<<"findblockuncle parenthash "<nHeight, chainparams.GetConsensus()); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus(), block); /*popchain ghost*/ std::string strError = ""; @@ -3477,7 +3424,6 @@ bool static DisconnectTip(CValidationState& state, const Consensus::Params& cons return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); assert(trieCache.flush()); - //assert(pindexDelete->pprev->hashClaimTrie == trieCache.getMerkleHash()); } LogPrint("bench", "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * 0.001); // Write the chain state to disk, if necessary. @@ -3724,9 +3670,6 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c possibleBlockHash = pindexPossibleBlock->GetBlockHash(); ReadBlockFromDisk(possibleBlock, pindexPossibleBlock, chainparams.GetConsensus()); mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); -// std::cout<<"ActivateBestChainStep add to possibleUncles block hash: "<GetHash(),*pblock)); -// std::cout<<"ActivateBestChain add to possibleUncles block hash: "<::iterator it = dBlock.vuh.begin(); it != dBlock.vuh.end(); ++it){ - CBlockHeader blockheader = *it; - //std::cout<<" bad-uncleshash block.vuh[]: "<::iterator bi = tmpBlock.vuh.begin(); bi != tmpBlock.vuh.end(); ++bi){ tmpBlockHeader = *bi; unclesset.insert(tmpBlockHeader.GetHash()); - //LogPrintf("AcceptUnclesHeader unclesset nNmber: %d , hash:%s \n",tmpBlockHeader.nNumber,tmpBlockHeader.GetHash().ToString()); } ancestorset.insert(tmpBlockIndex->GetBlockHash()); - //LogPrintf("AcceptUnclesHeader ancestorset nNmber: %d , hash:%s \n",tmpBlockIndex->nNumber,tmpBlockIndex->GetBlockHash().ToString()); } else{ return false; } } LogPrintf("AcceptUnclesHeader ancestorset size: %d \n", ancestorset.size()); - //LogPrintf("AcceptUnclesHeader unclesset size: %d \n", unclesset.size()); for(std::vector::iterator it = blockUncles.begin(); it != blockUncles.end(); ++it){ tmpBlockHeader = *it; @@ -4540,21 +4427,20 @@ static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, co if(unclesset.count(tmpHash) != 0){ return false; } - //LogPrintf("AcceptUnclesHeader unclesset check ok\n"); + if(ancestorset.count(tmpBlockHeader.hashPrevBlock) == 0){ return false; } - //LogPrintf("AcceptUnclesHeader ancestorset parent check ok\n"); + if(ancestorset.count(tmpHash) !=0){ return false; } - //LogPrintf("AcceptUnclesHeader ancestorset self check ok\n"); + if(fCheckPOW){ if(!CheckBlockHeader(tmpBlockHeader,state,fCheckPOW)){ return false; } } - //LogPrintf("AcceptUnclesHeader CheckBlockHeader check ok\n"); } LogPrintf("AcceptUnclesHeader OK \n"); @@ -4741,7 +4627,6 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c /*popchain ghost*/ if(pblock->hashUncles != uint256()){ CBlock blockhasuncle = *pblock; - //std::cout<<"ProcessNewBlock block have uncles: "<nHeight == lastCheckpoint_t.first && lastCheckpoint_t.first != 0){ - if (header.hashPrevBlock != lastCheckpoint_t.second){ - LogPrintf("synchronous chain hash = %s\n",header.hashPrevBlock.ToString()); - LogPrintf("lastCheckpoint height = %d, lastCheckpoint hash = %s\n",lastCheckpoint_t.first,lastCheckpoint_t.second.ToString()); - return error("prevent chain synchronization.\n"); - } - else LogPrintf("checkpoint verify correct.\n"); - }*/ if (pindexLast != NULL && header.hashPrevBlock != pindexLast->GetBlockHash()) { Misbehaving(pfrom->GetId(), 20); diff --git a/src/miner.cpp b/src/miner.cpp index 229eb1d..59bdd20 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -71,10 +71,6 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam // Updating time can change work required on testnet: if (consensusParams.fPowAllowMinDifficultyBlocks) { - //std::cout<<"update time: nOldTime"<nBits = getNBits(getHashTraget(calculateDifficulty(pindexPrev, pblock, consensusParams))); - //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams); - pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, consensusParams); pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); } @@ -498,7 +494,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s /*popchain ghost*/ UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nDifficulty = calculateDifficulty(pindexPrev, pblock, chainparams.GetConsensus()); - //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); /*popchain ghost*/ @@ -546,9 +541,7 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned pblock->vtx[0] = txCoinbase; pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - /*popchain ghost*/ - //pblock->hashUncles = BlockUncleRoot(*pblock); - /*popchain ghost*/ + } static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) @@ -561,7 +554,6 @@ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainpar LOCK(cs_main); if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash()) { - //LogPrintf("hashPrevBlock = %s, Tip hash = %s\n", pblock->hashPrevBlock, chainActive.Tip()->GetBlockHash()); return error("ProcessBlockFound -- generated block is stale"); } } @@ -638,7 +630,6 @@ void static BitcoinMiner(const CChainParams& chainparams) // Search // int64_t nStart = GetTime(); - //pblock->nDifficulty = calculateDifficulty() arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); while (true) { @@ -668,7 +659,6 @@ void static BitcoinMiner(const CChainParams& chainparams) //change parameter 0xFF to 0xffff to support the ghost protol if ((UintToArith256(pblock->nNonce) & 0xFF) == 0) { - //LogPrintf("PopMiner: %d nExtraNonce: %d\n", pblock->nNonce, nExtraNonce); break; } } diff --git a/src/pow.cpp b/src/pow.cpp index 173cb63..10265b9 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -21,10 +21,6 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo if (pindex == NULL) return params.minimumDifficulty; -// const CBlockIndex* pindexParent = pindex->pprev; -// if (pindexParent == NULL) -// return params.minimumDifficulty; - if (UintToArith256(pindex->GetBlockHash()) == UintToArith256(params.hashGenesisBlock)) return params.minimumDifficulty; @@ -34,11 +30,9 @@ uint64_t calculateDifficulty(const CBlockIndex* pindex, const CBlockHeader *pblo if (pindex->nHeight < params.nYolandaTime){ if (timestampDiff < 45) difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyRapidFitDivisor; else difficulty = pindex->nDifficulty - pindex->nDifficulty / params.difficultyRapidFitDivisor; - //std::cout<<"AStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "<hasUncles() ? 2 : 1) - timestampDiff / 29, -99); difficulty = pindex->nDifficulty + pindex->nDifficulty / params.difficultyBoundDivisor * adjFactor; - //std::cout<<"BStep"<<" height "<nHeight<<" nTime: "<nTime<<" timestampDiff: "< 0); @@ -67,72 +61,8 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindex, const CBlockHeader * } -/* -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) -{ - unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact(); - - // Genesis block - if (pindexLast == NULL) - return nProofOfWorkLimit; - - // Find the first block in the averaging interval - const CBlockIndex* pindexFirst = pindexLast; - arith_uint256 bnTot {0}; - for (int i = 0; pindexFirst && i < params.nPowAveragingWindow; i++) { // 17 - arith_uint256 bnTmp; - bnTmp.SetCompact(pindexFirst->nBits); - bnTot += bnTmp; - pindexFirst = pindexFirst->pprev; - } - - // Check we have enough blocks - if (pindexFirst == NULL) - return nProofOfWorkLimit; - - arith_uint256 bnAvg {bnTot / params.nPowAveragingWindow}; - - return CalculateNextWorkRequired(bnAvg, pindexLast->GetMedianTimePast(), pindexFirst->GetMedianTimePast(), params); -} - -unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, - int64_t nLastBlockTime, int64_t nFirstBlockTime, - const Consensus::Params& params) -{ - // Limit adjustment step - // Use medians to prevent time-warp attacks - int64_t nActualTimespan = nLastBlockTime - nFirstBlockTime; - LogPrint("pow", " nActualTimespan = %d before dampening\n", nActualTimespan); - nActualTimespan = params.AveragingWindowTimespan() + (nActualTimespan - params.AveragingWindowTimespan())/4; - LogPrint("pow", " nActualTimespan = %d before bounds\n", nActualTimespan); - - if (nActualTimespan < params.MinActualTimespan()) - nActualTimespan = params.MinActualTimespan(); - if (nActualTimespan > params.MaxActualTimespan()) - nActualTimespan = params.MaxActualTimespan(); - - // Retarget - const arith_uint256 bnPowLimit = UintToArith256(params.powLimit); - arith_uint256 bnNew {bnAvg}; - bnNew /= params.AveragingWindowTimespan(); - bnNew *= nActualTimespan; - - if (bnNew > bnPowLimit) - bnNew = bnPowLimit; - - /// debug print - LogPrint("pow", "GetNextWorkRequired RETARGET\n"); - LogPrint("pow", "params.AveragingWindowTimespan() = %d nActualTimespan = %d\n", params.AveragingWindowTimespan(), nActualTimespan); - LogPrint("pow", "Current average: %08x %s\n", bnAvg.GetCompact(), bnAvg.ToString()); - LogPrint("pow", "After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); - - return bnNew.GetCompact(); -} -*/ - /*popchain ghost*/ -//bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params& params) bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative = false; @@ -140,7 +70,6 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& arith_uint256 bnTarget; bnTarget.SetCompact(nBits, &fNegative, &fOverflow); - //bnTarget = maxUint256Div(nDifficulty); // Check range if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) @@ -159,27 +88,9 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& /*popchain ghost*/ arith_uint256 GetBlockDifficulty(const CBlockIndex& block) { -// arith_uint256 bnTarget; -// bool fNegative; -// bool fOverflow; - -// bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); -// if (fNegative || fOverflow || bnTarget == 0) -// return 0; - // We need to compute 2**256 / (bnTarget+1), but we can't represent 2**256 - // as it's too large for a arith_uint256. However, as 2**256 is at least as large - // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1, - // or ~bnTarget / (nTarget+1) + 1. - //return (~bnTarget / (bnTarget + 1)) + 1; - if (block.nDifficulty > 0) return block.nDifficulty; return 0; - - /*popchain ghost*/ - //bnTarget = maxUint256Div(block.nDifficulty); - //return bnTarget; - /*popchain ghost*/ } /*popchain ghost*/ diff --git a/src/pow.h b/src/pow.h index bef88e7..637a7eb 100644 --- a/src/pow.h +++ b/src/pow.h @@ -20,15 +20,12 @@ uint32_t getNBits(arith_uint256 hashTarget); unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); /*popchain ghost*/ -//unsigned int CalculateNextWorkRequired(arith_uint256 bnAvg, -// int64_t nLastBlockTime, int64_t nFirstBlockTime, -// const Consensus::Params&); + /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ /*popchain ghost*/ bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); -//bool CheckProofOfWork(uint256 hash, uint256 nDifficulty, const Consensus::Params&); /*popchain ghost*/ arith_uint256 GetBlockDifficulty(const CBlockIndex& block); diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index f77d207..eda92a3 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -10,15 +10,12 @@ // popchain ghost calc blockheader hash uint256 CBlockHeader::GetHash() const { -// return SerializeHash(*this); + uint256 hash; /*popchain ghost*/ CryptoPop(this, (unsigned char *)&hash); /*popchain ghost*/ -// view_data_u8("PoW 3", (unsigned char *)&hash, OUTPUT_LEN); -// std::cout<<"gethex() ="<vtx[0] = CTransaction(txCoinbase); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); - //pblock->nBits=GetNextWorkRequired(chainActive.Tip(),pblock,chainparams.GetConsensus()); pblock->nDifficulty = calculateDifficulty(chainActive.Tip(),pblock,chainparams.GetConsensus()); pblock->nBits = getNBits(getHashTraget(pblock->nDifficulty)); for (arith_uint256 i = 0; ; ++i) { pblock->nNonce = ArithToUint256(i); /*popchain ghost*/ - //if (CheckProofOfWork(pblock->GetHash(), pblock->nDifficulty, chainparams.GetConsensus())) if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, chainparams.GetConsensus())) { break; diff --git a/src/txdb.cpp b/src/txdb.cpp index 99b4a4a..a1f8220 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -341,7 +341,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; /*popchain ghost*/ - //if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nDifficulty, Params().GetConsensus())) if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); From 43195faf3c3e566f2ec8515c2140705b9eb5de41 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 17 Sep 2018 20:54:28 +0800 Subject: [PATCH 077/120] clean some no use print --- src/chainparams.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5f20ba1..effbf08 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -60,7 +60,7 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) { uint256 hash = pb->GetHash(); - //std::cout<<"hex hash = "<nNonce = ArithToUint256(UintToArith256(pb->nNonce) + 1); @@ -186,7 +186,7 @@ class CMainParams : public CChainParams { consensus.premine = int64_t(6e8 * COIN); // premine consensus.genesisReward = int64_t(1 * COIN); // genesis consensus.minerReward4 = int64_t(73.648 * COIN); // miners - //consensus.minerReward5 = int64_t(133.775 * COIN); + consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral @@ -249,7 +249,6 @@ class CMainParams : public CChainParams { //findGenesis(&genesis, "main"); #endif consensus.hashGenesisBlock = genesis.GetHash(); - //assert(consensus.hashGenesisBlock == uint256S("0x000000747aad802a9081bd47533cf105a6e7203ca6313155adf41bd11bf0f01f")); assert(consensus.hashGenesisBlock == uint256S("0x00000405ea05415dea82707713f47fe9bb40f877602b32f8b9303369c6040705")); assert(genesis.hashMerkleRoot == uint256S("0x69de4474f3172f2366a11b9d5a2b9138fb5bbb0b77713d42fdfe69fc64a34162")); @@ -312,7 +311,6 @@ class CTestNetParams : public CChainParams { consensus.premine = int64_t(6e8 * COIN); // premine consensus.genesisReward = int64_t(1 * COIN); // genesis consensus.minerReward4 = int64_t(73.648 * COIN); // miners - //consensus.minerReward5 = int64_t(535.103 * COIN); consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral From 730c7c4be5021218e500180b182a76e009c8ac64 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 17 Sep 2018 21:14:26 +0800 Subject: [PATCH 078/120] clean some not use code --- src/checkpoints.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 7d75cd1..65f8b37 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -94,13 +94,6 @@ namespace Checkpoints { } - /*PairCheckpoints ForceGetLastCheckpoint(const CCheckpointData& data){ - const MapCheckpoints& checkpoints = data.mapCheckpoints; - BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints){ - return i; - } - } - */ } // namespace Checkpoints From 778579e6bc70235380b6a7e893584d5b33956c0b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 17 Sep 2018 21:19:01 +0800 Subject: [PATCH 079/120] clean some no use code --- src/nameclaim.cpp | 136 ---------------------------------------------- 1 file changed, 136 deletions(-) diff --git a/src/nameclaim.cpp b/src/nameclaim.cpp index df0682b..4487802 100644 --- a/src/nameclaim.cpp +++ b/src/nameclaim.cpp @@ -2,21 +2,7 @@ #include "hash.h" #include "util.h" -/***************************************************************************** - º¯ Êý Ãû: uint32_t_to_vch - ¹¦ÄÜÃèÊö : ÎÞ·ûºÅintת»»³ÉÎÞ·ûºÅµÄchar - ÊäÈë²ÎÊý : uint32_t n - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : std::vector - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ std::vector uint32_t_to_vch(uint32_t n) { std::vector vchN; @@ -28,21 +14,7 @@ std::vector uint32_t_to_vch(uint32_t n) return vchN; } -/***************************************************************************** - º¯ Êý Ãû: vch_to_uint32_t - ¹¦ÄÜÃèÊö : ÎÞ·ûºÅµÄcharת»»³ÉÎÞ·ûºÅint - ÊäÈë²ÎÊý : uint32_t n - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : std::vector - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ uint32_t vch_to_uint32_t(std::vector& vchN) { uint32_t n; @@ -55,22 +27,7 @@ uint32_t vch_to_uint32_t(std::vector& vchN) return n; } -/***************************************************************************** - º¯ Êý Ãû: ClaimNameScript - ¹¦ÄÜÃèÊö : ÈÏÁì½Å±¾µÄÃû³Æ - ÊäÈë²ÎÊý : std::string name - std::string value - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ: CScript - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ CScript ClaimNameScript(std::string name, std::string value) { std::vector vchName(name.begin(), name.end()); @@ -78,22 +35,7 @@ CScript ClaimNameScript(std::string name, std::string value) return CScript() << OP_CLAIM_NAME << vchName << vchValue << OP_2DROP << OP_DROP << OP_TRUE; } -/***************************************************************************** - º¯ Êý Ãû: SupportClaimScript - ¹¦ÄÜÃèÊö : ÈÏÁì½Å±¾µÄÖ§³Ö - ÊäÈë²ÎÊý : std::string name - uint160 claimId - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ: CScript - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ CScript SupportClaimScript(std::string name, uint160 claimId) { std::vector vchName(name.begin(), name.end()); @@ -101,23 +43,7 @@ CScript SupportClaimScript(std::string name, uint160 claimId) return CScript() << OP_SUPPORT_CLAIM << vchName << vchClaimId << OP_2DROP << OP_DROP << OP_TRUE; } -/***************************************************************************** - º¯ Êý Ãû: UpdateClaimScript - ¹¦ÄÜÃèÊö : ÈÏÁì½Å±¾µÄ¸üР- ÊäÈë²ÎÊý : std::string name - uint160 claimId - std::string value - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : CScript - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value) { std::vector vchName(name.begin(), name.end()); @@ -126,47 +52,14 @@ CScript UpdateClaimScript(std::string name, uint160 claimId, std::string value) return CScript() << OP_UPDATE_CLAIM << vchName << vchClaimId << vchValue << OP_2DROP << OP_2DROP << OP_TRUE; } -/***************************************************************************** - º¯ Êý Ãû: DecodeClaimScript - ¹¦ÄÜÃèÊö : ¶ÔÓÐÒªÇóµÄ½Å±¾½âÂë - ÊäÈë²ÎÊý : const CScript& scriptIn - int& op - std::vector >& vvchParams - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : bool - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector >& vvchParams) { CScript::const_iterator pc = scriptIn.begin(); return DecodeClaimScript(scriptIn, op, vvchParams, pc); } -/***************************************************************************** - º¯ Êý Ãû: DecodeClaimScript - ¹¦ÄÜÃèÊö : È¡³ö½Å±¾µÄ²Ù×÷ÊýÖ¸Áî - ÊäÈë²ÎÊý : const CScript& scriptIn - int& op - std::vector >& vvchParams - CScript::const_iterator& pc - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : bool - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector >& vvchParams, CScript::const_iterator& pc) { opcodetype opcode; @@ -239,22 +132,7 @@ bool DecodeClaimScript(const CScript& scriptIn, int& op, std::vector claimToHash(txhash.begin(), txhash.end()); @@ -282,21 +160,7 @@ CScript StripClaimScriptPrefix(const CScript& scriptIn, int& op) return CScript(pc, scriptIn.end()); } -/***************************************************************************** - º¯ Êý Ãû : ClaimScriptSize - ¹¦ÄÜÃèÊö : ÈÏÁì½Å±¾µÄ´óС - ÊäÈë²ÎÊý : const CScript& scriptIn - Êä³ö²ÎÊý : ÎÞ - ·µ »Ø Öµ : size_t - µ÷Óú¯Êý : - ±»µ÷º¯Êý : - - ÐÞ¸ÄÀúÊ· : - 1.ÈÕ ÆÚ : 2017Äê10ÔÂ30ÈÕ - ×÷ Õß : zhoukaiyuan - ÐÞ¸ÄÄÚÈÝ : ÐÂÉú³Éº¯Êý -*****************************************************************************/ size_t ClaimScriptSize(const CScript& scriptIn) { CScript strippedScript = StripClaimScriptPrefix(scriptIn); From 1cf07fc57b0c38fbfda4b2eccc3016f250b0f4ed Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 18 Sep 2018 09:27:10 +0800 Subject: [PATCH 080/120] delete some notes --- share/qt/Info.plist.in | 2 +- src/chainparams.cpp | 18 +++++++++--------- src/hdchain.h | 6 +++--- src/qt/locale/pop_bg.ts | 4 ++-- src/qt/locale/pop_en.ts | 4 ++-- src/qt/locale/pop_es.ts | 4 ++-- src/qt/locale/pop_fi.ts | 4 ++-- src/qt/locale/pop_fr.ts | 4 ++-- src/qt/locale/pop_pl.ts | 4 ++-- src/qt/locale/pop_pt.ts | 4 ++-- src/qt/locale/pop_ru.ts | 4 ++-- src/qt/locale/pop_sk.ts | 4 ++-- src/qt/locale/pop_vi.ts | 2 +- src/qt/locale/pop_zh_CN.ts | 6 +++--- src/qt/locale/pop_zh_TW.ts | 4 ++-- src/qt/popstrings.cpp | 2 +- src/qt/res/css/crownium.css | 2 +- src/qt/res/css/drkblue.css | 2 +- src/qt/res/css/light.css | 2 +- src/wallet/wallet.cpp | 6 +++--- 20 files changed, 44 insertions(+), 44 deletions(-) diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 0aa1498..2aac062 100755 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -17,7 +17,7 @@ APPL CFBundleGetInfoString - @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2014-@COPYRIGHT_YEAR@ The Dash Core developers + @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@, Copyright © 2009-@COPYRIGHT_YEAR@ The Bitcoin Core developers, 2017-@COPYRIGHT_YEAR@ The Pop Core developers CFBundleShortVersionString @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index effbf08..4e7305e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -77,9 +77,9 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) } std::lock_guard guard(mtx); - std::cout << "\n\t\t----------------------------------------\t" << std::endl; - std::cout << "\t" << pb->ToString() << std::endl; - std::cout << "\n\t\t----------------------------------------\t" << std::endl; +// std::cout << "\n\t\t----------------------------------------\t" << std::endl; +// std::cout << "\t" << pb->ToString() << std::endl; +// std::cout << "\n\t\t----------------------------------------\t" << std::endl; delete pb; // stop while found one @@ -314,10 +314,10 @@ class CTestNetParams : public CChainParams { consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - consensus.nSubsidyHalvingInterval = 1920; //1 day + consensus.nSubsidyHalvingInterval = 2803200; //4 year consensus.nInstantSendKeepLock = 6; - consensus.nSuperblockStartBlock = 40; - consensus.nSuperblockCycle = 40; //30 minutes + consensus.nSuperblockStartBlock = 100; + consensus.nSuperblockCycle = 57600; //30 minutes consensus.nUncleblockRatio = 0.1; consensus.nPopnodeMinimumConfirmations = 2; consensus.nMajorityEnforceBlockUpgrade = 51; @@ -328,10 +328,10 @@ class CTestNetParams : public CChainParams { /* popchain ghost */ consensus.powLimit = uint256S("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.difficultyBoundDivisor = 1024; - consensus.difficultyRapidFitDivisor = 50; + consensus.difficultyBoundDivisor = 2048; + consensus.difficultyRapidFitDivisor = 1024; consensus.minimumDifficulty = 4096; - consensus.nYolandaTime = 960; + consensus.nYolandaTime = 57600; /* popchain ghost */ consensus.nPowTargetSpacing = 45; diff --git a/src/hdchain.h b/src/hdchain.h index 7492920..e3b7c71 100644 --- a/src/hdchain.h +++ b/src/hdchain.h @@ -1,7 +1,7 @@ // Copyright (c) 2017-2018 The Popchain Core Developers -#ifndef DASH_HDCHAIN_H -#define DASH_HDCHAIN_H +#ifndef POP_HDCHAIN_H +#define POP_HDCHAIN_H #include "key.h" #include "sync.h" @@ -149,4 +149,4 @@ class CHDPubKey std::string GetKeyPath() const; }; -#endif // DASH_HDCHAIN_H +#endif // POP_HDCHAIN_H diff --git a/src/qt/locale/pop_bg.ts b/src/qt/locale/pop_bg.ts index 7070372..8c18473 100644 --- a/src/qt/locale/pop_bg.ts +++ b/src/qt/locale/pop_bg.ts @@ -3787,8 +3787,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Запазени права (C) 2009-%i Bitcoin Core разработчици - Copyright (C) 2014-%i The Dash Core Developers - Запазени права (C) 2014-%i Pop Core разработчиците + Copyright (C) 2017-%i The Pop Core Developers + Запазени права (C) 2017-%i Pop Core разработчиците Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_en.ts b/src/qt/locale/pop_en.ts index a7d7f98..c0f9d02 100644 --- a/src/qt/locale/pop_en.ts +++ b/src/qt/locale/pop_en.ts @@ -4832,8 +4832,8 @@ for example: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i The Pop Core Developers diff --git a/src/qt/locale/pop_es.ts b/src/qt/locale/pop_es.ts index 0f68b7f..1d11b6b 100644 --- a/src/qt/locale/pop_es.ts +++ b/src/qt/locale/pop_es.ts @@ -3797,8 +3797,8 @@ por ejemplo: alertnotify=echo %%s | mail -s "Alerta de Pop" admin@foo.com Copyright (C) 2009-%i Los Desarrolladores de Bitcoin Core - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i Los Desarrolladores de Dash Core + Copyright (C) 2017%i The Pop Core Developers + Copyright (C) 2017-%i Los Desarrolladores de Pop Core Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_fi.ts b/src/qt/locale/pop_fi.ts index 9cbc83e..84cef38 100644 --- a/src/qt/locale/pop_fi.ts +++ b/src/qt/locale/pop_fi.ts @@ -3803,8 +3803,8 @@ esimerkiksi: alertnotify=echo %%s | mail -s "Pop Hälytys" admin@foo.com Copyright (C) 2009-%i Bitcoin Core Kehittäjät - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i Dash Core Kehittäjät + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i Pop Core Kehittäjät Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_fr.ts b/src/qt/locale/pop_fr.ts index 5cc13aa..a973e21 100644 --- a/src/qt/locale/pop_fr.ts +++ b/src/qt/locale/pop_fr.ts @@ -3796,8 +3796,8 @@ Pour exemple: alertnotify=echo %%s | mail -s "Alerte Pop" admin@foo.com Copyright (C) 2009-%i The Bitcoin Core Developers - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i The Pop Core Developers Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_pl.ts b/src/qt/locale/pop_pl.ts index 7f07e62..0e7f787 100644 --- a/src/qt/locale/pop_pl.ts +++ b/src/qt/locale/pop_pl.ts @@ -3795,8 +3795,8 @@ Zaleca siÄ™ również aby ustawić alarm powiadomieÅ„ tzw. alertnotify, aby dać Prawo autorskie (c) 2009-%i deweloperzy Bitcoin - Copyright (C) 2014-%i The Dash Core Developers - Prawa autorskie (C) 2014-%i deweloperzy Pop + Copyright (C) 2017-%i The Pop Core Developers + Prawa autorskie (C) 2017-%i deweloperzy Pop Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_pt.ts b/src/qt/locale/pop_pt.ts index 9462982..b40b323 100644 --- a/src/qt/locale/pop_pt.ts +++ b/src/qt/locale/pop_pt.ts @@ -3696,8 +3696,8 @@ https://www.transifex.com/projects/p/pop/ Copyright (C) 2009-%i The Bitcoin Core Developers - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i Dash Core Developers + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i Pop Core Developers Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_ru.ts b/src/qt/locale/pop_ru.ts index 66fbd1f..97de679 100644 --- a/src/qt/locale/pop_ru.ts +++ b/src/qt/locale/pop_ru.ts @@ -3796,8 +3796,8 @@ rpcpassword=%s Copyright (C) 2009-%i The Bitcoin Core Developers - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i The Pop Core Developers Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_sk.ts b/src/qt/locale/pop_sk.ts index 947ad69..fbb3fdd 100644 --- a/src/qt/locale/pop_sk.ts +++ b/src/qt/locale/pop_sk.ts @@ -3795,8 +3795,8 @@ napríklad: alertnotify=echo %%s | mail -s "Pop Upozornenie" admin@foo.com Autorské práva (C) 2009-%i Vývojári jadra Bitcoin - Copyright (C) 2014-%i The Dash Core Developers - Autorské práva (C) 2014-%i Vývojári jadra Pop + Copyright (C) 2017-%i The Pop Core Developers + Autorské práva (C) 2017-%i Vývojári jadra Pop Could not parse -rpcbind value %s as network address diff --git a/src/qt/locale/pop_vi.ts b/src/qt/locale/pop_vi.ts index 5d21ef7..fe1394b 100644 --- a/src/qt/locale/pop_vi.ts +++ b/src/qt/locale/pop_vi.ts @@ -3795,7 +3795,7 @@ ví dụ: alertnotify=echo %%s | mail -s "Pop Alert" admin@foo.com Bản quyá»n (C) 2009-%i bởi Nhóm phát triển Bitcoin Core - Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2017-%i The Pop Core Developers Bản quyá»n (C) 2014-%i bởi Nhóm phát triển Pop Core diff --git a/src/qt/locale/pop_zh_CN.ts b/src/qt/locale/pop_zh_CN.ts index a249a2e..804d8a8 100644 --- a/src/qt/locale/pop_zh_CN.ts +++ b/src/qt/locale/pop_zh_CN.ts @@ -2950,8 +2950,8 @@ https://www.transifex.com/projects/p/pop/ Bitcoin Core的开å‘者 - The Dash Core developers - Dash的开å‘者 + The Pop Core developers + Pop的开å‘者 Pop Foundation Ltd. @@ -3898,7 +3898,7 @@ https://www.transifex.com/projects/p/pop/ 版æƒ(C) 2009-%i The Bitcoin Core Developers - Copyright (C) 2014-%i The Dash Core Developers + Copyright (C) 2014-%i The Pop Core Developers ç‰ˆæƒ (C) 2017-%i Pop Foundation Ltd. diff --git a/src/qt/locale/pop_zh_TW.ts b/src/qt/locale/pop_zh_TW.ts index a5386b7..8452a84 100644 --- a/src/qt/locale/pop_zh_TW.ts +++ b/src/qt/locale/pop_zh_TW.ts @@ -3530,8 +3530,8 @@ https://www.transifex.com/projects/p/pop/ 版權為ä½å…ƒå¹£æ ¸å¿ƒé–‹ç™¼äººå“¡è‡ªè¥¿å…ƒ 2009 至 %i 年起所有 - Copyright (C) 2014-%i The Dash Core Developers - 版權為Pop全节点钱包開發人員自西元 2014 至 %i 年起所有 + Copyright (C) 2017-%i The Pop Core Developers + 版權為Pop全节点钱包開發人員自西元 2017 至 %i 年起所有 Could not parse -rpcbind value %s as network address diff --git a/src/qt/popstrings.cpp b/src/qt/popstrings.cpp index 83f5695..7c4107b 100644 --- a/src/qt/popstrings.cpp +++ b/src/qt/popstrings.cpp @@ -232,7 +232,7 @@ QT_TRANSLATE_NOOP("pop-core", "Connect to KeePassHttp on port (default: % QT_TRANSLATE_NOOP("pop-core", "Connect to a node to retrieve peer addresses, and disconnect"), QT_TRANSLATE_NOOP("pop-core", "Connection options:"), QT_TRANSLATE_NOOP("pop-core", "Copyright (C) 2009-%i The Bitcoin Core Developers"), -QT_TRANSLATE_NOOP("pop-core", "Copyright (C) 2014-%i The Dash Core Developers"), +QT_TRANSLATE_NOOP("pop-core", "Copyright (C) 2017-%i The Pop Core Developers"), QT_TRANSLATE_NOOP("pop-core", "Corrupted block database detected"), QT_TRANSLATE_NOOP("pop-core", "Could not parse -rpcbind value %s as network address"), QT_TRANSLATE_NOOP("pop-core", "Could not parse popnode.conf"), diff --git a/src/qt/res/css/crownium.css b/src/qt/res/css/crownium.css index ebd704a..984b53e 100644 --- a/src/qt/res/css/crownium.css +++ b/src/qt/res/css/crownium.css @@ -767,7 +767,7 @@ QDialog#AboutDialog { background-color:#F8F6F6; } -QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Dash Contents */ +QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Pop Contents */ margin-left:10px; } diff --git a/src/qt/res/css/drkblue.css b/src/qt/res/css/drkblue.css index 9956d96..d2344e2 100644 --- a/src/qt/res/css/drkblue.css +++ b/src/qt/res/css/drkblue.css @@ -745,7 +745,7 @@ QDialog#AboutDialog { background-color:#F8F6F6; } -QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Dash Contents */ +QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Pop Contents */ margin-left:10px; } diff --git a/src/qt/res/css/light.css b/src/qt/res/css/light.css index 67bbafd..2108141 100644 --- a/src/qt/res/css/light.css +++ b/src/qt/res/css/light.css @@ -789,7 +789,7 @@ QDialog#AboutDialog { background-color:#F8F6F6; } -QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Dash Contents */ +QDialog#AboutDialog QLabel#label, QDialog#AboutDialog QLabel#copyrightLabel, QDialog#AboutDialog QLabel#label_2 { /* About Pop Contents */ margin-left:10px; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 2ea24f8..55162e2 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3758,9 +3758,9 @@ bool CWallet::AbandonCash(const vector& vecSend, CWalletTx& wtxNew, if (!SelectCoins(nValueToSelect, setCoins, nValueIn, coinControl, nCoinType, fUseInstantSend)) { if (nCoinType == ONLY_NOT1000IFMN) { - strFailReason = _("Unable to locate enough funds for this transaction that are not equal 1000 DASH."); + strFailReason = _("Unable to locate enough funds for this transaction that are not equal 10000 PCH."); } else if (nCoinType == ONLY_NONDENOMINATED_NOT1000IFMN) { - strFailReason = _("Unable to locate enough PrivateSend non-denominated funds for this transaction that are not equal 1000 DASH."); + strFailReason = _("Unable to locate enough PrivateSend non-denominated funds for this transaction that are not equal 10000 PCH."); } else if (nCoinType == ONLY_DENOMINATED) { strFailReason = _("Unable to locate enough PrivateSend denominated funds for this transaction."); strFailReason += " " + _("PrivateSend uses exact denominated amounts to send funds, you might simply need to anonymize some more coins."); @@ -3769,7 +3769,7 @@ bool CWallet::AbandonCash(const vector& vecSend, CWalletTx& wtxNew, } if (fUseInstantSend) { if (nValueIn > sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)*COIN) { - strFailReason += " " + strprintf(_("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 DASH."), sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)); + strFailReason += " " + strprintf(_("InstantSend doesn't support sending values that high yet. Transactions are currently limited to %1 PCH."), sporkManager.GetSporkValue(SPORK_5_INSTANTSEND_MAX_VALUE)); } else { // could be not true but most likely that's the reason strFailReason += " " + strprintf(_("InstantSend requires inputs with at least %d confirmations, you might need to wait a few minutes and try again."), INSTANTSEND_CONFIRMATIONS_REQUIRED); From 863543ed7233faa28564c096ab92ec1f4e8ba8c0 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 18 Sep 2018 10:16:45 +0800 Subject: [PATCH 081/120] delete some notes --- src/qt/locale/pop_de.ts | 4 ++-- src/qt/splashscreen.cpp | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/qt/locale/pop_de.ts b/src/qt/locale/pop_de.ts index 5da0b60..9a430a8 100644 --- a/src/qt/locale/pop_de.ts +++ b/src/qt/locale/pop_de.ts @@ -3795,8 +3795,8 @@ zum Beispiel: alertnotify=echo %%s | mail -s \"Pop Alert\" admin@foo.comCopyright (C) 2009-%i Die "Bitcoin Core"-Entwickler - Copyright (C) 2014-%i The Dash Core Developers - Copyright (C) 2014-%i Die "Dash Core"-Entwickler + Copyright (C) 2017-%i The Pop Core Developers + Copyright (C) 2017-%i Die "Pop Core"-Entwickler Could not parse -rpcbind value %s as network address diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 975fc90..dbd3787 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -38,8 +38,6 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) // define text to place QString titleText = tr("Pop Core"); QString versionText = QString(tr("Version %1")).arg(QString::fromStdString(FormatFullVersion())); - // QString copyrightTextBtc = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); - // QString copyrightTextDash = QChar(0xA9)+QString(" 2014-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Dash Core developers")); QString copyrightTextPop = QChar(0xA9)+QString(" 2017-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("Pop Foundation Ltd.")); QString titleAddText = networkStyle->getTitleAddText(); @@ -77,8 +75,6 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) // draw copyright stuff pixPaint.setFont(QFont(font, 10*fontFactor)); - //pixPaint.drawText(paddingLeft,paddingTop+titleCopyrightVSpace,copyrightTextBtc); - //pixPaint.drawText(paddingLeft,paddingTop+titleCopyrightVSpace+12,copyrightTextDash); pixPaint.drawText(paddingLeft,paddingTop+titleCopyrightVSpace,copyrightTextPop); // draw additional text if special network From 433c52ddc8cbc0b021567cc9439c5b8af682df60 Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 18 Sep 2018 10:22:34 +0800 Subject: [PATCH 082/120] delete some notes --- src/wallet/rpcwallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 45ff7cb..64c82ca 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -997,10 +997,10 @@ UniValue sendfromAtoB(const UniValue ¶ms, bool fHelp) "\nSend an amount from specified address to another one.\n" + HelpRequiringPassphrase() + "\nArguments:\n" "1. \"from\" (string," - "required) The btcnano address to send " + "required) The pop address to send " "from.\n" "2. \"to\" (string," - "required) The btcnano address to send" + "required) The pop address to send" "to.\n" "3. \"amount\" (numeric or string," "required) The amount in " + CURRENCY_UNIT + @@ -1017,7 +1017,7 @@ UniValue sendfromAtoB(const UniValue ¶ms, bool fHelp) "6. subtractfeefromamount (boolean, optional, default=false) The " "fee will be deducted from the amount being sent.\n" "The recipient will receive less " - "btcnanos than you enter in the amount filed.\n" + "pop than you enter in the amount filed.\n" "nResult:\n" "\"txid\" (string) The transaction id.\n" "\nExamples:\n" + From e049d55fae1d590486e1f0e56c23c68243f7991b Mon Sep 17 00:00:00 2001 From: arminsu7 <734722864@qq.com> Date: Tue, 18 Sep 2018 10:26:24 +0800 Subject: [PATCH 083/120] delete some notes --- doc/release-notes.md | 115 ---------------------------------------- src/qt/locale/pop_pl.ts | 8 +-- 2 files changed, 4 insertions(+), 119 deletions(-) delete mode 100644 doc/release-notes.md diff --git a/doc/release-notes.md b/doc/release-notes.md deleted file mode 100644 index ecb16e7..0000000 --- a/doc/release-notes.md +++ /dev/null @@ -1,115 +0,0 @@ -Pop Core version 0.12.1 is now available from: - - - - - - -Older releases --------------- - -Pop was previously known as Darkcoin. - -Darkcoin tree 0.8.x was a fork of Litecoin tree 0.8, original name was XCoin -which was first released on Jan/18/2014. - -### Downgrade to a version < 0.12.0 - -Because release 0.12.0 and later will obfuscate the chainstate on every -fresh sync or reindex, the chainstate is not backwards-compatible with -pre-0.12 versions of Bitcoin Core or other software. - -If you want to downgrade after you have done a reindex with 0.12.0 or later, -you will need to reindex when you first start Bitcoin Core version 0.11 or -earlier. - -Notable changes -=============== - -Example item ---------------------------------------- - -Example text. - -0.12.1 Change log -================= - -Detailed release notes follow. This overview includes changes that affect -behavior, not code moves, refactors and string updates. For convenience in locating -the code changes and accompanying discussion, both the pull request and -git merge commit are mentioned. - -### RPC and REST - -Asm script outputs replacements for OP_NOP2 and OP_NOP3 -------------------------------------------------------- - -OP_NOP2 has been renamed to OP_CHECKLOCKTIMEVERIFY by [BIP -65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki) - -OP_NOP3 has been renamed to OP_CHECKSEQUENCEVERIFY by [BIP -112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki) - -The following outputs are affected by this change: -- RPC `getrawtransaction` (in verbose mode) -- RPC `decoderawtransaction` -- RPC `decodescript` -- REST `/rest/tx/` (JSON format) -- REST `/rest/block/` (JSON format when including extended tx details) -- `bitcoin-tx -json` - -### ZMQ - -Each ZMQ notification now contains an up-counting sequence number that allows -listeners to detect lost notifications. -The sequence number is always the last element in a multi-part ZMQ notification and -therefore backward compatible. -Each message type has its own counter. -(https://github.com/bitcoin/bitcoin/pull/7762) - -### Configuration and command-line options - -### Block and transaction handling - -### P2P protocol and network code - -### Validation - -### Build system - -### Wallet - -### GUI - -### Tests and QA - -### Miscellaneous - -Credits -======= - -Thanks to everyone who directly contributed to this release: - - -As well as everyone that helped translating on [Transifex](https://www.transifex.com/projects/p/bitcoin/). - -Darkcoin tree 0.9.x was the open source implementation of popnodes based on -the 0.8.x tree and was first released on Mar/13/2014. - -Darkcoin tree 0.10.x used to be the closed source implementation of Darksend -which was released open source on Sep/25/2014. - -Pop Core tree 0.11.x was a fork of Bitcoin Core tree 0.9, Darkcoin was rebranded -to Pop. - -Pop Core tree 0.12.0.x was a fork of Bitcoin Core tree 0.10. - -These release are considered obsolete. Old changelogs can be found here: - -- [v0.12.0](release-notes/pop/release-notes-0.12.0.md) released ???/??/2015 -- [v0.11.2](release-notes/pop/release-notes-0.11.2.md) released Mar/25/2015 -- [v0.11.1](release-notes/pop/release-notes-0.11.1.md) released Feb/10/2015 -- [v0.11.0](release-notes/pop/release-notes-0.11.0.md) released Jan/15/2015 -- [v0.10.x](release-notes/pop/release-notes-0.10.0.md) released Sep/25/2014 -- [v0.9.x](release-notes/pop/release-notes-0.9.0.md) released Mar/13/2014 - diff --git a/src/qt/locale/pop_pl.ts b/src/qt/locale/pop_pl.ts index 0e7f787..9a39677 100644 --- a/src/qt/locale/pop_pl.ts +++ b/src/qt/locale/pop_pl.ts @@ -1207,7 +1207,7 @@ Adres: %4 Automatically open the Pop client port on the router. This only works when your router supports UPnP and it is enabled. - Automatycznie uruchamiaj port klienta Darkcoina na ruterze. To dziaÅ‚a tylko jeÅ›li twój ruter wspiera i ma włączone UPnP. + Automatycznie uruchamiaj port klienta pop na ruterze. To dziaÅ‚a tylko jeÅ›li twój ruter wspiera i ma włączone UPnP. Map port using &UPnP @@ -1765,7 +1765,7 @@ https://www.transifex.com/projects/p/pop/ Open the Pop debug log file from the current data directory. This can take a few seconds for large log files. - Otwiera plik z zapisami debugowania Darkcoina z obecnego katalogu. Może to potrfać kilka sekund w zależnoÅ›ci od rozmiaru pliku. + Otwiera plik z zapisami debugowania pop z obecnego katalogu. Może to potrfać kilka sekund w zależnoÅ›ci od rozmiaru pliku. &Open @@ -1973,7 +1973,7 @@ https://www.transifex.com/projects/p/pop/ Welcome to the Pop RPC console. - Witaj w konsoli RPC Darkcoina + Witaj w konsoli RPC Pop Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. @@ -2560,7 +2560,7 @@ https://www.transifex.com/projects/p/pop/ A message that was attached to the pop: URI which will be stored with the transaction for your reference. Note: This message will not be sent over the Pop network. - Wiadomość, która zostaÅ‚a dołączona do pop: Link, który zostanie zapisany wraz z transakcjÄ… do wglÄ…du w przyszÅ‚oÅ›ci. Zauważ. że sama wiadomość nie zostanie wysÅ‚ana przez sieć Darkcoina. + Wiadomość, która zostaÅ‚a dołączona do pop: Link, który zostanie zapisany wraz z transakcjÄ… do wglÄ…du w przyszÅ‚oÅ›ci. Zauważ. że sama wiadomość nie zostanie wysÅ‚ana przez sieć Pop. This is an unverified payment request. From 89ce8c07c080c82daa93edd4c74f684feaf5c248 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 13 Oct 2018 16:18:57 +0800 Subject: [PATCH 084/120] Update configure.ac --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index bf62017..829ad40 100644 --- a/configure.ac +++ b/configure.ac @@ -465,7 +465,7 @@ if test x$use_hardening != xno; then AX_CHECK_COMPILE_FLAG([-Wstack-protector],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -Wstack-protector"]) AX_CHECK_COMPILE_FLAG([-fstack-protector-all],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fstack-protector-all"]) AX_CHECK_COMPILE_FLAG([-std=c++11],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -std=c++11"]) - AX_CHECK_COMPILE_FLAG([-std=c11],[HARDENED_CFLAGS="${HARDENED_CLFAGS -std=c11}"]) + AX_CHECK_COMPILE_FLAG([-std=c11],[HARDENED_CFLAGS="$(HARDENED_CLFAGS -std=c11)"]) AX_CHECK_PREPROC_FLAG([-D_FORTIFY_SOURCE=2],[ AX_CHECK_PREPROC_FLAG([-U_FORTIFY_SOURCE],[ From 7a8668ad92f9f948749b4c19662e3385916e5f68 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 16 Oct 2018 20:22:01 +0800 Subject: [PATCH 085/120] some change --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index 00460dd..7e8752b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4315,6 +4315,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn uint160 preCoinBaseAddress = uint160(); CAmount tmpPreAmount = 0; + //check the pay to uncle miner if(block.vuh.size() != 0 && nHeight != 0){ for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ coinBaseAddress = block.vuh[uncleCount].nCoinbase; From d27d4d5d343e0aff6e2723a7237001e68cb7ccc8 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 19 Oct 2018 13:51:22 +0800 Subject: [PATCH 086/120] add the block header coin base address valid check --- src/main.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 7e8752b..d7281ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4099,6 +4099,16 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f if (block.GetBlockTime() > GetAdjustedTime() + 2 * 60 * 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), REJECT_INVALID, "time-too-new"); + /*popchain ghost*/ + // Check the coinbaseaddress + CBitcoinAddress blockCoinBasePKHAddress(CTxDestination(CKeyID(block.nCoinbase))); + CBitcoinAddress blockCoinBaseP2SHAddress(CTxDestination(CScriptID(block.nCoinbase))); + if((block.nCoinbase != uint160() && (!blockCoinBasePKHAddress.IsValid()) && (!blockCoinBaseP2SHAddress.IsValid())){ + LogPrintf("CheckBlockHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.ToString().c_str(),block.nCoinbase.ToString()); + return state.Invalid(error("%s: block's coinbase address is not valid", __func__), + REJECT_INVALID, "coinbase-not-valide"); + } + /*popchain ghost*/ return true; } From 532abd2286fd357a3db660fe2400e6abd0542505 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 19 Oct 2018 14:07:49 +0800 Subject: [PATCH 087/120] correct some mistake --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d7281ed..3567efa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4103,7 +4103,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f // Check the coinbaseaddress CBitcoinAddress blockCoinBasePKHAddress(CTxDestination(CKeyID(block.nCoinbase))); CBitcoinAddress blockCoinBaseP2SHAddress(CTxDestination(CScriptID(block.nCoinbase))); - if((block.nCoinbase != uint160() && (!blockCoinBasePKHAddress.IsValid()) && (!blockCoinBaseP2SHAddress.IsValid())){ + if((block.nCoinbase != uint160()) && (!blockCoinBasePKHAddress.IsValid()) && (!blockCoinBaseP2SHAddress.IsValid())){ LogPrintf("CheckBlockHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.ToString().c_str(),block.nCoinbase.ToString()); return state.Invalid(error("%s: block's coinbase address is not valid", __func__), REJECT_INVALID, "coinbase-not-valide"); From f00a54a16afc76691c4e1898869777dd2fa2c873 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 20 Oct 2018 16:24:39 +0800 Subject: [PATCH 088/120] change for the big amount block get --- src/main.cpp | 16 +++++++++++++++- src/main.h | 4 ++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3567efa..1ba9429 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7334,8 +7334,22 @@ bool SendMessages(CNode* pto) if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); - if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { + LogPrintf("SendMessages():check block download timeout %d > %d + %d * %d * (%d + %d * %d) ,adjust: %f\n", nNow, state.nDownloadingSince, consensusParams.nPowTargetSpacing, BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT , BLOCK_DOWNLOAD_TIMEOUT_BASE , BLOCK_DOWNLOAD_TIMEOUT_PER_PEER , nOtherPeersWithValidatedDownloads,((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); + if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); + LogPrintf("state.vBlocksInFlight.size() %d \n", state.vBlocksInFlight.size()); + LogPrintf("nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0) \n"); + LogPrintf("nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); + LogPrintf("nPeersWithValidatedDownloads %d \n", nPeersWithValidatedDownloads); + LogPrintf("state.nBlocksInFlightValidHeaders %d \n", state.nBlocksInFlightValidHeaders); + LogPrintf("nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads) \n"); + LogPrintf("nNow %d \n", nNow); + LogPrintf("state.nDownloadingSince %d \n", state.nDownloadingSince); + LogPrintf("consensusParams.nPowTargetSpacing %d \n", consensusParams.nPowTargetSpacing); + LogPrintf("BLOCK_DOWNLOAD_TIMEOUT_BASE %d \n", BLOCK_DOWNLOAD_TIMEOUT_BASE); + LogPrintf("BLOCK_DOWNLOAD_TIMEOUT_PER_PEER %d \n", BLOCK_DOWNLOAD_TIMEOUT_PER_PEER); + LogPrintf("nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); + LogPrintf("(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads %f \n", ((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); pto->fDisconnect = true; } } diff --git a/src/main.h b/src/main.h index 34bf5d4..5a08723 100644 --- a/src/main.h +++ b/src/main.h @@ -105,6 +105,10 @@ static const unsigned int AVG_INVENTORY_BROADCAST_INTERVAL = 5; static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000; /** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 125000; +/*popchain ghost*/ +/** Block download timeout base adjustment paramater , > 1, <3*/ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT = 2; +/*popchain ghost*/ static const unsigned int DEFAULT_LIMITFREERELAY = 15; static const bool DEFAULT_RELAYPRIORITY = true; From 167dcc5f61afc814895c0db13dc4487be34893f6 Mon Sep 17 00:00:00 2001 From: liangqi1983 <65593062@qq.com> Date: Sat, 20 Oct 2018 17:37:28 +0800 Subject: [PATCH 089/120] change for genensis block header check --- src/main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1ba9429..68938bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4100,10 +4100,18 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"), REJECT_INVALID, "time-too-new"); /*popchain ghost*/ - // Check the coinbaseaddress + // Check the coinbaseaddress only p2pkh address CBitcoinAddress blockCoinBasePKHAddress(CTxDestination(CKeyID(block.nCoinbase))); - CBitcoinAddress blockCoinBaseP2SHAddress(CTxDestination(CScriptID(block.nCoinbase))); - if((block.nCoinbase != uint160()) && (!blockCoinBasePKHAddress.IsValid()) && (!blockCoinBaseP2SHAddress.IsValid())){ + const CChainParams& chainparams = Params(); + if(block.nCoinbase == uint160()){ + if(block.GetHash() != chainparams.GetConsensus().hashGenesisBlock){ + LogPrintf("CheckBlockHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.ToString().c_str(),block.nCoinbase.ToString()); + return state.Invalid(error("%s: block's coinbase address is not valid", __func__), + REJECT_INVALID, "coinbase-not-valide"); + } + } + + if((!blockCoinBasePKHAddress.IsValid())){ LogPrintf("CheckBlockHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.ToString().c_str(),block.nCoinbase.ToString()); return state.Invalid(error("%s: block's coinbase address is not valid", __func__), REJECT_INVALID, "coinbase-not-valide"); From 108fa990723dc2fa8e6afb30447de6452da3e2e1 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 23 Oct 2018 16:58:49 +0800 Subject: [PATCH 090/120] change some doc --- INSTALL | 2 +- configure.ac | 2 +- contrib/debian/control | 6 +++--- contrib/debian/watch | 2 +- contrib/gitian-descriptors/README.md | 6 +++--- contrib/gitian-descriptors/gitian-linux.yml | 2 +- .../gitian-descriptors/gitian-osx-signer.yml | 2 +- contrib/gitian-descriptors/gitian-osx.yml | 2 +- contrib/gitian-descriptors/gitian-rpi2.yml | 2 +- .../gitian-descriptors/gitian-win-signer.yml | 2 +- contrib/gitian-descriptors/gitian-win.yml | 2 +- contrib/linearize/README.md | 2 +- contrib/verify-commits/pre-push-hook.sh | 2 +- doc/README.md | 10 +++++----- doc/README_windows.txt | 2 +- doc/gitian-building.md | 10 +++++----- doc/guide-startmany.md | 2 +- doc/release-process.md | 20 +++++++++---------- share/qt/Info.plist.in | 4 ++-- src/qt/utilitydialog.cpp | 2 +- 20 files changed, 42 insertions(+), 42 deletions(-) diff --git a/INSTALL b/INSTALL index e8a36dc..494bc02 100644 --- a/INSTALL +++ b/INSTALL @@ -7,7 +7,7 @@ Use the autogen script to prepare the build environment. make user gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.5) Precompiled binaries are available at github, see -https://github.com/poppay/pop-binaries +https://github.com/PopchainOrg/PopChain-gho Always verify the signatures and checksums. diff --git a/configure.ac b/configure.ac index 829ad40..5f85b09 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 0) define(_CLIENT_VERSION_IS_RELEASE, true) define(_COPYRIGHT_YEAR, 2018) -AC_INIT([Pop Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/poppay/pop/issues],[popcore]) +AC_INIT([Pop Core],[_CLIENT_VERSION_MAJOR._CLIENT_VERSION_MINOR._CLIENT_VERSION_REVISION],[https://github.com/PopchainOrg/PopChain-gho],[popcore]) AC_CONFIG_SRCDIR([src/main.cpp]) AC_CONFIG_HEADERS([src/config/pop-config.h]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/contrib/debian/control b/contrib/debian/control index 52b3229..9771c8b 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -24,9 +24,9 @@ Build-Depends: debhelper, libprotobuf-dev, protobuf-compiler, python Standards-Version: 3.9.2 -Homepage: https://www.pop.org/ -Vcs-Git: git://github.com/poppay/pop.git -Vcs-Browser: https://github.com/poppay/pop +Homepage: https://popchain.org/popchain +Vcs-Git: git://github.com/PopchainOrg/PopChain-gho.git +Vcs-Browser: https://github.com/PopchainOrg/PopChain-gho Package: popd Architecture: any diff --git a/contrib/debian/watch b/contrib/debian/watch index 852bd68..4e546ad 100644 --- a/contrib/debian/watch +++ b/contrib/debian/watch @@ -2,4 +2,4 @@ version=3 # use qa.debian.org redirector; see man uscan opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/,dversionmangle=s/~dfsg\d*// \ - http://githubredir.debian.net/github/poppay/pop v(.*).tar.gz + https://github.com/PopchainOrg/PopChain-gho v(.*).tar.gz diff --git a/contrib/gitian-descriptors/README.md b/contrib/gitian-descriptors/README.md index d909f3a..8e11018 100644 --- a/contrib/gitian-descriptors/README.md +++ b/contrib/gitian-descriptors/README.md @@ -19,8 +19,8 @@ Sanity checks: Once you've got the right hardware and software: - git clone git://github.com/poppay/pop.git - git clone git://github.com/devrandom/gitian-builder.git + git clone git://github.com/PopchainOrg/PopChain-gho.git + git clone git://github.com/PopchainOrg/PopChain-gho.git mkdir gitian-builder/inputs cd gitian-builder/inputs @@ -61,5 +61,5 @@ Here's a description of Gavin's setup on OSX 10.6: 5. Still inside Ubuntu, tell gitian-builder to use LXC, then follow the "Once you've got the right hardware and software" instructions above: export USE_LXC=1 - git clone git://github.com/poppay/pop.git + git clone git://github.com/PopchainOrg/PopChain-gho.git ... etc diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index e4f8839..812b5c5 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -20,7 +20,7 @@ packages: - "python" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "pop" files: [] script: | diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml index 82f8301..02f3082 100644 --- a/contrib/gitian-descriptors/gitian-osx-signer.yml +++ b/contrib/gitian-descriptors/gitian-osx-signer.yml @@ -8,7 +8,7 @@ packages: - "faketime" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop-detached-sigs.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "signature" files: - "pop-osx-unsigned.tar.gz" diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml index 7c5b038..6217b31 100644 --- a/contrib/gitian-descriptors/gitian-osx.yml +++ b/contrib/gitian-descriptors/gitian-osx.yml @@ -23,7 +23,7 @@ packages: - "python" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "pop" files: - "MacOSX10.9.sdk.tar.gz" diff --git a/contrib/gitian-descriptors/gitian-rpi2.yml b/contrib/gitian-descriptors/gitian-rpi2.yml index b376221..e6b0579 100644 --- a/contrib/gitian-descriptors/gitian-rpi2.yml +++ b/contrib/gitian-descriptors/gitian-rpi2.yml @@ -17,7 +17,7 @@ packages: - "binutils-gold" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "pop" files: - "raspberrypi-tools.tar.gz" diff --git a/contrib/gitian-descriptors/gitian-win-signer.yml b/contrib/gitian-descriptors/gitian-win-signer.yml index 480efc0..036ac2e 100644 --- a/contrib/gitian-descriptors/gitian-win-signer.yml +++ b/contrib/gitian-descriptors/gitian-win-signer.yml @@ -9,7 +9,7 @@ packages: - "autoconf" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop-detached-sigs.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "signature" files: - "osslsigncode-1.7.1.tar.gz" diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml index 2437b38..95957b4 100644 --- a/contrib/gitian-descriptors/gitian-win.yml +++ b/contrib/gitian-descriptors/gitian-win.yml @@ -23,7 +23,7 @@ packages: - "python" reference_datetime: "2017-01-01 00:00:00" remotes: -- "url": "https://github.com/poppay/pop.git" +- "url": "https://github.com/PopchainOrg/PopChain-gho.git" "dir": "pop" files: [] script: | diff --git a/contrib/linearize/README.md b/contrib/linearize/README.md index 3d96ca3..3051c50 100644 --- a/contrib/linearize/README.md +++ b/contrib/linearize/README.md @@ -3,7 +3,7 @@ Construct a linear, no-fork, best version of the blockchain. ## Step 0: Install pop_hash -https://github.com/poppay/pop_hash +https://github.com/PopchainOrg/PopChain-gho ## Step 1: Download hash list diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh index 900643a..72cc427 100644 --- a/contrib/verify-commits/pre-push-hook.sh +++ b/contrib/verify-commits/pre-push-hook.sh @@ -1,5 +1,5 @@ #!/bin/bash -if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)poppay/pop(.git)?$ ]]; then +if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)PopchainOrg/PopChain-gho(.git)?$ ]]; then exit 0 fi diff --git a/doc/README.md b/doc/README.md index a9707b0..7e1f466 100644 --- a/doc/README.md +++ b/doc/README.md @@ -24,10 +24,10 @@ Drag Pop-Qt to your applications folder, and then run Pop-Qt. ### Need Help? -* See the [Pop documentation](https://poppay.atlassian.net/wiki/display/DOC) +* See the [Pop documentation](https://github.com/PopchainOrg/PopChain-gho/tree/master/doc) for help and more information. -* Ask for help on [#poppay](http://webchat.freenode.net?channels=poppay) on Freenode. If you don't have an IRC client use [webchat here](http://webchat.freenode.net?channels=poppay). -* Ask for help on the [PopTalk](https://poptalk.org/) forums. +* Ask for help on [#Telegram](https://t.me/popchain_global) on Freenode. If you don't have an IRC client use [Twitter](https://twitter.com/POPCHAIN_Global). +* Ask for help on the [web](https://popchain.org/popchain) forums. Building --------------------- @@ -57,8 +57,8 @@ The Pop Core repo's [root README](/README.md) contains relevant information on t - [Dnsseed Policy](dnsseed-policy.md) ### Resources -* Discuss on the [PopTalk](https://poptalk.org/) forums, in the Development & Technical Discussion board. -* Discuss on [#poppay](http://webchat.freenode.net/?channels=poppay) on Freenode. If you don't have an IRC client use [webchat here](http://webchat.freenode.net/?channels=poppay). +* Discuss on the [web](https://popchain.org/popchain) forums, in the Development & Technical Discussion board. +* Discuss on [Telegram](https://t.me/popchain_global) on Freenode. If you don't have an IRC client use [Twitter](https://twitter.com/POPCHAIN_Global). ### Miscellaneous - [Assets Attribution](assets-attribution.md) diff --git a/doc/README_windows.txt b/doc/README_windows.txt index c640aea..0a44b2a 100644 --- a/doc/README_windows.txt +++ b/doc/README_windows.txt @@ -19,5 +19,5 @@ depending on the speed of your computer and network connection, the synchronizat process can take anywhere from a few hours to a day or more. See the pop wiki at: - https://poppay.atlassian.net/wiki/ + http://coinwik.org/POPCHAIN for more help and information. diff --git a/doc/gitian-building.md b/doc/gitian-building.md index f150f73..cff0272 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -303,8 +303,8 @@ cd .. Clone the git repositories for Pop Core and Gitian. ```bash -git clone https://github.com/devrandom/gitian-builder.git -git clone https://github.com/poppay/pop +git clone https://github.com/PopchainOrg/PopChain-gho.git +git clone https://github.com/PopchainOrg/PopChain-gho.git ``` Setting up the Gitian image @@ -368,7 +368,7 @@ Output from `gbuild` will look something like remote: Total 57959 (delta 0), reused 0 (delta 0), pack-reused 57958 Receiving objects: 100% (57959/57959), 53.76 MiB | 484.00 KiB/s, done. Resolving deltas: 100% (41590/41590), done. - From https://github.com/poppay/pop + From https://github.com/PopchainOrg/PopChain-gho ... (new tags, new branch etc) --- Building for precise amd64 --- Stopping target if it is up @@ -444,7 +444,7 @@ Then when building, override the remote URLs that gbuild would otherwise pull fr ```bash cd /some/root/path/ -git clone https://github.com/poppay/pop-detached-sigs.git +git clone https://github.com/PopchainOrg/PopChain-gho.git UCPATH=/some/root/path/pop.git SIGPATH=/some/root/path/pop-detached-sigs.git @@ -476,6 +476,6 @@ Uploading signatures (not yet implemented) --------------------- In the future it will be possible to push your signatures (both the `.assert` and `.assert.sig` files) to the -[pop/gitian.sigs](https://github.com/poppay/gitian.sigs/) repository, or if that's not possible to create a pull +[pop/gitian.sigs](https://github.com/PopchainOrg/PopChain-gho/) repository, or if that's not possible to create a pull request. There will be an official announcement when this repository is online. diff --git a/doc/guide-startmany.md b/doc/guide-startmany.md index c3cf3f1..4b6184e 100644 --- a/doc/guide-startmany.md +++ b/doc/guide-startmany.md @@ -95,7 +95,7 @@ Issue the following: Make note of the hash (which is your collateral_output) and index. ### Enter your Popnode details into your popnode.conf file -[From the pop github repo](https://github.com/poppay/pop/blob/master/doc/popnode_conf.md) +[From the pop github repo](https://github.com/PopchainOrg/PopChain-gho/doc/popnode_conf.md) `popnode.conf` format is a space seperated text file. Each line consisting of an alias, IP address followed by port, popnode private key, collateral output transaction id and collateral output index. diff --git a/doc/release-process.md b/doc/release-process.md index fd77872..208638d 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -1,7 +1,7 @@ Release Process ==================== -* Update translations, see [translation_process.md](https://github.com/poppay/pop/blob/master/doc/translation_process.md#syncing-with-transifex) +* Update translations, see [translation_process.md](https://github.com/PopchainOrg/PopChain-gho/tree/master/doc/translation_process.md#syncing-with-transifex) * Update hardcoded [seeds](/contrib/seeds) * * * @@ -10,10 +10,10 @@ Release Process Check out the source code in the following directory hierarchy. cd /path/to/your/toplevel/build - git clone https://github.com/poppay/gitian.sigs.git - git clone https://github.com/poppay/pop-detached-sigs.git - git clone https://github.com/devrandom/gitian-builder.git - git clone https://github.com/poppay/pop.git + git clone https://github.com/PopchainOrg/PopChain-gho.git + git clone https://github.com/PopchainOrg/PopChain-gho.git + git clone https://github.com/PopchainOrg/PopChain-gho.git + git clone https://github.com/PopchainOrg/PopChain-gho.git ###Pop Core maintainers/release engineers, update (commit) version in sources @@ -139,7 +139,7 @@ Commit your signature to gitian.sigs: Wait for Windows/OS X detached signatures: Once the Windows/OS X builds each have 3 matching signatures, they will be signed with their respective release keys. - Detached signatures will then be committed to the [pop-detached-sigs](https://github.com/poppay/pop-detached-sigs) repository, which can be combined with the unsigned apps to create signed binaries. + Detached signatures will then be committed to the [pop-detached-sigs](https://github.com/PopchainOrg/PopChain-gho) repository, which can be combined with the unsigned apps to create signed binaries. Create (and optionally verify) the signed OS X binary: @@ -188,15 +188,15 @@ Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spur - Announce the release: - - Release on Pop forum: https://www.pop.org/forum/topic/official-announcements.54/ + - Release on Pop forum: https://popchain.org/popchain - Pop-development mailing list - - Update title of #poppay on Freenode IRC + - Update title of #popchain on Freenode IRC - - Optionally reddit /r/Poppay, ... but this will usually sort out itself + - Optionally reddit /r/popchain, ... but this will usually sort out itself -- Notify flare so that he can start building [the PPAs](https://launchpad.net/~pop.org/+archive/ubuntu/pop) +- Notify flare so that he can start building [the PPAs](https://popchain.org/popchain) - Add release notes for the new version to the directory `doc/release-notes` in git master diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 2aac062..9cbe310 100755 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -46,7 +46,7 @@ CFBundleTypeRole Editor CFBundleURLName - org.pop.PopPayment + org.pop.Payment CFBundleURLSchemes pop @@ -71,7 +71,7 @@ application/x-pop-payment-request public.filename-extension - poppaymentrequest + popmentrequest diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 384df0e..cebb6a6 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -163,7 +163,7 @@ your funds will already be anonymized. No additional waiting is required. \ This means those 1000 addresses last for about 100 mixing events. When 900 of them are used, your wallet must create more addresses. \ It can only do this, however, if you have automatic backups enabled.
\ Consequently, users who have backups disabled will also have PrivateSend disabled.
\ -For more info see https://poppay.atlassian.net/wiki/display/DOC/PrivateSend \ +For more info see https://github.com/PopchainOrg/PopChain-gho/tree/master/doc \ ")); ui->aboutMessage->setWordWrap(true); ui->helpMessage->setVisible(false); From e05fb09ab0b8052e4cf7624c94e7d9efa0ae0e7f Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 23 Oct 2018 17:31:47 +0800 Subject: [PATCH 091/120] change the doc --- contrib/debian/control | 4 ++-- doc/gitian-building.md | 8 ++++---- doc/guide-startmany.md | 2 +- doc/keepass.md | 2 +- doc/release-process.md | 4 ++-- share/qt/Info.plist.in | 2 +- share/setup.nsi.in | 2 +- src/popd.cpp | 2 +- src/qt/guiconstants.h | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contrib/debian/control b/contrib/debian/control index 9771c8b..b76df95 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,8 +1,8 @@ Source: pop Section: utils Priority: optional -Maintainer: Holger Schinzel -Uploaders: Holger Schinzel +Maintainer: Holger Schinzel +Uploaders: Holger Schinzel Build-Depends: debhelper, devscripts, automake, diff --git a/doc/gitian-building.md b/doc/gitian-building.md index cff0272..0432493 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -11,7 +11,7 @@ the same, tested dependencies are used and statically built into the executable. Multiple developers build the source code by following a specific descriptor ("recipe"), cryptographically sign the result, and upload the resulting signature. These results are compared and only if they match, the build is accepted and uploaded -to pop.org. +to popchain.org. More independent Gitian builders are needed, which is why this guide exists. It is preferred you follow these steps yourself instead of using someone else's @@ -394,7 +394,7 @@ and inputs. For example: ```bash -URL=https://github.com/crowning-/pop.git +URL=https://github.com/PopchainOrg/PopChain-gho.git COMMIT=b616fb8ef0d49a919b72b0388b091aaec5849b96 ./bin/gbuild --commit pop=${COMMIT} --url pop=${URL} ../pop/contrib/gitian-descriptors/gitian-linux.yml ./bin/gbuild --commit pop=${COMMIT} --url pop=${URL} ../pop/contrib/gitian-descriptors/gitian-win.yml @@ -446,8 +446,8 @@ Then when building, override the remote URLs that gbuild would otherwise pull fr cd /some/root/path/ git clone https://github.com/PopchainOrg/PopChain-gho.git -UCPATH=/some/root/path/pop.git -SIGPATH=/some/root/path/pop-detached-sigs.git +UCPATH=/some/root/path/PopChain-gho.git +SIGPATH=/some/root/path/PopChain-gho.git ./bin/gbuild --url pop=${UCPATH},signature=${SIGPATH} ../pop/contrib/gitian-descriptors/gitian-win-signer.yml ``` diff --git a/doc/guide-startmany.md b/doc/guide-startmany.md index 4b6184e..c41d0f0 100644 --- a/doc/guide-startmany.md +++ b/doc/guide-startmany.md @@ -135,7 +135,7 @@ You can confirm that remote server is on the correct block by issuing ```pop-cli getinfo``` -and comparing with the official explorer at https://explorer.pop.org/chain/Pop +and comparing with the official explorer at https://popchain.org/popchain ### Local diff --git a/doc/keepass.md b/doc/keepass.md index 1c103fe..ae14357 100644 --- a/doc/keepass.md +++ b/doc/keepass.md @@ -51,4 +51,4 @@ At this point, the association is made. The next action depends on your particul At this point, the passphrase is stored in KeePassHttp. When Unlocking the wallet, one can use _keepass_ as the passphrase to trigger retrieval of the password. This works from the RPC commands as well as the GUI. -Extended guide with screenshots is also available: https://poptalk.org/threads/keepass-integration.3620/ +Extended guide with screenshots is also available: https://popchain.org/popchain diff --git a/doc/release-process.md b/doc/release-process.md index 208638d..394a95e 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -182,9 +182,9 @@ rm SHA256SUMS (the digest algorithm is forced to sha256 to avoid confusion of the `Hash:` header that GPG adds with the SHA256 used for the files) Note: check that SHA256SUMS itself doesn't end up in SHA256SUMS, which is a spurious/nonsensical entry. -- Upload zips and installers, as well as `SHA256SUMS.asc` from last step, to the pop.org server +- Upload zips and installers, as well as `SHA256SUMS.asc` from last step, to the popchain.org server -- Update pop.org +- Update popchain.org - Announce the release: diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in index 9cbe310..34a8157 100755 --- a/share/qt/Info.plist.in +++ b/share/qt/Info.plist.in @@ -60,7 +60,7 @@ UTTypeIdentifier org.pop.paymentrequest UTTypeDescription - Pop payment request + payment request UTTypeConformsTo public.data diff --git a/share/setup.nsi.in b/share/setup.nsi.in index 05e0865..38b3716 100755 --- a/share/setup.nsi.in +++ b/share/setup.nsi.in @@ -7,7 +7,7 @@ SetCompressor /SOLID lzma !define REGKEY "SOFTWARE\$(^Name)" !define VERSION @CLIENT_VERSION_MAJOR@.@CLIENT_VERSION_MINOR@.@CLIENT_VERSION_REVISION@ !define COMPANY "Pop Core project" -!define URL https://www.pop.org/ +!define URL https://popchain.org/popchain # MUI Symbol Definitions !define MUI_ICON "@abs_top_srcdir@/share/pixmaps/bitcoin.ico" diff --git a/src/popd.cpp b/src/popd.cpp index 2489352..8bfe347 100644 --- a/src/popd.cpp +++ b/src/popd.cpp @@ -24,7 +24,7 @@ * * \section intro_sec Introduction * - * This is the developer documentation of the reference client for an experimental new digital currency called Pop (https://www.pop.org/), + * This is the developer documentation of the reference client for an experimental new digital currency called Pop (https://popchain.org/popchain), * which enables instant payments to anyone, anywhere in the world. Pop uses peer-to-peer technology to operate * with no central authority: managing transactions and issuing money are carried out collectively by the network. * diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 646dc93..b72f7a5 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -45,7 +45,7 @@ static const int MAX_URI_LENGTH = 255; #define SPINNER_FRAMES 36 #define QAPP_ORG_NAME "Pop" -#define QAPP_ORG_DOMAIN "pop.org" +#define QAPP_ORG_DOMAIN "popchain.org" #define QAPP_APP_NAME_DEFAULT "Pop-Qt" #define QAPP_APP_NAME_TESTNET "Pop-Qt-testnet" From eb3f56d7d95d66102f315af3e2841868b11f8ee7 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 25 Oct 2018 09:21:38 +0800 Subject: [PATCH 092/120] change for test --- src/chainparams.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 4e7305e..8e77949 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -314,10 +314,10 @@ class CTestNetParams : public CChainParams { consensus.foundersReward = int64_t(20833333.333 * COIN); // founders consensus.colleteral = int64_t(1e4 * COIN); // popnode colleteral - consensus.nSubsidyHalvingInterval = 2803200; //4 year + consensus.nSubsidyHalvingInterval = 1920; //1 day consensus.nInstantSendKeepLock = 6; - consensus.nSuperblockStartBlock = 100; - consensus.nSuperblockCycle = 57600; //30 minutes + consensus.nSuperblockStartBlock = 40; + consensus.nSuperblockCycle = 40; //30 minutes consensus.nUncleblockRatio = 0.1; consensus.nPopnodeMinimumConfirmations = 2; consensus.nMajorityEnforceBlockUpgrade = 51; @@ -328,10 +328,10 @@ class CTestNetParams : public CChainParams { /* popchain ghost */ consensus.powLimit = uint256S("0x000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - consensus.difficultyBoundDivisor = 2048; - consensus.difficultyRapidFitDivisor = 1024; + consensus.difficultyBoundDivisor = 1024; + consensus.difficultyRapidFitDivisor = 50; consensus.minimumDifficulty = 4096; - consensus.nYolandaTime = 57600; + consensus.nYolandaTime = 960; /* popchain ghost */ consensus.nPowTargetSpacing = 45; From 541f180ff006707eeab84deb06901473b4a16c0b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 25 Oct 2018 16:29:57 +0800 Subject: [PATCH 093/120] change the uncle block coin base address valid check --- src/main.cpp | 32 +++++++++++++++++++++++++++++++- src/miner.cpp | 17 +++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 68938bb..0cf9393 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4101,6 +4101,7 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f REJECT_INVALID, "time-too-new"); /*popchain ghost*/ // Check the coinbaseaddress only p2pkh address + /* CBitcoinAddress blockCoinBasePKHAddress(CTxDestination(CKeyID(block.nCoinbase))); const CChainParams& chainparams = Params(); if(block.nCoinbase == uint160()){ @@ -4109,13 +4110,14 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f return state.Invalid(error("%s: block's coinbase address is not valid", __func__), REJECT_INVALID, "coinbase-not-valide"); } + return true; } - if((!blockCoinBasePKHAddress.IsValid())){ LogPrintf("CheckBlockHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.ToString().c_str(),block.nCoinbase.ToString()); return state.Invalid(error("%s: block's coinbase address is not valid", __func__), REJECT_INVALID, "coinbase-not-valide"); } + */ /*popchain ghost*/ return true; @@ -4322,6 +4324,10 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return false; } + /*popchain ghost*/ + + /*popchain ghost*/ + uint160 coinBaseAddress; uint160 tmpAddress; int addressType; @@ -4332,11 +4338,19 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn const CChainParams& chainparams = Params(); uint160 preCoinBaseAddress = uint160(); CAmount tmpPreAmount = 0; + CBitcoinAddress blockCoinBasePKHAddress; //check the pay to uncle miner if(block.vuh.size() != 0 && nHeight != 0){ for(int uncleCount = 0;uncleCount < block.vuh.size(); uncleCount++){ coinBaseAddress = block.vuh[uncleCount].nCoinbase; + + blockCoinBasePKHAddress = CBitcoinAddress(CTxDestination(CKeyID(coinBaseAddress))); + if((!blockCoinBasePKHAddress.IsValid())){ + LogPrintf("CheckBlock() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", block.vuh[uncleCount].ToString().c_str(),coinBaseAddress.ToString()); + return false; + } + for (const CTxOut &out: block.vtx[0].vout){ if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)){ if(coinBaseAddress == tmpAddress){ @@ -4410,6 +4424,22 @@ static bool AcceptUnclesHeader(const CBlock& block, CValidationState& state, co } LogPrintf("AcceptUnclesHeader block:%s \n", block.GetHash().ToString()); + /*popchain ghost*/ + /* + // Check the coinbaseaddress only p2pkh address + CBlockHeader uncleBlockHeader; + for(std::vector::iterator it = blockUncles.begin(); it != blockUncles.end(); ++it){ + uncleBlockHeader = *it; + CBitcoinAddress blockCoinBasePKHAddress(CTxDestination(CKeyID(uncleBlockHeader.nCoinbase))); + if((!blockCoinBasePKHAddress.IsValid())){ + LogPrintf("AcceptUnclesHeader() coinbase-not-valide: \n--b-l-o-c-k---%s\n nCoinBase %s\n", uncleBlockHeader.ToString().c_str(),uncleBlockHeader.nCoinbase.ToString()); + return false; + } + } + */ + + /*popchain ghost*/ + //const CChainParams& chainparams = Params(); LogPrintf("AcceptUnclesHeader() GetAncestorBlocksFromHash block.hashPrevBlock %s \n", block.hashPrevBlock.ToString()); std::vector vecAncestor; diff --git a/src/miner.cpp b/src/miner.cpp index 59bdd20..9fb1209 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -27,6 +27,8 @@ #include "validationinterface.h" #include "arith_uint256.h" +#include "base58.h" + #include #include #include @@ -453,7 +455,10 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s int addressType; if(DecodeAddressHash(scriptPubKeyIn, coinBaseAddress, addressType)){ pblock->nCoinbase = coinBaseAddress; - } else{ + }else if(*(scriptPubKeyIn.begin()) == OP_TRUE){ + pblock->nCoinbase = uint160(); + } + else{ return NULL; } @@ -463,9 +468,17 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s int uncleCount = 0; for(std::vector::iterator it = unclesBlock.begin();it != unclesBlock.end(); ++it){ uncleBlock = *it; + CScript uncleScriptPubKeyIn; + CBitcoinAddress blockCoinBasePKHAddress; if(uncleCount < 2){ pblock->vuh.push_back(uncleBlock.GetBlockHeader()); - CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); + blockCoinBasePKHAddress = CBitcoinAddress(CTxDestination(CKeyID(uncleBlock.nCoinbase))); + if(blockCoinBasePKHAddress.IsValid()){ + uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); + }else { + continue; + } + //CScript uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); int tmpBlockHeight = 0; if(!GetBlockHeight(uncleBlock.hashPrevBlock,&tmpBlockHeight)){ return NULL; From 287d01a5681c483b7cb853e15229433ac4baf736 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 25 Oct 2018 17:29:01 +0800 Subject: [PATCH 094/120] change some print --- src/main.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0cf9393..4609683 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7372,22 +7372,28 @@ bool SendMessages(CNode* pto) if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) { QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0); - LogPrintf("SendMessages():check block download timeout %d > %d + %d * %d * (%d + %d * %d) ,adjust: %f\n", nNow, state.nDownloadingSince, consensusParams.nPowTargetSpacing, BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT , BLOCK_DOWNLOAD_TIMEOUT_BASE , BLOCK_DOWNLOAD_TIMEOUT_PER_PEER , nOtherPeersWithValidatedDownloads,((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); + LogPrint("net", "SendMessages -- check block download timeout %d > %d + %d * %d * (%d + %d * %d) ,adjust: %f\n", \ + nNow, state.nDownloadingSince, consensusParams.nPowTargetSpacing, BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT , \ + BLOCK_DOWNLOAD_TIMEOUT_BASE , BLOCK_DOWNLOAD_TIMEOUT_PER_PEER , nOtherPeersWithValidatedDownloads, \ + ((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER \ + * nOtherPeersWithValidatedDownloads))); + //LogPrintf("SendMessages():check block download timeout %d > %d + %d * %d * (%d + %d * %d) ,adjust: %f\n", nNow, state.nDownloadingSince, consensusParams.nPowTargetSpacing, BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT , BLOCK_DOWNLOAD_TIMEOUT_BASE , BLOCK_DOWNLOAD_TIMEOUT_PER_PEER , nOtherPeersWithValidatedDownloads,((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); if (nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads)) { LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id); - LogPrintf("state.vBlocksInFlight.size() %d \n", state.vBlocksInFlight.size()); - LogPrintf("nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0) \n"); - LogPrintf("nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); - LogPrintf("nPeersWithValidatedDownloads %d \n", nPeersWithValidatedDownloads); - LogPrintf("state.nBlocksInFlightValidHeaders %d \n", state.nBlocksInFlightValidHeaders); - LogPrintf("nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads) \n"); - LogPrintf("nNow %d \n", nNow); - LogPrintf("state.nDownloadingSince %d \n", state.nDownloadingSince); - LogPrintf("consensusParams.nPowTargetSpacing %d \n", consensusParams.nPowTargetSpacing); - LogPrintf("BLOCK_DOWNLOAD_TIMEOUT_BASE %d \n", BLOCK_DOWNLOAD_TIMEOUT_BASE); - LogPrintf("BLOCK_DOWNLOAD_TIMEOUT_PER_PEER %d \n", BLOCK_DOWNLOAD_TIMEOUT_PER_PEER); - LogPrintf("nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); - LogPrintf("(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads %f \n", ((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); + LogPrint("net", "state.vBlocksInFlight.size() %d \n", state.vBlocksInFlight.size()); + LogPrint("net", "nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - (state.nBlocksInFlightValidHeaders > 0) \n"); + LogPrint("net", "nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); + LogPrint("net", "nPeersWithValidatedDownloads %d \n", nPeersWithValidatedDownloads); + LogPrint("net", "state.nBlocksInFlightValidHeaders %d \n", state.nBlocksInFlightValidHeaders); + LogPrint("net", "nNow > state.nDownloadingSince + consensusParams.nPowTargetSpacing * BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT * (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads) \n"); + LogPrint("net", "nNow %d \n", nNow); + LogPrint("net", "state.nDownloadingSince %d \n", state.nDownloadingSince); + LogPrint("net", "consensusParams.nPowTargetSpacing %d \n", consensusParams.nPowTargetSpacing); + LogPrint("net", "BLOCK_DOWNLOAD_TIMEOUT_BASE %d \n", BLOCK_DOWNLOAD_TIMEOUT_BASE); + LogPrint("net", "BLOCK_DOWNLOAD_TIMEOUT_PER_PEER %d \n", BLOCK_DOWNLOAD_TIMEOUT_PER_PEER); + LogPrint("net", "nOtherPeersWithValidatedDownloads %d \n", nOtherPeersWithValidatedDownloads); + LogPrint("net", "(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads %f \n", \ + ((float)(nNow - state.nDownloadingSince)/ (BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads))); pto->fDisconnect = true; } } From 54ab7180d01f30b5942a634cc6b5b24c9cc9548c Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 26 Oct 2018 13:39:31 +0800 Subject: [PATCH 095/120] change rpcmining --- src/miner.cpp | 1 + src/primitives/block.h | 3 +++ src/rpcmining.cpp | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 9fb1209..9869f39 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -486,6 +486,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); CTxOut outNew(nAmount,uncleScriptPubKeyIn); txNew.vout.push_back(outNew); + pblock->vTxoutUncle.push_back(outNew); LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); } diff --git a/src/primitives/block.h b/src/primitives/block.h index a80a0c2..f59213a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -97,6 +97,9 @@ class CBlock : public CBlockHeader // memory only mutable CTxOut txoutFound; // Found payment + /*popchain ghost*/ + std::vector vTxoutUncle; //uncle miner payment + /*popchain ghost*/ mutable bool fChecked; /*popchain ghost*/ diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 2078ad7..9fd04d2 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -580,6 +580,24 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) transactions.push_back(entry); } + UniValue uncleheaders(UniValue::VARR); + map setUhIndex; + i = 0; + BOOST_FOREACH (const CBlockHeader& uh, pblock->vuh) { + uint256 uhHash = uh.GetHash(); + setUhIndex[uhHash] = i++; + + UniValue entryUh(UniValue::VOBJ); + + CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); + ssBlock << uh; + std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); + entryUh.push_back(Pair("data", strHex)); + entryUh.push_back(Pair("hash", uhHash.GetHex())); + + uncleheaders.push_back(entryUh); + } + UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); @@ -598,6 +616,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); + result.push_back(Pair("uncleblockheader", uncleheaders)); result.push_back(Pair("coinbaseaux", aux)); result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut())); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); @@ -622,9 +641,23 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) FoundnodeObj.push_back(Pair("foundpayee", address2.ToString().c_str())); FoundnodeObj.push_back(Pair("foundscript", HexStr(pblock->txoutFound.scriptPubKey.begin(), pblock->txoutFound.scriptPubKey.end()))); FoundnodeObj.push_back(Pair("foundamount", pblock->txoutFound.nValue)); - } + } result.push_back(Pair("Foundnode", FoundnodeObj)); + UniValue UncleBlockRewardObj(UniValue::VOBJ); + if(pblock->vTxoutUncle.size() != 0) { + CTxDestination address1; + CBitcoinAddress address2; + BOOST_FOREACH (const CTxOut& uhTx, pblock->vTxoutUncle) { + ExtractDestination(uhTx.scriptPubKey, address1); + address2 = CBitcoinAddress(address1); + FoundnodeObj.push_back(Pair("unclepayee", address2.ToString().c_str())); + FoundnodeObj.push_back(Pair("unclescript", HexStr(pblock->txoutFound.scriptPubKey.begin(), pblock->txoutFound.scriptPubKey.end()))); + FoundnodeObj.push_back(Pair("uncleamount", uhTx.nValue)); + } + } + result.push_back(Pair("UncleBlockReward", UncleBlockRewardObj)); + return result; } From 6e14a6e0a11b7860819681cd3cd42e904c4fbd29 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 26 Oct 2018 15:05:20 +0800 Subject: [PATCH 096/120] change the the getblocktemplate --- src/rpcmining.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 9fd04d2..c68864c 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -644,19 +644,32 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) } result.push_back(Pair("Foundnode", FoundnodeObj)); - UniValue UncleBlockRewardObj(UniValue::VOBJ); + /* + std::string uncleheaderaddrss1 = "pnndY8hSqtogsgiXFpR87nCPCquKAACx7T"; + std::string uncleheaderaddrss2 = "ppeSuqEwXkapogu7XUsHr47VKM3sLmkq6n"; + CBitcoinAddress uncleaddress1(uncleheaderaddrss1); + CScript uncle1P2PkHScript = GetScriptForDestination(uncleaddress1.Get()); + CTxOut tmpUncleblock(2899890000,uncle1P2PkHScript); + pblock->vTxoutUncle.push_back(tmpUncleblock); + */ + + UniValue UncleBlockReward(UniValue::VARR); if(pblock->vTxoutUncle.size() != 0) { + CTxDestination address1; CBitcoinAddress address2; BOOST_FOREACH (const CTxOut& uhTx, pblock->vTxoutUncle) { + UniValue UncleBlockRewardObj(UniValue::VOBJ); ExtractDestination(uhTx.scriptPubKey, address1); address2 = CBitcoinAddress(address1); - FoundnodeObj.push_back(Pair("unclepayee", address2.ToString().c_str())); - FoundnodeObj.push_back(Pair("unclescript", HexStr(pblock->txoutFound.scriptPubKey.begin(), pblock->txoutFound.scriptPubKey.end()))); - FoundnodeObj.push_back(Pair("uncleamount", uhTx.nValue)); + UncleBlockRewardObj.push_back(Pair("unclepayee", address2.ToString().c_str())); + UncleBlockRewardObj.push_back(Pair("unclescript", HexStr(uhTx.scriptPubKey.begin(), uhTx.scriptPubKey.end()))); + UncleBlockRewardObj.push_back(Pair("uncleamount", uhTx.nValue)); + UncleBlockReward.push_back(UncleBlockRewardObj); } + } - result.push_back(Pair("UncleBlockReward", UncleBlockRewardObj)); + result.push_back(Pair("UncleBlockReward", UncleBlockReward)); return result; } From 07205b657040e17b123bbd2385855ec77a7acb01 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 26 Oct 2018 15:35:57 +0800 Subject: [PATCH 097/120] change the getblocktemplate --- src/main.h | 4 ++-- src/rpcmining.cpp | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main.h b/src/main.h index 5a08723..93039d9 100644 --- a/src/main.h +++ b/src/main.h @@ -106,8 +106,8 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 250000; /** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 125000; /*popchain ghost*/ -/** Block download timeout base adjustment paramater , > 1, <3*/ -static const int64_t BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT = 2; +/** Block download timeout base adjustment paramater , > 1*/ +static const int64_t BLOCK_DOWNLOAD_TIMEOUT_ADJUSTMENT = 5; /*popchain ghost*/ static const unsigned int DEFAULT_LIMITFREERELAY = 15; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index c68864c..c1d6dba 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -579,7 +579,19 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) transactions.push_back(entry); } - +/* + std::string uncleheaderaddrss1 = "pnndY8hSqtogsgiXFpR87nCPCquKAACx7T"; + CBitcoinAddress uncleaddress1(uncleheaderaddrss1); + std::string uncleheaderaddrss2 = "ppeSuqEwXkapogu7XUsHr47VKM3sLmkq6n"; + CBitcoinAddress uncleaddress2(uncleheaderaddrss2); + + CBlockHeader uncleheader1 = CBlockHeader(); + uncleheader1.nCoinbase = uncleaddress1.GetData(); + CBlockHeader uncleheader2 = CBlockHeader(); + uncleheader2.nCoinbase = uncleaddress2.GetData(); + pblock->vuh.push_back(uncleheader1); + pblock->vuh.push_back(uncleheader2); +*/ UniValue uncleheaders(UniValue::VARR); map setUhIndex; i = 0; @@ -645,12 +657,17 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("Foundnode", FoundnodeObj)); /* - std::string uncleheaderaddrss1 = "pnndY8hSqtogsgiXFpR87nCPCquKAACx7T"; - std::string uncleheaderaddrss2 = "ppeSuqEwXkapogu7XUsHr47VKM3sLmkq6n"; - CBitcoinAddress uncleaddress1(uncleheaderaddrss1); + //std::string uncleheaderaddrss1 = "pnndY8hSqtogsgiXFpR87nCPCquKAACx7T"; + //CBitcoinAddress uncleaddress1(uncleheaderaddrss1); CScript uncle1P2PkHScript = GetScriptForDestination(uncleaddress1.Get()); - CTxOut tmpUncleblock(2899890000,uncle1P2PkHScript); - pblock->vTxoutUncle.push_back(tmpUncleblock); + CTxOut tmpUncleblock1(2899890000,uncle1P2PkHScript); + pblock->vTxoutUncle.push_back(tmpUncleblock1); + + //std::string uncleheaderaddrss2 = "ppeSuqEwXkapogu7XUsHr47VKM3sLmkq6n"; + //CBitcoinAddress uncleaddress2(uncleheaderaddrss2); + CScript uncle2P2PkHScript = GetScriptForDestination(uncleaddress2.Get()); + CTxOut tmpUncleblock2(2899890000,uncle1P2PkHScript); + pblock->vTxoutUncle.push_back(tmpUncleblock2); */ UniValue UncleBlockReward(UniValue::VARR); From 738c0509f2f97ec3e2d31576d781b1314b533bf3 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 26 Oct 2018 16:06:30 +0800 Subject: [PATCH 098/120] change the getblocktemplate --- src/rpcmining.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index c1d6dba..d11f4d2 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -579,7 +579,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) transactions.push_back(entry); } -/* + + /* std::string uncleheaderaddrss1 = "pnndY8hSqtogsgiXFpR87nCPCquKAACx7T"; CBitcoinAddress uncleaddress1(uncleheaderaddrss1); std::string uncleheaderaddrss2 = "ppeSuqEwXkapogu7XUsHr47VKM3sLmkq6n"; @@ -591,7 +592,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) uncleheader2.nCoinbase = uncleaddress2.GetData(); pblock->vuh.push_back(uncleheader1); pblock->vuh.push_back(uncleheader2); -*/ + */ + UniValue uncleheaders(UniValue::VARR); map setUhIndex; i = 0; @@ -627,6 +629,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); + result.push_back(Pair("hashUncles", pblock->hashUncles.GetHex())); + result.push_back(Pair("difficulty", pblock->nDifficulty)); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("uncleblockheader", uncleheaders)); result.push_back(Pair("coinbaseaux", aux)); @@ -640,7 +644,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); result.push_back(Pair("curtime", pblock->GetBlockTime())); // ghost - result.push_back(Pair("difficulty", pblock->nDifficulty)); + result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); result.push_back(Pair("claimtrie", pblock->hashClaimTrie.GetHex())); From 6541ab32012d8b78b4285838b4a07d513c1cba55 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 27 Oct 2018 08:30:37 +0800 Subject: [PATCH 099/120] change for mining test --- src/popnode-sync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popnode-sync.h b/src/popnode-sync.h index 0cd4883..d6b6c57 100644 --- a/src/popnode-sync.h +++ b/src/popnode-sync.h @@ -19,7 +19,7 @@ static const int POPNODE_SYNC_FINISHED = 999; static const int POPNODE_SYNC_TICK_SECONDS = 6; static const int POPNODE_SYNC_TIMEOUT_SECONDS = 30; // our blocks are 2.5 minutes so 30 seconds should be fine -static const int POPNODE_SYNC_ENOUGH_PEERS = 6; +static const int POPNODE_SYNC_ENOUGH_PEERS = 2; extern CPopnodeSync popnodeSync; From 3569aa4816b2ae19fb63dae23a39866ab973e855 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 30 Oct 2018 16:16:27 +0800 Subject: [PATCH 100/120] prepare for the testnet --- src/popnode-sync.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popnode-sync.h b/src/popnode-sync.h index d6b6c57..0cd4883 100644 --- a/src/popnode-sync.h +++ b/src/popnode-sync.h @@ -19,7 +19,7 @@ static const int POPNODE_SYNC_FINISHED = 999; static const int POPNODE_SYNC_TICK_SECONDS = 6; static const int POPNODE_SYNC_TIMEOUT_SECONDS = 30; // our blocks are 2.5 minutes so 30 seconds should be fine -static const int POPNODE_SYNC_ENOUGH_PEERS = 2; +static const int POPNODE_SYNC_ENOUGH_PEERS = 6; extern CPopnodeSync popnodeSync; From c20a56aa06d5cf364ec0b95bb2dd1292b077e175 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 2 Nov 2018 11:10:14 +0800 Subject: [PATCH 101/120] change for pool --- src/chainparams.cpp | 22 +++++++++++----------- src/main.cpp | 14 ++++++++++---- src/main.h | 3 +++ src/miner.cpp | 9 ++++++++- src/rpcmining.cpp | 2 ++ 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8e77949..1b64707 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -77,9 +77,9 @@ void _get(const ch * const pblock, const arith_uint256 hashTarget) } std::lock_guard guard(mtx); -// std::cout << "\n\t\t----------------------------------------\t" << std::endl; -// std::cout << "\t" << pb->ToString() << std::endl; -// std::cout << "\n\t\t----------------------------------------\t" << std::endl; + std::cout << "\n\t\t----------------------------------------\t" << std::endl; + std::cout << "\t" << pb->ToString() << std::endl; + std::cout << "\n\t\t----------------------------------------\t" << std::endl; delete pb; // stop while found one @@ -156,7 +156,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi /*popchain ghost*/ static CBlock CreateGenesisBlock(uint32_t nTime, uint256 nNonce, uint64_t nDifficulty, uint32_t nBits, int32_t nVersion, const int64_t& genesisReward) { - const char* pszTimestamp = "pop hold value testnet."; + const char* pszTimestamp = "pop hold value testnet 20181031."; const CScript genesisOutputScript = CScript() << ParseHex("034c73d75f59061a08032b68369e5034390abc5215b3df79be01fb4319173a88f8") << OP_CHECKSIG; return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nDifficulty, nBits, nVersion, genesisReward); } @@ -357,7 +357,7 @@ class CTestNetParams : public CChainParams { nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); - genesis = CreateGenesisBlock(1529894661, uint256S("0x00005f1403ee998d921de9a0d0b5d53a9a37ef9f58d9cefb8ae1936ae07c00e8"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); + genesis = CreateGenesisBlock(1529894661, uint256S("0x0000a2b4ff83976ddff3d24167494ced45373184ad9c1e677292f748eacb00b4"), consensus.minimumDifficulty, nTempBit.GetCompact(), 1, 1 * COIN); /*popchain ghost*/ #ifdef GENESIS_GENERATION @@ -368,8 +368,8 @@ class CTestNetParams : public CChainParams { //findGenesis(&genesis, "testnet"); #endif consensus.hashGenesisBlock = genesis.GetHash(); - assert(consensus.hashGenesisBlock == uint256S("0x0009d363a3cb4f69655dc06f4fcd8f648b38e0b35ca545fb05f21f2e1f2ba92d")); - assert(genesis.hashMerkleRoot == uint256S("0x6f73646aa71aeec2163e047e0028e2c4313f3e88d4fb3e1ade176c56e1a148c4")); + assert(consensus.hashGenesisBlock == uint256S("0x000c31af61fefa27a8cc4e716d7637befeea7c43b1284a30679acde16caee349")); + assert(genesis.hashMerkleRoot == uint256S("0x7e60a27544bfb66612693dbce63dfd8c4b902375fea44cfa4c74555b84e13d71")); vFixedSeeds.clear(); vSeeds.clear(); @@ -401,11 +401,11 @@ class CTestNetParams : public CChainParams { nPoolMaxTransactions = 3; nFulfilledRequestExpireTime = 5*60; // fulfilled requests expire in 5 minutes - strSporkPubKey = "02284dd24544e031b1b575fc4bf720a57d57425157290a9882f4d0dd192b1a316c"; + strSporkPubKey = "02b970d9f88bcd8705d6f17da775617952302511a36edad520916d8b3e67c558ca"; checkpointData = (CCheckpointData) { boost::assign::map_list_of - (0, uint256S("0x0009d363a3cb4f69655dc06f4fcd8f648b38e0b35ca545fb05f21f2e1f2ba92d")), + (0, uint256S("0x000c31af61fefa27a8cc4e716d7637befeea7c43b1284a30679acde16caee349")), 0, // * UNIX timestamp of last checkpoint block 0, // * total number of transactions between genesis and last checkpoint // (the tx=... number in the SetBestChain debug.log lines) @@ -414,8 +414,8 @@ class CTestNetParams : public CChainParams { // Founders reward script expects a vector of 2-of-3 multisig addresses vFoundersRewardAddress = { - "pbFyUjHfZB8BBivQS1LXh8EaJNH5jjGbzk", - "pbvTm479A2XTp2nCa8Z9qwAhindNbKarrX" + "pVRBFM1Z2xqpmPBBY12ybcS4N7hyLNrgyD", + "pVWuNwNfZEVxw7Lj2wKf3NnpS2nFFV3hjP" }; } }; diff --git a/src/main.cpp b/src/main.cpp index 4609683..a4f2a61 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -83,6 +83,9 @@ int nScriptCheckThreads = 0; bool fImporting = false; bool fReindex = false; bool fTxIndex = true; +/*popchain ghost*/ +bool fRpcMining = false; +/*popchain ghost*/ bool fAddressIndex = false; bool fTimestampIndex = false; bool fSpentIndex = false; @@ -3660,13 +3663,13 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c /*popchain ghost*/ while (chainActive.Tip() && chainActive.Tip() != pindexFork) { /*popchain ghost*/ - if (GetBoolArg("-gen", false) && pblock != NULL) + if ((GetBoolArg("-gen", false) || fRpcMining) && pblock != NULL) pindexPossibleBlock = chainActive.Tip(); /*popchain ghost*/ if (!DisconnectTip(state, chainparams.GetConsensus())) return false; /*popchain ghost*/ - if (GetBoolArg("-gen", false) && pblock != NULL){ + if ((GetBoolArg("-gen", false) || fRpcMining) && pblock != NULL){ possibleBlockHash = pindexPossibleBlock->GetBlockHash(); ReadBlockFromDisk(possibleBlock, pindexPossibleBlock, chainparams.GetConsensus()); mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); @@ -3757,7 +3760,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, // Whether we have anything to do at all. /*popchain ghost*/ if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip()){ - if (GetBoolArg("-gen", false) && pblock != NULL){ + if ((GetBoolArg("-gen", false) || fRpcMining) && pblock != NULL){ CBlock possibleBlock = *pblock; uint256 possibleBlockHash = possibleBlock.GetHash(); mapPossibleUncles.insert(std::make_pair(possibleBlockHash,possibleBlock)); @@ -4356,10 +4359,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } - } else{ + } + /* + else{ LogPrintf("CheckBlock():ERROR DecodeAddressHash uncle header %d error \n",uncleCount); return false; } + */ } if(GetBlockHeight(block.vuh[uncleCount].hashPrevBlock,&tmpBlockHeight)){ tmpSubAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); diff --git a/src/main.h b/src/main.h index 93039d9..26ea11f 100644 --- a/src/main.h +++ b/src/main.h @@ -311,6 +311,9 @@ extern bool fImporting; extern bool fReindex; extern int nScriptCheckThreads; extern bool fTxIndex; +/*popchain ghost*/ +extern bool fRpcMining; +/*popchain ghost*/ extern bool fIsBareMultisigStd; extern bool fRequireStandard; extern unsigned int nBytesPerSigOp; diff --git a/src/miner.cpp b/src/miner.cpp index 9869f39..0c0eba4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -466,6 +466,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s FindBlockUncles(pblock->hashPrevBlock,unclesBlock); CBlock uncleBlock; int uncleCount = 0; + uint160 preCoinBase = uint160(); for(std::vector::iterator it = unclesBlock.begin();it != unclesBlock.end(); ++it){ uncleBlock = *it; CScript uncleScriptPubKeyIn; @@ -474,7 +475,13 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s pblock->vuh.push_back(uncleBlock.GetBlockHeader()); blockCoinBasePKHAddress = CBitcoinAddress(CTxDestination(CKeyID(uncleBlock.nCoinbase))); if(blockCoinBasePKHAddress.IsValid()){ - uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); + if((uncleBlock.nCoinbase != uint160()) && (uncleBlock.nCoinbase != preCoinBase)){ + uncleScriptPubKeyIn = GetScriptForDestination(CKeyID(uncleBlock.nCoinbase)); + preCoinBase = uncleBlock.nCoinbase; + } + else{ + continue; + } }else { continue; } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index d11f4d2..04cca3b 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -464,6 +464,8 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (!popnodeSync.IsSynced()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Pop Core is syncing with network..."); + fRpcMining = true; + static unsigned int nTransactionsUpdatedLast; if (!lpval.isNull()) From 3a320137f5d2b08d115df1c0c24a2b2058c0e4e8 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Fri, 2 Nov 2018 16:20:01 +0800 Subject: [PATCH 102/120] change for testnet --- src/chainparams.cpp | 4 ++-- src/chainparamsbase.cpp | 2 +- src/main.cpp | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1b64707..6281246 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -352,7 +352,7 @@ class CTestNetParams : public CChainParams { pchMessageStart[2] = 0xc8; pchMessageStart[3] = 0x4f; vAlertPubKey = ParseHex("0244a0bb22e931bf59cc8a434d9d22bd2fa493f579bd2659bc9188361d78bdc45f"); - nDefaultPort = 12888; + nDefaultPort = 12778; nMaxTipAge = 0x7fffffff; // allow mining on top of old blocks for testnet nPruneAfterHeight = 1000; /*popchain ghost*/ @@ -474,7 +474,7 @@ class CRegTestParams : public CChainParams { pchMessageStart[2] = 0xc9; pchMessageStart[3] = 0xe3; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin - nDefaultPort = 12888; + nDefaultPort = 22888; nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index ebbaf88..a1230b4 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -42,7 +42,7 @@ class CBaseTestNetParams : public CBaseChainParams public: CBaseTestNetParams() { - nRPCPort = 12889; + nRPCPort = 12779; strDataDir = "testnet3"; } }; diff --git a/src/main.cpp b/src/main.cpp index a4f2a61..b5822b9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4380,6 +4380,15 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn return false; } /*only work uncle header size 2*/ + if((preCoinBaseAddress == coinBaseAddress)||(coinBaseAddress == uint160())){ + LogPrintf("CheckBlock():ERROR %s two same uncle miner uncle header coinbase not match \n",CBitcoinAddress(CKeyID(coinBaseAddress)).ToString()); + return false; + } + + tmpPreAmount = tmpSubAmount; + preCoinBaseAddress = coinBaseAddress; + + /* if(preCoinBaseAddress == coinBaseAddress){ tmpPreAmount += tmpSubAmount; if(tmpAmount >= tmpPreAmount){ @@ -4392,7 +4401,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn tmpPreAmount = tmpSubAmount; preCoinBaseAddress = coinBaseAddress; } - + */ tmpAmount = 0; tmpBlockHeight = 0; tmpSubAmount =0; From 52f7a78c0f2900ccf3d62471d8c5dd1b5a445471 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 3 Nov 2018 10:23:49 +0800 Subject: [PATCH 103/120] updata the miner check --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 0c0eba4..a4fb022 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -472,7 +472,6 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s CScript uncleScriptPubKeyIn; CBitcoinAddress blockCoinBasePKHAddress; if(uncleCount < 2){ - pblock->vuh.push_back(uncleBlock.GetBlockHeader()); blockCoinBasePKHAddress = CBitcoinAddress(CTxDestination(CKeyID(uncleBlock.nCoinbase))); if(blockCoinBasePKHAddress.IsValid()){ if((uncleBlock.nCoinbase != uint160()) && (uncleBlock.nCoinbase != preCoinBase)){ @@ -493,6 +492,7 @@ CBlockTemplate* CreateNewBlock(const CChainParams& chainparams, const CScript& s CAmount nAmount = GetUncleMinerSubsidy(nHeight, Params().GetConsensus(), (tmpBlockHeight + 1)); CTxOut outNew(nAmount,uncleScriptPubKeyIn); txNew.vout.push_back(outNew); + pblock->vuh.push_back(uncleBlock.GetBlockHeader()); pblock->vTxoutUncle.push_back(outNew); LogPrintf("createnewblock: add %d uncle block reward %s \n",uncleCount,outNew.ToString()); From 52bec91ed1f996ced28f3d95124f92f9207c9964 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 3 Nov 2018 14:59:56 +0800 Subject: [PATCH 104/120] more check for founder reward --- src/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index b5822b9..7047bf2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,6 +41,10 @@ #include "popnode-sync.h" #include "popnodeman.h" +/*popchain ghost*/ +#include "superblock.h" +/*popchain ghost*/ + #include #include @@ -1802,6 +1806,9 @@ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) { const int beg = cp.nSuperblockStartBlock; const int end = cp.endOfFoundersReward(); + if(!CSuperblock::IsValidBlockHeight(height)){ + return 0; + } if (height >= beg && height < end) // before super block starting { LogPrintf("GetFoundersReward at height: %d, amount: %d \n",height,cp.foundersReward); From d7bbba509e6a40d8c9e86adb66f4344e04ba735e Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 5 Nov 2018 15:53:50 +0800 Subject: [PATCH 105/120] change the getdifficult function --- src/main.cpp | 12 ++++++++---- src/rpcblockchain.cpp | 7 ++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7047bf2..0a79dc3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1757,7 +1757,8 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) // first 4 years if (height < intval) { - return cp.minerReward4*(1-cp.nUncleblockRatio); + //return cp.minerReward4*(1-cp.nUncleblockRatio); + return cp.minerReward4; } // from the 5th year on else @@ -1768,7 +1769,8 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) { return 0; } - CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); + //CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); + CAmount subsidy(cp.minerReward4*/2); subsidy >>= halvings; return subsidy; } @@ -1782,7 +1784,8 @@ CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - CAmount ret = (reward + (reward * uc / 32)); + //CAmount ret = (reward + (reward * uc / 32)); + CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); return ret; } @@ -1794,7 +1797,8 @@ CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - CAmount ret = ( diff * reward / 8); + //CAmount ret = ( diff * reward / 8); + CAmount ret = ( diff * reward * 3 / 32); LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); return ret; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 0b48ae5..dd3fa5f 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -30,7 +30,7 @@ uint64_t GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. - /* + if (blockindex == NULL) { if (chainActive.Tip() == NULL) @@ -56,8 +56,8 @@ uint64_t GetDifficulty(const CBlockIndex* blockindex) } return dDiff; - */ - + + /* if (blockindex == NULL) { if (chainActive.Tip() == NULL) @@ -66,6 +66,7 @@ uint64_t GetDifficulty(const CBlockIndex* blockindex) blockindex = chainActive.Tip(); } return blockindex->nDifficulty; + */ } UniValue blockheaderToJSON(const CBlockIndex* blockindex) From 882966535d622f9bd67ceee302300961ffd8219b Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 5 Nov 2018 16:21:21 +0800 Subject: [PATCH 106/120] change the show of block difficult --- src/main.cpp | 16 ++++++++-------- src/rpcblockchain.cpp | 10 +++++----- src/rpcmining.cpp | 2 +- src/rpcmisc.cpp | 2 +- src/rpcserver.h | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0a79dc3..f2ab993 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1757,8 +1757,8 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) // first 4 years if (height < intval) { - //return cp.minerReward4*(1-cp.nUncleblockRatio); - return cp.minerReward4; + return cp.minerReward4*(1-cp.nUncleblockRatio); + //return cp.minerReward4; } // from the 5th year on else @@ -1769,8 +1769,8 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) { return 0; } - //CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); - CAmount subsidy(cp.minerReward4*/2); + CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); + //CAmount subsidy(cp.minerReward4*/2); subsidy >>= halvings; return subsidy; } @@ -1784,8 +1784,8 @@ CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - //CAmount ret = (reward + (reward * uc / 32)); - CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); + CAmount ret = (reward + (reward * uc / 32)); + //CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); return ret; } @@ -1797,8 +1797,8 @@ CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - //CAmount ret = ( diff * reward / 8); - CAmount ret = ( diff * reward * 3 / 32); + CAmount ret = ( diff * reward / 8); + //CAmount ret = ( diff * reward * 3 / 32); LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); return ret; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index dd3fa5f..a43a52a 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -26,7 +26,7 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); //popchain ghost -uint64_t GetDifficulty(const CBlockIndex* blockindex) +double GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. @@ -91,7 +91,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("difficulty", (double)GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) @@ -204,7 +204,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("unclesize",block.vuh.size())); result.push_back(Pair("nonce", block.nNonce.GetHex())); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); + result.push_back(Pair("difficulty", (double)GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) @@ -1132,7 +1132,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); - obj.push_back(Pair("difficulty", GetDifficulty())); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); @@ -1254,7 +1254,7 @@ UniValue getchaintips(const UniValue& params, bool fHelp) UniValue obj(UniValue::VOBJ); obj.push_back(Pair("height", block->nHeight)); obj.push_back(Pair("hash", block->phashBlock->GetHex())); - obj.push_back(Pair("difficulty", GetDifficulty(block))); + obj.push_back(Pair("difficulty", (double)GetDifficulty(block))); obj.push_back(Pair("chainwork", block->nChainWork.GetHex())); obj.push_back(Pair("branchlen", branchLen)); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 04cca3b..21cfb44 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -265,7 +265,7 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); - obj.push_back(Pair("difficulty", GetDifficulty())); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", DEFAULT_GENERATE_THREADS))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index 4bf92f3..4c664e7 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -96,7 +96,7 @@ UniValue getinfo(const UniValue& params, bool fHelp) obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); - obj.push_back(Pair("difficulty", GetDifficulty())); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); #ifdef ENABLE_WALLET if (pwalletMain) { diff --git a/src/rpcserver.h b/src/rpcserver.h index 3ddd304..d4b2397 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -166,7 +166,7 @@ extern std::vector ParseHexO(const UniValue& o, std::string strKe extern int64_t nWalletUnlockTime; extern CAmount AmountFromValue(const UniValue& value); extern UniValue ValueFromAmount(const CAmount& amount); -extern uint64_t GetDifficulty(const CBlockIndex* blockindex = NULL); +extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); From 1c14d3a6a9eb7cb78640e53634c7e238f2e751db Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 6 Nov 2018 10:07:13 +0800 Subject: [PATCH 107/120] change for rpc miner --- src/rpcmining.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 21cfb44..9bf46a0 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -632,7 +632,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("hashUncles", pblock->hashUncles.GetHex())); - result.push_back(Pair("difficulty", pblock->nDifficulty)); + //pblock->nDifficulty = 0x123456789abcdef0; + CDataStream ssBlockDifficulty(SER_NETWORK, PROTOCOL_VERSION); + ssBlockDifficulty << (pblock->nDifficulty); + std::string strHexDifficulty = HexStr(ssBlockDifficulty.begin(), ssBlockDifficulty.end()); + //result.push_back(Pair("difficulty", pblock->nDifficulty)); + result.push_back(Pair("difficulty", strHexDifficulty)); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("uncleblockheader", uncleheaders)); result.push_back(Pair("coinbaseaux", aux)); From 2723815685f0ea27471a22774d5945b610ba4890 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 6 Nov 2018 16:31:22 +0800 Subject: [PATCH 108/120] for the testnet --- src/chainparams.cpp | 4 ++-- src/chainparamsbase.cpp | 4 ++-- src/main.cpp | 29 +++++++++++++++++------------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 6281246..2760adf 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -233,7 +233,7 @@ class CMainParams : public CChainParams { pchMessageStart[2] = 0x3f; pchMessageStart[3] = 0xc9; vAlertPubKey = ParseHex("028efd0f3c697689f8f1f6744edbbc1f85871b8c51218ddd89d90a3e435d1a8691"); - nDefaultPort = 2888; + nDefaultPort = 2778; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin nPruneAfterHeight = 100000; /*popchain ghost*/ @@ -474,7 +474,7 @@ class CRegTestParams : public CChainParams { pchMessageStart[2] = 0xc9; pchMessageStart[3] = 0xe3; nMaxTipAge = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin - nDefaultPort = 22888; + nDefaultPort = 22778; nPruneAfterHeight = 1000; /*popchain ghost*/ arith_uint256 nTempBit = UintToArith256( consensus.powLimit); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index a1230b4..a6a89b8 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -29,7 +29,7 @@ class CBaseMainParams : public CBaseChainParams public: CBaseMainParams() { - nRPCPort = 2889; + nRPCPort = 2779; } }; static CBaseMainParams mainParams; @@ -56,7 +56,7 @@ class CBaseRegTestParams : public CBaseChainParams public: CBaseRegTestParams() { - nRPCPort = 22889; + nRPCPort = 22779; strDataDir = "regtest"; } }; diff --git a/src/main.cpp b/src/main.cpp index f2ab993..a1bddea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1757,20 +1757,19 @@ CAmount GetMinerSubsidy(const int height, const Consensus::Params &cp) // first 4 years if (height < intval) { - return cp.minerReward4*(1-cp.nUncleblockRatio); - //return cp.minerReward4; + //return cp.minerReward4*(1-cp.nUncleblockRatio); + return cp.minerReward4; } // from the 5th year on else { int halvings = (height - intval) / intval; // force subsidy to 0 when right shift 64 bit is undifined - if (halvings > 3) - { - return 0; - } - CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); - //CAmount subsidy(cp.minerReward4*/2); + if (halvings > 0){ + return 0; + } + //CAmount subsidy(cp.minerReward4/2*(1-cp.nUncleblockRatio)); + CAmount subsidy(cp.minerReward4 / 2); subsidy >>= halvings; return subsidy; } @@ -1784,8 +1783,11 @@ CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - CAmount ret = (reward + (reward * uc / 32)); - //CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); + //CAmount ret = (reward + (reward * uc / 32)); + if(height < 2){ + return reward; + } + CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); return ret; } @@ -1797,8 +1799,11 @@ CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) return 0; } CAmount reward = GetMinerSubsidy(height,cp); - CAmount ret = ( diff * reward / 8); - //CAmount ret = ( diff * reward * 3 / 32); + //CAmount ret = ( diff * reward / 8); + if(height < 2){ + return 0; + } + CAmount ret = ( diff * reward * 3 / (32 * 7)); LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); return ret; } From 5c39d58b44f171663d529765ea380346227929fe Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 6 Nov 2018 16:40:32 +0800 Subject: [PATCH 109/120] add the block reward test --- src/rpcmining.cpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 1 + src/rpcserver.h | 6 +++++ 3 files changed, 72 insertions(+) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 9bf46a0..749cf9b 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -326,7 +326,72 @@ static UniValue BIP22ValidationResult(const CValidationState& state) // Should be impossible return "valid?"; } +/*popchain ghost*/ +// Popchain DevTeam +UniValue getblockrewarddata(const UniValue& params, bool fHelp) +{ + + if (fHelp || params.size() != 1) + throw runtime_error( + "dumpwallet \"filename\"\n" + "\nDumps all wallet keys in a human-readable format.\n" + "\nArguments:\n" + "1. \"filename\" (string, required) The filename\n" + "\nExamples:\n" + + HelpExampleCli("dumpwallet", "\"test\"") + + HelpExampleRpc("dumpwallet", "\"test\"") + ); + ofstream file; + file.open(params[0].get_str().c_str()); + if (!file.is_open()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open block reward data file"); + const CChainParams& chainParams = Params(); + + file << strprintf("# block reward created by Ulord Core %s (%s)\n", CLIENT_BUILD, CLIENT_DATE); + file << strprintf("# consensus.genesisReward %f \n", chainParams.GetConsensus().genesisReward); + file << strprintf("# consensus.premine %f \n", chainParams.GetConsensus().premine); + file << strprintf("# consensus.minerReward4 %f \n", chainParams.GetConsensus().minerReward4); + file << strprintf("# consensus.foundersReward %f \n", chainParams.GetConsensus().foundersReward); + file << strprintf("# consensus.colleteral %f \n", chainParams.GetConsensus().colleteral); + file << "# height MinerSubsidy FoundersReward maxMainMinerSubsidy maxUncleMinerSubsidy maxBlockSubsidey\n"; + + CAmount totalMinerSubsidy = 0; + CAmount totalFoundersReward = 0; + CAmount totalMaxMinerSubsidy = 0; + CAmount totalMaxUncleMinerSubsidy = 0; + CAmount totalMaxBlockSubsidy = 0; + + //for(int i =2;i<(chainParams.GetConsensus().nSubsidyHalvingInterval * 5 +1 );i++){ + for(int i= 0;i<(chainParams.GetConsensus().nSubsidyHalvingInterval * 5 +1 );i++){ + if(i==0){ + continue; + } + if(i==1){ + continue; + } + + + CAmount minerSubsidy = GetMinerSubsidy(i,chainParams.GetConsensus()); + totalMinerSubsidy +=minerSubsidy; + CAmount foundersReward = GetFoundersReward(i, chainParams.GetConsensus()); + totalFoundersReward +=foundersReward; + CAmount maxMinerSubsidy = GetMainMinerSubsidy(i,chainParams.GetConsensus(),2); + totalMaxMinerSubsidy +=totalMaxMinerSubsidy; + CAmount maxUncleMinerSubsidy = GetUncleMinerSubsidy(i,chainParams.GetConsensus(),(i-1)) + GetUncleMinerSubsidy(i,chainParams.GetConsensus(),(i-1)); + totalMaxUncleMinerSubsidy +=maxUncleMinerSubsidy; + CAmount maxBlockSubsidy = foundersReward + maxMinerSubsidy + maxUncleMinerSubsidy; + totalMaxBlockSubsidy +=maxBlockSubsidy; + file << strprintf("#%d %d %d %d %d %d \n",i, (int64_t)minerSubsidy,(int64_t)foundersReward,(int64_t)maxMinerSubsidy,(int64_t)maxUncleMinerSubsidy,(int64_t)maxBlockSubsidy); + } + file << strprintf("#total %d %d %d %d %d \n", (int64_t)totalMinerSubsidy,(int64_t)totalFoundersReward,(int64_t)totalMaxMinerSubsidy,(int64_t)totalMaxUncleMinerSubsidy,(int64_t)totalMaxBlockSubsidy); + file << "\n"; + file << "# End of block reward data\n"; + file.close(); + + return "get block reward ok"; +} +/*popchain ghost*/ // Popchain DevTeam UniValue getblocktemplate(const UniValue& params, bool fHelp) { diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 54ee54f..a16fffd 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -342,6 +342,7 @@ static const CRPCCommand vRPCCommands[] = { "hidden", "invalidateblock", &invalidateblock, true }, { "hidden", "reconsiderblock", &reconsiderblock, true }, { "hidden", "setmocktime", &setmocktime, true }, + { "hidden", "getblockrewarddata", &getblockrewarddata, true }, #ifdef ENABLE_WALLET { "hidden", "resendwallettransactions", &resendwallettransactions, true}, #endif diff --git a/src/rpcserver.h b/src/rpcserver.h index d4b2397..9981383 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -304,6 +304,12 @@ extern UniValue atomicswapgetrawhash(const UniValue ¶ms, bool fHelp); extern UniValue atomicswapchecktx(const UniValue ¶ms, bool fHelp); /*popchain atomic swap*/ +/*popchain ghost*/ +UniValue getblockrewarddata(const UniValue& params, bool fHelp); +/*popchain ghost*/ + + + extern UniValue getblock(const UniValue& params, bool fHelp); extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp); extern UniValue gettxout(const UniValue& params, bool fHelp); From a5ca85ad62eb174d204be47474b4375db35aa1bb Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Wed, 7 Nov 2018 17:08:02 +0800 Subject: [PATCH 110/120] change for the differentiation for getdifficulty and nDifficulty --- src/amount.h | 2 +- src/rpcblockchain.cpp | 16 +++++++++++++--- src/rpcmining.cpp | 17 +++++++---------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/amount.h b/src/amount.h index 04bc63f..e0ca8f9 100644 --- a/src/amount.h +++ b/src/amount.h @@ -24,7 +24,7 @@ extern const std::string CURRENCY_UNIT; * critical; in unusual circumstances like a(nother) overflow bug that allowed * for the creation of coins out of thin air modification could lead to a fork. * */ -static const CAmount MAX_MONEY = /*21000000*/1000000000 * COIN; +static const CAmount MAX_MONEY = /*21000000*/2000000000 * COIN; inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } /** Type-safe wrapper class for fee rates diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index a43a52a..0c8b60a 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -91,6 +91,9 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); + /*popchain ghost*/ + result.push_back(Pair("hdifficulty",blockindex->nDifficulty)); + /*popchain ghost*/ result.push_back(Pair("difficulty", (double)GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); @@ -99,6 +102,7 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); + return result; } @@ -117,7 +121,10 @@ void uncleblockheaderToJSON(const CBlockHeader& blockheader,UniValue& entry,int entry.push_back(Pair("hashUncles", blockheader.hashUncles.GetHex())); //entry.push_back(Pair("coinbase", blockheader.nCoinbase.GetHex())); entry.push_back(Pair("coinbase",CBitcoinAddress(CKeyID(blockheader.nCoinbase)).ToString())); - entry.push_back(Pair("difficulty", blockheader.nDifficulty)); + /*popchain ghost*/ + entry.push_back(Pair("hdifficulty",blockheader.nDifficulty)); + /*popchain ghost*/ + //entry.push_back(Pair("difficulty", blockheader.nDifficulty)); entry.push_back(Pair("hashMerkleRoot", blockheader.hashMerkleRoot.GetHex())); entry.push_back(Pair("hashClaimTrie", blockheader.hashClaimTrie.GetHex())); entry.push_back(Pair("time", (int64_t)blockheader.nTime)); @@ -176,7 +183,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx { coinBaseAddress = block.vuh[uncleCount].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= (7 * GetMinerSubsidy(blockindex->nHeight,chainparams.GetConsensus()) / 8))){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= GetUncleMinerSubsidy(blockindex->nHeight,chainparams.GetConsensus(),(blockindex->nHeight -1)))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } @@ -204,6 +211,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("unclesize",block.vuh.size())); result.push_back(Pair("nonce", block.nNonce.GetHex())); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); + /*popchain ghost*/ + result.push_back(Pair("hdifficulty",block.nDifficulty)); + /*popchain ghost*/ result.push_back(Pair("difficulty", (double)GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); @@ -712,7 +722,7 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) int addressType; coinBaseAddress = block.vuh[nIndex].nCoinbase; for (const CTxOut &out: block.vtx[0].vout){ - if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= (7 * GetMinerSubsidy(pblockindex->nHeight,chainparams.GetConsensus()) / 8))){ + if(DecodeAddressHash(out.scriptPubKey, tmpAddress, addressType)&&(out.nValue <= GetUncleMinerSubsidy(pblockindex->nHeight,chainparams.GetConsensus(),(pblockindex->nHeight -1)))){ if(coinBaseAddress == tmpAddress){ tmpAmount += out.nValue; } diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 749cf9b..9943a79 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -26,6 +26,11 @@ #include +/*popchain ghost*/ +#include +/*popchain ghost*/ + + #include #include @@ -362,15 +367,7 @@ UniValue getblockrewarddata(const UniValue& params, bool fHelp) CAmount totalMaxBlockSubsidy = 0; //for(int i =2;i<(chainParams.GetConsensus().nSubsidyHalvingInterval * 5 +1 );i++){ - for(int i= 0;i<(chainParams.GetConsensus().nSubsidyHalvingInterval * 5 +1 );i++){ - if(i==0){ - continue; - } - if(i==1){ - continue; - } - - + for(int i= 0;i<(chainParams.GetConsensus().nSubsidyHalvingInterval * 2 +1 );i++){ CAmount minerSubsidy = GetMinerSubsidy(i,chainParams.GetConsensus()); totalMinerSubsidy +=minerSubsidy; CAmount foundersReward = GetFoundersReward(i, chainParams.GetConsensus()); @@ -702,7 +699,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) ssBlockDifficulty << (pblock->nDifficulty); std::string strHexDifficulty = HexStr(ssBlockDifficulty.begin(), ssBlockDifficulty.end()); //result.push_back(Pair("difficulty", pblock->nDifficulty)); - result.push_back(Pair("difficulty", strHexDifficulty)); + result.push_back(Pair("hdifficulty", strHexDifficulty)); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("uncleblockheader", uncleheaders)); result.push_back(Pair("coinbaseaux", aux)); From e41c76e24c8517cd73104c433ff841eb76980200 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Thu, 15 Nov 2018 10:42:01 +0800 Subject: [PATCH 111/120] add the deal to future block --- src/init.cpp | 4 +++ src/main.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.h | 6 +++++ 3 files changed, 81 insertions(+) diff --git a/src/init.cpp b/src/init.cpp index 28712aa..cfa118b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1918,6 +1918,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) StartNode(threadGroup, scheduler); + /*popchain ghost*/ + threadGroup.create_thread(boost::bind(&ThreadProcFutureBlocks)); + /*popchain ghost*/ + // Monitor the chain, and alert if we get blocks much quicker or slower than expected // The "bad chain alert" scheduler has been disabled because the current system gives far // too many false positives, such that users are starting to ignore them. diff --git a/src/main.cpp b/src/main.cpp index a1bddea..c091a92 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2759,6 +2759,57 @@ void FindBlockUncles(uint256 parenthash,std::vector& vuncles) /*popchain ghost*/ +/*popchain ghost*/ +void ThreadProcFutureBlocks() +{ + static bool fOneThread; + if(fOneThread) return; + fOneThread = true; + + // Make this thread recognisable as the PrivateSend thread + RenameThread("pop-procfutureblocks"); + static int threadCount = 0; + + const CChainParams& chainparams = Params(); + CValidationState state; + + lruFutureBlock.purge(); + + while (true) + { + MilliSleep(15000); + LogPrintf("ThreadProcFutureBlocks count %d\n",threadCount); + int len = 0; + lruFutureBlock.length(len); + if(len > 0){ + std::vector key; + lruFutureBlock.keys(key); + for(int i =0;inTime > (GetAdjustedTime() + 2*45)){ + LogPrintf("%s : farfuture block: %s,nTime:%d ,farfuturetime:%d\n", __func__,pblock->GetHash().ToString(),pblock->nTime,(GetAdjustedTime() + 2*45)); + return false; + } + /*popchain ghost*/ + + + // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -4700,6 +4761,16 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c return error("%s: AcceptBlock FAILED", __func__); } + //check is future block or not + /*popchain ghost*/ + if(pblock->nTime >= (GetAdjustedTime() + 45)){ + LogPrintf("%s : future block: %s,nTime:%d ,farfuturetime:%d\n", __func__,pblock->GetHash().ToString(),pblock->nTime,(GetAdjustedTime() + 45)); + lruFutureBlock.add(pblock->GetHash(),*pblock); + LogPrintf("%s : lruFutureBlock.add %s \n", __func__,pblock->GetHash().ToString()); + return false; + } + /*popchain ghost*/ + if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); diff --git a/src/main.h b/src/main.h index 26ea11f..ab441f5 100644 --- a/src/main.h +++ b/src/main.h @@ -250,6 +250,10 @@ class LRUCache { } } + void length(int &len){ + len = vmap_.size(); + } + private: struct Cache { Cache() = default; @@ -299,6 +303,7 @@ class LRUCache { std::map vmap_; }; +//extern LRUCache lruFutureBlock(DEFAULT_MAXFUTUREBLOCKS, CBlock()); /*popchain ghost*/ @@ -1077,6 +1082,7 @@ bool CommitUncle(CBlockHeader uncle); void FindBlockUncles(uint256 parenthash,std::vector& vuncles); +void ThreadProcFutureBlocks(); From 7b19a8f109248e1f44369a48266e19a73f3396b7 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Sat, 17 Nov 2018 10:39:29 +0800 Subject: [PATCH 112/120] change some commit --- src/rpcblockchain.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 0c8b60a..89e42bb 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -644,8 +644,8 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( "getuncleblockheader \"hash\" hashuncle\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block header 'hash'.\n" - "If verbose is true, returns an Object with information about block .\n" + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for uncle block header.\n" + "If verbose is true, returns an Object with information about uncle block header.\n" "\nArguments:\n" "1. \"hash\" (string, required) The block hash\n" "2. \"hashuncle\" (string, required) The uncle block header hash\n" @@ -767,8 +767,8 @@ UniValue getalluncleblock(const UniValue& params, bool fHelp) if (fHelp || params.size() < 0 || params.size() > 1) throw runtime_error( "getalluncleblock \n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" - "If verbose is true, returns an Object with information about block .\n" + "\nIf verbose is false, returns hex-encoded data for block 'hash' of block in chain contain uncle.\n" + "If verbose is true, returns hex-encoded data for block 'hash' of block contain uncle.\n" "\nArguments:\n" "1. fGetAll (boolean, optional, default=true) true for get all block contain uncle, false for main chain block cotain uncle \n" "\nResult :\n" From acb5e52828fd25b5055f6bfd155bc58e5674e928 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 11:19:09 +0800 Subject: [PATCH 113/120] change some commit --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 64c82ca..b480265 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1128,7 +1128,7 @@ UniValue instantsendtoaddress(const UniValue& params, bool fHelp) " to which you're sending the transaction. This is not part of the \n" " transaction, just kept in your wallet.\n" "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" - " The recipient will receive less bitcoins than you enter in the amount field.\n" + " The recipient will receive less amount than you enter in the amount field.\n" "\nResult:\n" "\"transactionid\" (string) The transaction id.\n" "\nExamples:\n" From a78db03971d9807192146e4cc2726113eff447f9 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 11:54:31 +0800 Subject: [PATCH 114/120] change getblocktemplate help --- src/rpcmining.cpp | 144 +++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 9943a79..6465e6d 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -394,73 +394,83 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( - "getblocktemplate ( \"jsonrequestobject\" )\n" - "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" - "It returns data needed to construct a block to work on.\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - - "\nArguments:\n" - "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" - " {\n" - " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" - " \"capabilities\":[ (array, optional) A list of strings\n" - " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" - " ,...\n" - " ]\n" - " }\n" - "\n" - - "\nResult:\n" - "{\n" - " \"version\" : n, (numeric) The block version\n" - " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" - " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" - " {\n" - " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" - " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" - " \"depends\" : [ (array) array of numbers \n" - " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" - " ,...\n" - " ],\n" - " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" - " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" - " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" - " }\n" - " ,...\n" - " ],\n" - " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" - " \"flags\" : \"flags\" (string) \n" - " },\n" - " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" - " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" - " \"target\" : \"xxxx\", (string) The hash target\n" - " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" - " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" - " ,...\n" - " ],\n" - " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" - " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" - " \"sizelimit\" : n, (numeric) limit of block size\n" - " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" - " \"bits\" : \"xxx\", (string) compressed target of next block\n" - " \"height\" : n (numeric) The height of the next block\n" - " \"popnode\" : { (json object) \n" - " \"amount\": n (numeric) required amount to pay\n" - " },\n" - " \"superblock\" : [ (array) required superblock payees that must be included in the next block\n" - " {\n" - " \"payee\" : \"xxxx\", (string) payee address\n" - " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" - " \"amount\": n (numeric) required amount to pay\n" - " }\n" - " ,...\n" - " ],\n" - " \"superblocks_started\" : true|false, (boolean) true, if superblock payments started\n" - " \"superblocks_enabled\" : true|false (boolean) true, if superblock payments are enabled\n" - "}\n" - - "\nExamples:\n" + "getblocktemplate ( \"jsonrequestobject\" )\n" + "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" + "It returns data needed to construct a block to work on.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" + + "\nArguments:\n" + "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" + " {\n" + " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" + " \"capabilities\":[ (array, optional) A list of strings\n" + " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" + " ,...\n" + " ]\n" + " }\n" + "\n" + + "\nResult:\n" + "{\n" + " \"version\" : n, (numeric) The block version\n" + " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" + " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" + " {\n" + " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" + " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" + " \"depends\" : [ (array) array of numbers \n" + " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" + " ,...\n" + " ],\n" + " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in duffs); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" + " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" + " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" + " }\n" + " ,...\n" + " ],\n" + " \"uncleblockheader\" : [ (array) contents of uncleblockheader that should be included in the next block\n" + " {\n" + " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" + " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" + " }\n" + " ,...\n" + " ],\n" + " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" + " \"flags\" : \"flags\" (string) \n" + " },\n" + " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in duffs)\n" + " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" + " \"target\" : \"xxxx\", (string) The hash target\n" + " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" + " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" + " ,...\n" + " ],\n" + " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" + " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" + " \"sizelimit\" : n, (numeric) limit of block size\n" + " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" + " \"bits\" : \"xxx\", (string) compressed target of next block\n" + " \"height\" : n (numeric) The height of the next block\n" + " \"claimtrie\" : string (string) The hash claimtrie of the next block\n" + " \"Foundnode\" : [ (array) required found payees that must be included in the next block\n" + " {\n" + " \"payee\" : \"xxxx\", (string) payee address\n" + " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" + " \"amount\": n (numeric) required amount to pay\n" + " }\n" + " ,...\n" + " ],\n" + " \"UncleBlockReward\" : [ (array) required uncle block reward payees that must be included in the next block\n" + " {\n" + " \"payee\" : \"xxxx\", (string) payee address\n" + " \"script\" : \"xxxx\", (string) payee scriptPubKey\n" + " \"amount\": n (numeric) required amount to pay\n" + " }\n" + " ,...\n" + " ],\n" + "}\n" + "\nExamples:\n" + HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "") ); From 3b684263f819f81ffdda55e2d9126d78ae3b6597 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 12:02:45 +0800 Subject: [PATCH 115/120] change the getblocktemlate help --- src/rpcmining.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 6465e6d..a50826d 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -413,7 +413,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) "\nResult:\n" "{\n" " \"version\" : n, (numeric) The block version\n" - " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" + " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" + " \"hashUncles\" : \"xxxx\", (string) The hash of uncles of next block\n" + " \"hdifficulty\" : \"xxxx\", (string) The hdifficuty data of next block\n" " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" " {\n" " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" From 391b16dd0caeb2bb8ae2f923e94cb6ea0c47a5a6 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 15:09:52 +0800 Subject: [PATCH 116/120] change the getblock help --- src/rpcblockchain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 89e42bb..d2cf77d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -858,6 +858,7 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"unclesize\" : n, (numeric) The size of block uncle header\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"hdifficulty\" : x.xxx, (numeric) The difficulty in the block header\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"chainwork\" : \"xxxx\", (string) Expected number of hashes required to produce the chain up to this block (in hex)\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" From 1d61aef7b15b5f29a43365bbeb6aed8f7d8fa0f6 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 15:55:48 +0800 Subject: [PATCH 117/120] change the getblockheadr getblockheaders help --- src/rpcblockchain.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index d2cf77d..3fe3f07 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -504,11 +504,14 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" + " \"hashUncles\" : \"xxxx\",(string) The hash of uncles\n" + " \"coinbase\" : \"xxxx\", (string) The miner address\n" + " \"merkleroot\" : \"xxxx\",(string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"hdifficulty\" : x.xxx, (numeric) The difficulty in blockheader\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" @@ -561,15 +564,18 @@ UniValue getblockheaders(const UniValue& params, bool fHelp) "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "[ {\n" - " \"hash\" : \"hash\", (string) The block hash\n" + " \"hash\" : \"hash\", (string) The block hash\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" + " \"hashUncles\" : \"xxxx\", (string)The hash of uncles\n" + " \"coinbase\" : \"xxxx\", (string)The miner address\n"s + " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"bits\" : \"1d00ffff\", (string) The bits\n" + " \"hdifficulty\" : x.xxx, (numeric)The difficulty in blockheader\n" " \"difficulty\" : x.xxx, (numeric) The difficulty\n" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" From 882890d691d0b415d60a763719cbd1716d79ed75 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 16:16:18 +0800 Subject: [PATCH 118/120] change the getblockhears help --- src/rpcblockchain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 3fe3f07..5e7e109 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -564,12 +564,12 @@ UniValue getblockheaders(const UniValue& params, bool fHelp) "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "[ {\n" - " \"hash\" : \"hash\", (string) The block hash\n" + " \"hash\" : \"hash\", (string) The block hash\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" " \"hashUncles\" : \"xxxx\", (string)The hash of uncles\n" - " \"coinbase\" : \"xxxx\", (string)The miner address\n"s + " \"coinbase\" : \"xxxx\", (string)The miner address\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" From 777596d05951a256052cb69784db70b8fa2b545d Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Mon, 19 Nov 2018 17:21:54 +0800 Subject: [PATCH 119/120] change getuncleblockheader help --- src/rpcblockchain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 5e7e109..8a0bf82 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -649,12 +649,12 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( - "getuncleblockheader \"hash\" hashuncle\" ( verbose )\n" + "getuncleblockheader \"hash\" index\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for uncle block header.\n" "If verbose is true, returns an Object with information about uncle block header.\n" "\nArguments:\n" "1. \"hash\" (string, required) The block hash\n" - "2. \"hashuncle\" (string, required) The uncle block header hash\n" + "2. \"index\" (numeric, required) The index of uncle block header in block \n" "3. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" @@ -665,7 +665,7 @@ UniValue getuncleblockheader(const UniValue& params, bool fHelp) " \"hashPrevBlock\" : \"hash\", (string) the uncle block header hashPrevBlock \n" " \"hashUncles\" : \"hash\", (string) the uncle block header hashUncles \n" " \"coinbase\" : \"hash\", (string) the uncle block header nCoinbase \n" - " \"difficulty\" : n, (numeric) the uncle block header nDifficulty \n" + " \"hdifficulty\" : n, (numeric) the uncle block header nDifficulty \n" " \"hashMerkleRoot\" : \"hash\", (string) the uncle block header hashMerkleRoot \n" " \"hashClaimTrie\" : \"hash\", (string) the uncle block header hashClaimTrie \n" " \"time\" : n, (numeric) the uncle block header nTime \n" From a0a43aae2ae04b37763f5fb4c2f5c6ca750ab5e5 Mon Sep 17 00:00:00 2001 From: crazyfrog2001 Date: Tue, 20 Nov 2018 19:32:23 +0800 Subject: [PATCH 120/120] chang some print --- src/main.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c091a92..4df5e95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1788,7 +1788,7 @@ CAmount GetMainMinerSubsidy(int height, const Consensus::Params &cp, int uc) return reward; } CAmount ret = (reward* 3 / 4 + (reward * uc / 32)); - LogPrintf("GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); + LogPrint("pop","GetMainMinerSubsidy at height: %d,uc: %d amount: %d \n",height,uc,ret); return ret; } @@ -1804,7 +1804,7 @@ CAmount GetUncleMinerSubsidy(int height, const Consensus::Params &cp, int uh) return 0; } CAmount ret = ( diff * reward * 3 / (32 * 7)); - LogPrintf("GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); + LogPrint("pop","GetUncleMinerSubsidy at height: %d,uh: %d amount: %d \n",height,uh,ret); return ret; } @@ -1820,10 +1820,10 @@ CAmount GetFoundersReward(const int height, const Consensus::Params &cp) } if (height >= beg && height < end) // before super block starting { - LogPrintf("GetFoundersReward at height: %d, amount: %d \n",height,cp.foundersReward); + LogPrint("pop","GetFoundersReward at height: %d, amount: %d \n",height,cp.foundersReward); return cp.foundersReward; } - LogPrintf("GetFoundersReward at height: %d, amount: 0 \n",height); + LogPrint("pop","GetFoundersReward at height: %d, amount: 0 \n",height); return 0; } @@ -2635,7 +2635,7 @@ bool GetBlockHeight(uint256 hash, int* hight) bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vCbi) { LOCK(cs_main); - LogPrintf("GetAncestorBlocksFromHash \n"); + LogPrint("pop","GetAncestorBlocksFromHash \n"); if(hash == uint256()) return false; BlockMap::iterator mi = mapBlockIndex.find(hash); @@ -2654,7 +2654,7 @@ bool GetAncestorBlocksFromHash(uint256 hash,int n, std::vector& vC bool MakeCurrentCycle(uint256 hash) { - LogPrintf("MakeCurrentCycle \n"); + LogPrint("pop","MakeCurrentCycle \n"); if(hash == uint256()) return false; if(currentParenthash == hash) @@ -2669,7 +2669,7 @@ bool MakeCurrentCycle(uint256 hash) CBlockHeader blockheader; for(std::vector::iterator it = ancestor.begin(); it != ancestor.end(); ++it){ pBlockIndex = *it; - LogPrintf("MakeCurrentCycle():ReadBlockFromDisk %s \n", pBlockIndex->GetBlockHash().ToString()); + LogPrint("pop","MakeCurrentCycle():ReadBlockFromDisk %s \n", pBlockIndex->GetBlockHash().ToString()); if(ReadBlockFromDisk(block, pBlockIndex, chainparams.GetConsensus())){ for(std::vector::iterator bi = block.vuh.begin(); bi != block.vuh.end(); ++bi){ blockheader = *bi; @@ -2688,7 +2688,7 @@ bool MakeCurrentCycle(uint256 hash) bool CommitUncle(CBlockHeader uncle) { - LogPrintf("CommitUncle \n"); + LogPrint("pop","CommitUncle \n"); uint256 hash = uncle.GetHash(); if(setCurrentUncle.count(hash) != 0){ return false; @@ -2707,14 +2707,14 @@ bool CommitUncle(CBlockHeader uncle) void FindBlockUncles(uint256 parenthash,std::vector& vuncles) { LOCK(cs_main); - LogPrintf("FindBlockUncles in \n"); + LogPrint("pop","FindBlockUncles in \n"); if(parenthash == uint256()){ - LogPrintf("FindBlockUncles out 1 \n"); + LogPrint("pop","FindBlockUncles out 1 \n"); return; } if(parenthash == currentParenthash){ - LogPrintf("FindBlockUncles out 2 \n"); + LogPrint("pop","FindBlockUncles out 2 \n"); for(BlockSetGho::iterator it = setCurrentUncle.begin(); it != setCurrentUncle.end(); ++it){ BlockMapGho::iterator mi = mapPossibleUncles.find(*it); vuncles.push_back((*mi).second); @@ -2728,7 +2728,7 @@ void FindBlockUncles(uint256 parenthash,std::vector& vuncles) if(!MakeCurrentCycle(parenthash)){ - LogPrintf("FindBlockUncles out 3 \n"); + LogPrint("pop","FindBlockUncles out 3 \n"); return; } @@ -2752,8 +2752,8 @@ void FindBlockUncles(uint256 parenthash,std::vector& vuncles) BlockMapGho::iterator mi = mapPossibleUncles.find(*it); mapPossibleUncles.erase(mi); } - LogPrintf("FindBlockUncles mapPossibleUncles size %d\n",mapPossibleUncles.size()); - LogPrintf("FindBlockUncles out 4 \n"); + LogPrint("pop","FindBlockUncles mapPossibleUncles size %d\n",mapPossibleUncles.size()); + LogPrint("pop","FindBlockUncles out 4 \n"); return; } @@ -2778,7 +2778,7 @@ void ThreadProcFutureBlocks() while (true) { MilliSleep(15000); - LogPrintf("ThreadProcFutureBlocks count %d\n",threadCount); + LogPrint("pop","ThreadProcFutureBlocks count %d\n",threadCount); int len = 0; lruFutureBlock.length(len); if(len > 0){ @@ -2788,11 +2788,11 @@ void ThreadProcFutureBlocks() LogPrintf("ThreadProcFutureBlocks key[%d]: %s\n",i,key[i].ToString()); CBlock block= lruFutureBlock.get(key[i]); if(block.nTime < (GetAdjustedTime() + 45)){ - LogPrintf("%s :ActivateBestChain block %s doing\n", __func__,block.GetHash().ToString()); + LogPrintf("%s :ThreadProcFutureBlocks ActivateBestChain block %s doing\n", __func__,block.GetHash().ToString()); if (ActivateBestChain(state, chainparams, &block)){ popnodeSync.IsBlockchainSynced(true); if(block.hashUncles != uint256()){ - LogPrintf("%s :block %s has uncle \n", __func__,block.GetHash().ToString()); + LogPrint("pop","%s :block %s has uncle \n", __func__,block.GetHash().ToString()); } LogPrintf("%s : ActivateBestChain ACCEPTED\n", __func__); }else{ @@ -4778,7 +4778,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, c /*popchain ghost*/ if(pblock->hashUncles != uint256()){ CBlock blockhasuncle = *pblock; - LogPrintf("%s :block %s has uncle \n", __func__,blockhasuncle.ToString()); + LogPrint("pop","%s :block %s has uncle \n", __func__,blockhasuncle.ToString()); } /*popchain ghost*/