Example #1
0
/**
 * class CoinQBlockTreeSqlite3
*/
void CoinQBlockTreeSqlite3::open(const std::string& filename, const Coin::CoinBlockHeader& header, bool bCreateIfNotExists)
{
    uchar_vector genesisHeaderHash = header.getHashLittleEndian();

    std::stringstream sql;
    db.open(filename, bCreateIfNotExists);

    sql << "CREATE TABLE IF NOT EXISTS `block_headers` ("
        <<      "`hash` TEXT UNIQUE NOT NULL,"
        <<      "`in_best_chain` INTEGER NOT NULL,"
        <<      "`height` INTEGER NOT NULL,"
        <<      "`chain_work` TEXT NOT NULL,"
        <<      "`version` INTEGER NOT NULL,"
        <<      "`prev_block_hash` TEXT NOT NULL,"
        <<      "`merkle_root` TEXT NOT NULL,"
        <<      "`timestamp` INTEGER NOT NULL,"
        <<      "`bits` INTEGER NOT NULL,"
        <<      "`nonce` INTEGER NOT NULL,"
        <<      "`time_inserted` INTEGER DEFAULT (strftime('%s', 'now')))";
    db.query(sql.str()); sql.str("");

    SQLite3Tx sqliteTx(db, SQLite3Tx::Type::EXCLUSIVE);
    SQLite3Stmt stmt;
    sql << "SELECT `hash` FROM `block_headers` WHERE `height` = 0";
    stmt.prepare(db, sql.str());
    int count = 0;
    while (stmt.step() == SQLITE_ROW) {
        if (count > 0) {
            throw std::runtime_error("File contains more than one genesis block.");
        }
        uchar_vector hash;
        hash.setHex((char*)stmt.getText(0));
        if (genesisHeaderHash != hash) {
            throw std::runtime_error("Genesis block mismatch.");
        }
        count++;
    }

    if (count == 0) {
        ChainHeader genesisHeader(header, true, 0, header.getWork());

        sql.str("");
        sql << "INSERT INTO `block_headers` (`hash`, `in_best_chain`, `height`, `chain_work`, `version`, `prev_block_hash`, `merkle_root`, `timestamp`, `bits`, `nonce`)"
            << " VALUES ('"
            << genesisHeaderHash.getHex() << "',1,0,'"
            << genesisHeader.chainWork.getDec() << "',"
            << genesisHeader.version << ",'"
            << genesisHeader.prevBlockHash.getHex() << "','"
            << genesisHeader.merkleRoot.getHex() << "',"
            << genesisHeader.timestamp << ","
            << genesisHeader.bits << ","
            << genesisHeader.nonce << ")";
        db.query(sql.str());
        sqliteTx.commit();

        notifyInsert(genesisHeader);
        notifyAddBestChain(genesisHeader);
    }
}
Example #2
0
void BlockHeader::fromCoinClasses(const Coin::CoinBlockHeader& blockheader, uint32_t height)
{
    hash_ = blockheader.getHashLittleEndian();
    height_ = height;
    version_ = blockheader.version;
    prevhash_ = blockheader.prevBlockHash;
    merkleroot_ = blockheader.merkleRoot;
    timestamp_ = blockheader.timestamp;
    bits_ = blockheader.bits;
    nonce_ = blockheader.nonce;
}
Example #3
0
void BlockHeader::fromCoinCore(const Coin::CoinBlockHeader& blockheader, uint32_t height)
{
    hash_ = blockheader.hash();
    height_ = height;
    version_ = blockheader.version();
    prevhash_ = blockheader.prevBlockHash();
    merkleroot_ = blockheader.merkleRoot();
    timestamp_ = blockheader.timestamp();
    bits_ = blockheader.bits();
    nonce_ = blockheader.nonce();
}
Example #4
0
bool CoinQBlockTreeMem::insertHeader(const Coin::CoinBlockHeader& header, bool bCheckProofOfWork, bool bReplaceTip)
{
    if (mHeaderHashMap.size() == 0) throw std::runtime_error("No genesis block.");

    uchar_vector headerHash = header.hash();
    if (hasHeader(headerHash)) return false;

    header_hash_map_t::iterator it = mHeaderHashMap.find(header.prevBlockHash());
    if (it == mHeaderHashMap.end()) throw std::runtime_error("Parent not found.");

    ChainHeader& parent = it->second;

    // TODO: Check version, compute work required.

    // Check timestamp
/*    if (bCheckTimestamp && header.timestamp > time(NULL) + 2 * 60 * 60) {
        throw std::runtime_error("Timestamp too far in the future.");
    }*/

    // Check proof of work
    if (bCheckProofOfWork && BigInt(header.getPOWHashLittleEndian()) > header.getTarget()) throw std::runtime_error("Header hash is too big.");

    ChainHeader& chainHeader = mHeaderHashMap[headerHash] = header;
    chainHeader.height = parent.height + 1;
    chainHeader.chainWork = parent.chainWork + chainHeader.getWork();
    parent.childHashes.insert(headerHash);
    notifyInsert(chainHeader);

    if ((bReplaceTip && chainHeader.chainWork >= mTotalWork) || chainHeader.chainWork > mTotalWork)
    {
        setBestChain(chainHeader);
    }

    bFlushed = false;
    return true;
}
Example #5
0
void CoinQBlockTreeMem::setGenesisBlock(const Coin::CoinBlockHeader& header)
{
    if (mHeaderHashMap.size() != 0) throw std::runtime_error("Tree is not empty.");

    bFlushed = false;
    uchar_vector hash = header.hash();
    ChainHeader& genesisHeader = mHeaderHashMap[hash] = header;
    mHeaderHeightMap[0] = &genesisHeader;
    genesisHeader.height = 0;
    genesisHeader.inBestChain = true;
    genesisHeader.chainWork = genesisHeader.getWork();
    mBestHeight = 0;
    mTotalWork = genesisHeader.chainWork;
    pHead = &genesisHeader;
    notifyInsert(header);
    notifyAddBestChain(header);
}
Example #6
0
void CoinQBlockTreeMem::loadFromFile(const std::string& filename, bool bCheckProofOfWork, CoinQBlockTreeMem::callback_t callback)
{
    boost::filesystem::path p(filename);
    if (!boost::filesystem::exists(p)) throw BlockTreeFileNotFoundException();

    if (!boost::filesystem::is_regular_file(p)) throw BlockTreeInvalidFileTypeException();

    const unsigned int RECORD_SIZE = MIN_COIN_BLOCK_HEADER_SIZE + 4;
    if (boost::filesystem::file_size(p) % RECORD_SIZE != 0) throw BlockTreeInvalidFileLengthException();

#ifndef _WIN32
    std::ifstream fs(p.native(), std::ios::binary);
#else
    std::ifstream fs(filename, std::ios::binary);
#endif
    if (!fs.good()) throw BlockTreeFailedToOpenFileForReadException();

    clear();
    uchar_vector headerBytes;
    uchar_vector hash;
    Coin::CoinBlockHeader header;

    unsigned int count = 0;

    char buf[RECORD_SIZE * 64];
    while (fs)
    {
        fs.read(buf, RECORD_SIZE * 64);
        if (fs.bad()) throw BlockTreeFileReadFailureException();

        unsigned int nbytesread = fs.gcount();
        unsigned int pos = 0;
        for (; pos <= nbytesread - RECORD_SIZE; pos += RECORD_SIZE)
        {
            headerBytes.assign((unsigned char*)&buf[pos], (unsigned char*)&buf[pos + MIN_COIN_BLOCK_HEADER_SIZE]);
            header.setSerialized(headerBytes);
            hash = header.hash();
            if (memcmp(&buf[pos + MIN_COIN_BLOCK_HEADER_SIZE], &hash[0], 4)) throw BlockTreeChecksumErrorException();

            try
            {
                if (mBestHeight >= 0)
                {
                    insertHeader(header, bCheckProofOfWork);
                    if (count % 10000 == 0)
                    {
                        if (callback && !callback(*this)) throw BlockTreeLoadInterruptedException();
                        LOGGER(debug) << "CoinQBlockTreeMem::loadFromFile() - header hash: " << header.hash().getHex() << " height: " << count << std::endl;
                    }
                    count++;
                }
                else
                { 
                    setGenesisBlock(header);
                    if (callback && !callback(*this)) throw BlockTreeLoadInterruptedException();
                    LOGGER(debug) << "CoinQBlockTreeMem::loadFromFile() - genesis hash: " << header.hash().getHex() << std::endl;
                    count++;
                }
            }
            catch (const BlockTreeException& e)
            {
                throw e;
            }
            catch (const std::exception& e)
            {
                throw std::runtime_error(std::string("Block ") + hash.getHex() + ": " + e.what());
            }
        }

        if (pos != nbytesread) throw BlockTreeUnexpectedEndOfFileException();
    }

    if (callback) callback(*this); // No need to interrupt since we're done.
}