// Czecoin: reset synchronized checkpoint to last hardened checkpoint
    bool ResetSyncCheckpoint()
    {
        LOCK(cs_hashSyncCheckpoint);
        const uint256& hash = mapCheckpoints.rbegin()->second;
        if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
        {
            // checkpoint block accepted but not yet in main chain
            printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str());
            CTxDB txdb;
            CBlock block;
            if (!block.ReadFromDisk(mapBlockIndex[hash]))
                return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
            if (!block.SetBestChain(txdb, mapBlockIndex[hash]))
            {
                return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
            }
        }
        else if(!mapBlockIndex.count(hash))
        {
            // checkpoint block not yet accepted
            hashPendingCheckpoint = hash;
            checkpointMessagePending.SetNull();
            printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
        }

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
            {
                if (!WriteSyncCheckpoint(hash))
                    return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str());
                printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str());
                return true;
            }
        }

        return false;
    }
Example #2
0
Value dumpbootstrap(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 2)
        throw runtime_error(
            "dumpbootstrap \"destination\" \"blocks\"\n"
            "\nCreates a bootstrap format block dump of the blockchain in destination, which can be a directory or a path with filename, up to the given block number.");

    string strDest = params[0].get_str();
    int nBlocks = params[1].get_int();
    if (nBlocks < 0 || nBlocks > nBestHeight)
        throw runtime_error("Block number out of range.");

    boost::filesystem::path pathDest(strDest);
    if (boost::filesystem::is_directory(pathDest))
        pathDest /= "bootstrap.dat";

    try {
        FILE* file = fopen(pathDest.string().c_str(), "wb");
        if (!file)
            throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not open bootstrap file for writing.");

        CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION);
        if (!fileout)
            throw JSONRPCError(RPC_MISC_ERROR, "Error: Could not open bootstrap file for writing.");

        for (int nHeight = 0; nHeight <= nBlocks; nHeight++)
        {
            CBlock block;
            CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
            block.ReadFromDisk(pblockindex, true);
            fileout << FLATDATA(Params().MessageStart()) << fileout.GetSerializeSize(block) << block;
        }
    } catch(const boost::filesystem::filesystem_error &e) {
        throw JSONRPCError(RPC_MISC_ERROR, "Error: Bootstrap dump failed!");
    }

    return Value::null;
}
Example #3
0
Value getblock(const Array& params, bool fHelp, CACLUser &user) {
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <hash> [verbose=true]\n"
            "If 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>."
        );
	
	if(!user.check(ACL_PUBLICREAD)) {
		throw JSONRPCError(RPC_PERMISSION_DENIED, "Permission denied!");
	}
	
    std::string strHash = params[0].get_str();
    uint256 hash(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];
    block.ReadFromDisk(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);
}
Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblock <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");

    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}
Example #5
0
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++;
                        }
                    }
                }
