double BitsToDifficulty(int nBits) { CBigNum target; target.SetCompact(nBits); // approximate return pow(2, 256-32)/target.getuint256().getdouble(); }
void SimulateNextBlock(CBlockIndex*& tip, double* hashRates) { double recTime = 1e9; CBlockIndex* newTip = new CBlockIndex; newTip->pprev = tip; newTip->nHeight = tip->nHeight+1; for (int i=0; i<NUM_ALGOS; i++) { if (hashRates[i] == 0) continue; CBigNum target; unsigned int nBits = GetNextWorkRequired(tip, NULL, i); target.SetCompact(nBits); double dtarget = target.getuint256().getdouble()/pow(2,256); double mean = 1/(hashRates[i]*dtarget); boost::exponential_distribution<double> distr(1/mean); double received = distr(prng); if (received < recTime) { recTime = received; newTip->nVersion = VersionForAlgo(i); newTip->nTime = tip->nTime + received; newTip->nBits=nBits; } } assert(recTime < 1e9); tip = newTip; return; }
arith_uint256 GetGeometricMeanPrevWork(const CBlockIndex& block) { //arith_uint256 bnRes; arith_uint256 nBlockWork = GetBlockProofBase(block); CBigNum bnBlockWork = CBigNum(ArithToUint256(nBlockWork)); int nAlgo = block.GetAlgo(); for (int algo = 0; algo < NUM_ALGOS; algo++) { if (algo != nAlgo) { arith_uint256 nBlockWorkAlt = GetPrevWorkForAlgoWithDecayV3(block, algo); CBigNum bnBlockWorkAlt = CBigNum(ArithToUint256(nBlockWorkAlt)); if (bnBlockWorkAlt != 0) bnBlockWork *= bnBlockWorkAlt; } } // Compute the geometric mean CBigNum bnRes = bnBlockWork.nthRoot(NUM_ALGOS); // Scale to roughly match the old work calculation bnRes <<= 8; //return bnRes; return UintToArith256(bnRes.getuint256()); }
/// This function has changed as it served two purposes: sanity check for headers and real proof of work check. We only need the proofOfWorkLimit for the latter /// For namecoin we allow merged mining for the PoW! const bool NamecoinChain::checkProofOfWork(const Block& block) const { log_trace("Enter %s (block.version = %d)", __FUNCTION__, block.getVersion()); // we accept aux pow all the time - the lockins will ensure we get the right chain // Prevent same work from being submitted twice: // - this block must have our chain ID // - parent block must not have the same chain ID (see CAuxPow::Check) // - index of this chain in chain merkle tree must be pre-determined (see CAuxPow::Check) // if (nHeight != INT_MAX && GetChainID() != GetOurChainID()) // return error("CheckProofOfWork() : block does not have our chain ID"); CBigNum target; target.SetCompact(block.getBits()); if (proofOfWorkLimit() != 0 && (target <= 0 || target > proofOfWorkLimit())) { cout << target.GetHex() << endl; cout << proofOfWorkLimit().GetHex() << endl; log_error("CheckProofOfWork() : nBits below minimum work"); return false; } if (block.getVersion()&BLOCK_VERSION_AUXPOW) { if (!block.getAuxPoW().Check(block.getHash(), block.getVersion()/BLOCK_VERSION_CHAIN_START)) { log_error("CheckProofOfWork() : AUX POW is not valid"); return false; } // Check proof of work matches claimed amount if (block.getAuxPoW().GetParentBlockHash() > target.getuint256()) { log_error("CheckProofOfWork() : AUX proof of work failed"); return false; } } else { // Check proof of work matches claimed amount if (block.getHash() > target.getuint256()) { log_error("CheckProofOfWork() : proof of work failed"); return false; } } log_trace("Return(true): %s", __FUNCTION__); return true; }
int LitecoinChain::nextWorkRequired(BlockIterator blk) const { const int64_t nTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks const int64_t nTargetSpacing = 2.5 * 60; const int64_t nInterval = nTargetTimespan / nTargetSpacing; // Genesis block int h = blk.height(); if (h == 0) // trick to test that it is asking for the genesis block return _genesisBlock.getBits(); // proofOfWorkLimit().GetCompact(); Actually not for the genesisblock - here it is 0x1e0ffff0, not 0x1e0fffff // Only change once per interval if ((h + 1) % nInterval != 0) return blk->bits; // Litecoin: This fixes an issue where a 51% attack can change difficulty at will. // Go back the full period unless it's the first retarget after genesis. Code courtesy of Art Forz int blockstogoback = nInterval-1; if ((h + 1) != nInterval) blockstogoback = nInterval; // Go back by what we want to be 3.5 days worth of blocks BlockIterator former = blk - blockstogoback; // Limit adjustment step int nActualTimespan = blk->time - former->time; log_debug(" nActualTimespan = %"PRI64d" before bounds", nActualTimespan); if (nActualTimespan < nTargetTimespan/4) nActualTimespan = nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; // Retarget CBigNum bnNew; bnNew.SetCompact(blk->bits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > proofOfWorkLimit()) bnNew = proofOfWorkLimit(); /// debug print log_info("GetNextWorkRequired RETARGET"); log_info("\tnTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan); log_info("\tBefore: %08x %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str()); log_info("\tAfter: %08x %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str()); return bnNew.GetCompact(); }
Shamir::Shares Shamir::split(uint256 secret) const { Shares shares; std::vector<CBigNum> coef; coef.push_back(CBigNum(secret)); for (unsigned char i = 1; i < _quorum; ++i) coef.push_back(rnd()); for (unsigned char x = 1; x <= _shares; ++x) { CBigNum accum = coef[0]; for (unsigned char i = 1; i < _quorum; ++i) accum = (accum + (coef[i] * ModPow(CBigNum(x), i, _order))) % _order; shares[x] = accum.getuint256(); } return shares; }
int TestNet3Chain::nextWorkRequired(BlockIterator blk) const { const int64_t nTargetTimespan = 14 * 24 * 60 * 60; // two weeks const int64_t nTargetSpacing = 10 * 60; const int64_t nInterval = nTargetTimespan / nTargetSpacing; // Genesis block int h = blk.height(); if (h == 0) // trick to test that it is asking for the genesis block return proofOfWorkLimit().GetCompact(); // Only change once per interval if ((h + 1) % nInterval != 0) { // Return the last non-special-min-difficulty-rules-block while (blk.height() % nInterval != 0 && blk->bits == proofOfWorkLimit().GetCompact()) blk--; return blk->bits; } // Go back by what we want to be 14 days worth of blocks BlockIterator former = blk - (nInterval-1); // Limit adjustment step int nActualTimespan = blk->time - former->time; log_debug(" nActualTimespan = %"PRI64d" before bounds", nActualTimespan); if (nActualTimespan < nTargetTimespan/4) nActualTimespan = nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; // Retarget CBigNum bnNew; bnNew.SetCompact(blk->bits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > proofOfWorkLimit()) bnNew = proofOfWorkLimit(); /// debug print log_info("GetNextWorkRequired RETARGET"); log_info("\tnTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan); log_info("\tBefore: %08x %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str()); log_info("\tAfter: %08x %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str()); return bnNew.GetCompact(); }
uint256 Shamir::recover(const Shamir::Shares& shares) const { CBigNum accum = 0; for(Shares::const_iterator formula = shares.begin(); formula != shares.end(); ++formula) { CBigNum numerator = 1; CBigNum denominator = 1; for(Shares::const_iterator count = shares.begin(); count != shares.end(); ++count) { if(formula == count) continue; // If not the same value unsigned char startposition = formula->first; unsigned char nextposition = count->first; numerator = (-nextposition * numerator) % _order; denominator = ((startposition - nextposition)*denominator) % _order; } accum = (_order + accum + (CBigNum(formula->second) * numerator * ModInverse(denominator, _order))) % _order; } return accum.getuint256(); }
unsigned int BitcoinChain::nextWorkRequired(const CBlockIndex* pindexLast) const { const int64 nTargetTimespan = 14 * 24 * 60 * 60; // two weeks const int64 nTargetSpacing = 10 * 60; const int64 nInterval = nTargetTimespan / nTargetSpacing; // Genesis block if (pindexLast == NULL) return proofOfWorkLimit().GetCompact(); // Only change once per interval if ((pindexLast->nHeight+1) % nInterval != 0) return pindexLast->nBits; // Go back by what we want to be 14 days worth of blocks const CBlockIndex* pindexFirst = pindexLast; for (int i = 0; pindexFirst && i < nInterval-1; i++) pindexFirst = pindexFirst->pprev; assert(pindexFirst); // Limit adjustment step int64 nActualTimespan = pindexLast->GetBlockTime() - pindexFirst->GetBlockTime(); printf(" nActualTimespan = %"PRI64d" before bounds\n", nActualTimespan); if (nActualTimespan < nTargetTimespan/4) nActualTimespan = nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; // Retarget CBigNum bnNew; bnNew.SetCompact(pindexLast->nBits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > proofOfWorkLimit()) bnNew = proofOfWorkLimit(); /// debug print printf("GetNextWorkRequired RETARGET\n"); printf("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"\n", nTargetTimespan, nActualTimespan); printf("Before: %08x %s\n", pindexLast->nBits, CBigNum().SetCompact(pindexLast->nBits).getuint256().toString().c_str()); printf("After: %08x %s\n", bnNew.GetCompact(), bnNew.getuint256().toString().c_str()); return bnNew.GetCompact(); }
int TerracoinChain::nextWorkRequired(BlockIterator blk) const { const int64_t nTargetTimespan = 60 * 60; // one hour weeks const int64_t nTargetSpacing = 2 * 60; // new block every two minutes const int64_t nInterval = nTargetTimespan / nTargetSpacing; // Genesis block int h = blk.height(); if (h == 0) // trick to test that it is asking for the genesis block return proofOfWorkLimit().GetCompact(); // Only change once per interval if ((h + 1) % nInterval != 0) return blk->bits; // Go back by what we want to be 14 days worth of blocks BlockIterator former = blk - (nInterval-1); // Limit adjustment step int nActualTimespan = blk->time - former->time; log_debug(" nActualTimespan = %"PRI64d" before bounds", nActualTimespan); if (nActualTimespan < nTargetTimespan/4) nActualTimespan = nTargetTimespan/4; if (nActualTimespan > nTargetTimespan*4) nActualTimespan = nTargetTimespan*4; // Retarget CBigNum bnNew; bnNew.SetCompact(blk->bits); bnNew *= nActualTimespan; bnNew /= nTargetTimespan; if (bnNew > proofOfWorkLimit()) bnNew = proofOfWorkLimit(); /// debug print log_info("GetNextWorkRequired RETARGET"); log_info("nTargetTimespan = %"PRI64d" nActualTimespan = %"PRI64d"", nTargetTimespan, nActualTimespan); log_info("Before: %08x %s", blk->bits, CBigNum().SetCompact(blk->bits).getuint256().toString().c_str()); log_info("After: %08x %s", bnNew.GetCompact(), bnNew.getuint256().toString().c_str()); return bnNew.GetCompact(); }
/// This function has changed as it served two purposes: sanity check for headers and real proof of work check. We only need the proofOfWorkLimit for the latter const bool TerracoinChain::checkProofOfWork(const Block& block) const { uint256 hash = block.getHash(); unsigned int nBits = block.getBits(); CBigNum bnTarget; bnTarget.SetCompact(nBits); // Check range if (proofOfWorkLimit() != 0 && (bnTarget <= 0 || bnTarget > proofOfWorkLimit())) { log_error("CheckProofOfWork() : nBits below minimum work"); return false; } // Check proof of work matches claimed amount if (hash > bnTarget.getuint256()) { log_error("CheckProofOfWork() : hash doesn't match nBits"); return false; } return true; }
void CzPIVWallet::GenerateMint(const uint32_t& nCount, const CoinDenomination denom, PrivateCoin& coin, CDeterministicMint& dMint) { uint512 seedZerocoin = GetZerocoinSeed(nCount); CBigNum bnValue; CBigNum bnSerial; CBigNum bnRandomness; CKey key; SeedToZPIV(seedZerocoin, bnValue, bnSerial, bnRandomness, key); coin = PrivateCoin(Params().Zerocoin_Params(false), denom, bnSerial, bnRandomness); coin.setPrivKey(key.GetPrivKey()); coin.setVersion(PrivateCoin::CURRENT_VERSION); uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end()); uint256 hashSerial = GetSerialHash(bnSerial); uint256 nSerial = bnSerial.getuint256(); uint256 hashStake = Hash(nSerial.begin(), nSerial.end()); uint256 hashPubcoin = GetPubCoinHash(bnValue); dMint = CDeterministicMint(coin.getVersion(), nCount, hashSeed, hashSerial, hashPubcoin, hashStake); dMint.SetDenomination(denom); }
CMainParams() { // The message start string is designed to be unlikely to occur in normal data. // The characters are rarely used upper ASCII, not valid as UTF-8, and produce // a large 4-byte int at any alignment. pchMessageStart[0] = 0xf9; pchMessageStart[1] = 0xbe; pchMessageStart[2] = 0xb4; pchMessageStart[3] = 0xd9; vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 28333; nRPCPort = 8332; bnProofOfWorkLimit = CBigNum(~uint256(0) >> 16); nSubsidyHalvingInterval = 210000; // Build the genesis block. Note that the output of the genesis coinbase cannot // be spent as it did not originally exist in the database. // // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) // vMerkleTree: 4a5e1e const char* pszTimestamp = "2014-03-30 Nobody 50.06, Kiska 29.66, Fico 20.28; Founder: heXKRhnGdSg"; int extranonce = 42; CTransaction txNew; txNew.vin.resize(1); txNew.vout.resize(1); txNew.vin[0].scriptSig = CScript() << extranonce << CBigNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); txNew.vout[0].nValue = 50 * COIN; txNew.vout[0].scriptPubKey = CScript() << ParseHex("2dc4f1967fbf825c77dadd9da14c3608428ada53") << OP_EQUALVERIFY << OP_CHECKSIG; genesis.vtx.push_back(txNew); genesis.hashPrevBlock = 0; genesis.hashMerkleRoot = genesis.BuildMerkleTree(); genesis.nVersion = 1; genesis.nTime = 1396187239; genesis.nBits = 0x1e008fff; genesis.nNonce = 23443383; hashGenesisBlock = genesis.GetHash(); #ifdef MINE_GENESIS CBigNum bnTarget; bnTarget.SetCompact(genesis.nBits); fprintf(stderr, "Target: %s\n", bnTarget.ToString().c_str()); assert(!(bnTarget <= 0 || bnTarget > Params().ProofOfWorkLimit())); while(hashGenesisBlock > bnTarget.getuint256()) { ++genesis.nNonce; if(!genesis.nNonce) { ++extranonce; }; hashGenesisBlock = genesis.GetHash(); } fprintf(stderr, "Nonce = %d\nExtranonce = %d\n", genesis.nNonce, extranonce); fprintf(stderr, "Genesis hash = %s\nMerkle root = %s\n", hashGenesisBlock.GetHex().c_str(), genesis.hashMerkleRoot.GetHex().c_str()); #else assert(hashGenesisBlock == uint256("0x000000530b4b2d75534bfa61c42e62f4402ce579dd8507c70009e69439f4bd19")); assert(genesis.hashMerkleRoot == uint256("0x2446d19ab3361d3484c4f1dade799a54dfd010f193521659a26341c6f50b811a")); #endif vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be")); vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); base58Prefixes[PUBKEY_ADDRESS] = list_of(45); base58Prefixes[SCRIPT_ADDRESS] = list_of(50); base58Prefixes[SECRET_KEY] = list_of(173); base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x88)(0xB2)(0x1E); base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x88)(0xAD)(0xE4); // Convert the pnSeeds array into usable address objects. for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++) { // It'll only connect to one or two seed nodes because once it connects, // it'll get a pile of addresses with newer timestamps. // Seed nodes are given a random 'last seen time' of between one and two // weeks ago. const int64_t nOneWeek = 7*24*60*60; struct in_addr ip; memcpy(&ip, &pnSeed[i], sizeof(ip)); CAddress addr(CService(ip, GetDefaultPort())); addr.nTime = GetTime() - GetRand(nOneWeek) - nOneWeek; vFixedSeeds.push_back(addr); } }
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++; } } }
bool CTxDB::LoadBlockIndex() { if (!LoadBlockIndexGuts()) return false; 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(); // 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; 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()); // 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 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++; } } }
bool CzPIVWallet::SetMintSeen(const CBigNum& bnValue, const int& nHeight, const uint256& txid, const CoinDenomination& denom) { if (!mintPool.Has(bnValue)) return error("%s: value not in pool", __func__); pair<uint256, uint32_t> pMint = mintPool.Get(bnValue); // Regenerate the mint uint512 seedZerocoin = GetZerocoinSeed(pMint.second); CBigNum bnValueGen; CBigNum bnSerial; CBigNum bnRandomness; CKey key; SeedToZPIV(seedZerocoin, bnValueGen, bnSerial, bnRandomness, key); //Sanity check if (bnValueGen != bnValue) return error("%s: generated pubcoin and expected value do not match!", __func__); // Create mint object and database it uint256 hashSeed = Hash(seedMaster.begin(), seedMaster.end()); uint256 hashSerial = GetSerialHash(bnSerial); uint256 hashPubcoin = GetPubCoinHash(bnValue); uint256 nSerial = bnSerial.getuint256(); uint256 hashStake = Hash(nSerial.begin(), nSerial.end()); CDeterministicMint dMint(PrivateCoin::CURRENT_VERSION, pMint.second, hashSeed, hashSerial, hashPubcoin, hashStake); dMint.SetDenomination(denom); dMint.SetHeight(nHeight); dMint.SetTxHash(txid); // Check if this is also already spent int nHeightTx; uint256 txidSpend; CTransaction txSpend; if (IsSerialInBlockchain(hashSerial, nHeightTx, txidSpend, txSpend)) { //Find transaction details and make a wallettx and add to wallet dMint.SetUsed(true); CWalletTx wtx(pwalletMain, txSpend); CBlockIndex* pindex = chainActive[nHeightTx]; CBlock block; if (ReadBlockFromDisk(block, pindex)) wtx.SetMerkleBranch(block); wtx.nTimeReceived = pindex->nTime; pwalletMain->AddToWallet(wtx); } // Add to zpivTracker which also adds to database pwalletMain->zpivTracker->Add(dMint, true); //Update the count if it is less than the mint's count if (nCountLastUsed < pMint.second) { CWalletDB walletdb(strWalletFile); nCountLastUsed = pMint.second; walletdb.WriteZPIVCount(nCountLastUsed); } //remove from the pool mintPool.Remove(dMint.GetPubcoinHash()); return true; }