// ppcoin: only descendant of current sync-checkpoint is allowed bool ValidateSyncCheckpoint(uint256 hashCheckpoint) { if (!mapBlockIndex.count(hashSyncCheckpoint)) return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString()); if (!mapBlockIndex.count(hashCheckpoint)) return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString()); CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint]; CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint]; if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight) { // Received an older checkpoint, trace back from current checkpoint // to the same height of the received checkpoint to verify // that current checkpoint should be a descendant block CBlockIndex* pindex = pindexSyncCheckpoint; while (pindex->nHeight > pindexCheckpointRecv->nHeight) if (!(pindex = pindex->pprev)) return error("ValidateSyncCheckpoint: pprev null - block index structure failure"); if (pindex->GetBlockHash() != hashCheckpoint) { hashInvalidCheckpoint = hashCheckpoint; return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString(), hashSyncCheckpoint.ToString()); } return false; // ignore older checkpoint } // Received checkpoint should be a descendant block of the current // checkpoint. Trace back to the same height of current checkpoint // to verify. CBlockIndex* pindex = pindexCheckpointRecv; while (pindex->nHeight > pindexSyncCheckpoint->nHeight) if (!(pindex = pindex->pprev)) return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure"); if (pindex->GetBlockHash() != hashSyncCheckpoint) { hashInvalidCheckpoint = hashCheckpoint; return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString(), hashSyncCheckpoint.ToString()); } return true; }
std::string getexplorerBlockHash(int64_t Height) { std::string genesisblockhash = "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818"; CBlockIndex* pindexBest = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; if ((Height < 0) || (Height > pindexBest->nHeight)) { return genesisblockhash; } CBlock block; CBlockIndex* pblockindex = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; while (pblockindex->nHeight > Height) pblockindex = pblockindex->pprev; return pblockindex->GetBlockHash().GetHex(); // pblockindex->phashBlock->GetHex(); }
Value getblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( "getblockhash <index>\n" "Returns hash of block in best-block-chain at <index>."); int nHeight = params[0].get_int(); if (nHeight < 0 || nHeight > chainActive.Height()) throw runtime_error("Block number out of range."); CBlockIndex* pblockindex = chainActive[nHeight]; return pblockindex->GetBlockHash().GetHex(); }
std::string getBlockHash(qint64 Height) { if(Height > pindexBest->nHeight) { return ""; } if(Height < 0) { return ""; } qint64 desiredheight; desiredheight = Height; if (desiredheight < 0 || desiredheight > nBestHeight) return 0; CBlockIndex* pblockindex = mapBlockIndex[hashBestChain]; while (pblockindex->nHeight > desiredheight) pblockindex = pblockindex->pprev; return pblockindex->GetBlockHash().GetHex(); // pblockindex->phashBlock->GetHex(); }
std::string getBlockHash(int Height) { if(Height > pindexBest->nHeight) { return "351c6703813172725c6d660aa539ee6a3d7a9fe784c87fae7f36582e3b797058"; } if(Height < 0) { return "351c6703813172725c6d660aa539ee6a3d7a9fe784c87fae7f36582e3b797058"; } int desiredheight; desiredheight = Height; if (desiredheight < 0 || desiredheight > nBestHeight) return 0; CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hashBestChain]; while (pblockindex->nHeight > desiredheight) pblockindex = pblockindex->pprev; return pblockindex->GetBlockHash().GetHex(); // pblockindex->phashBlock->GetHex(); }
bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue, CAmount nMinted) { CBlockIndex* pindexPrev = chainActive.Tip(); if (pindexPrev == NULL) return true; int nHeight = 0; if (pindexPrev->GetBlockHash() == block.hashPrevBlock) { nHeight = pindexPrev->nHeight + 1; } else { //out of order BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi != mapBlockIndex.end() && (*mi).second) nHeight = (*mi).second->nHeight + 1; } if (nHeight == 0) { LogPrint("masternode","IsBlockValueValid() : WARNING: Couldn't find previous block\n"); } //LogPrintf("XX69----------> IsBlockValueValid(): nMinted: %d, nExpectedValue: %d\n", FormatMoney(nMinted), FormatMoney(nExpectedValue)); if (!masternodeSync.IsSynced()) { //there is no budget data to use to check anything //super blocks will always be on these blocks, max 100 per budgeting if (nHeight % GetBudgetPaymentCycleBlocks() < 100) { return true; } else { if (nMinted > nExpectedValue) { return false; } } } else { // we're synced and have data so check the budget schedule //are these blocks even enabled if (!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)) { return nMinted <= nExpectedValue; } if (budget.IsBudgetPaymentBlock(nHeight)) { //the value of the block is evaluated in CheckBlock return true; } else { if (nMinted > nExpectedValue) { return false; } } } return true; }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); 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)); result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion))); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("nameclaimroot", block.hashClaimTrie.GetHex())); UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); bool fNegative; bool fOverflow; arith_uint256 target; target.SetCompact(block.nBits, &fNegative, &fOverflow); result.push_back(Pair("target", target.ToString())); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
std::string getBlockHash(int64_t Height) { CBlockIndex* pindexBest = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; if(Height > pindexBest->nHeight) { return ""; } if(Height < 0) { return ""; } int64_t desiredheight; desiredheight = Height; if (desiredheight < 0 || desiredheight > pindexBest->nHeight) return 0; CBlock block; CBlockIndex* pblockindex = mapBlockIndex[chainActive.Tip()->GetBlockHash()]; while (pblockindex->nHeight > desiredheight) pblockindex = pblockindex->pprev; return pblockindex->GetBlockHash().GetHex(); // pblockindex->phashBlock->GetHex(); }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); 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.GetFullVersion())); int algo = block.GetAlgo(); result.push_back(Pair("pow_algo_id", algo)); result.push_back(Pair("pow_algo", GetAlgoName(algo))); result.push_back(Pair("pow_hash", block.GetPoWHash(algo).GetHex())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { Object objTx; TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex, miningAlgo))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (block.auxpow) result.push_back(Pair("auxpow", auxpowToJSON(*block.auxpow))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
bool IsBlockValueValid(const CBlock& block, CAmount nExpectedValue){ CBlockIndex* pindexPrev = pindexBest; if(pindexPrev == NULL) return true; int nHeight = 0; if(pindexPrev->GetBlockHash() == block.hashPrevBlock) { nHeight = pindexPrev->nHeight+1; } //TODO (Amir): Put back... conversion from 'std::map<uint256, CBlockIndex*>::iterator error. // else { //out of order // BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); // if (mi != mapBlockIndex.end() && (*mi).second) // nHeight = (*mi).second->nHeight+1; //} if(nHeight == 0){ LogPrintf("IsBlockValueValid() : WARNING: Couldn't find previous block"); } if(!stormnodeSync.IsSynced()) { //there is no budget data to use to check anything //super blocks will always be on these blocks, max 100 per budgeting if(nHeight % GetBudgetPaymentCycleBlocks() < 100){ return true; } else { if(block.vtx[0].GetValueOut() > nExpectedValue) return false; } } else { // we're synced and have data so check the budget schedule //are these blocks even enabled if(!IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)){ return block.vtx[0].GetValueOut() <= nExpectedValue; } if(budget.IsBudgetPaymentBlock(nHeight)){ //the value of the block is evaluated in CheckBlock return true; } else { if(block.vtx[0].GetValueOut() > nExpectedValue) return false; } } return true; }
bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex) { boost::scoped_ptr<CDBIterator> pcursor(NewIterator()); pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); // Load mapBlockIndex while (pcursor->Valid()) { boost::this_thread::interruption_point(); std::pair<char, uint256> 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->nDustVote = diskindex.nDustVote; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; 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; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); 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)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; Array txuserhashes; Array usernames; std::string spamMessage; std::string spamUser; BOOST_FOREACH(const CTransaction&tx, block.vtx) { txs.push_back(tx.GetHash().GetHex()); if( tx.IsSpamMessage() ) { spamMessage = tx.message.ExtractPushDataString(0); spamUser = tx.userName.ExtractPushDataString(0); } else { txuserhashes.push_back(tx.GetUsernameHash().GetHex()); usernames.push_back(tx.userName.ExtractSmallString()); } } result.push_back(Pair("tx", txs)); result.push_back(Pair("spamMessage", spamMessage)); result.push_back(Pair("spamUser", spamUser)); result.push_back(Pair("userhashes", txuserhashes)); result.push_back(Pair("usernames", usernames)); result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = blockindex->GetNextInMainChain(); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); 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.GetFullVersion())); result.push_back(Pair("proof_type", block.IsProofOfStake() ? "PoS" : "PoW")); if (block.IsProofOfStake()) result.push_back(Pair("stake_source", COutPoint(block.stakePointer.txid, block.stakePointer.nPos).ToString())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) { if(txDetails) { Object objTx; TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("block_witnesses", (int64_t)g_proofTracker->GetWitnessCount(block.GetHash()))); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
Value getblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( "getblockhash index\n" "\nReturns hash of block in best-block-chain at index provided.\n" "\nArguments:\n" "1. index (numeric, required) The block index\n" "\nResult:\n" "\"hash\" (string) The block hash\n" "\nExamples:\n" + HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000") ); int nHeight = params[0].get_int(); if (nHeight < 0 || nHeight > chainActive.Height()) throw runtime_error("Block number out of range."); CBlockIndex* pblockindex = chainActive[nHeight]; return pblockindex->GetBlockHash().GetHex(); }
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { Object result; result.push_back(Pair("hash", block.GetHash().GetHex())); CMerkleTx txGen(block.vtx[0]); txGen.SetMerkleBranch(&block); result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain())); result.push_back(Pair("size", (int)blockindex->nSize)); result.push_back(Pair("chainsize", blockindex->nChainSize)); if (chainActive.Contains(blockindex)) result.push_back(Pair("maxsize", (int)chainActive.MaxBlockSize(blockindex->nHeight))); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", (uint64_t)block.GetVersion())); result.push_back(Pair("ispok", block.IsPoKBlock())); if (block.IsPoKBlock()) result.push_back(Pair("pok", (uint64_t)block.GetPoK())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); result.push_back(Pair("tx", txs)); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); result.push_back(Pair("ntx", (int64_t)blockindex->nTx)); result.push_back(Pair("nchaintx", (int64_t)blockindex->nChainTx)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
CBlockTemplate* CreateNewBlock(CAccountViewCache &view, CTransactionDBCache &txCache, CScriptDBViewCache &scriptCache){ // // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if (!pblocktemplate.get()) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience // Create coinbase tx CRewardTransaction rtx; // Add our coinbase tx as first transaction pblock->vptx.push_back(make_shared<CRewardTransaction>(rtx)); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: unsigned int nBlockMaxSize = SysCfg().GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity: nBlockMaxSize = max((unsigned int) 1000, 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 = SysCfg().GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE); nBlockPrioritySize = 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 = SysCfg().GetArg("-blockminsize", DEFAULT_BLOCK_MIN_SIZE); nBlockMinSize = min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block int64_t nFees = 0; { LOCK2(cs_main, mempool.cs); CBlockIndex* pIndexPrev = chainActive.Tip(); pblock->SetFuelRate(GetElementForBurn(pIndexPrev)); // This vector will be sorted into a priority queue: vector<TxPriority> vecPriority; GetPriorityTx(vecPriority, pblock->GetFuelRate()); // Collect transactions into block uint64_t nBlockSize = ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); uint64_t nBlockTx(0); bool fSortedByFee(true); uint64_t nTotalRunStep(0); int64_t nTotalFuel(0); TxPriorityCompare comparer(fSortedByFee); make_heap(vecPriority.begin(), vecPriority.end(), comparer); while (!vecPriority.empty()) { // Take highest priority transaction off the priority queue: double dPriority = vecPriority.front().get<0>(); double dFeePerKb = vecPriority.front().get<1>(); shared_ptr<CBaseTransaction> stx = vecPriority.front().get<2>(); CBaseTransaction *pBaseTx = stx.get(); //const CTransaction& tx = *(vecPriority.front().get<2>()); pop_heap(vecPriority.begin(), vecPriority.end(), comparer); vecPriority.pop_back(); // Size limits unsigned int nTxSize = ::GetSerializeSize(*pBaseTx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) continue; // Skip free transactions if we're past the minimum block size: if (fSortedByFee && (dFeePerKb < CTransaction::nMinRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; // Prioritize by fee once past the priority size or we run out of high-priority // transactions: if (!fSortedByFee && ((nBlockSize + nTxSize >= nBlockPrioritySize) || !AllowFree(dPriority))) { fSortedByFee = true; comparer = TxPriorityCompare(fSortedByFee); make_heap(vecPriority.begin(), vecPriority.end(), comparer); } if(uint256() != std::move(txCache.IsContainTx(std::move(pBaseTx->GetHash())))) { LogPrint("INFO","CreatePosTx duplicate tx\n"); continue; } CTxUndo txundo; CValidationState state; if(pBaseTx->IsCoinBase()){ ERRORMSG("TX type is coin base tx error......"); // assert(0); //never come here } if (CONTRACT_TX == pBaseTx->nTxType) { LogPrint("vm", "tx hash=%s CreateNewBlock run contract\n", pBaseTx->GetHash().GetHex()); } CAccountViewCache viewTemp(view, true); CScriptDBViewCache scriptCacheTemp(scriptCache, true); pBaseTx->nFuelRate = pblock->GetFuelRate(); if (!pBaseTx->ExecuteTx(nBlockTx + 1, viewTemp, state, txundo, pIndexPrev->nHeight + 1, txCache, scriptCacheTemp)) { continue; } // Run step limits if(nTotalRunStep + pBaseTx->nRunStep >= MAX_BLOCK_RUN_STEP) continue; assert(viewTemp.Flush()); assert(scriptCacheTemp.Flush()); nFees += pBaseTx->GetFee(); nBlockSize += stx->GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION); nTotalRunStep += pBaseTx->nRunStep; nTotalFuel += pBaseTx->GetFuel(pblock->GetFuelRate()); nBlockTx++; pblock->vptx.push_back(stx); LogPrint("fuel", "miner total fuel:%d, tx fuel:%d runStep:%d fuelRate:%d txhash:%s\n",nTotalFuel, pBaseTx->GetFuel(pblock->GetFuelRate()), pBaseTx->nRunStep, pblock->GetFuelRate(), pBaseTx->GetHash().GetHex()); } nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; LogPrint("INFO","CreateNewBlock(): total size %u\n", nBlockSize); assert(nFees-nTotalFuel >= 0); ((CRewardTransaction*) pblock->vptx[0].get())->rewardValue = nFees - nTotalFuel + GetBlockSubsidy(pIndexPrev->nHeight + 1); // Fill in header pblock->SetHashPrevBlock(pIndexPrev->GetBlockHash()); UpdateTime(*pblock, pIndexPrev); pblock->SetBits(GetNextWorkRequired(pIndexPrev, pblock)); pblock->SetNonce(0); pblock->SetHeight(pIndexPrev->nHeight + 1); pblock->SetFuel(nTotalFuel); } return pblocktemplate.release(); }
bool CTxDB::LoadBlockIndex() { if (!LoadBlockIndexGuts()) return false; if (fRequestShutdown) return true; // Calculate bnChainTrust vector<pair<int, CBlockIndex*> > 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->bnChainTrust = (pindex->pprev ? pindex->pprev->bnChainTrust : 0) + pindex->GetBlockTrust(); // ppcoin: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; bnBestChainTrust = pindexBest->bnChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // ppcoin: load hashSyncCheckpoint if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); // Load bnBestInvalidTrust, OK if it doesn't exist ReadBestInvalidTrust(bnBestInvalidTrust); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity if (nCheckLevel>0 && !block.CheckBlock()) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } nOutput++; } } }
bool CBlockTreeDB::LoadBlockIndexGuts() { boost::scoped_ptr<CDBIterator> pcursor(NewIterator()); pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256())); // Load mapBlockIndex while (pcursor->Valid()) { boost::this_thread::interruption_point(); std::pair<char, uint256> 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->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; } } // Load fork activation info pcursor->Seek(make_pair(DB_FORK_ACTIVATION, 0)); while (pcursor->Valid()) { try { std::pair<char, uint32_t> key; if (pcursor->GetKey(key) && key.first == DB_FORK_ACTIVATION) { uint256 blockHash; if (pcursor->GetValue(blockHash)) { forkActivationMap[key.second] = blockHash; } pcursor->Next(); } else { break; // finished loading block index } } catch (std::exception &e) { return error("%s : Deserialize or I/O error - %s", __func__, e.what()); } } return true; }
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,const int nHeightIn) { // Create new block auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience CBlockIndex* pindexPrev; if(nHeightIn<=0) { pindexPrev = chainActive.Tip(); } else pindexPrev = chainActive[nHeightIn-1]; int nHeight = pindexPrev->nBlockHeight + 1; pblock->nBlockHeight=nHeight; UpdateTime(pblock, pindexPrev); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (Params().MineBlocksOnDemand()) pblock->nVersion = GetArg("-blockversion", pblock->nVersion); // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); txNew.vin[0].prevout.SetNull(); txNew.vin[0].prevout.n=nHeight; txNew.vin[0].scriptSig=CScript()<<0; txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nLockTime=nHeight +COINBASE_MATURITY; // Add dummy coinbase tx as first transaction pblock->vtx.push_back(CTransaction()); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOps.push_back(-1); // updated at end // Largest block you're willing to create: unsigned int nBlockMaxSize = GetArg("-blockmaxsize", DEFAULT_BLOCK_MAX_SIZE); // Limit to betweeen 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); //min tx size to judge finish of block.set this a little bit higher so as to make mining faster unsigned int nMinTxSize=200; // Collect memory pool transactions into the block CAmount nFees = 0; uint64_t nBlockSize = 1000; uint64_t nBlockTx = 0; int nBlockSigOps = 100; { LOCK2(cs_main, mempool.cs); if(nHeightIn<=0) { CCoinsViewCache view(pcoinsTip); // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move map<uint256, vector<COrphan*> > mapDependers; // Collect transactions into block for (int i=0;i<(int)mempool.queue.size();i++) { const CTransaction& tx = mempool.mapTx[mempool.queue[i]].GetTx(); if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight)) continue; COrphan* porphan = NULL; CAmount nTotalIn = 0; bool fMissingInputs = false; BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Read prev transaction if (!view.HaveCoins(txin.prevout.hash)) { //don't take in transactions with prevout in mempool,because txs are queued by fee, not sequence, we can't guarantee it's //previous tx can be included in this block fMissingInputs = true; break; // This should never happen; all transactions in the memory // pool should connect to either transactions in the chain // or other transactions in the memory pool. if (!mempool.mapTx.count(txin.prevout.hash)) { LogPrintf("ERROR: mempool transaction missing input\n"); if (fDebug) assert("mempool transaction missing input" == 0); fMissingInputs = true; if (porphan) vOrphan.pop_back(); break; } // Has to wait for dependencies if (!porphan) { // Use list for automatic deletion vOrphan.push_back(COrphan(&tx)); porphan = &vOrphan.back(); } mapDependers[txin.prevout.hash].push_back(porphan); porphan->setDependsOn.insert(txin.prevout.hash); nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue; continue; } const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); if ((int64_t)coins->vout[txin.prevout.n].nLockTime >= ((int64_t)coins->vout[txin.prevout.n].nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nHeight : std::min((int64_t)pindexPrev->nTime,std::max((int64_t)pindexPrev->GetMedianTimePast()+1, (int64_t)GetAdjustedTime())))) fMissingInputs = true; CAmount nValueIn = coins->vout[txin.prevout.n].nValue; nTotalIn += nValueIn; } if (fMissingInputs) continue; // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); if (nBlockSize + nTxSize >= nBlockMaxSize) continue; // Legacy limits on sigOps: unsigned int nTxSigOps = GetLegacySigOpCount(tx); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; if (!view.HaveInputs(tx)) continue; CAmount nTxFees = tx.GetFee(); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) continue; // Note that flags: we don't want to set mempool/IsStandard() // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; if (!CheckInputs(tx, tx,state, view, pblock,true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) continue; CTxUndo txundo; UpdateCoins(tx, state, view, txundo, nHeight); // Added pblock->vtx.push_back(tx); pblocktemplate->vTxFees.push_back(nTxFees); pblocktemplate->vTxSigOps.push_back(nTxSigOps); nBlockSize += nTxSize; ++nBlockTx; nBlockSigOps += nTxSigOps; nFees += nTxFees; if (nBlockSize+nMinTxSize>nBlockMaxSize) break; } } CBlock prevBlock; ReadBlockFromDisk(prevBlock, pindexPrev); CAmount prevCoinbaseFee=prevBlock.vtx[0].GetFee(); nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; // Compute final coinbase transaction. CAmount coinbaseInput=GetBlockValue(nHeight, nFees)+prevCoinbaseFee; txNew.vin[0].prevout.nValue = coinbaseInput; txNew.vout[0].nValue = 0; CAmount coinbaseFee=CFeeRate(DEFAULT_TRANSACTION_FEE).GetFee(txNew.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)+10); CAmount coinbaseOutput=coinbaseInput-coinbaseFee; if(nHeightIn<=0&&coinbaseOutput<=minRelayTxFee.GetFee(DUST_THRESHOLD)) return NULL; txNew.vout[0].nValue =coinbaseOutput; pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); CValidationState state; if (nHeightIn<=0&&!TestBlockValidity(state, *pblock, pindexPrev, false, false)) { LogPrintf("CreateNewBlock() : TestBlockValidity failed \n" ); return NULL; } }
bool FindRAC(bool CheckingWork, std::string TargetCPID, std::string TargetProjectName, double pobdiff, bool bCreditNodeVerification, std::string& out_errors, int& out_position) { try { //Gridcoin; Find CPID+Project+RAC in chain int nMaxDepth = nBestHeight-1; if (nMaxDepth < 3) nMaxDepth=3; double pobdifficulty; if (bCreditNodeVerification) { pobdifficulty=14; } else { pobdifficulty = pobdiff; } if (pobdifficulty < .002) pobdifficulty=.002; int nLookback = 576*pobdifficulty; //Daily block count * Lookback in days int nMinDepth = nMaxDepth - nLookback; if (nMinDepth < 2) nMinDepth = 2; out_position = 0; //////////////////////////// if (CheckingWork) nMinDepth=nMinDepth+10; if (nMinDepth > nBestHeight) nMinDepth=nBestHeight-1; //////////////////////////// if (nMinDepth > nMaxDepth) { nMinDepth = nMaxDepth-1; } if (nMaxDepth < 5 || nMinDepth < 5) return false; //Check the cache first: StructCPIDCache cache; std::string sKey = TargetCPID + ":" + TargetProjectName; cache = mvCPIDCache[sKey]; double cachedblocknumber = 0; if (cache.initialized) { cachedblocknumber=cache.blocknumber; } if (cachedblocknumber > 0 && cachedblocknumber >= nMinDepth && cachedblocknumber <= nMaxDepth && cache.cpidproject==sKey) { out_position = cache.blocknumber; if (CheckingWork) printf("Project %s found at position %i PoBLevel %f Start depth %i end depth %i \r\n", TargetProjectName.c_str(),out_position,pobdifficulty,nMaxDepth,nMinDepth); return true; } CBlock block; out_errors = ""; for (int ii = nMaxDepth; ii > nMinDepth; ii--) { CBlockIndex* pblockindex = FindBlockByHeight(ii); int out_height = 0; bool result1 = GetBlockNew(pblockindex->GetBlockHash(), out_height, block, false); if (result1) { MiningCPID bb = DeserializeBoincBlock(block.hashBoinc); if (bb.cpid==TargetCPID && bb.projectname==TargetProjectName && block.nVersion==3) { out_position = ii; //Cache this: cache = mvCPIDCache[sKey]; if (!cache.initialized) { cache.initialized = true; mvCPIDCache.insert(map<string,StructCPIDCache>::value_type(sKey, cache)); } cache.cpid = TargetCPID; cache.cpidproject = sKey; cache.blocknumber = ii; if (CheckingWork) printf("Project %s found at position %i PoBLevel %f Start depth %i end depth %i \r\n",TargetProjectName.c_str(),ii,pobdifficulty,nMaxDepth,nMinDepth); mvCPIDCache[sKey]=cache; return true; } } } printf("Start depth %i end depth %i",nMaxDepth,nMinDepth); out_errors = out_errors + "Start depth " + RoundToString(nMaxDepth,0) + "; "; out_errors = out_errors + "Not found; "; return false; } catch (std::exception& e) { return false; } }
Value listsinceblock(const Array& params, bool fHelp) { if (fHelp) throw runtime_error( "listsinceblock [blockhash] [target-confirmations]\n" "Get all transactions in blocks since block [blockhash], or all transactions if omitted"); CBlockIndex *pindex = NULL; int target_confirms = 1; if (params.size() > 0) { uint256 blockId = 0; blockId.SetHex(params[0].get_str()); pindex = CBlockLocator(blockId).GetBlockIndex(); } if (params.size() > 1) { target_confirms = params[1].get_int(); if (target_confirms < 1) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter"); } int depth = pindex ? (1 + nBestHeight - pindex->nHeight) : -1; Array transactions; for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++) { CWalletTx tx = (*it).second; if (depth == -1 || tx.GetDepthInMainChain() < depth) ListTransactions(tx, "*", 0, true, transactions); } uint256 lastblock; if (target_confirms == 1) { lastblock = hashBestChain; } else { int target_height = pindexBest->nHeight + 1 - target_confirms; CBlockIndex *block; for (block = pindexBest; block && block->nHeight > target_height; block = block->pprev) { } lastblock = block ? block->GetBlockHash() : 0; } Object ret; ret.push_back(Pair("transactions", transactions)); ret.push_back(Pair("lastblock", lastblock.GetHex())); return ret; }
bool CTxDB::LoadBlockIndex() { if (mapBlockIndex.size() > 0) { // Already loaded once in this session. It can happen during migration // from BDB. return true; } // The block index is an in-memory structure that maps hashes to on-disk // locations where the contents of the block can be found. Here, we scan it // out of the DB and into mapBlockIndex. leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions()); // Seek to start key. CDataStream ssStartKey(SER_DISK, CLIENT_VERSION); ssStartKey << make_pair(string("blockindex"), uint256(0)); iterator->Seek(ssStartKey.str()); // Now read each entry. while (iterator->Valid()) { // Unpack keys and values. CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.write(iterator->key().data(), iterator->key().size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.write(iterator->value().data(), iterator->value().size()); string strType; ssKey >> strType; // Did we reach the end of the data to read? if (fRequestShutdown || strType != "blockindex") break; CDiskBlockIndex diskindex; ssValue >> diskindex; uint256 blockHash = diskindex.GetBlockHash(); // Construct block index object CBlockIndex* pindexNew = InsertBlockIndex(blockHash); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; pindexNew->nHeight = diskindex.nHeight; pindexNew->nMint = diskindex.nMint; pindexNew->nMoneySupply = diskindex.nMoneySupply; pindexNew->nFlags = diskindex.nFlags; pindexNew->nStakeModifier = diskindex.nStakeModifier; pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProofOfStake = diskindex.hashProofOfStake; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; // Watch for genesis block if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) pindexGenesisBlock = pindexNew; if (!pindexNew->CheckIndex()) { delete iterator; return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); } // CurrentCoin: build setStakeSeen if (pindexNew->IsProofOfStake()) setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); iterator->Next(); } delete iterator; if (fRequestShutdown) return true; // Calculate nChainTrust vector<pair<int, CBlockIndex*> > 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->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust(); // CurrentCoin: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; nBestChainTrust = pindexBest->nChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // CurrentCoin: load hashSyncCheckpoint if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); // Load bnBestInvalidTrust, OK if it doesn't exist CBigNum bnBestInvalidTrust; ReadBestInvalidTrust(bnBestInvalidTrust); nBestInvalidTrust = bnBestInvalidTrust.getuint256(); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity // check level 7: verify block signature too if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6))) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } nOutput++; } } }
Value gettxout(const Array& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( "gettxout \"txid\" n ( includemempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. n (numeric, required) vout value\n" "3. includemempool (boolean, optional) Whether to included the mem pool\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" " \"confirmations\" : n, (numeric) The number of confirmations\n" " \"value\" : x.xxx, (numeric) The transaction value in btc\n" " \"scriptPubKey\" : { (json object)\n" " \"asm\" : \"code\", (string) \n" " \"hex\" : \"hex\", (string) \n" " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" " \"addresses\" : [ (array of string) array of bitcoin addresses\n" " \"bitcoinaddress\" (string) bitcoin address\n" " ,...\n" " ]\n" " },\n" " \"version\" : n, (numeric) The version\n" " \"coinbase\" : true|false (boolean) Coinbase or not\n" "}\n" "\nExamples:\n" "\nGet unspent transactions\n" + HelpExampleCli("listunspent", "") + "\nView the details\n" + HelpExampleCli("gettxout", "\"txid\" 1") + "\nAs a json rpc call\n" + HelpExampleRpc("gettxout", "\"txid\", 1") ); Object ret; std::string strHash = params[0].get_str(); uint256 hash(strHash); int n = params[1].get_int(); bool fMempool = true; if (params.size() > 2) fMempool = params[2].get_bool(); CCoins coins; if (fMempool) { LOCK(mempool.cs); CCoinsViewMemPool view(*pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) return Value::null; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { if (!pcoinsTip->GetCoins(hash, coins)) return Value::null; } if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) return Value::null; std::map<uint256, CBlockIndex*>::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex *pindex = it->second; ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex())); if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT) ret.push_back(Pair("confirmations", 0)); else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1)); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); Object o; ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); ret.push_back(Pair("coinbase", coins.fCoinBase)); return ret; }
UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, const uint32_t nMode = 0) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) confirmations = chainActive.Height() - blockindex->nHeight + 1; result.push_back(Pair("confirmations", confirmations)); 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)); result.push_back(Pair("payload", blockindex->GetPayloadString())); result.push_back(Pair("payloadhash", blockindex->hashPayload.ToString())); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("creator", strprintf("0x%08x", blockindex->nCreatorId))); result.push_back(Pair("creatorSignature", block.creatorSignature.ToString())); result.push_back(Pair("nSignatures", (uint64_t)GetNumChainSigs(blockindex))); result.push_back(Pair("nAdminSignatures", (uint64_t)block.vAdminIds.size())); result.push_back(Pair("chainSignature", block.chainMultiSig.ToString())); result.push_back(Pair("adminMultiSig", block.adminMultiSig.IsNull() ? "" : block.adminMultiSig.ToString())); ///////// MISSING CHAIN SIGNERS UniValue missingSigners(UniValue::VARR); BOOST_FOREACH(const uint32_t& signerId, block.vMissingSignerIds) { missingSigners.push_back(strprintf("0x%08x", signerId)); } result.push_back(Pair("missingCreatorIds", missingSigners)); ///////// ADMIN SIGNERS UniValue adminSigners(UniValue::VARR); BOOST_FOREACH(const uint32_t& signerId, block.vAdminIds) { adminSigners.push_back(strprintf("0x%08x", signerId)); } result.push_back(Pair("adminSignerIds", adminSigners)); ///////// TRANSACTIONS UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction& tx, block.vtx) { if (nMode >= 5) { UniValue objTx(UniValue::VOBJ); TxToJSON(tx, uint256(), objTx); txs.push_back(objTx); } else txs.push_back(tx.GetHash().GetHex()); } result.push_back(Pair("tx", txs)); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); if (nMode < 2) return result; ///////// CVN INFO UniValue cvns(UniValue::VARR); BOOST_FOREACH(const CCvnInfo& cvn, block.vCvns) { UniValue objCvn(UniValue::VOBJ); objCvn.push_back(Pair("nodeId", strprintf("0x%08x", cvn.nNodeId))); objCvn.push_back(Pair("heightAdded", (int) cvn.nHeightAdded)); if (nMode >= 3) objCvn.push_back(Pair("pubKey", cvn.pubKey.ToString())); cvns.push_back(objCvn); } result.push_back(Pair("cvnInfo", cvns)); ///////// DYNAMIC CHAIN PARAMETERS UniValue dParams(UniValue::VOBJ); if (block.HasChainParameters()) { DynamicChainparametersToJSON(block.dynamicChainParams, dParams); } result.push_back(Pair("chainParameters", dParams)); ///////// ADMIN INFO UniValue admins(UniValue::VARR); BOOST_FOREACH(const CChainAdmin& admin, block.vChainAdmins) { UniValue objAdmin(UniValue::VOBJ); objAdmin.push_back(Pair("adminId", strprintf("0x%08x", admin.nAdminId))); objAdmin.push_back(Pair("heightAdded", (int) admin.nHeightAdded)); if (nMode >= 3) objAdmin.push_back(Pair("pubKey", admin.pubKey.ToString())); admins.push_back(objAdmin); } result.push_back(Pair("chainAdmins", admins)); ///////// COINS SUPPLY UniValue coinSupply(UniValue::VOBJ); if (block.HasCoinSupplyPayload()) { CoinSupplyToJSON(block.coinSupply, coinSupply); } result.push_back(Pair("coinSupply", coinSupply)); return result; }
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, bool fMineWitnessTx) { int64_t nTimeStart = GetTimeMicros(); resetBlock(); pblocktemplate.reset(new CBlockTemplate()); if(!pblocktemplate.get()) return nullptr; pblock = &pblocktemplate->block; // pointer for convenience // Add dummy coinbase tx as first transaction pblock->vtx.emplace_back(); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); assert(pindexPrev != nullptr); nHeight = pindexPrev->nHeight + 1; pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()); // -regtest only: allow overriding block.nVersion with // -blockversion=N to test forking scenarios if (chainparams.MineBlocksOnDemand()) pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion); pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); nLockTimeCutoff = (STANDARD_LOCKTIME_VERIFY_FLAGS & LOCKTIME_MEDIAN_TIME_PAST) ? nMedianTimePast : pblock->GetBlockTime(); // Decide whether to include witness transactions // This is only needed in case the witness softfork activation is reverted // (which would require a very deep reorganization) or when // -promiscuousmempoolflags is used. // TODO: replace this with a call to main to assess validity of a mempool // transaction (which in most cases can be a no-op). fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()) && fMineWitnessTx; int nPackagesSelected = 0; int nDescendantsUpdated = 0; addPackageTxs(nPackagesSelected, nDescendantsUpdated); int64_t nTime1 = GetTimeMicros(); nLastBlockTx = nBlockTx; nLastBlockWeight = nBlockWeight; // Create coinbase transaction. CMutableTransaction coinbaseTx; coinbaseTx.vin.resize(1); coinbaseTx.vin[0].prevout.SetNull(); coinbaseTx.vout.resize(1); coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); } int64_t nTime2 = GetTimeMicros(); LogPrint(BCLog::BENCH, "CreateNewBlock() packages: %.2fms (%d packages, %d updated descendants), validity: %.2fms (total %.2fms)\n", 0.001 * (nTime1 - nTimeStart), nPackagesSelected, nDescendantsUpdated, 0.001 * (nTime2 - nTime1), 0.001 * (nTime2 - nTimeStart)); return std::move(pblocktemplate); }
Value getblock(const Array& 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 <hash>.\n" "\nArguments:\n" "1. \"hash or height\"(string or numeric,required) string for The block hash,numeric for the block height\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\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" " \"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" " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\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" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" "\nExamples:\n" + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") ); std::string strHash; if(int_type == params[0].type()) { int nHeight = params[0].get_int(); if (nHeight < 0 || nHeight > chainActive.Height()) throw runtime_error("Block number out of range."); CBlockIndex* pblockindex = chainActive[nHeight]; strHash= pblockindex->GetBlockHash().GetHex(); }else{ strHash = params[0].get_str(); } uint256 hash(uint256S(strHash)); bool fVerbose = true; if (params.size() > 1) fVerbose = params[1].get_bool(); if (mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; ReadBlockFromDisk(block, pblockindex); if (!fVerbose) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); ssBlock << block; std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); return strHex; } return blockToJSON(block, pblockindex); }
bool CTxDB::LoadBlockIndex() { if (mapBlockIndex.size() > 0) { // Already loaded once in this session. It can happen during migration // from BDB. return true; } #ifdef WIN32 const int #ifdef _DEBUG nREFRESH = 2000; // generally resfresh rates are chosen to give ~1 update/sec #else // seems to be slowing down?? nREFRESH = 12000; #endif int nMaxHeightGuess = 1, nCounter = 0, nRefresh = nREFRESH; ::int64_t n64MsStartTime = GetTimeMillis(); #endif // The block index is an in-memory structure that maps hashes to on-disk // locations where the contents of the block can be found. Here, we scan it // out of the DB and into mapBlockIndex. leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions()); // Seek to start key. CDataStream ssStartKey(SER_DISK, CLIENT_VERSION); ssStartKey << make_pair(string("blockindex"), uint256(0)); iterator->Seek(ssStartKey.str()); // Now read each entry. while (iterator->Valid()) { // Unpack keys and values. CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.write(iterator->key().data(), iterator->key().size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.write(iterator->value().data(), iterator->value().size()); string strType; ssKey >> strType; // Did we reach the end of the data to read? if (fRequestShutdown || strType != "blockindex") break; CDiskBlockIndex diskindex; ssValue >> diskindex; uint256 blockHash = diskindex.GetBlockHash(); if ( 0 == blockHash ) { if (fPrintToConsole) (void)printf( "Error? at nHeight=%d" "\n" "", diskindex.nHeight ); continue; //? } // Construct block index object CBlockIndex * pindexNew = InsertBlockIndex(blockHash); // what if null? Can't be, since blockhash is known to be != 0 //if( NULL == pindexNew ) // ??? //{ // iterator->Next(); // continue; //} pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; pindexNew->nHeight = diskindex.nHeight; pindexNew->nMint = diskindex.nMint; pindexNew->nMoneySupply = diskindex.nMoneySupply; pindexNew->nFlags = diskindex.nFlags; pindexNew->nStakeModifier = diskindex.nStakeModifier; pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProofOfStake = diskindex.hashProofOfStake; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; // Watch for genesis block if( (0 == diskindex.nHeight) && (NULL != pindexGenesisBlock) ) { if (fPrintToConsole) (void)printf( "Error? an extra null block???" "\n" "" ); } if ( (0 == diskindex.nHeight) && // ought to be faster than a hash check!? (NULL == pindexGenesisBlock) ) { if (blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet))// check anyway, but only if block 0 { pindexGenesisBlock = pindexNew; /************* #ifdef WIN32 if (fPrintToConsole) (void)printf( "Found block 0 at nCounter=%d" "\n" "", nCounter ); #endif *************/ } else { if (fPrintToConsole) (void)printf( "Error? a extra genesis block with the wrong hash???" "\n" "" ); } } // there seem to be 2 errant blocks? else { if( (NULL != pindexGenesisBlock) && (0 == diskindex.nHeight) ) { if (fPrintToConsole) (void)printf( "Error? a extra genesis null block???" "\n" "" ); } } //if (!pindexNew->CheckIndex()) // as it stands, this never fails??? So why bother????? //{ // delete iterator; // return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); //} // NovaCoin: build setStakeSeen if (pindexNew->IsProofOfStake()) setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); #ifdef WIN32 ++nCounter; // could "guess at the max nHeight & %age against the loop count // to "hone in on" the %age done. // Towards the end it ought to be pretty accurate. if( nMaxHeightGuess < pindexNew->nHeight ) { nMaxHeightGuess = pindexNew->nHeight; } if( 0 == ( nCounter % nRefresh ) ) // every nRefresh-th time through the loop { float // these #s are just to slosh the . around dEstimate = float( ( 100.0 * nCounter ) / nMaxHeightGuess ); std::string sGutsNoise = strprintf( "%7d (%3.2f%%)" "", nCounter, //pindexNew->nHeight, dEstimate > 100.0? 100.0: dEstimate ); if (fPrintToConsole) { /**************** (void)printf( "%s" " " "", sGutsNoise.c_str() ); ****************/ DoProgress( nCounter, nMaxHeightGuess, n64MsStartTime ); //(void)printf( // "\r" // ); } #ifdef QT_GUI // uiInterface.InitMessage( sGutsNoise.c_str() ); #endif } #endif iterator->Next(); } delete iterator; if (fRequestShutdown) return true; #ifdef WIN32 if (fPrintToConsole) (void)printf( "\n" ); #ifdef QT_GUI uiInterface.InitMessage(_("<b>...done.</b>")); #endif #endif // <<<<<<<<< #ifdef WIN32 if (fPrintToConsole) (void)printf( "Sorting by height...\n" ); #ifdef QT_GUI uiInterface.InitMessage( _("Sorting by height...") ); #endif nCounter = 0; #endif // Calculate bnChainTrust { LOCK(cs_main); vector< pair< int, CBlockIndex*> > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); //vSortedByHeight.resize( mapBlockIndex.size() ); int nUpdatePeriod = 10000; BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { CBlockIndex * pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); #ifdef WIN32 ++nCounter; if( 0 == (nCounter % nUpdatePeriod) ) { #ifdef QT_GUI uiInterface.InitMessage( strprintf( _("%7d"), nCounter ) ); #else if (fPrintToConsole) printf( "%7d\r", nCounter ); #endif } #endif } sort(vSortedByHeight.begin(), vSortedByHeight.end()); #ifdef WIN32 if (fPrintToConsole) (void)printf( "\ndone\nChecking stake checksums...\n" ); #ifdef _DEBUG nUpdatePeriod /= 4; // speed up update for debug mode #else nUpdatePeriod *= 5; // slow down update for release mode #endif #ifdef QT_GUI uiInterface.InitMessage( _("done") ); uiInterface.InitMessage( _("Checking stake checksums...") ); #endif nCounter = 0; #endif BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->nPosBlockCount = ( pindex->pprev ? pindex->pprev->nPosBlockCount : 0 ) + ( pindex->IsProofOfStake() ? 1 : 0 ); pindex->nBitsMA = pindex->IsProofOfStake() ? GetProofOfWorkMA(pindex->pprev) : 0; pindex->bnChainTrust = (pindex->pprev ? pindex->pprev->bnChainTrust : CBigNum(0)) + pindex->GetBlockTrust(); // NovaCoin: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016" PRIx64, pindex->nHeight, pindex->nStakeModifier); #ifdef WIN32 ++nCounter; if( 0 == (nCounter % nUpdatePeriod) ) { #ifdef QT_GUI uiInterface.InitMessage( strprintf( _("%7d"), nCounter ) ); #else if (fPrintToConsole) printf( "%7d\r", nCounter ); #endif } #endif } } #ifdef WIN32 if (fPrintToConsole) (void)printf( "\ndone\n" "Read best chain\n" ); #ifdef QT_GUI uiInterface.InitMessage( _("...done") ); uiInterface.InitMessage( _("Read best chain") ); #endif #endif // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; bnBestChainTrust = pindexBest->bnChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // NovaCoin: load hashSyncCheckpoint if( !fTestNet ) { if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str() ); } // Load bnBestInvalidTrust, OK if it doesn't exist ReadBestInvalidTrust(bnBestInvalidTrust); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 750); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; #ifdef WIN32 nCounter = 0; //#ifdef _MSC_VER #ifdef _DEBUG /**************** const int nMINUTESperBLOCK = 1, // or whatever you want to do in this *coin nMINUTESperHOUR = 60, nBLOCKSperHOUR = nMINUTESperHOUR / nMINUTESperBLOCK, nHOURStoCHECK = 1, //12, // this could be a variable nBLOCKSinLASTwhateverHOURS = nBLOCKSperHOUR * nHOURStoCHECK; nCheckDepth = nBLOCKSinLASTwhateverHOURS; ****************/ #endif //#endif #ifdef QT_GUI std::string sX; uiInterface.InitMessage( strprintf( _("Verifying the last %i blocks at level %i"), nCheckDepth, nCheckLevel ).c_str() ); #endif #endif printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity // check level 7: verify block signature too if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6))) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } ++nOutput; } } }
UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) { UniValue result(UniValue::VOBJ); result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) { confirmations = chainActive.Height() - blockindex->nHeight + 1; } else { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan"); } result.push_back(Pair("confirmations", confirmations)); 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)); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue deltas(UniValue::VARR); for (unsigned int i = 0; i < block.vtx.size(); i++) { const CTransaction &tx = block.vtx[i]; const uint256 txhash = tx.GetHash(); UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", txhash.GetHex())); entry.push_back(Pair("index", (int)i)); UniValue inputs(UniValue::VARR); if (!tx.IsCoinBase()) { for (size_t j = 0; j < tx.vin.size(); j++) { const CTxIn input = tx.vin[j]; UniValue delta(UniValue::VOBJ); CSpentIndexValue spentInfo; CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n); if (GetSpentIndex(spentKey, spentInfo)) { if (spentInfo.addressType == 1) { delta.push_back(Pair("address", CDeuscoinAddress(CKeyID(spentInfo.addressHash)).ToString())); } else if (spentInfo.addressType == 2) { delta.push_back(Pair("address", CDeuscoinAddress(CScriptID(spentInfo.addressHash)).ToString())); } else { continue; } delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis)); delta.push_back(Pair("index", (int)j)); delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex())); delta.push_back(Pair("prevout", (int)input.prevout.n)); inputs.push_back(delta); } else { throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available"); } } } entry.push_back(Pair("inputs", inputs)); UniValue outputs(UniValue::VARR); for (unsigned int k = 0; k < tx.vout.size(); k++) { const CTxOut &out = tx.vout[k]; UniValue delta(UniValue::VOBJ); if (out.scriptPubKey.IsPayToScriptHash()) { vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); delta.push_back(Pair("address", CDeuscoinAddress(CScriptID(uint160(hashBytes))).ToString())); } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); delta.push_back(Pair("address", CDeuscoinAddress(CKeyID(uint160(hashBytes))).ToString())); } else { continue; } delta.push_back(Pair("satoshis", out.nValue)); delta.push_back(Pair("index", (int)k)); outputs.push_back(delta); } entry.push_back(Pair("outputs", outputs)); deltas.push_back(entry); } result.push_back(Pair("deltas", deltas)); result.push_back(Pair("time", block.GetBlockTime())); result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; }
// Stake Modifier (hash modifier of proof-of-stake): // The purpose of stake modifier is to prevent a txout (coin) owner from // computing future proof-of-stake generated by this txout at the time // of transaction confirmation. To meet kernel protocol, the txout // must hash with a future stake modifier to generate the proof. // Stake modifier consists of bits each of which is contributed from a // selected block of a given block group in the past. // The selection of a block is based on a hash of the block's proof-hash and // the previous stake modifier. // Stake modifier is recomputed at a fixed time interval instead of every // block. This is to make it difficult for an attacker to gain control of // additional bits in the stake modifier, even after generating a chain of // blocks. bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModifier, bool& fGeneratedStakeModifier) { nStakeModifier = 0; fGeneratedStakeModifier = false; if (!pindexPrev) { fGeneratedStakeModifier = true; return true; // genesis block's modifier is 0 } // First find current stake modifier and its generation block time // if it's not old enough, return the same stake modifier if(modifierLast == NULL) { if (pindexPrev->GetBlockTime() < 1392281929 + nModifierInterval) return true; } else { //printf("modifierLast = %i \n", modifierLast->nHeight); if (fDebug) printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s\n", nStakeModifier, DateTimeStrFormat(modifierLast->GetBlockTime()).c_str()); if (pindexPrev->GetBlockTime() < modifierLast->GetBlockTime() + nModifierInterval) return true; } modifierLast = const_cast<CBlockIndex*>(pindexPrev); // Sort candidate blocks by timestamp vector<pair<int64, uint256> > vSortedByTimestamp; vSortedByTimestamp.reserve(64 * nModifierInterval / nStakeTargetSpacing); int64 nSelectionInterval = GetStakeModifierSelectionInterval(); int64 nSelectionIntervalStart = (pindexPrev->GetBlockTime() / nModifierInterval) * nModifierInterval - nSelectionInterval; const CBlockIndex* pindex = pindexPrev; while (pindex && pindex->GetBlockTime() >= nSelectionIntervalStart) { vSortedByTimestamp.push_back(make_pair(pindex->GetBlockTime(), pindex->GetBlockHash())); pindex = pindex->pprev; } int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0; reverse(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end()); // Select 64 blocks from candidate blocks to generate stake modifier uint64 nStakeModifierNew = 0; int64 nSelectionIntervalStop = nSelectionIntervalStart; map<uint256, const CBlockIndex*> mapSelectedBlocks; for (int nRound=0; nRound<min(6, (int)vSortedByTimestamp.size()); nRound++) { // add an interval section to the current selection round nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound); // write the entropy bit of the selected block pair<int64, uint256> ts = vSortedByTimestamp[nRound]; uint256 hash = ts.second; std::map<uint256,CBlockIndex*>::iterator it; it = mapBlockIndex.find(hash); if(it != mapBlockIndex.end()) { CBlockIndex* cBlock = it->second; nStakeModifierNew |= (((uint64) cBlock->GetBlockTime()) >> nRound); // add the selected block from candidates to selected list mapSelectedBlocks.insert(make_pair(cBlock->GetBlockHash(), cBlock)); //if (fDebug) //printf("ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n",nRound, DateTimeStrFormat(nSelectionIntervalStop).c_str(), pindex->nHeight, pindex->GetStakeEntropyBit()); } }