Example #6
0
// pindex must belong to the main branch, i.e. corresponding blocks must be connected
// Returns a copy of the game state
bool
GetGameState (DatabaseSet& dbset, CBlockIndex *pindex, GameState &outState)
{
    if (!pindex)
    {
        outState = GameState();
        return true;
    }

    /* See if we have the block in the state cache.  */
    if (stateCache.query (*pindex->phashBlock, outState))
      return true;

    // Get the latest saved state
    CGameDB gameDb("r", dbset.tx ());

    if (gameDb.Read(pindex->nHeight, outState))
    {
        if (outState.nHeight != pindex->nHeight)
            return error("GetGameState: wrong height");
        if (outState.hashBlock != *pindex->phashBlock)
            return error("GetGameState: wrong hash");
        return true;
    }

    if (!pindex->IsInMainChain())
        return error("GetGameState called for non-main chain");

    printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
    printf("GetGameState: need to integrate state for height %d (current %d)\n",
           pindex->nHeight, nBestHeight);

    CBlockIndex *plast = pindex;
    GameState lastState;
    for (; plast->pprev; plast = plast->pprev)
    {
        if (stateCache.query (*plast->pprev->phashBlock, lastState))
            break;
        if (gameDb.Read(plast->pprev->nHeight, lastState))
            break;
    }

    printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
    printf("GetGameState: last saved block has height %d\n", lastState.nHeight);

    // Integrate steps starting from the last saved state
    // FIXME: Might want to store intermediate steps in stateCache, too.
    loop
    {
        std::vector<CTransaction> vgametx;

        CBlock block;
        block.ReadFromDisk(plast);

        int64 nTax;
        if (!PerformStep (dbset.name (), lastState, &block, nTax,
                          outState, vgametx))
            return false;
        if (block.vgametx != vgametx)
        {
            printf("Error: GetGameState: computed vgametx is different from the stored one\n");
            printf("  block %s (height = %d) vgametx:\n", block.GetHash().ToString().c_str(), plast->nHeight);
            BOOST_FOREACH (const CTransaction &tx, block.vgametx)
            {
                printf("    ");
                tx.print();
            }
            printf("  computed vgametx (height = %d):\n", outState.nHeight);
            BOOST_FOREACH (const CTransaction &tx, vgametx)
            {
                printf("    ");
                tx.print();
            }
            return false;
        }
Example #7
0
Value rewindchain(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "rewindchain <number>\n"
            "Remove <number> blocks from the chain.");

    int nNumber = params[0].get_int();
    if (nNumber < 0 || nNumber > nBestHeight)
        throw runtime_error("Block number out of range.");


    Object result;
    int nRemoved = 0;

    {
        LOCK2(cs_main, pwalletMain->cs_wallet);


        uint32_t nFileRet = 0;

        uint8_t buffer[512];

        LogPrintf("rewindchain %d\n", nNumber);

        void* nFind;

        for (int i = 0; i < nNumber; ++i)
        {
            memset(buffer, 0, sizeof(buffer));

            FILE* fp = AppendBlockFile(false, nFileRet, "r+b");
            if (!fp)
            {
                LogPrintf("AppendBlockFile failed.\n");
                break;
            };

            errno = 0;
            if (fseek(fp, 0, SEEK_END) != 0)
            {
                LogPrintf("fseek failed: %s\n", strerror(errno));
                break;
            };

            long int fpos = ftell(fp);

            if (fpos == -1)
            {
                LogPrintf("ftell failed: %s\n", strerror(errno));
                break;
            };

            long int foundPos = -1;
            long int readSize = sizeof(buffer) / 2;
            while (fpos > 0)
            {
                if (fpos < (long int)sizeof(buffer) / 2)
                    readSize = fpos;

                memcpy(buffer+readSize, buffer, readSize); // move last read data (incase token crosses a boundary)
                fpos -= readSize;

                if (fseek(fp, fpos, SEEK_SET) != 0)
                {
                    LogPrintf("fseek failed: %s\n", strerror(errno));
                    break;
                };

                errno = 0;
                if (fread(buffer, sizeof(uint8_t), readSize, fp) != (size_t)readSize)
                {
                    if (errno != 0)
                        LogPrintf("fread failed: %s\n", strerror(errno));
                    else
                        LogPrintf("End of file.\n");
                    break;
                };

                uint32_t findPos = sizeof(buffer);
                while (findPos > MESSAGE_START_SIZE)
                {
                    if ((nFind = shellk::memrchr(buffer, Params().MessageStart()[0], findPos-MESSAGE_START_SIZE)))
                    {
                        if (memcmp(nFind, Params().MessageStart(), MESSAGE_START_SIZE) == 0)
                        {
                            foundPos = ((uint8_t*)nFind - buffer) + MESSAGE_START_SIZE;
                            break;
                        } else
                        {
                            findPos = ((uint8_t*)nFind - buffer);
                            // -- step over matched char that wasn't pchMessageStart
                            if (findPos > 0) // prevent findPos < 0 (unsigned)
                                findPos--;
                        };
                    } else
                    {
                        break; // pchMessageStart[0] not found in buffer
                    };
                };

                if (foundPos > -1)
                    break;
            };

            LogPrintf("fpos %d, foundPos %d.\n", fpos, foundPos);

            if (foundPos < 0)
            {
                LogPrintf("block start not found.\n");
                fclose(fp);
                break;
            };

            CAutoFile blkdat(fp, SER_DISK, CLIENT_VERSION);

            if (fseek(blkdat, fpos+foundPos, SEEK_SET) != 0)
            {
                LogPrintf("fseek blkdat failed: %s\n", strerror(errno));
                break;
            };

            unsigned int nSize;
            blkdat >> nSize;
            LogPrintf("nSize %u .\n", nSize);

            if (nSize < 1 || nSize > MAX_BLOCK_SIZE)
            {
                LogPrintf("block size error %u\n", nSize);

            };

            CBlock block;
            blkdat >> block;
            uint256 hashblock = block.GetHash();
            LogPrintf("hashblock %s .\n", hashblock.ToString().c_str());

            std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashblock);
            if (mi != mapBlockIndex.end() && (*mi).second)
            {
                LogPrintf("block is in main chain.\n");

                if (!mi->second->pprev)
                {
                    LogPrintf("! mi->second.pprev\n");
                } else
                {
                    {
                        CBlock blockPrev; // strange way SetBestChain works, TODO: does it need the full block?
                        if (!blockPrev.ReadFromDisk(mi->second->pprev))
                        {
                            LogPrintf("blockPrev.ReadFromDisk failed %s.\n", mi->second->pprev->GetBlockHash().ToString().c_str());
                            break;
                        };

                        CTxDB txdb;
                        if (!blockPrev.SetBestChain(txdb, mi->second->pprev))
                        {
                            LogPrintf("SetBestChain failed.\n");
                        };
                    }
                    mi->second->pprev->pnext = NULL;
                };

                delete mi->second;
                mapBlockIndex.erase(mi);
            };

            std::map<uint256, COrphanBlock*>::iterator miOph = mapOrphanBlocks.find(hashblock);
            if (miOph != mapOrphanBlocks.end())
            {
                LogPrintf("block is an orphan.\n");
                mapOrphanBlocks.erase(miOph);
            };

            CTxDB txdb;
            for (vector<CTransaction>::iterator it = block.vtx.begin(); it != block.vtx.end(); ++it)
            {
                LogPrintf("EraseTxIndex().\n");
                txdb.EraseTxIndex(*it);
            };

            LogPrintf("EraseBlockIndex().\n");
            txdb.EraseBlockIndex(hashblock);

            errno = 0;
            if (ftruncate(fileno(fp), fpos+foundPos-MESSAGE_START_SIZE) != 0)
            {
                LogPrintf("ftruncate failed: %s\n", strerror(errno));
            };

            LogPrintf("hashBestChain %s, nBestHeight %d\n", hashBestChain.ToString().c_str(), nBestHeight);

            //fclose(fp); // ~CAutoFile() will close the file
            nRemoved++;
        };
    }


    result.push_back(Pair("no. blocks removed", itostr(nRemoved)));

    result.push_back(Pair("hashBestChain", hashBestChain.ToString()));
    result.push_back(Pair("nBestHeight", itostr(nBestHeight)));

    // -- need restart, setStakeSeen etc
    if (nRemoved > 0)
        result.push_back(Pair("Please restart Taurus", ""));

    if (nRemoved == nNumber)
        result.push_back(Pair("result", "success"));
    else
        result.push_back(Pair("result", "failure"));
    return result;
}
Example #8
0
// pindex must belong to the main branch, i.e. corresponding blocks must be connected
// Returns a copy of the game state
bool GetGameState(CTxDB &txdb, CBlockIndex *pindex, GameState &outState)
{
    if (!pindex)
    {
        outState = GameState();
        return true;
    }

    if (*pindex->phashBlock == currentState.hashBlock)
    {
        outState = currentState;
        return true;
    }

    // Get the latest saved state
    CGameDB gameDb("cr", txdb);

    if (gameDb.Read(pindex->nHeight, outState))
    {
        if (outState.nHeight != pindex->nHeight)
            return error("GetGameState: wrong height");
        if (outState.hashBlock != *pindex->phashBlock)
            return error("GetGameState: wrong hash");
        return true;
    }

    if (!pindex->IsInMainChain())
        return error("GetGameState called for non-main chain");
        
    CBlockIndex *plast = pindex;
    GameState lastState;
    for (; plast->pprev; plast = plast->pprev)
    {
        if (gameDb.Read(plast->pprev->nHeight, lastState))
            break;
    }

    // When connecting genesis block, there is no nameindexfull.dat file yet
    std::auto_ptr<CNameDB> nameDb(pindex == pindexGenesisBlock ? NULL : new CNameDB("r", txdb));

    // Integrate steps starting from the last saved state
    loop
    {
        std::vector<CTransaction> vgametx;

        CBlock block;
        block.ReadFromDisk(plast);

        int64 nTax;
        if (!PerformStep(nameDb.get(), lastState, &block, nTax, outState, vgametx))
            return false;
        if (block.vgametx != vgametx)
        {
            printf("Error: GetGameState: computed vgametx is different from the stored one\n");
            printf("  block %s (height = %d) vgametx:\n", block.GetHash().ToString().c_str(), plast->nHeight);
            BOOST_FOREACH (const CTransaction &tx, block.vgametx)
            {
                printf("    ");
                tx.print();
            }
            printf("  computed vgametx (height = %d):\n", outState.nHeight);
            BOOST_FOREACH (const CTransaction &tx, vgametx)
            {
                printf("    ");
                tx.print();
            }
            return false;
        }
Example #9
0
/** Initialize Gridcoin.
 *  @pre Parameters should be parsed and config file should be read.
 */
bool AppInit2(ThreadHandlerPtr threads)
{
    // ********************************************************* Step 1: setup
#ifdef _MSC_VER
    // Turn off Microsoft heap dump noise
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
#endif
#if _MSC_VER >= 1400
    // Disable confusing "helpful" text message on abort, Ctrl-C
    _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif
#ifdef WIN32
    // Enable Data Execution Prevention (DEP)
    // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
    // A failure is non-critical and needs no further attention!
#ifndef PROCESS_DEP_ENABLE
// We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
// which is not correct. Can be removed, when GCCs winbase.h is fixed!
#define PROCESS_DEP_ENABLE 0x00000001
#endif
    typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
    PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
    if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);
#endif
#ifndef WIN32
    umask(077);

    // Clean shutdown on SIGTERM
    struct sigaction sa;
    sa.sa_handler = HandleSIGTERM;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    // Reopen debug.log on SIGHUP
    struct sigaction sa_hup;
    sa_hup.sa_handler = HandleSIGHUP;
    sigemptyset(&sa_hup.sa_mask);
    sa_hup.sa_flags = 0;
    sigaction(SIGHUP, &sa_hup, NULL);
#endif

    // ********************************************************* Step 2: parameter interactions


    // Gridcoin - Check to see if config is empty?
    if (IsConfigFileEmpty())
    {
           uiInterface.ThreadSafeMessageBox(
                 "Configuration file empty.  \n" + _("Please wait for new user wizard to start..."), "", 0);
    }

    //6-10-2014: R Halford: Updating Boost version to 1.5.5 to prevent sync issues; print the boost version to verify:
	//5-04-2018: J Owens: Boost now needs to be 1.65 or higher to avoid thread sleep problems with system clock resets.
    std::string boost_version = "";
    std::ostringstream s;
    s << boost_version  << "Using Boost "
          << BOOST_VERSION / 100000     << "."  // major version
          << BOOST_VERSION / 100 % 1000 << "."  // minior version
          << BOOST_VERSION % 100                // patch level
          << "\n";

    LogPrintf("Boost Version: %s", s.str());

    //Placeholder: Load Remote CPIDs Here

    nNodeLifespan = GetArg("-addrlifespan", 7);
    fUseFastIndex = GetBoolArg("-fastindex", false);

    nMinerSleep = GetArg("-minersleep", 8000);
    nDerivationMethodIndex = 0;
    fTestNet = GetBoolArg("-testnet");

    if (mapArgs.count("-bind")) {
        // when specifying an explicit binding address, you want to listen on it
        // even when -connect or -proxy is specified
        SoftSetBoolArg("-listen", true);
    }

    if (mapArgs.count("-connect") && mapMultiArgs["-connect"].size() > 0) {
        // when only connecting to trusted nodes, do not seed via DNS, or listen by default
        SoftSetBoolArg("-dnsseed", false);
        SoftSetBoolArg("-listen", false);
    }

    if (mapArgs.count("-proxy")) {
        // to protect privacy, do not listen by default if a proxy server is specified
        SoftSetBoolArg("-listen", false);
    }

    if (!GetBoolArg("-listen", true)) {
        // do not map ports or try to retrieve public IP when not listening (pointless)
        SoftSetBoolArg("-upnp", false);
        SoftSetBoolArg("-discover", false);
    }

    if (mapArgs.count("-externalip")) {
        // if an explicit public IP is specified, do not try to find others
        SoftSetBoolArg("-discover", false);
    }

    if (GetBoolArg("-salvagewallet")) {
        // Rewrite just private keys: rescan to find transactions
        SoftSetBoolArg("-rescan", true);
    }

     if (GetBoolArg("-zapwallettxes", false)) {
        // -zapwallettx implies a rescan
        SoftSetBoolArg("-rescan", true);
    }

    // Verify testnet is using the testnet directory for the config file:
    std::string sTestNetSpecificArg = GetArgument("testnetarg","default");
    LogPrintf("Using specific arg %s",sTestNetSpecificArg);


    // ********************************************************* Step 3: parameter-to-internal-flags

    fDebug=false;

    if (fDebug)
        fDebugNet = true;
    else
        fDebugNet = GetBoolArg("-debugnet");

    if (GetArg("-debug", "false")=="true")
    {
            fDebug = true;
            LogPrintf("Entering debug mode.");
    }

    fDebug2 = false;

    if (GetArg("-debug2", "false")=="true")
    {
            fDebug2 = true;
            LogPrintf("Entering GRC debug mode 2.");
    }

    fDebug3 = false;

    if (GetArg("-debug3", "false")=="true")
    {
            fDebug3 = true;
            LogPrintf("Entering GRC debug mode 3.");
    }

    if (GetArg("-debug4", "false")=="true")
    {
        fDebug4 = true;
        LogPrintf("Entering RPC time debug mode");
    }

    fDebug10= (GetArg("-debug10","false")=="true");

#if defined(WIN32)
    fDaemon = false;
#else
    if(fQtActive)
        fDaemon = false;
    else
        fDaemon = GetBoolArg("-daemon");
#endif

    if (fDaemon)
        fServer = true;
    else
        fServer = GetBoolArg("-server");

    /* force fServer when running without GUI */
    if(!fQtActive)
        fServer = true;

    fPrintToConsole = GetBoolArg("-printtoconsole");
    fPrintToDebugger = GetBoolArg("-printtodebugger");
    fLogTimestamps = GetBoolArg("-logtimestamps");
    fLogTimestamps = true;

    if (mapArgs.count("-timeout"))
    {
        int nNewTimeout = GetArg("-timeout", 4000);
        if (nNewTimeout > 0 && nNewTimeout < 600000)
            nConnectTimeout = nNewTimeout;
    }

    if (mapArgs.count("-paytxfee"))
    {
        if (!ParseMoney(mapArgs["-paytxfee"], nTransactionFee))
            return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"]));
        if (nTransactionFee > 0.25 * COIN)
            InitWarning(_("Warning: -paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
    }

    fConfChange = GetBoolArg("-confchange", false);
    fEnforceCanonical = GetBoolArg("-enforcecanonical", true);

    if (mapArgs.count("-mininput"))
    {
        if (!ParseMoney(mapArgs["-mininput"], nMinimumInputValue))
            return InitError(strprintf(_("Invalid amount for -mininput=<amount>: '%s'"), mapArgs["-mininput"]));
    }

    // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
    // Sanity check
    if (!InitSanityCheck())
        return InitError(_("Initialization sanity check failed. Gridcoin is shutting down."));

    // Initialize internal hashing code with SSE/AVX2 optimizations. In the future we will also have ARM/NEON optimizations.
    std::string sha256_algo = SHA256AutoDetect();
    LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);                                                                                      

    std::string strDataDir = GetDataDir().string();
    std::string strWalletFileName = GetArg("-wallet", "wallet.dat");

    // strWalletFileName must be a plain filename without a directory
    if (strWalletFileName != boost::filesystem::basename(strWalletFileName) + boost::filesystem::extension(strWalletFileName))
        return InitError(strprintf(_("Wallet %s resides outside data directory %s."), strWalletFileName, strDataDir));

    // Make sure only a single Bitcoin process is using the data directory.
    boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
    FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
    if (file) fclose(file);
    static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
    if (!lock.try_lock())
        return InitError(strprintf(_("Cannot obtain a lock on data directory %s.  Gridcoin is probably already running."), strDataDir));

#if !defined(WIN32) 
    if (fDaemon)
    {
        // Daemonize
        pid_t pid = fork();
        if (pid < 0)
        {
            fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
            return false;
        }
        if (pid > 0)
        {
            CreatePidFile(GetPidFile(), pid);

            // Now that we are forked we can request a shutdown so the parent
            // exits while the child lives on.
            StartShutdown();
            return true;
        }

        pid_t sid = setsid();
        if (sid < 0)
            fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
    }
#endif

    ShrinkDebugFile();
    LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
    LogPrintf("Gridcoin version %s (%s)", FormatFullVersion(), CLIENT_DATE);
    LogPrintf("Using OpenSSL version %s", SSLeay_version(SSLEAY_VERSION));
    if (!fLogTimestamps)
        LogPrintf("Startup time: %s", DateTimeStrFormat("%x %H:%M:%S",  GetAdjustedTime()));
    LogPrintf("Default data directory %s", GetDefaultDataDir().string());
    LogPrintf("Used data directory %s", strDataDir);
    std::ostringstream strErrors;

    fDevbuildCripple = false;
    if((CLIENT_VERSION_BUILD != 0) && !fTestNet)
    {
        fDevbuildCripple = true;
        LogPrintf("WARNING: Running development version outside of testnet!\n"
                  "Staking and sending transactions will be disabled.");
        if( (GetArg("-devbuild", "") == "override") && fDebug )
            fDevbuildCripple = false;
    }

    if (fDaemon)
        fprintf(stdout, "Gridcoin server starting\n");

    int64_t nStart;

    // ********************************************************* Step 5: verify database integrity

    uiInterface.InitMessage(_("Verifying database integrity..."));

    if (!bitdb.Open(GetDataDir()))
    {
         string msg = strprintf(_("Error initializing database environment %s!"
                                 " To recover, BACKUP THAT DIRECTORY, then remove"
                                 " everything from it except for wallet.dat."), strDataDir);
        return InitError(msg);
    }

    if (GetBoolArg("-salvagewallet"))
    {
        // Recover readable keypairs:
        if (!CWalletDB::Recover(bitdb, strWalletFileName, true))
            return false;
    }

    if (filesystem::exists(GetDataDir() / strWalletFileName))
    {
        CDBEnv::VerifyResult r = bitdb.Verify(strWalletFileName, CWalletDB::Recover);
        if (r == CDBEnv::RECOVER_OK)
        {
            string msg = strprintf(_("Warning: wallet.dat corrupt, data salvaged!"
                                     " Original wallet.dat saved as wallet.{timestamp}.bak in %s; if"
                                     " your balance or transactions are incorrect you should"
                                     " restore from a backup."), strDataDir);
            uiInterface.ThreadSafeMessageBox(msg, _("Gridcoin"),
                CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
        }
        if (r == CDBEnv::RECOVER_FAIL)
            return InitError(_("wallet.dat corrupt, salvage failed"));
    }

    // ********************************************************* Step 6: network initialization

    int nSocksVersion = GetArg("-socks", 5);

    if (nSocksVersion != 4 && nSocksVersion != 5)
        return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));

    if (mapArgs.count("-onlynet")) {
        std::set<enum Network> nets;
        for (auto const& snet : mapMultiArgs["-onlynet"])
        {
            enum Network net = ParseNetwork(snet);
            if (net == NET_UNROUTABLE)
                return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
            nets.insert(net);
        }
        for (int n = 0; n < NET_MAX; n++) {
            enum Network net = (enum Network)n;
            if (!nets.count(net))
                SetLimited(net);
        }
    }

    CService addrProxy;
    bool fProxy = false;
    if (mapArgs.count("-proxy")) {
        addrProxy = CService(mapArgs["-proxy"], 9050);
        if (!addrProxy.IsValid())
            return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));

        if (!IsLimited(NET_IPV4))
            SetProxy(NET_IPV4, addrProxy, nSocksVersion);
        if (nSocksVersion > 4) {
            if (!IsLimited(NET_IPV6))
                SetProxy(NET_IPV6, addrProxy, nSocksVersion);
            SetNameProxy(addrProxy, nSocksVersion);
        }
        fProxy = true;
    }

    // -tor can override normal proxy, -notor disables tor entirely
    if (!(mapArgs.count("-tor") && mapArgs["-tor"] == "0") && (fProxy || mapArgs.count("-tor"))) {
        CService addrOnion;
        if (!mapArgs.count("-tor"))
            addrOnion = addrProxy;
        else
            addrOnion = CService(mapArgs["-tor"], 9050);
        if (!addrOnion.IsValid())
            return InitError(strprintf(_("Invalid -tor address: '%s'"), mapArgs["-tor"]));
        SetProxy(NET_TOR, addrOnion, 5);
        SetReachable(NET_TOR);
    }

    // see Step 2: parameter interactions for more information about these
    fNoListen = !GetBoolArg("-listen", true);
    fDiscover = GetBoolArg("-discover", true);
    fNameLookup = GetBoolArg("-dns", true);
#ifdef USE_UPNP
    fUseUPnP = GetBoolArg("-upnp", USE_UPNP);
#endif

    bool fBound = false;
    if (!fNoListen)
    {
        std::string strError;
        if (mapArgs.count("-bind")) {
            for (auto const& strBind : mapMultiArgs["-bind"])
            {
                CService addrBind;
                if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
                    return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
                fBound |= Bind(addrBind);
            }
        } else {
            struct in_addr inaddr_any;
            inaddr_any.s_addr = INADDR_ANY;
            if (!IsLimited(NET_IPV6))
                fBound |= Bind(CService(in6addr_any, GetListenPort()), false);
            if (!IsLimited(NET_IPV4))
                fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound);
        }
        if (!fBound)
            return InitError(_("Failed to listen on any port. Use -listen=0 if you want this."));
    }

    if (mapArgs.count("-externalip"))
    {
        for (auto const& strAddr : mapMultiArgs["-externalip"])
        {
            CService addrLocal(strAddr, GetListenPort(), fNameLookup);
            if (!addrLocal.IsValid())
                return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr));
            AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
        }
    }

    if (mapArgs.count("-reservebalance")) // ppcoin: reserve balance amount
    {
        if (!ParseMoney(mapArgs["-reservebalance"], nReserveBalance))
        {
            InitError(_("Invalid amount for -reservebalance=<amount>"));
            return false;
        }
    }

    for (auto const& strDest : mapMultiArgs["-seednode"])
        AddOneShot(strDest);

    // ********************************************************* Step 7: load blockchain

    if (!bitdb.Open(GetDataDir()))
    {
        string msg = strprintf(_("Error initializing database environment %s!"
                                 " To recover, BACKUP THAT DIRECTORY, then remove"
                                 " everything from it except for wallet.dat."), strDataDir);
        return InitError(msg);
    }

    if (GetBoolArg("-loadblockindextest"))
    {
        CTxDB txdb("r");
        txdb.LoadBlockIndex();
        PrintBlockTree();
        return false;
    }

    uiInterface.InitMessage(_("Loading block index..."));
    LogPrintf("Loading block index...");
    nStart = GetTimeMillis();
    if (!LoadBlockIndex())
        return InitError(_("Error loading blkindex.dat"));

    // as LoadBlockIndex can take several minutes, it's possible the user
    // requested to kill bitcoin-qt during the last operation. If so, exit.
    // As the program has not fully started yet, Shutdown() is possibly overkill.
    if (fRequestShutdown)
    {
        LogPrintf("Shutdown requested. Exiting.");
        return false;
    }
    LogPrintf(" block index %15" PRId64 "ms", GetTimeMillis() - nStart);

    if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree"))
    {
        PrintBlockTree();
        return false;
    }

    if (mapArgs.count("-printblock"))
    {
        string strMatch = mapArgs["-printblock"];
        int nFound = 0;
        for (BlockMap::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
        {
            uint256 hash = (*mi).first;
            if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
            {
                CBlockIndex* pindex = (*mi).second;
                CBlock block;
                block.ReadFromDisk(pindex);
                block.BuildMerkleTree();
                block.print();
                LogPrintf("");
                nFound++;
            }
        }
        if (nFound == 0)
            LogPrintf("No blocks matching %s were found", strMatch);
        return false;
    }

    // ********************************************************* Step 8: load wallet

    uiInterface.InitMessage(_("Loading wallet..."));
    LogPrintf("Loading wallet...");
    nStart = GetTimeMillis();
    bool fFirstRun = true;
    pwalletMain = new CWallet(strWalletFileName);
    DBErrors nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
    if (nLoadWalletRet != DB_LOAD_OK)
    {
        if (nLoadWalletRet == DB_CORRUPT)
            strErrors << _("Error loading wallet.dat: Wallet corrupted") << "\n";
        else if (nLoadWalletRet == DB_NONCRITICAL_ERROR)
        {
            string msg(_("Warning: error reading wallet.dat! All keys read correctly, but transaction data"
                         " or address book entries might be missing or incorrect."));
            uiInterface.ThreadSafeMessageBox(msg, _("Gridcoin"), CClientUIInterface::OK | CClientUIInterface::ICON_EXCLAMATION | CClientUIInterface::MODAL);
        }
        else if (nLoadWalletRet == DB_TOO_NEW)
            strErrors << _("Error loading wallet.dat: Wallet requires newer version of Gridcoin") << "\n";
        else if (nLoadWalletRet == DB_NEED_REWRITE)
        {
            strErrors << _("Wallet needed to be rewritten: restart Gridcoin to complete") << "\n";
            LogPrintf("%s", strErrors.str());
            return InitError(strErrors.str());
        }
        else
            strErrors << _("Error loading wallet.dat") << "\n";
    }

    if (GetBoolArg("-upgradewallet", fFirstRun))
    {
        int nMaxVersion = GetArg("-upgradewallet", 0);
        if (nMaxVersion == 0) // the -upgradewallet without argument case
        {
            LogPrintf("Performing wallet upgrade to %i", FEATURE_LATEST);
            nMaxVersion = CLIENT_VERSION;
            pwalletMain->SetMinVersion(FEATURE_LATEST); // permanently upgrade the wallet immediately
        }
        else
            LogPrintf("Allowing wallet upgrade up to %i", nMaxVersion);
        if (nMaxVersion < pwalletMain->GetVersion())
            strErrors << _("Cannot downgrade wallet") << "\n";
        pwalletMain->SetMaxVersion(nMaxVersion);
    }

    if (fFirstRun)
    {
        // Create new keyUser and set as default key
        RandAddSeedPerfmon();

        CPubKey newDefaultKey;
        if (pwalletMain->GetKeyFromPool(newDefaultKey, false)) {
            pwalletMain->SetDefaultKey(newDefaultKey);
            if (!pwalletMain->SetAddressBookName(pwalletMain->vchDefaultKey.GetID(), ""))
                strErrors << _("Cannot write default address") << "\n";
        }
    }

    LogPrintf("%s", strErrors.str());
    LogPrintf(" wallet      %15" PRId64 "ms", GetTimeMillis() - nStart);

    RegisterWallet(pwalletMain);

    CBlockIndex *pindexRescan = pindexBest;
    if (GetBoolArg("-rescan"))
        pindexRescan = pindexGenesisBlock;
    else
    {
        CWalletDB walletdb(strWalletFileName);
        CBlockLocator locator;
        if (walletdb.ReadBestBlock(locator))
            pindexRescan = locator.GetBlockIndex();
    }
    if (pindexBest != pindexRescan && pindexBest && pindexRescan && pindexBest->nHeight > pindexRescan->nHeight)
    {
        uiInterface.InitMessage(_("Rescanning..."));
        LogPrintf("Rescanning last %i blocks (from block %i)...", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight);
        nStart = GetTimeMillis();
        pwalletMain->ScanForWalletTransactions(pindexRescan, true);
        LogPrintf(" rescan      %15" PRId64 "ms", GetTimeMillis() - nStart);
    }

    // ********************************************************* Step 9: import blocks

    if (mapArgs.count("-loadblock"))
    {
        uiInterface.InitMessage(_("Importing blockchain data file."));

        for (auto const& strFile : mapMultiArgs["-loadblock"])
        {
            FILE *file = fopen(strFile.c_str(), "rb");
            if (file)
                LoadExternalBlockFile(file);
        }
        exit(0);
    }

    filesystem::path pathBootstrap = GetDataDir() / "bootstrap.dat";
    if (filesystem::exists(pathBootstrap)) {
        uiInterface.InitMessage(_("Importing bootstrap blockchain data file."));

        FILE *file = fopen(pathBootstrap.string().c_str(), "rb");
        if (file) {
            filesystem::path pathBootstrapOld = GetDataDir() / "bootstrap.dat.old";
            LoadExternalBlockFile(file);
            RenameOver(pathBootstrap, pathBootstrapOld);
        }
    }

    // ********************************************************* Step 10: load peers

    uiInterface.InitMessage(_("Loading addresses..."));
    if (fDebug10) LogPrintf("Loading addresses...");
    nStart = GetTimeMillis();

    {
        CAddrDB adb;
        if (!adb.Read(addrman))
            LogPrintf("Invalid or missing peers.dat; recreating");
    }

    LogPrintf("Loaded %i addresses from peers.dat  %" PRId64 "ms",  addrman.size(), GetTimeMillis() - nStart);


    // ********************************************************* Step 11: start node
    uiInterface.InitMessage(_("Loading Persisted Data Cache..."));
    //
    std::string sOut = "";
    if (fDebug3) LogPrintf("Loading admin Messages");
    LoadAdminMessages(true,sOut);
    LogPrintf("Done loading Admin messages");

    uiInterface.InitMessage(_("Compute Neural Network Hashes..."));
    ComputeNeuralNetworkSupermajorityHashes();

    LoadCPIDs();

    uiInterface.InitMessage(_("Finding first applicable Research Project..."));

    if (!CheckDiskSpace())
        return false;

    RandAddSeedPerfmon();

    //// debug print
    if (fDebug)
    {
        LogPrintf("mapBlockIndex.size() = %" PRIszu,   mapBlockIndex.size());
        LogPrintf("nBestHeight = %d",            nBestHeight);
        LogPrintf("setKeyPool.size() = %" PRIszu,      pwalletMain->setKeyPool.size());
        LogPrintf("mapWallet.size() = %" PRIszu,       pwalletMain->mapWallet.size());
        LogPrintf("mapAddressBook.size() = %" PRIszu,  pwalletMain->mapAddressBook.size());
    }


    uiInterface.InitMessage(_("Loading Network Averages..."));
    if (fDebug3) LogPrintf("Loading network averages");

    CBlockIndex* tallyHeight = FindTallyTrigger(pindexBest);
    if(tallyHeight)
        TallyResearchAverages(tallyHeight);

    if (!threads->createThread(StartNode, NULL, "Start Thread"))
        InitError(_("Error: could not start node"));

    if (fServer)
        StartRPCThreads();

    // ********************************************************* Step 12: finished

    uiInterface.InitMessage(_("Done loading"));
    LogPrintf("Done loading");

    if (!strErrors.str().empty())
        return InitError(strErrors.str());

    // Add wallet transactions that aren't already in a block to mapTransactions
    pwalletMain->ReacceptWalletTransactions();

    int nMismatchSpent;
    int64_t nBalanceInQuestion;
    pwalletMain->FixSpentCoins(nMismatchSpent, nBalanceInQuestion);

    return true;
}
Example #10
0
// pNut: list top prime chain within pnut network
Value listtopprimes(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "listtopprimes <primechain length> [primechain type]\n"
            "Returns the list of top prime chains in pnut network.\n"
            "<primechain length> is integer like 10, 11, 12 etc.\n"
            "[primechain type] is optional type, among 1CC, 2CC and TWN");

    int nPrimeChainLength = params[0].get_int();
    unsigned int nPrimeChainType = 0;
    if (params.size() > 1)
    {
        std::string strPrimeChainType = params[1].get_str();
        if (strPrimeChainType.compare("1CC") == 0)
            nPrimeChainType = PRIME_CHAIN_CUNNINGHAM1;
        else if (strPrimeChainType.compare("2CC") == 0)
            nPrimeChainType = PRIME_CHAIN_CUNNINGHAM2;
        else if (strPrimeChainType.compare("TWN") == 0)
            nPrimeChainType = PRIME_CHAIN_BI_TWIN;
        else
            throw runtime_error("Prime chain type must be 1CC, 2CC or TWN.");
    }

    // Search for top prime chains
    unsigned int nRankingSize = 10; // ranking list size
    unsigned int nSortVectorSize = 64; // vector size for sort operation
    CBigNum bnPrimeQualify = 0; // minimum qualify value for ranking list
    vector<pair<CBigNum, uint256> > vSortedByOrigin;
    for (CBlockIndex* pindex = pindexGenesisBlock; pindex; pindex = pindex->pnext)
    {
        if (nPrimeChainLength != (int) TargetGetLength(pindex->nPrimeChainLength))
            continue; // length not matching, next block
        if (nPrimeChainType && nPrimeChainType != pindex->nPrimeChainType)
            continue; // type not matching, next block

        CBlock block;
        block.ReadFromDisk(pindex); // read block
        CBigNum bnPrimeChainOrigin = CBigNum(block.GetHeaderHash()) * block.bnPrimeChainMultiplier; // compute prime chain origin

        if (bnPrimeChainOrigin > bnPrimeQualify)
            vSortedByOrigin.push_back(make_pair(bnPrimeChainOrigin, block.GetHash()));

        if (vSortedByOrigin.size() >= nSortVectorSize)
        {
            // Sort prime chain candidates
            sort(vSortedByOrigin.begin(), vSortedByOrigin.end());
            reverse(vSortedByOrigin.begin(), vSortedByOrigin.end());
            // Truncate candidate list
            while (vSortedByOrigin.size() > nRankingSize)
                vSortedByOrigin.pop_back();
            // Update minimum qualify value for top prime chains
            bnPrimeQualify = vSortedByOrigin.back().first;
        }
    }

    // Final sort of prime chain candidates
    sort(vSortedByOrigin.begin(), vSortedByOrigin.end());
    reverse(vSortedByOrigin.begin(), vSortedByOrigin.end());
    // Truncate candidate list
    while (vSortedByOrigin.size() > nRankingSize)
        vSortedByOrigin.pop_back();

    // Output top prime chains
    Array ret;
    BOOST_FOREACH(const PAIRTYPE(CBigNum, uint256)& item, vSortedByOrigin)
    {
        CBigNum bnPrimeChainOrigin = item.first;
        CBlockIndex* pindex = mapBlockIndex[item.second];
        CBlock block;
        block.ReadFromDisk(pindex); // read block
        Object entry;
        entry.push_back(Pair("time", DateTimeStrFormat("%Y-%m-%d %H:%M:%S UTC", pindex->GetBlockTime()).c_str()));
        entry.push_back(Pair("epoch", (boost::int64_t) pindex->GetBlockTime()));
        entry.push_back(Pair("height", pindex->nHeight));
        entry.push_back(Pair("ismine", pwalletMain->IsMine(block.vtx[0])));
        CTxDestination address;
        entry.push_back(Pair("mineraddress", (block.vtx[0].vout.size() > 1)? "multiple" : ExtractDestination(block.vtx[0].vout[0].scriptPubKey, address)? CBitcoinAddress(address).ToString().c_str() : "invalid"));
        entry.push_back(Pair("primedigit", (int) bnPrimeChainOrigin.ToString().length()));
        entry.push_back(Pair("primechain", GetPrimeChainName(pindex->nPrimeChainType, pindex->nPrimeChainLength).c_str()));
        entry.push_back(Pair("primeorigin", bnPrimeChainOrigin.ToString().c_str()));
        entry.push_back(Pair("primorialform", GetPrimeOriginPrimorialForm(bnPrimeChainOrigin).c_str()));
        ret.push_back(entry);
    }

    return ret;
}
Example #11
0
Value scaninput(const Array& params, bool fHelp)
{
    if (fHelp || params.size() > 4 || params.size() < 2)
        throw runtime_error(
            "scaninput <txid> <nout> [difficulty] [days]\n"
            "Scan specified input for suitable kernel solutions.\n"
            "    [difficulty] - upper limit for difficulty, current difficulty by default;\n"
            "    [days] - time window, 365 days by default.\n"
        );


    uint256 hash;
    hash.SetHex(params[0].get_str());

    uint32_t nOut = params[1].get_int(), nBits = GetNextTargetRequired(pindexBest, true), nDays = 365;

    if (params.size() > 2)
    {
        CBigNum bnTarget(nPoWBase);
        bnTarget *= 1000;
        bnTarget /= (int) (params[2].get_real() * 1000);
        nBits = bnTarget.GetCompact();
    }

    if (params.size() > 3)
    {
        nDays = params[3].get_int();
    }

    CTransaction tx;
    uint256 hashBlock = 0;
    if (GetTransaction(hash, tx, hashBlock))
    {
        if (nOut > tx.vout.size())
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Incorrect output number");

        if (hashBlock == 0)
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain");

        CTxDB txdb("r");

        CBlock block;
        CTxIndex txindex;

        // Load transaction index item
        if (!txdb.ReadTxIndex(tx.GetHash(), txindex))
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to read block index item");

        // Read block header
        if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "CBlock::ReadFromDisk() failed");

        uint64_t nStakeModifier = 0;
        if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier))
            throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No kernel stake modifier generated yet");

        std::pair<uint32_t, uint32_t> interval;
        interval.first = GetTime();
        // Only count coins meeting min age requirement
        if (nStakeMinAge + block.nTime > interval.first)
            interval.first += (nStakeMinAge + block.nTime - interval.first);
        interval.second = interval.first + nDays * 86400;

        SHA256_CTX ctx;
        GetKernelMidstate(nStakeModifier, block.nTime, txindex.pos.nTxPos - txindex.pos.nBlockPos, tx.nTime, nOut, ctx);

        std::pair<uint256, uint32_t> solution;
        if (ScanMidstateForward(ctx, nBits, tx.nTime, tx.vout[nOut].nValue, interval, solution))
        {
            Object r;
            r.push_back(Pair("hash", solution.first.GetHex()));
            r.push_back(Pair("time", DateTimeStrFormat(solution.second)));

            return r;
        }
    }
    else
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");

    return Value::null;
}
Example #12
0
Value getstakers(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 4)
        throw runtime_error(
            "getstakers <min block> <max block> [total]"
            "Returns array of stakers in between min and max block, inclusive."
			" If [total] is provided, outputs an array of stakers with proportionate amounts. Can be used as input to sendmany for dividends.");

    int nHeight = params[0].get_int();
	int max = params[1].get_int();
	double amount = 0.0, amountEach = 0.0;
	int amtProvided = 0;
	int iCount = 0;

    std::string outStr(" '{");

    if (max < nHeight)
	    throw runtime_error("Max Block is less than Min Block.");
    if (nHeight < 20161 || nHeight > nBestHeight)
        throw runtime_error("Min Block number out of range. (First PoS Block: 20,161)");
    if (max < 0 || max > nBestHeight)
        throw runtime_error("Max Block number out of range.");

	if(params.size() >= 3)
	{
		amount = params[2].get_real();
	    if( amount / (max - nHeight + 1) < 1)
		    throw runtime_error("Amount is less than 1 BTCD per staker.");
	    amountEach = amount/(max-nHeight+1);
        amtProvided = 1;
	}

	
    //Find Min. Block
    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;


	CTransaction tx;
	CTxOut txout;
    uint256 txHash = 0;
    uint256 hash;
	vector<CTxDestination> addresses;
	int nRequired;
    txnouttype type;
	
	Object entry;
	Object result;

    std::ostringstream s;
    s << amountEach;
    std::string strAmount = s.str();
	
	for(iCount = nHeight; iCount <= max; iCount++)
	{
        hash = *pblockindex->phashBlock;

        pblockindex = mapBlockIndex[hash];
        block.ReadFromDisk(pblockindex, true);

        tx = block.vtx[1];
        txout = tx.vout[1];
        txHash = tx.GetHash();


        addresses.clear();
		
        ExtractDestinations(txout.scriptPubKey, type, addresses, nRequired);

        outStr += std::string("\"") +
                  CBitcoinAddress(addresses[0]).ToString() + 
                  std::string("\"");
        if(amtProvided == 1)
        {
            outStr += std::string(": ") +
                      strAmount;
            if( iCount != max)
            outStr += std::string(", ");
        }
        else
            if( iCount != max)
                outStr += std::string(", ");
		
        pblockindex = pblockindex->pnext;
    }
    outStr += std::string("}' ");
    char *finalString = (char*)outStr.c_str();

    result.push_back(Pair("Addresses:", std::string(unstringify(finalString))));

    return result;
}
void ProfitExplorerPage::loadStakeChart(bool firstRun)
{
        if(fShutdown)
	return;

    nTimeData.clear();
    netStakeData.clear();
    myStakeData.clear();
    difficultyData.clear();
    velTimeData.clear();
    velAmountData.clear();

    // go back this many blocks max
    int max = ui->spinBox->value();
    int i = 0;

    //BOOST_REVERSE_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& b, mapBlockIndex)
    //{
    //    if(i >= max)
    //        break;
    CBlockIndex* pindex = pindexBest;
    while(i < max && pindex != NULL)
    {
        //CBlockIndex* pindex = b.second;
        if(pindex->IsProofOfStake())
	{
            nTimeData.append(pindex->nTime);
	    netStakeData.append(pindex->nMint / COIN);

	    // Read the block in and check if the coinstake is ours
	    CBlock block;
	    block.ReadFromDisk(pindex, true);
	    if(block.IsProofOfStake()) // this should always be true here
	    {
		velTimeData.append(pindex->nTime);
		double blockOutAmount = 0;
		for(int j=0; j<block.vtx.size(); j++)
		{
		    blockOutAmount += block.vtx[j].GetValueOut() / COIN;
		}
		velAmountData.append(blockOutAmount);

		difficultyData.append(GetDifficulty(pindex));
		if(pwalletMain->IsMine(block.vtx[1]))
		{
		    myStakeData.append(pindex->nMint / COIN);
		}
		else
		{
		    myStakeData.append(0);
		}
	    }
	    else
	    {
		myStakeData.append(0); // should never happen
	    }
	    i = i + 1;
	}
        pindex = pindex->pprev;
        //++i;
    }    

    if(!firstRun)
    {
        uint64_t nMinWeight = 0, nMaxWeight = 0, nWeight = 0;
        pwalletMain->GetStakeWeight(*pwalletMain, nMinWeight, nMaxWeight, nWeight);

        uint64_t nNetworkWeight = 0;
        if(pindexBest)
            nNetworkWeight = GetPoSKernelPS();
        bool staking = nLastCoinStakeSearchInterval && nWeight;
        int nExpectedTime = staking ? (nTargetSpacing * nNetworkWeight / nWeight) : -1;

        ui->stakingLabel->setText(staking ? "Enabled" : "Disabled");
        if(pindexBest)
            ui->difficultyLabel->setText(QString::number(GetDifficulty(GetLastBlockIndex(pindexBest, true))));
        ui->weightLabel->setText(QString::number(nWeight));
        ui->netWeightLabel->setText(QString::number(nNetworkWeight));
        ui->timeToStakeLabel->setText(QString::number(nExpectedTime) + " secs");
    }

    //qDebug() << "Stake blocks processed:";
    //qDebug() << i;
    ui->customPlot->clearPlottables();
    ui->customPlot->clearGraphs();
    ui->customPlot->clearItems();
    ui->customPlot->addGraph();
    ui->customPlot->graph(0)->setPen(QPen(QColor(206, 206, 206))); // line color green for first graph
    ui->customPlot->graph(0)->setBrush(QBrush(QColor(206, 206, 206, 20))); // first graph will be filled with translucent green
    ui->customPlot->addGraph();
    ui->customPlot->graph(1)->setPen(QPen(QColor(76, 255, 0))); // line color red for second graph
    ui->customPlot->graph(1)->setBrush(QBrush(QColor(76, 255, 0, 20)));

    if(ui->networkCheckBox->isChecked())
        ui->customPlot->graph(0)->setData(nTimeData, netStakeData);
    ui->customPlot->graph(1)->setData(nTimeData, myStakeData);
    //ui->customPlot->xAxis->setRangeLower(nTimeData.first());
    //ui->customPlot->xAxis->setRangeUpper(nTimeData.last());

    QLinearGradient plotGradient;
    plotGradient.setStart(0, 0);
    plotGradient.setFinalStop(0, 350);
    plotGradient.setColorAt(0, QColor(10, 10, 10));
    plotGradient.setColorAt(1, QColor(0, 0, 0));
    ui->customPlot->setBackground(plotGradient);

    ui->customPlot->xAxis->grid()->setVisible(false);
    ui->customPlot->yAxis->grid()->setVisible(false);
    ui->customPlot->xAxis->grid()->setSubGridVisible(false);
    ui->customPlot->yAxis->grid()->setSubGridVisible(false);

    ui->customPlot->xAxis->setAutoTickStep(true);
    ui->customPlot->xAxis->setTickStep(3600 * 24); // 24 hr tickstep
    ui->customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
    ui->customPlot->xAxis->setDateTimeSpec(Qt::UTC);
    ui->customPlot->xAxis->setDateTimeFormat("dd. MMM hh:mm");
    ui->customPlot->xAxis->setTickLabelRotation(15);

    ui->customPlot->xAxis->setTickLabelColor(QColor(137, 140, 146));
    ui->customPlot->yAxis->setTickLabelColor(QColor(137, 140, 146));

    ui->customPlot->rescaleAxes();

    ui->customPlot->xAxis->setLabelColor(QColor(137, 140, 146));
    ui->customPlot->yAxis->setLabelColor(QColor(137, 140, 146));
    ui->customPlot->yAxis->setLabel("$XQN Minted");
    ui->customPlot->xAxis->setLabel("Stake Block Generation Time");

    ui->customPlot->replot();


    ui->difficultyPlot->clearPlottables();
    ui->difficultyPlot->clearGraphs();
    ui->difficultyPlot->clearItems();
    ui->difficultyPlot->addGraph();
    ui->difficultyPlot->graph(0)->setPen(QPen(QColor(76, 255, 0))); // line color green for first graph
    ui->difficultyPlot->graph(0)->setBrush(QBrush(QColor(76, 255, 0, 20))); // first graph will be filled with translucent green
    
    ui->difficultyPlot->graph(0)->setData(nTimeData, difficultyData);
    ui->difficultyPlot->xAxis->setRangeLower(nTimeData.first());
    ui->difficultyPlot->xAxis->setRangeUpper(nTimeData.last());

    QLinearGradient diffPlotGradient;
    diffPlotGradient.setStart(0, 0);
    diffPlotGradient.setFinalStop(0, 350);
    diffPlotGradient.setColorAt(0, QColor(10, 10, 10));
    diffPlotGradient.setColorAt(1, QColor(0, 0, 0));
    ui->difficultyPlot->setBackground(diffPlotGradient);

    ui->difficultyPlot->xAxis->grid()->setVisible(false);
    ui->difficultyPlot->yAxis->grid()->setVisible(false);
    ui->difficultyPlot->xAxis->grid()->setSubGridVisible(false);
    ui->difficultyPlot->yAxis->grid()->setSubGridVisible(false);

    ui->difficultyPlot->xAxis->setAutoTickStep(false);
    ui->difficultyPlot->xAxis->setTickStep(3600 * 24); // 24 hr tickstep
    ui->difficultyPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
    ui->difficultyPlot->xAxis->setDateTimeSpec(Qt::UTC);
    ui->difficultyPlot->xAxis->setDateTimeFormat("dd. MMM hh:mm");
    ui->difficultyPlot->xAxis->setTickLabelRotation(15);

    ui->difficultyPlot->xAxis->setTickLabelColor(QColor(137, 140, 146));
    ui->difficultyPlot->yAxis->setTickLabelColor(QColor(137, 140, 146));

    ui->difficultyPlot->rescaleAxes();
    ui->difficultyPlot->yAxis->setTickStep(0.00005);
    ui->difficultyPlot->xAxis->setLabelColor(QColor(137, 140, 146));
    ui->difficultyPlot->yAxis->setLabelColor(QColor(137, 140, 146));
    ui->difficultyPlot->yAxis->setLabel("Difficulty");
    ui->difficultyPlot->xAxis->setTickLabels(false);
    //ui->difficultyPlot->xAxis->setLabel("Stake Block Generation Time");

    ui->difficultyPlot->replot();


    ui->velocityPlot->clearPlottables();
    ui->velocityPlot->clearGraphs();
    ui->velocityPlot->clearItems();
    ui->velocityPlot->addGraph();
    ui->velocityPlot->graph(0)->setPen(QPen(QColor(76, 255, 0))); // line color green for first graph
    ui->velocityPlot->graph(0)->setBrush(QBrush(QColor(76, 255, 0, 20))); // first graph will be filled with translucent green
    
    ui->velocityPlot->graph(0)->setData(velTimeData, velAmountData);
    ui->velocityPlot->xAxis->setRangeLower(velTimeData.first());
    ui->velocityPlot->xAxis->setRangeUpper(velTimeData.last());

    QLinearGradient velPlotGradient;
    velPlotGradient.setStart(0, 0);
    velPlotGradient.setFinalStop(0, 150);
    velPlotGradient.setColorAt(0, QColor(10, 10, 10));
    velPlotGradient.setColorAt(1, QColor(0, 0, 0));
    ui->velocityPlot->setBackground(velPlotGradient);

    ui->velocityPlot->xAxis->grid()->setVisible(false);
    ui->velocityPlot->yAxis->grid()->setVisible(false);
    ui->velocityPlot->xAxis->grid()->setSubGridVisible(false);
    ui->velocityPlot->yAxis->grid()->setSubGridVisible(false);

    ui->velocityPlot->xAxis->setAutoTickStep(false);
    ui->velocityPlot->xAxis->setTickStep(3600 * 24); // 24 hr tickstep
    ui->velocityPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
    ui->velocityPlot->xAxis->setDateTimeSpec(Qt::UTC);
    ui->velocityPlot->xAxis->setDateTimeFormat("dd. MMM hh:mm");
    ui->velocityPlot->xAxis->setTickLabelRotation(15);

    ui->velocityPlot->xAxis->setTickLabelColor(QColor(137, 140, 146));
    ui->velocityPlot->yAxis->setTickLabelColor(QColor(137, 140, 146));

    ui->velocityPlot->yAxis->setScaleType(QCPAxis::stLogarithmic);
    ui->velocityPlot->yAxis->setTickStep(1000);
    ui->velocityPlot->xAxis->setLabelColor(QColor(137, 140, 146));
    ui->velocityPlot->yAxis->setLabelColor(QColor(137, 140, 146));
    ui->velocityPlot->yAxis->setLabel("$XQN");
    ui->velocityPlot->xAxis->setTickLabels(false);
    ui->velocityPlot->xAxis->setLabel("Financial Velocity");

    ui->velocityPlot->rescaleAxes();
    ui->velocityPlot->replot();

}
Example #14
0
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;
                        }
                    }
                }
Example #15
0
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++;
                        }
                    }
                }
Value getblockbynumber(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblockbynumber <number> [txinfo]\n"
            "txinfo optional to print more detailed tx info\n"
            "Returns details of a block with given block-number.");

    int nHeight = params[0].get_int();
    if (nHeight < 0 || nHeight > nBestHeight)
        throw runtime_error("Block number out of range.");
    
    if (nNodeMode == NT_THIN)
    {
        if (!fThinFullIndex
            && pindexRear
            && nHeight < pindexRear->nHeight)
        {
            CDiskBlockThinIndex diskindex;
            uint256 hashPrev = pindexRear->GetBlockHash();
            
            // -- find closest checkpoint
            Checkpoints::MapCheckpoints& checkpoints = (fTestNet ? Checkpoints::mapCheckpointsTestnet : Checkpoints::mapCheckpoints);
            Checkpoints::MapCheckpoints::reverse_iterator rit;

            for (rit = checkpoints.rbegin(); rit != checkpoints.rend(); ++rit)
            {
                if (rit->first < nHeight)
                    break;
                hashPrev = rit->second;
            };
            
            CTxDB txdb("r");
            while (hashPrev != 0)
            {
                if (!txdb.ReadBlockThinIndex(hashPrev, diskindex))
                    throw runtime_error("Read header from db failed.\n");
                
                if (diskindex.nHeight == nHeightFilteredNeeded)
                    return diskBlockThinIndexToJSON(diskindex);
                
                hashPrev = diskindex.hashPrev;
            };
            
            throw runtime_error("block not found.");
        };
        
        
        CBlockThin block;
        std::map<uint256, CBlockThinIndex*>::iterator mi = mapBlockThinIndex.find(hashBestChain);
        if (mi != mapBlockThinIndex.end())
        {
            CBlockThinIndex* pblockindex = mi->second;
            while (pblockindex->pprev && pblockindex->nHeight > nHeight)
                pblockindex = pblockindex->pprev;
            
            if (nHeight != pblockindex->nHeight)
            {
                throw runtime_error("block not in chain index.");
            }
            return blockHeaderToJSON(block, pblockindex);
        } else
        {
            throw runtime_error("hashBestChain not in chain index.");
        }
        
        
    };
    
    CBlock block;
    CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
    while (pblockindex->nHeight > nHeight)
        pblockindex = pblockindex->pprev;

    uint256 hash = *pblockindex->phashBlock;

    pblockindex = mapBlockIndex[hash];
    block.ReadFromDisk(pblockindex, true);

    return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}
Example #17
0
bool CreateCoinStake( CBlock &blocknew, CKey &key,
    vector<const CWalletTx*> &StakeInputs, uint64_t &CoinAge,
    CWallet &wallet, CBlockIndex* pindexPrev )
{
    int64_t CoinWeight;
    CBigNum StakeKernelHash;
    CTxDB txdb("r");
    int64_t StakeWeightSum = 0;
    double StakeValueSum = 0;
    int64_t StakeWeightMin=MAX_MONEY;
    int64_t StakeWeightMax=0;
    uint64_t StakeCoinAgeSum=0;
    double StakeDiffSum = 0;
    double StakeDiffMax = 0;
    CTransaction &txnew = blocknew.vtx[1]; // second tx is coinstake

    //initialize the transaction
    txnew.nTime = blocknew.nTime & (~STAKE_TIMESTAMP_MASK);
    txnew.vin.clear();
    txnew.vout.clear();

    // Choose coins to use
    set <pair <const CWalletTx*,unsigned int> > CoinsToStake;

    int64_t BalanceToStake = wallet.GetBalance();
    int64_t nValueIn = 0;
    //Request all the coins here, check reserve later

    if ( BalanceToStake<=0
        || !wallet.SelectCoinsForStaking(BalanceToStake*2, txnew.nTime, CoinsToStake, nValueIn) )
    {
        LOCK(MinerStatus.lock);
        MinerStatus.ReasonNotStaking+=_("No coins; ");
        if (fDebug) LogPrintf("CreateCoinStake: %s",MinerStatus.ReasonNotStaking);
        return false;
    }
    BalanceToStake -= nReserveBalance;

    if(fDebug2) LogPrintf("\nCreateCoinStake: Staking nTime/16= %d Bits= %u",
    txnew.nTime/16,blocknew.nBits);

    for(const auto& pcoin : CoinsToStake)
    {
        const CTransaction &CoinTx =*pcoin.first; //transaction that produced this coin
        unsigned int CoinTxN =pcoin.second; //index of this coin inside it

        CTxIndex txindex;
        {
            LOCK2(cs_main, wallet.cs_wallet);
            if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex))
                continue; //error?
        }

        CBlock CoinBlock; //Block which contains CoinTx
        {
            LOCK2(cs_main, wallet.cs_wallet);
            if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
                continue;
        }

        // only count coins meeting min age requirement
        if (CoinBlock.GetBlockTime() + nStakeMinAge > txnew.nTime)
            continue;

        if (CoinTx.vout[CoinTxN].nValue > BalanceToStake)
            continue;

        {
            int64_t nStakeValue= CoinTx.vout[CoinTxN].nValue;
            StakeValueSum += nStakeValue /(double)COIN;
            //crazy formula...
            // todo: clean this
            // todo reuse calculated value for interst
            CBigNum bn = CBigNum(nStakeValue) * (blocknew.nTime-CoinTx.nTime) / CENT;
            bn = bn * CENT / COIN / (24 * 60 * 60);
            StakeCoinAgeSum += bn.getuint64();
        }

        if(blocknew.nVersion==7)
        {
            NetworkTimer();
            CoinWeight = CalculateStakeWeightV3(CoinTx,CoinTxN,GlobalCPUMiningCPID);
            StakeKernelHash= CalculateStakeHashV3(CoinBlock,CoinTx,CoinTxN,txnew.nTime,GlobalCPUMiningCPID,mdPORNonce);
        }
        else
        {
            uint64_t StakeModifier = 0;
            if(!FindStakeModifierRev(StakeModifier,pindexPrev))
                continue;
            CoinWeight = CalculateStakeWeightV8(CoinTx,CoinTxN,GlobalCPUMiningCPID);
            StakeKernelHash= CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier,GlobalCPUMiningCPID);
        }

        CBigNum StakeTarget;
        StakeTarget.SetCompact(blocknew.nBits);
        StakeTarget*=CoinWeight;
        StakeWeightSum += CoinWeight;
        StakeWeightMin=std::min(StakeWeightMin,CoinWeight);
        StakeWeightMax=std::max(StakeWeightMax,CoinWeight);
        double StakeKernelDiff = GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight;
        StakeDiffSum += StakeKernelDiff;
        StakeDiffMax = std::max(StakeDiffMax,StakeKernelDiff);

        if (fDebug2) {
            int64_t RSA_WEIGHT = GetRSAWeightByBlock(GlobalCPUMiningCPID);
            LogPrintf(
"CreateCoinStake: V%d Time %.f, Por_Nonce %.f, Bits %jd, Weight %jd\n"
" RSA_WEIGHT %.f\n"
" Stk %72s\n"
" Trg %72s\n"
" Diff %0.7f of %0.7f\n",
            blocknew.nVersion,
            (double)txnew.nTime, mdPORNonce,
            (intmax_t)blocknew.nBits,(intmax_t)CoinWeight,
            (double)RSA_WEIGHT,
            StakeKernelHash.GetHex().c_str(), StakeTarget.GetHex().c_str(),
            StakeKernelDiff, GetBlockDifficulty(blocknew.nBits)
            );
        }

        if( StakeKernelHash <= StakeTarget )
        {
            // Found a kernel
            LogPrintf("\nCreateCoinStake: Found Kernel;\n");
            blocknew.nNonce= mdPORNonce;
            vector<valtype> vSolutions;
            txnouttype whichType;
            CScript scriptPubKeyOut;
            CScript scriptPubKeyKernel;
            scriptPubKeyKernel = CoinTx.vout[CoinTxN].scriptPubKey;
            if (!Solver(scriptPubKeyKernel, whichType, vSolutions))
            {
                LogPrintf("CreateCoinStake: failed to parse kernel\n");
                break;
            }
            if (whichType == TX_PUBKEYHASH) // pay to address type
            {
                // convert to pay to public key type
                if (!wallet.GetKey(uint160(vSolutions[0]), key))
                {
                    LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType);
                    break;  // unable to find corresponding public key
                }
                scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG;
            }
            else if (whichType == TX_PUBKEY)  // pay to public key type
            {
                valtype& vchPubKey = vSolutions[0];
                if (!wallet.GetKey(Hash160(vchPubKey), key)
                    || key.GetPubKey() != vchPubKey)
                {
                    LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType);
                    break;  // unable to find corresponding public key
                }

                scriptPubKeyOut = scriptPubKeyKernel;
            }
            else
            {
                LogPrintf("CreateCoinStake: no support for kernel type=%d\n", whichType);
                break;  // only support pay to public key and pay to address
            }

            txnew.vin.push_back(CTxIn(CoinTx.GetHash(), CoinTxN));
            StakeInputs.push_back(pcoin.first);
            if (!txnew.GetCoinAge(txdb, CoinAge))
                return error("CreateCoinStake: failed to calculate coin age");
            int64_t nCredit = CoinTx.vout[CoinTxN].nValue;

            txnew.vout.push_back(CTxOut(0, CScript())); // First Must be empty
            txnew.vout.push_back(CTxOut(nCredit, scriptPubKeyOut));
            //txnew.vout.push_back(CTxOut(0, scriptPubKeyOut));

            LogPrintf("CreateCoinStake: added kernel type=%d credit=%f\n", whichType,CoinToDouble(nCredit));

            LOCK(MinerStatus.lock);
            MinerStatus.KernelsFound++;
            MinerStatus.KernelDiffMax = 0;
            MinerStatus.KernelDiffSum = StakeDiffSum;
            return true;
        }
    }

    LOCK(MinerStatus.lock);
    MinerStatus.WeightSum = StakeWeightSum;
    MinerStatus.ValueSum = StakeValueSum;
    MinerStatus.WeightMin=StakeWeightMin;
    MinerStatus.WeightMax=StakeWeightMax;
    MinerStatus.CoinAgeSum=StakeCoinAgeSum;
    MinerStatus.KernelDiffMax = std::max(MinerStatus.KernelDiffMax,StakeDiffMax);
    MinerStatus.KernelDiffSum = StakeDiffSum;
    MinerStatus.nLastCoinStakeSearchInterval= txnew.nTime;
    return false;
}