<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';

static const char DB_BEST_BLOCK = 'B';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';

void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair(DB_COINS, hash));
    else
        batch.Write(make_pair(DB_COINS, hash), coins);
}

void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
    batch.Write(DB_BEST_BLOCK, hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair(DB_COINS, txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair(DB_COINS, txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read(DB_BEST_BLOCK, hashBestChain))
        return uint256(0);
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CLevelDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (hashBlock != uint256(0))
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
    if (!Read('S', salt)) {
        salt = GetRandHash();
        Write('S', salt);
    }
}

bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
    return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
}

bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
    return Write(make_pair('f', nFile), info);
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair(DB_BLOCK_FILES, nFile), info);
}

bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
    return Write('l', nFile);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write(DB_REINDEX_FLAG, '1');
    else
        return Erase(DB_REINDEX_FLAG);
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists(DB_REINDEX_FLAG);
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read(DB_LAST_BLOCK, nFile);
}

bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
    pcursor->SeekToFirst();

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = GetBestBlock();
    ss << stats.hashBlock;
    CAmount nTotalAmount = 0;
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == DB_COINS) {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CCoins coins;
                ssValue >> coins;
                uint256 txhash;
                ssKey >> txhash;
                ss << txhash;
                ss << VARINT(coins.nVersion);
                ss << (coins.fCoinBase ? 'c' : 'n');
                ss << VARINT(coins.nHeight);
                stats.nTransactions++;
                for (unsigned int i=0; i<coins.vout.size(); i++) {
                    const CTxOut &out = coins.vout[i];
                    if (!out.IsNull()) {
                        stats.nTransactionOutputs++;
                        ss << VARINT(i+1);
                        ss << out;
                        nTotalAmount += out.nValue;
                    }
                }
                stats.nSerializedSize += 32 + slValue.size();
                ss << VARINT(0);
            }
            pcursor->Next();
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }
    stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
    stats.hashSerialized = ss.GetHash();
    stats.nTotalAmount = nTotalAmount;
    return true;
}

bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
    CLevelDBBatch batch;
    for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
    }
    batch.Write(DB_LAST_BLOCK, nLastFile);
    for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
    }
    return WriteBatch(batch, true);
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair(DB_TXINDEX, txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::ReadAddrIndex(uint160 addrid, std::vector<CExtDiskTxPos> &list) {
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
    uint64_t lookupid;
    {
        CHashWriter ss(SER_GETHASH, 0);
        ss << salt;
        ss << addrid;
        lookupid = ss.GetHash().GetLow64();
    }
    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair('a', lookupid);
    pcursor->Seek(ssKeySet.str());

    while (pcursor->Valid()) {
        std::pair<std::pair<char, uint64_t>, CExtDiskTxPos> key;
        leveldb::Slice slKey = pcursor->key();
        try {
            CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
            ssKey >> key;
        } catch(std::exception &e) {
            break;
        }
        if (key.first.first == 'a' && key.first.second == lookupid) {
            list.push_back(key.second);
        } else {
            break;
        }
        pcursor->Next();
    }
    return true;
}

bool CBlockTreeDB::AddAddrIndex(const std::vector<std::pair<uint160, CExtDiskTxPos> > &list) {
    unsigned char foo[0];
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint160, CExtDiskTxPos> >::const_iterator it=list.begin(); it!=list.end(); it++) {
        CHashWriter ss(SER_GETHASH, 0);
        ss << salt;
        ss << it->first;
        batch.Write(make_pair(make_pair('a', ss.GetHash().GetLow64()), it->second), FLATDATA(foo));
    }
    return WriteBatch(batch, true);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair(DB_FLAG, name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts()
{
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());

    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
    pcursor->Seek(ssKeySet.str());

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == DB_BLOCK_INDEX) {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CDiskBlockIndex diskindex;
                ssValue >> diskindex;

                // Construct block index object
                CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;

                if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
                    return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                break; // if shutdown requested or finished loading block index
            }
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }

    return true;
}
<commit_msg>remove code added from cherry-pikcing from bitcoin master<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';

static const char DB_BEST_BLOCK = 'B';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';

void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair(DB_COINS, hash));
    else
        batch.Write(make_pair(DB_COINS, hash), coins);
}

void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
    batch.Write(DB_BEST_BLOCK, hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair(DB_COINS, txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair(DB_COINS, txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read(DB_BEST_BLOCK, hashBestChain))
        return uint256(0);
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CLevelDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (hashBlock != uint256(0))
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
    if (!Read('S', salt)) {
        salt = GetRandHash();
        Write('S', salt);
    }
}

bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
    return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
}

bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
    return Write(make_pair('f', nFile), info);
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair(DB_BLOCK_FILES, nFile), info);
}

bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
    return Write('l', nFile);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write(DB_REINDEX_FLAG, '1');
    else
        return Erase(DB_REINDEX_FLAG);
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists(DB_REINDEX_FLAG);
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read(DB_LAST_BLOCK, nFile);
}

bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
    pcursor->SeekToFirst();

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = GetBestBlock();
    ss << stats.hashBlock;
    CAmount nTotalAmount = 0;
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == DB_COINS) {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CCoins coins;
                ssValue >> coins;
                uint256 txhash;
                ssKey >> txhash;
                ss << txhash;
                ss << VARINT(coins.nVersion);
                ss << (coins.fCoinBase ? 'c' : 'n');
                ss << VARINT(coins.nHeight);
                stats.nTransactions++;
                for (unsigned int i=0; i<coins.vout.size(); i++) {
                    const CTxOut &out = coins.vout[i];
                    if (!out.IsNull()) {
                        stats.nTransactionOutputs++;
                        ss << VARINT(i+1);
                        ss << out;
                        nTotalAmount += out.nValue;
                    }
                }
                stats.nSerializedSize += 32 + slValue.size();
                ss << VARINT(0);
            }
            pcursor->Next();
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }
    stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
    stats.hashSerialized = ss.GetHash();
    stats.nTotalAmount = nTotalAmount;
    return true;
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair(DB_TXINDEX, txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::ReadAddrIndex(uint160 addrid, std::vector<CExtDiskTxPos> &list) {
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
    uint64_t lookupid;
    {
        CHashWriter ss(SER_GETHASH, 0);
        ss << salt;
        ss << addrid;
        lookupid = ss.GetHash().GetLow64();
    }
    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair('a', lookupid);
    pcursor->Seek(ssKeySet.str());

    while (pcursor->Valid()) {
        std::pair<std::pair<char, uint64_t>, CExtDiskTxPos> key;
        leveldb::Slice slKey = pcursor->key();
        try {
            CDataStream ssKey(slKey.data(), slKey.data() + slKey.size(), SER_DISK, CLIENT_VERSION);
            ssKey >> key;
        } catch(std::exception &e) {
            break;
        }
        if (key.first.first == 'a' && key.first.second == lookupid) {
            list.push_back(key.second);
        } else {
            break;
        }
        pcursor->Next();
    }
    return true;
}

bool CBlockTreeDB::AddAddrIndex(const std::vector<std::pair<uint160, CExtDiskTxPos> > &list) {
    unsigned char foo[0];
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint160, CExtDiskTxPos> >::const_iterator it=list.begin(); it!=list.end(); it++) {
        CHashWriter ss(SER_GETHASH, 0);
        ss << salt;
        ss << it->first;
        batch.Write(make_pair(make_pair('a', ss.GetHash().GetLow64()), it->second), FLATDATA(foo));
    }
    return WriteBatch(batch, true);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair(DB_FLAG, name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts()
{
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());

    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair(DB_BLOCK_INDEX, uint256());
    pcursor->Seek(ssKeySet.str());

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == DB_BLOCK_INDEX) {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CDiskBlockIndex diskindex;
                ssValue >> diskindex;

                // Construct block index object
                CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;

                if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
                    return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                break; // if shutdown requested or finished loading block index
            }
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }

    return true;
}
<|endoftext|>


<commit_before>/* Copyright 2009 Juan González de Benito.
 * This source comes from the XtreemFS project. It is licensed under the GPLv2
 * (see COPYING for terms and conditions).
 */

#include "xtreemfs/main.h"
using namespace xtreemfs;

#include "vivaldi_node.h"

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <cstring>

#include <typeinfo>

#ifdef _WIN32
YIELD::platform::CountingSemaphore YIELD::Main::pause_semaphore;
#endif

/*
 * Minimum recalculation period.
 *
 * The recalculation period is randomly determined and is always included
 * between the minimum and the maximum period.
 */
#define MIN_RECALCULATION_IN_MS 1000 * 270

/*
 * Maximum recalculation period.
 *
 * The recalculation period is randomly determined and is always included
 * between the minimum and the maximum period.
 */
#define MAX_RECALCULATION_IN_MS 1000 * 330

/*
 * Number of times the node recalculates its position before updating
 * its list of existent OSDs.
 */
#define ITERATIONS_BEFORE_UPDATING 24

/*
 * Number of retries sent before accepting a high RTT.
 */
#define MAX_RETRIES_FOR_A_REQUEST 2

//#define MAX_REQUEST_TIMEOUT_IN_NS 1000000000ul * 120ul

#ifndef _WIN32
  #define SPRINTF_VIV(buff,size,format,...) \
          snprintf(buff,size,format,__VA_ARGS__)
#else
  #define SPRINTF_VIV(buff,size,format,...) \
          sprintf_s(buff,size,format,__VA_ARGS__)
#endif

namespace xtfs_vivaldi
{
  class Main : public xtreemfs::Main, public YIELD::platform::Thread
  {
  public:
    Main()
      : xtreemfs::Main( "xtfs_vivaldi", "start the XtreemFS Vivaldi service ",
                        "<dir host>[:port] <path to Vivaldi coordinates output file>" )
    {
      std::srand( static_cast<unsigned int>( std::time( NULL ) ) );
    }

  private:
    auto_DIRProxy dir_proxy;
    YIELD::platform::Path vivaldi_coordinates_file_path;

    // YIELD::Main
    int _main( int, char** )
    {
      YIELD::platform::Thread::start();

      YIELD::Main::pause();

      return 0;
    }

    void parseFiles( int file_count, char** files )
    {
      if ( file_count >= 2 )
      {
        YIELD::ipc::auto_URI dir_uri = parseURI( files[0] );
        dir_proxy = createDIRProxy( *dir_uri );
        vivaldi_coordinates_file_path = files[1];
      }
      else
        throw YIELD::platform::Exception("must specify dir_host and a "\
                                         "Vivaldi coordinates output file path");
    }

    // YIELD::Thread
    void run()
    {

      //Initialized to (0,0) by default
      org::xtreemfs::interfaces::VivaldiCoordinates \
                                my_vivaldi_coordinates( 0, 0, 0 );

      //Try to read coordinates from local file
      YIELD::platform::auto_File vivaldi_coordinates_file =
        YIELD::platform::Volume().open( vivaldi_coordinates_file_path, O_RDONLY );

      if ( vivaldi_coordinates_file != NULL )
      {
        for ( ;; )
        {
          //x,y,local_error => 3 doubles
          yidl::runtime::StackBuffer<3*sizeof(double)> xdr_buffer;

          if (  vivaldi_coordinates_file->read( xdr_buffer.incRef() ) ==
                3*sizeof(double) )
          {

            YIELD::platform::XDRUnmarshaller xdr_unmarshaller( xdr_buffer.incRef() );
            my_vivaldi_coordinates.unmarshal( xdr_unmarshaller );

            get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                "xtfs_vivaldi:coordinates readed from file:(" <<
                my_vivaldi_coordinates.get_x_coordinate() <<
                "," << my_vivaldi_coordinates.get_y_coordinate() << ")";

          }else
          {
            break;
          }
        }
        vivaldi_coordinates_file->close();
      }else{
        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:impossible to read coordinates from file."\
            "Initializing them by default...";
      }

      VivaldiNode own_node(my_vivaldi_coordinates);

      long vivaldiIterations = 0;

      org::xtreemfs::interfaces::ServiceSet osd_services;

      std::vector<uint64_t> currentRetries;
      int retriesInARow = 0;

      org::xtreemfs::interfaces::Service *random_osd_service;

  		for ( ;; )
  		{
  			try
  			{

          //Get a list of OSDs from the DS
          if( (vivaldiIterations%ITERATIONS_BEFORE_UPDATING) == 1)
          {
            updateKnownOSDs(osd_services);
            currentRetries.clear(); /*The pending retries are discarded, because
                                    the old OSDs might not be in the new list*/
            retriesInARow = 0;
          }

  				if ( !osd_services.empty() )
  				{

            if(retriesInARow==0){
              //Choose one OSD randomly, only if there's no pending retry
              random_osd_service = &osd_services[std::rand() % osd_services.size()];
            }

  					yidl::runtime::auto_Object<org::xtreemfs::interfaces::AddressMappingSet> \
              random_osd_address_mappings =
                dir_proxy->getAddressMappingsFromUUID(random_osd_service->get_uuid());

  					//Several mappings for the same UUID
  					for ( org::xtreemfs::interfaces::AddressMappingSet::iterator \
                    random_osd_address_mapping_i = random_osd_address_mappings->begin();
                  random_osd_address_mapping_i != random_osd_address_mappings->end();
                  random_osd_address_mapping_i++ )
  					{

  						if (  (*random_osd_address_mapping_i).get_protocol() ==
                    org::xtreemfs::interfaces::ONCRPCU_SCHEME )
  						{
                auto_OSDProxy osd_proxy =
                  OSDProxy::create( ( *random_osd_address_mapping_i ).get_uri(),
                                    OSDProxy::CONCURRENCY_LEVEL_DEFAULT,
                                    get_proxy_flags(),
                                    get_log(),
                                    get_operation_timeout() );

  							org::xtreemfs::interfaces::VivaldiCoordinates random_osd_vivaldi_coordinates;

  							//Send the request and measure the RTT
                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:recalculating against " <<
                    random_osd_service->get_uuid();

  							YIELD::platform::Time start_time;

                osd_proxy->xtreemfs_ping( org::xtreemfs::interfaces::VivaldiCoordinates(),
                                          random_osd_vivaldi_coordinates );

                YIELD::platform::Time rtt( YIELD::platform::Time() - start_time );

                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:ping response received";

                //Next code is not executed if the ping request times out

                uint64_t measuredRTT = rtt.as_unix_time_ms();

                bool retried = false;
  							// Recalculate coordinates here
                if( retriesInARow < MAX_RETRIES_FOR_A_REQUEST ){
                  if( !own_node.recalculatePosition(random_osd_vivaldi_coordinates,
                                                    measuredRTT,
                                                    false) ){

                    /*The movement has been postponed because the measured RTT
                    seems to be a peak*/
                    currentRetries.push_back(measuredRTT);
                    retriesInARow++;
                    retried = true;

                  }else{

                    //The movement has been accepted
                    currentRetries.clear();
                    retriesInARow = 0;

                  }
                }else{

                  //Choose the lowest RTT
                  uint64_t lowestOne = measuredRTT;
                  for(  std::vector<uint64_t>::iterator it = currentRetries.begin();
                        it<currentRetries.end();
                        it++){

                    if( (*it) < lowestOne ){
                      lowestOne = (*it);
                    }

                  }

                  //Forcing recalculation because we've retried too many times
                  own_node.recalculatePosition( random_osd_vivaldi_coordinates,
                                                lowestOne,
                                                true);
                  currentRetries.clear();
                  retriesInARow = 0;

                  //This is just to include in the trace the definitive RTT
                  measuredRTT = lowestOne;

                }

                //Print trace
                char auxStr[256];
                SPRINTF_VIV(  auxStr,
                              256,

                              "%s:%lld(Viv:%.3f) Own:(%.3f,%.3f) lE=%.3f "\
                                                "Rem:(%.3f,%.3f) rE=%.3f %s",
                                retried?"RETRY":"RTT",
                                static_cast<long long int>(measuredRTT),
                                own_node.calculateDistance((*own_node.getCoordinates()),
                                                            random_osd_vivaldi_coordinates),
                                own_node.getCoordinates()->get_x_coordinate(),
                                own_node.getCoordinates()->get_y_coordinate(),
                                own_node.getCoordinates()->get_local_error(),
                                random_osd_vivaldi_coordinates.get_x_coordinate(),
                                random_osd_vivaldi_coordinates.get_y_coordinate(),
                                random_osd_vivaldi_coordinates.get_local_error(),
                                random_osd_service->get_uuid().data());

                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:" << auxStr;

  						}
  					}
  				}else{
            get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                "xtfs_vivaldi:no OSD available";
          }

        }catch ( std::exception& exc ){
  				get_log()->getStream( YIELD::platform::Log::LOG_ERR ) <<
              "xtfs_vivaldi: error pinging OSDs: " << exc.what() << ".";

          //TOFIX:This must be done only for timeout exceptions

          //We must avoid to keep retrying indefinitely against an OSD which is not responding
  				if(retriesInARow && (++retriesInARow >= MAX_RETRIES_FOR_A_REQUEST) ){
            //If the last retry times out all the previous retries are discarded
            currentRetries.clear();
            retriesInARow = 0;
          }
  			}

        //Store the new coordinates in a local file
        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:storing coordinates in file:(" <<
            own_node.getCoordinates()->get_x_coordinate() <<
            "," << own_node.getCoordinates()->get_y_coordinate() << ")";

  			vivaldi_coordinates_file = \
          YIELD::platform::Volume().open( vivaldi_coordinates_file_path,
                                          O_CREAT|O_TRUNC|O_WRONLY );

  			if ( vivaldi_coordinates_file != NULL )
  			{

  				YIELD::platform::XDRMarshaller xdr_marshaller;
  				own_node.getCoordinates()->marshal( xdr_marshaller );
  				vivaldi_coordinates_file->write( xdr_marshaller.get_buffer().release() );
          vivaldi_coordinates_file->close();

  			}

        //Sleep until the next iteration
        uint64_t sleep_in_ms =
            MIN_RECALCULATION_IN_MS +
                ( (static_cast<double>(std::rand())/(RAND_MAX-1)) *
                (MAX_RECALCULATION_IN_MS - MIN_RECALCULATION_IN_MS) );

        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:sleeping during " << sleep_in_ms << " ms.";

        YIELD::platform::Thread::sleep( sleep_in_ms * NS_IN_MS );

        vivaldiIterations = (vivaldiIterations+1)%LONG_MAX;

  		}
    }

    /* Retrieves a list of available OSDs from the DS
     */
    void updateKnownOSDs(org::xtreemfs::interfaces::ServiceSet &osds){

      try{

        dir_proxy->xtreemfs_service_get_by_type( \
            org::xtreemfs::interfaces::SERVICE_TYPE_OSD,
            osds );

        org::xtreemfs::interfaces::ServiceSet::iterator ss_iterator = osds.begin();

        while( ss_iterator != osds.end() ){

          if( (*ss_iterator).get_last_updated_s() == 0)
          {
            osds.erase(ss_iterator);
          }else
          {
            ss_iterator++;
          }

        }
      }catch( std::exception ex ){

        get_log()->getStream( YIELD::platform::Log::LOG_ERR ) <<
            "xtfs_vivaldi:Impossible to update known OSDs";

      }

    }
  };
};

int main( int argc, char** argv )
{
  return xtfs_vivaldi::Main().main( argc, argv );
}
<commit_msg>xtfs_vivaldi: Fixed some remaining formatting errors<commit_after>/* Copyright 2009 Juan González de Benito.
 * This source comes from the XtreemFS project. It is licensed under the GPLv2
 * (see COPYING for terms and conditions).
 */

#include "xtreemfs/main.h"
using namespace xtreemfs;

#include "vivaldi_node.h"

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <cstring>

#include <typeinfo>

#ifdef _WIN32
YIELD::platform::CountingSemaphore YIELD::Main::pause_semaphore;
#endif

/*
 * Minimum recalculation period.
 *
 * The recalculation period is randomly determined and is always included
 * between the minimum and the maximum period.
 */
#define MIN_RECALCULATION_IN_MS 1000 * 270

/*
 * Maximum recalculation period.
 *
 * The recalculation period is randomly determined and is always included
 * between the minimum and the maximum period.
 */
#define MAX_RECALCULATION_IN_MS 1000 * 330

/*
 * Number of times the node recalculates its position before updating
 * its list of existent OSDs.
 */
#define ITERATIONS_BEFORE_UPDATING 24

/*
 * Number of retries sent before accepting a high RTT.
 */
#define MAX_RETRIES_FOR_A_REQUEST 2

//#define MAX_REQUEST_TIMEOUT_IN_NS 1000000000ul * 120ul

#ifndef _WIN32
  #define SPRINTF_VIV(buff,size,format,...) \
          snprintf(buff,size,format,__VA_ARGS__)
#else
  #define SPRINTF_VIV(buff,size,format,...) \
          sprintf_s(buff,size,format,__VA_ARGS__)
#endif

namespace xtfs_vivaldi
{
  class Main : public xtreemfs::Main, public YIELD::platform::Thread
  {
  public:
    Main()
      : xtreemfs::Main( "xtfs_vivaldi", "start the XtreemFS Vivaldi service ",
                        "<dir host>[:port] <path to Vivaldi coordinates output file>" )
    {
      std::srand( static_cast<unsigned int>( std::time( NULL ) ) );
    }

  private:
    auto_DIRProxy dir_proxy;
    YIELD::platform::Path vivaldi_coordinates_file_path;

    // YIELD::Main
    int _main( int, char** )
    {
      YIELD::platform::Thread::start();

      YIELD::Main::pause();

      return 0;
    }

    void parseFiles( int file_count, char** files )
    {
      if ( file_count >= 2 )
      {
        YIELD::ipc::auto_URI dir_uri = parseURI( files[0] );
        dir_proxy = createDIRProxy( *dir_uri );
        vivaldi_coordinates_file_path = files[1];
      }
      else
        throw YIELD::platform::Exception("must specify dir_host and a "\
                                         "Vivaldi coordinates output file path");
    }

    // YIELD::Thread
    void run()
    {

      //Initialized to (0,0) by default
      org::xtreemfs::interfaces::VivaldiCoordinates \
                                my_vivaldi_coordinates( 0, 0, 0 );

      //Try to read coordinates from local file
      YIELD::platform::auto_File vivaldi_coordinates_file =
        YIELD::platform::Volume().open( vivaldi_coordinates_file_path, O_RDONLY );

      if ( vivaldi_coordinates_file != NULL )
      {
        for ( ;; )
        {
          //x,y,local_error => 3 doubles
          yidl::runtime::StackBuffer<3*sizeof(double)> xdr_buffer;

          if (  vivaldi_coordinates_file->read( xdr_buffer.incRef() ) ==
                3*sizeof(double) )
          {

            YIELD::platform::XDRUnmarshaller xdr_unmarshaller( xdr_buffer.incRef() );
            my_vivaldi_coordinates.unmarshal( xdr_unmarshaller );

            get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                "xtfs_vivaldi:coordinates readed from file:(" <<
                my_vivaldi_coordinates.get_x_coordinate() <<
                "," << my_vivaldi_coordinates.get_y_coordinate() << ")";

          }else
          {
            break;
          }
        }
        vivaldi_coordinates_file->close();
      }else{
        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:impossible to read coordinates from file."\
            "Initializing them by default...";
      }

      VivaldiNode own_node(my_vivaldi_coordinates);

      long vivaldiIterations = 0;

      org::xtreemfs::interfaces::ServiceSet osd_services;

      std::vector<uint64_t> currentRetries;
      int retriesInARow = 0;

      org::xtreemfs::interfaces::Service *random_osd_service;

      for ( ;; )
      {
        try
        {

          //Get a list of OSDs from the DS
          if( (vivaldiIterations%ITERATIONS_BEFORE_UPDATING) == 1)
          {
            updateKnownOSDs(osd_services);
            currentRetries.clear(); /*The pending retries are discarded, because
                                    the old OSDs might not be in the new list*/
            retriesInARow = 0;
          }

          if ( !osd_services.empty() )
          {

            if(retriesInARow==0){
              //Choose one OSD randomly, only if there's no pending retry
              random_osd_service = &osd_services[std::rand() % osd_services.size()];
            }

            yidl::runtime::auto_Object<org::xtreemfs::interfaces::AddressMappingSet> \
              random_osd_address_mappings =
                dir_proxy->getAddressMappingsFromUUID(random_osd_service->get_uuid());

            //Several mappings for the same UUID
            for ( org::xtreemfs::interfaces::AddressMappingSet::iterator \
                  random_osd_address_mapping_i = random_osd_address_mappings->begin();
                  random_osd_address_mapping_i != random_osd_address_mappings->end();
                  random_osd_address_mapping_i++ )
              {

              if (  (*random_osd_address_mapping_i).get_protocol() ==
                    org::xtreemfs::interfaces::ONCRPCU_SCHEME )
              {
                auto_OSDProxy osd_proxy =
                  OSDProxy::create( ( *random_osd_address_mapping_i ).get_uri(),
                                    OSDProxy::CONCURRENCY_LEVEL_DEFAULT,
                                    get_proxy_flags(),
                                    get_log(),
                                    get_operation_timeout() );

                org::xtreemfs::interfaces::VivaldiCoordinates random_osd_vivaldi_coordinates;

                //Send the request and measure the RTT
                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:recalculating against " <<
                    random_osd_service->get_uuid();

                YIELD::platform::Time start_time;

                osd_proxy->xtreemfs_ping( org::xtreemfs::interfaces::VivaldiCoordinates(),
                                          random_osd_vivaldi_coordinates );

                YIELD::platform::Time rtt( YIELD::platform::Time() - start_time );

                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:ping response received";

                //Next code is not executed if the ping request times out

                uint64_t measuredRTT = rtt.as_unix_time_ms();

                bool retried = false;
                // Recalculate coordinates here
                if( retriesInARow < MAX_RETRIES_FOR_A_REQUEST ){
                  if( !own_node.recalculatePosition(random_osd_vivaldi_coordinates,
                                                    measuredRTT,
                                                    false) ){

                    /*The movement has been postponed because the measured RTT
                    seems to be a peak*/
                    currentRetries.push_back(measuredRTT);
                    retriesInARow++;
                    retried = true;

                  }else{

                    //The movement has been accepted
                    currentRetries.clear();
                    retriesInARow = 0;

                  }
                }else{

                  //Choose the lowest RTT
                  uint64_t lowestOne = measuredRTT;
                  for(  std::vector<uint64_t>::iterator it = currentRetries.begin();
                        it<currentRetries.end();
                        it++){

                    if( (*it) < lowestOne ){
                      lowestOne = (*it);
                    }

                  }

                  //Forcing recalculation because we've retried too many times
                  own_node.recalculatePosition( random_osd_vivaldi_coordinates,
                                                lowestOne,
                                                true);
                  currentRetries.clear();
                  retriesInARow = 0;

                  //This is just to include in the trace the definitive RTT
                  measuredRTT = lowestOne;

                }

                //Print trace
                char auxStr[256];
                SPRINTF_VIV(  auxStr,
                              256,

                              "%s:%lld(Viv:%.3f) Own:(%.3f,%.3f) lE=%.3f "\
                                                "Rem:(%.3f,%.3f) rE=%.3f %s",
                                retried?"RETRY":"RTT",
                                static_cast<long long int>(measuredRTT),
                                own_node.calculateDistance((*own_node.getCoordinates()),
                                                            random_osd_vivaldi_coordinates),
                                own_node.getCoordinates()->get_x_coordinate(),
                                own_node.getCoordinates()->get_y_coordinate(),
                                own_node.getCoordinates()->get_local_error(),
                                random_osd_vivaldi_coordinates.get_x_coordinate(),
                                random_osd_vivaldi_coordinates.get_y_coordinate(),
                                random_osd_vivaldi_coordinates.get_local_error(),
                                random_osd_service->get_uuid().data());

                get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                    "xtfs_vivaldi:" << auxStr;

                }
              }

            }else{

              get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
                  "xtfs_vivaldi:no OSD available";
          }

        }catch ( std::exception& exc ){
          get_log()->getStream( YIELD::platform::Log::LOG_ERR ) <<
              "xtfs_vivaldi: error pinging OSDs: " << exc.what() << ".";

          //TOFIX:This must be done only for timeout exceptions

          //We must avoid to keep retrying indefinitely against an OSD which is not responding
          if(retriesInARow && (++retriesInARow >= MAX_RETRIES_FOR_A_REQUEST) ){
            //If the last retry times out all the previous retries are discarded
            currentRetries.clear();
            retriesInARow = 0;
          }
        }

        //Store the new coordinates in a local file
        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:storing coordinates in file:(" <<
            own_node.getCoordinates()->get_x_coordinate() <<
            "," << own_node.getCoordinates()->get_y_coordinate() << ")";

        vivaldi_coordinates_file = \
          YIELD::platform::Volume().open( vivaldi_coordinates_file_path,
                                          O_CREAT|O_TRUNC|O_WRONLY );

        if ( vivaldi_coordinates_file != NULL )
        {

          YIELD::platform::XDRMarshaller xdr_marshaller;
          own_node.getCoordinates()->marshal( xdr_marshaller );
              vivaldi_coordinates_file->write( xdr_marshaller.get_buffer().release() );
          vivaldi_coordinates_file->close();

        }

        //Sleep until the next iteration
        uint64_t sleep_in_ms =
            MIN_RECALCULATION_IN_MS +
                ( (static_cast<double>(std::rand())/(RAND_MAX-1)) *
                (MAX_RECALCULATION_IN_MS - MIN_RECALCULATION_IN_MS) );

        get_log()->getStream( YIELD::platform::Log::LOG_DEBUG ) <<
            "xtfs_vivaldi:sleeping during " << sleep_in_ms << " ms.";

        YIELD::platform::Thread::sleep( sleep_in_ms * NS_IN_MS );

        vivaldiIterations = (vivaldiIterations+1)%LONG_MAX;

      }
    }

    /* Retrieves a list of available OSDs from the DS
     */
    void updateKnownOSDs(org::xtreemfs::interfaces::ServiceSet &osds){

      try{

        dir_proxy->xtreemfs_service_get_by_type( \
            org::xtreemfs::interfaces::SERVICE_TYPE_OSD,
            osds );

        org::xtreemfs::interfaces::ServiceSet::iterator ss_iterator = osds.begin();

        while( ss_iterator != osds.end() ){

          if( (*ss_iterator).get_last_updated_s() == 0)
          {
            osds.erase(ss_iterator);
          }else
          {
            ss_iterator++;
          }

        }
      }catch( std::exception ex ){

        get_log()->getStream( YIELD::platform::Log::LOG_ERR ) <<
            "xtfs_vivaldi:Impossible to update known OSDs";

      }

    }
  };
};

int main( int argc, char** argv )
{
  return xtfs_vivaldi::Main().main( argc, argv );
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair('c', hash));
    else
        batch.Write(make_pair('c', hash), coins);
}

void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
    batch.Write('B', hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair('c', txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair('c', txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read('B', hashBestChain))
        return uint256(0);
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CLevelDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (hashBlock != uint256(0))
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}

bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
    return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
}

bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
    return Write(make_pair('f', nFile), info);
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair('f', nFile), info);
}

bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
    return Write('l', nFile);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write('R', '1');
    else
        return Erase('R');
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists('R');
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read('l', nFile);
}

bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
    pcursor->SeekToFirst();

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = GetBestBlock();
    ss << stats.hashBlock;
    CAmount nTotalAmount = 0;
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == 'c') {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CCoins coins;
                ssValue >> coins;
                uint256 txhash;
                ssKey >> txhash;
                ss << txhash;
                ss << VARINT(coins.nVersion);
                ss << (coins.fCoinBase ? 'c' : 'n');
                ss << VARINT(coins.nHeight);
                stats.nTransactions++;
                for (unsigned int i=0; i<coins.vout.size(); i++) {
                    const CTxOut &out = coins.vout[i];
                    if (!out.IsNull()) {
                        stats.nTransactionOutputs++;
                        ss << VARINT(i+1);
                        ss << out;
                        nTotalAmount += out.nValue;
                    }
                }
                stats.nSerializedSize += 32 + slValue.size();
                ss << VARINT(0);
            }
            pcursor->Next();
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }
    stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
    stats.hashSerialized = ss.GetHash();
    stats.nTotalAmount = nTotalAmount;
    return true;
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair('t', txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair('t', it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair('F', name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair('F', name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts()
{
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());

    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair('b', uint256(0));
    pcursor->Seek(ssKeySet.str());

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == 'b') {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CDiskBlockIndex diskindex;
                ssValue >> diskindex;

                // Construct block index object
                CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;

                if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
                    return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                break; // if shutdown requested or finished loading block index
            }
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }

    return true;
}
<commit_msg>change PoW checking for block index to properly use PoW hash rather than sha256 hash<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

void static BatchWriteCoins(CLevelDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair('c', hash));
    else
        batch.Write(make_pair('c', hash), coins);
}

void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
    batch.Write('B', hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair('c', txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair('c', txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read('B', hashBestChain))
        return uint256(0);
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CLevelDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (hashBlock != uint256(0))
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
}

bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
{
    return Write(make_pair('b', blockindex.GetBlockHash()), blockindex);
}

bool CBlockTreeDB::WriteBlockFileInfo(int nFile, const CBlockFileInfo &info) {
    return Write(make_pair('f', nFile), info);
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair('f', nFile), info);
}

bool CBlockTreeDB::WriteLastBlockFile(int nFile) {
    return Write('l', nFile);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write('R', '1');
    else
        return Erase('R');
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists('R');
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read('l', nFile);
}

bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    boost::scoped_ptr<leveldb::Iterator> pcursor(const_cast<CLevelDBWrapper*>(&db)->NewIterator());
    pcursor->SeekToFirst();

    CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
    stats.hashBlock = GetBestBlock();
    ss << stats.hashBlock;
    CAmount nTotalAmount = 0;
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == 'c') {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CCoins coins;
                ssValue >> coins;
                uint256 txhash;
                ssKey >> txhash;
                ss << txhash;
                ss << VARINT(coins.nVersion);
                ss << (coins.fCoinBase ? 'c' : 'n');
                ss << VARINT(coins.nHeight);
                stats.nTransactions++;
                for (unsigned int i=0; i<coins.vout.size(); i++) {
                    const CTxOut &out = coins.vout[i];
                    if (!out.IsNull()) {
                        stats.nTransactionOutputs++;
                        ss << VARINT(i+1);
                        ss << out;
                        nTotalAmount += out.nValue;
                    }
                }
                stats.nSerializedSize += 32 + slValue.size();
                ss << VARINT(0);
            }
            pcursor->Next();
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }
    stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
    stats.hashSerialized = ss.GetHash();
    stats.nTotalAmount = nTotalAmount;
    return true;
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair('t', txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CLevelDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair('t', it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair('F', name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair('F', name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts()
{
    boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());

    CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
    ssKeySet << make_pair('b', uint256(0));
    pcursor->Seek(ssKeySet.str());

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        try {
            leveldb::Slice slKey = pcursor->key();
            CDataStream ssKey(slKey.data(), slKey.data()+slKey.size(), SER_DISK, CLIENT_VERSION);
            char chType;
            ssKey >> chType;
            if (chType == 'b') {
                leveldb::Slice slValue = pcursor->value();
                CDataStream ssValue(slValue.data(), slValue.data()+slValue.size(), SER_DISK, CLIENT_VERSION);
                CDiskBlockIndex diskindex;
                ssValue >> diskindex;

                // Construct block index object
                CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = InsertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;

                if (!CheckProofOfWork(pindexNew->GetBlockHeader().GetPoWHash(), pindexNew->nBits))
                    return error("LoadBlockIndex() : CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                break; // if shutdown requested or finished loading block index
            }
        } catch (std::exception &e) {
            return error("%s : Deserialize or I/O error - %s", __func__, e.what());
        }
    }

    return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "chainparams.h"
#include "hash.h"
#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';

static const char DB_BEST_BLOCK = 'B';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';

void static BatchWriteCoins(CDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair(DB_COINS, hash));
    else
        batch.Write(make_pair(DB_COINS, hash), coins);
}

void static BatchWriteHashBestChain(CDBBatch &batch, const uint256 &hash) {
    batch.Write(DB_BEST_BLOCK, hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool &isObfuscated, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, isObfuscated, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair(DB_COINS, txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair(DB_COINS, txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read(DB_BEST_BLOCK, hashBestChain))
        return uint256();
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (!hashBlock.IsNull())
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool &isObfuscated, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, isObfuscated, fMemory, fWipe) {
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair(DB_BLOCK_FILES, nFile), info);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write(DB_REINDEX_FLAG, '1');
    else
        return Erase(DB_REINDEX_FLAG);
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists(DB_REINDEX_FLAG);
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read(DB_LAST_BLOCK, nFile);
}

CCoinsViewCursor *CCoinsViewDB::Cursor() const
{
    CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    i->pcursor->Seek(DB_COINS);
    // Cache key of first record
    i->pcursor->GetKey(i->keyTmp);
    return i;
}

bool CCoinsViewDBCursor::GetKey(uint256 &key) const
{
    // Return cached key
    if (keyTmp.first == DB_COINS) {
        key = keyTmp.second;
        return true;
    }
    return false;
}

bool CCoinsViewDBCursor::GetValue(CCoins &coins) const
{
    return pcursor->GetValue(coins);
}

unsigned int CCoinsViewDBCursor::GetValueSize() const
{
    return pcursor->GetValueSize();
}

bool CCoinsViewDBCursor::Valid() const
{
    return keyTmp.first == DB_COINS;
}

void CCoinsViewDBCursor::Next()
{
    pcursor->Next();
    if (pcursor->Valid()) {
        bool ok = pcursor->GetKey(keyTmp);
        assert(ok); // If GetKey fails here something must be wrong with underlying database, we cannot handle that here
    } else {
        keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
    }
}

bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
    CDBBatch batch;
    for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
    }
    batch.Write(DB_LAST_BLOCK, nLastFile);
    for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
    }
    return WriteBatch(batch, true);
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair(DB_TXINDEX, txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair(DB_FLAG, name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
    std::unique_ptr<CDBIterator> pcursor(NewIterator());

    pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        std::pair<char, uint256> key;
        if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
            CDiskBlockIndex diskindex;
            if (pcursor->GetValue(diskindex)) {
                // Construct block index object
                CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = insertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;
                pindexNew->nSerialVersion = diskindex.nSerialVersion;
                pindexNew->nMaxBlockSize  = diskindex.nMaxBlockSize;
                pindexNew->nMaxBlockSizeVote = diskindex.nMaxBlockSizeVote;

                if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
                    return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                return error("LoadBlockIndex() : failed to read value");
            }
        } else {
            break;
        }
    }

    return true;
}
<commit_msg>txdb: Fix assert crash in new UTXO set cursor<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "txdb.h"

#include "chainparams.h"
#include "hash.h"
#include "pow.h"
#include "uint256.h"

#include <stdint.h>

#include <boost/thread.hpp>

using namespace std;

static const char DB_COINS = 'c';
static const char DB_BLOCK_FILES = 'f';
static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';

static const char DB_BEST_BLOCK = 'B';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';

void static BatchWriteCoins(CDBBatch &batch, const uint256 &hash, const CCoins &coins) {
    if (coins.IsPruned())
        batch.Erase(make_pair(DB_COINS, hash));
    else
        batch.Write(make_pair(DB_COINS, hash), coins);
}

void static BatchWriteHashBestChain(CDBBatch &batch, const uint256 &hash) {
    batch.Write(DB_BEST_BLOCK, hash);
}

CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool &isObfuscated, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, isObfuscated, fMemory, fWipe) {
}

bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
    return db.Read(make_pair(DB_COINS, txid), coins);
}

bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
    return db.Exists(make_pair(DB_COINS, txid));
}

uint256 CCoinsViewDB::GetBestBlock() const {
    uint256 hashBestChain;
    if (!db.Read(DB_BEST_BLOCK, hashBestChain))
        return uint256();
    return hashBestChain;
}

bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
    CDBBatch batch;
    size_t count = 0;
    size_t changed = 0;
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) {
            BatchWriteCoins(batch, it->first, it->second.coins);
            changed++;
        }
        count++;
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    if (!hashBlock.IsNull())
        BatchWriteHashBestChain(batch, hashBlock);

    LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
    return db.WriteBatch(batch);
}

CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool &isObfuscated, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, isObfuscated, fMemory, fWipe) {
}

bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
    return Read(make_pair(DB_BLOCK_FILES, nFile), info);
}

bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
    if (fReindexing)
        return Write(DB_REINDEX_FLAG, '1');
    else
        return Erase(DB_REINDEX_FLAG);
}

bool CBlockTreeDB::ReadReindexing(bool &fReindexing) {
    fReindexing = Exists(DB_REINDEX_FLAG);
    return true;
}

bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
    return Read(DB_LAST_BLOCK, nFile);
}

CCoinsViewCursor *CCoinsViewDB::Cursor() const
{
    CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper*>(&db)->NewIterator(), GetBestBlock());
    /* It seems that there are no "const iterators" for LevelDB.  Since we
       only need read operations on it, use a const-cast to get around
       that restriction.  */
    i->pcursor->Seek(DB_COINS);
    // Cache key of first record
    i->pcursor->GetKey(i->keyTmp);
    return i;
}

bool CCoinsViewDBCursor::GetKey(uint256 &key) const
{
    // Return cached key
    if (keyTmp.first == DB_COINS) {
        key = keyTmp.second;
        return true;
    }
    return false;
}

bool CCoinsViewDBCursor::GetValue(CCoins &coins) const
{
    return pcursor->GetValue(coins);
}

unsigned int CCoinsViewDBCursor::GetValueSize() const
{
    return pcursor->GetValueSize();
}

bool CCoinsViewDBCursor::Valid() const
{
    return keyTmp.first == DB_COINS;
}

void CCoinsViewDBCursor::Next()
{
    pcursor->Next();
    if (!pcursor->Valid() || !pcursor->GetKey(keyTmp))
        keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
}

bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
    CDBBatch batch;
    for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_FILES, it->first), *it->second);
    }
    batch.Write(DB_LAST_BLOCK, nLastFile);
    for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
        batch.Write(make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
    }
    return WriteBatch(batch, true);
}

bool CBlockTreeDB::ReadTxIndex(const uint256 &txid, CDiskTxPos &pos) {
    return Read(make_pair(DB_TXINDEX, txid), pos);
}

bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >&vect) {
    CDBBatch batch;
    for (std::vector<std::pair<uint256,CDiskTxPos> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
        batch.Write(make_pair(DB_TXINDEX, it->first), it->second);
    return WriteBatch(batch);
}

bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
    return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
}

bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
    char ch;
    if (!Read(std::make_pair(DB_FLAG, name), ch))
        return false;
    fValue = ch == '1';
    return true;
}

bool CBlockTreeDB::LoadBlockIndexGuts(boost::function<CBlockIndex*(const uint256&)> insertBlockIndex)
{
    std::unique_ptr<CDBIterator> pcursor(NewIterator());

    pcursor->Seek(make_pair(DB_BLOCK_INDEX, uint256()));

    // Load mapBlockIndex
    while (pcursor->Valid()) {
        boost::this_thread::interruption_point();
        std::pair<char, uint256> key;
        if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
            CDiskBlockIndex diskindex;
            if (pcursor->GetValue(diskindex)) {
                // Construct block index object
                CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
                pindexNew->pprev          = insertBlockIndex(diskindex.hashPrev);
                pindexNew->nHeight        = diskindex.nHeight;
                pindexNew->nFile          = diskindex.nFile;
                pindexNew->nDataPos       = diskindex.nDataPos;
                pindexNew->nUndoPos       = diskindex.nUndoPos;
                pindexNew->nVersion       = diskindex.nVersion;
                pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
                pindexNew->nTime          = diskindex.nTime;
                pindexNew->nBits          = diskindex.nBits;
                pindexNew->nNonce         = diskindex.nNonce;
                pindexNew->nStatus        = diskindex.nStatus;
                pindexNew->nTx            = diskindex.nTx;
                pindexNew->nSerialVersion = diskindex.nSerialVersion;
                pindexNew->nMaxBlockSize  = diskindex.nMaxBlockSize;
                pindexNew->nMaxBlockSizeVote = diskindex.nMaxBlockSizeVote;

                if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus()))
                    return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString());

                pcursor->Next();
            } else {
                return error("LoadBlockIndex() : failed to read value");
            }
        } else {
            break;
        }
    }

    return true;
}
<|endoftext|>


<commit_before>#pragma once

#include <memory>
#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
#include <variant>

namespace dlvm {

using namespace dlvm;
using namespace std;

typedef uint64_t vaddr_t;
typedef uint32_t addr_t;

typedef uint32_t array_t;
typedef variant<int64_t, uint64_t, double, bool, char, addr_t> VType;
typedef variant<array_t, VType> RType;

struct ValueType;
struct ReferenceType;
template<typename Type>
struct Result;

typedef enum type_e {
    NIL,
    INTEGER,
    UINTEGER,
    FLOAT,
    BOOL,
    STRING,
    ARRAY,
    REFERENCE,
    STRUCT
} type_t;

struct ValueType {
    type_t type;
    VType Value;

    ValueType()
    { type = NIL; }

    ValueType(type_t type, VType value)
        : type{type}
        , Value{value}
    { }

    ReferenceType Box();
};

struct ReferenceType {
    type_t type;
    bool Marked = false;
    RType Value;

    ReferenceType()
    { type = NIL; }

    ReferenceType(ValueType value)
        : type{value.type}
        , Value{value.Value}
    { }

    ReferenceType(type_t type, RType value)
        : type{type}
        , Value{value}
    { }

    Result<ValueType> Unbox();
};

typedef enum ErrorCode {
    OK,
    OUT_OF_MEMORY,
    OUT_OF_BOUNDS,
    STACK_OVERFLOW,
    TYPE_ERROR,
    NULL_REFERENCE,
    INVALID_ARGUMENT,
    UNKNOWN
} ErrorCode;

template<typename Type>
struct Result {
    ErrorCode ErrCode;
    Type Value;
    string Message;

    Result(Type value, string msg, ErrorCode error_code)
        : Value{value}
        , Message{msg}
        , ErrCode{error_code}
    { }

    Result(Type value)
        : Value{value}
        , ErrCode{OK}
    { }

    Result(string msg, ErrorCode error_code)
        : Message{msg}
        , ErrCode{error_code}
    { }
};

template<typename Type>
Result<Type> OkResult(Type value);
template<typename Type>
Result<Type> TypeError(Type value);
template<typename Type>
Result<Type> ThrowError(string msg, Type value, ErrorCode error_code);
template<typename Type>
Result<Type> ThrowError(string msg, ErrorCode error_code);

/*
Result operator+ (Result lhs, Result rhs);
Result operator- (Type lhs, Type rhs);
Result operator* (Type lhs, Type rhs);
Result operator/ (Type lhs, Type rhs);
Result operator&& (Type lhs, Type rhs);
Result operator|| (Type lhs, Type rhs);
Result operator! (Type rhs);
ostream& operator<< (ostream &o, Type t);
*/
}<commit_msg>switched to 'using' instead of typedef<commit_after>#pragma once

#include <memory>
#include <cstdint>
#include <string>
#include <vector>
#include <iostream>
#include <variant>

namespace dlvm {

using namespace dlvm;
using namespace std;

using vaddr_t = uint64_t;
using addr_t = uint32_t;

using array_t = uint32_t;
using VType = variant<int64_t, uint64_t, double, bool, char, addr_t>;
using RType = variant<array_t, VType>;

struct ValueType;
struct ReferenceType;
template<typename Type>
struct Result;

typedef enum type_e {
    NIL,
    INTEGER,
    UINTEGER,
    FLOAT,
    BOOL,
    STRING,
    ARRAY,
    REFERENCE,
    STRUCT
} type_t;

struct ValueType {
    type_t type;
    VType Value;

    ValueType()
    { type = NIL; }

    ValueType(type_t type, VType value)
        : type{type}
        , Value{value}
    { }

    ReferenceType Box();
};

struct ReferenceType {
    type_t type;
    bool Marked = false;
    RType Value;

    ReferenceType()
    { type = NIL; }

    ReferenceType(ValueType value)
        : type{value.type}
        , Value{value.Value}
    { }

    ReferenceType(type_t type, RType value)
        : type{type}
        , Value{value}
    { }

    Result<ValueType> Unbox();
};

typedef enum ErrorCode {
    OK,
    OUT_OF_MEMORY,
    OUT_OF_BOUNDS,
    STACK_OVERFLOW,
    TYPE_ERROR,
    NULL_REFERENCE,
    INVALID_ARGUMENT,
    UNKNOWN
} ErrorCode;

template<typename Type>
struct Result {
    ErrorCode ErrCode;
    Type Value;
    string Message;

    Result(Type value, string msg, ErrorCode error_code)
        : Value{value}
        , Message{msg}
        , ErrCode{error_code}
    { }

    Result(Type value)
        : Value{value}
        , ErrCode{OK}
    { }

    Result(string msg, ErrorCode error_code)
        : Message{msg}
        , ErrCode{error_code}
    { }
};

template<typename Type>
Result<Type> OkResult(Type value);
template<typename Type>
Result<Type> TypeError(Type value);
template<typename Type>
Result<Type> ThrowError(string msg, Type value, ErrorCode error_code);
template<typename Type>
Result<Type> ThrowError(string msg, ErrorCode error_code);

/*
Result operator+ (Result lhs, Result rhs);
Result operator- (Type lhs, Type rhs);
Result operator* (Type lhs, Type rhs);
Result operator/ (Type lhs, Type rhs);
Result operator&& (Type lhs, Type rhs);
Result operator|| (Type lhs, Type rhs);
Result operator! (Type rhs);
ostream& operator<< (ostream &o, Type t);
*/
}<|endoftext|>


<commit_before>#include "degenerate.hpp"

//retourne les nucléotides concaténés dans l'ordre (assuré par une itération sur le vecteur nucleotides)
const string find_neighbor_motifs(  sparse_hash_map<string, pair<int, Node *>> &motifs,
                                    sparse_hash_map<char, pair<string, Node *>> &neighbor_motifs,
                                    const string &motif,
                                    unsigned int pos) {

    string neighbor_motif(motif);
    string neighbors_nuc;
    neighbors_nuc.reserve(4);
    //pour tous les nucléotides
    for (auto const &nuc : nucleotides) {
        //on remplace la (pos)ième position du motif de base par ce nucléotide
        neighbor_motif.replace(pos, 1, 1, nuc);

        //on passe au suivant si le voisin n'est pas dans la table
        auto const motif_it = motifs.find(neighbor_motif);
        if(motif_it == motifs.end())
            continue;
        motif_it->second.first = pos;
        //sinon, on insère dans la table des résultats le motif et son compte
        neighbor_motifs[nuc] = make_pair(neighbor_motif, motifs[neighbor_motif].second);
        neighbors_nuc.push_back(nuc);
    }
    return neighbors_nuc;
}

void degenerate(sparse_hash_map<string, pair<int, Node *>> &motifs,
                sparse_hash_map<string, pair<int, Node *>> &degenerated_motifs,
                const unsigned int kmer_size,
                bool rc) {

    //pour chaque position
    for (unsigned int pos = 0; pos < kmer_size; pos++) {

        //pour chaque motif dans la table
        for (auto const &motif_it : motifs) {
            //s'il n'a pas été marqué pour cette position ou si la position a déjà été dégénérée
            if(motif_it.second.first == pos || motif_it.second.first == kmer_size || !string("ACGT").find(motif_it.first[pos])) {
                continue;
            }

            sparse_hash_map<char, pair<string, Node *>> neighbor_motifs;
            neighbor_motifs.reserve(4);
            //on trouve les voisins du kmer par rapport à la position courante
            const string neighbors_nuc = find_neighbor_motifs(motifs, neighbor_motifs, motif_it.first, pos);

            if (neighbors_nuc.size() <= 1) {
                continue;
            }
            //this is where things can explode if the string is not sorted alphabetically
            auto iupacs = nucs_to_iupacs.find(neighbors_nuc);
            assert(iupacs != nucs_to_iupacs.end());

            //string that will be transformed into the degenerated motif later
            string degenerated_motif(motif_it.first);

            //TODO not required since lookup in a hashtable is O(1)
            sparse_hash_map<char, Node *> iupac_to_node;
            iupac_to_node.reserve(11);

            // pour tous les iupacs dérivant des nucléotides
            for (int degeneration_degree = 0; degeneration_degree < iupacs->second.size(); degeneration_degree++) {
                for (auto const iupac : iupacs->second[degeneration_degree]) {

                    degenerated_motif.replace(pos, 1, 1, iupac);
                    Node *current_node_ptr;

                    //checks if the node has already been created
                    auto entry_ptr = degenerated_motifs.find(degenerated_motif);
                    if(entry_ptr != degenerated_motifs.end()) {
                        current_node_ptr = entry_ptr->second.second;
                    }
                    else {
                        //node creation
                        current_node_ptr = new Node(0, 0);
                        unsigned int degenerated_motif_positive_count = 0;
                        unsigned int degenerated_motif_negative_count = 0;
                        for (auto const &nuc : iupac_to_nucs[iupac]) {
                            //add child count
                            if (degenerated_motif_positive_count > ~0 - neighbor_motifs[nuc].second->get_positive_count()) {
                                std::cerr << "Error : an overflow occurred while setting the positive count of a degenerated motif. You should consider switching to a bigger unsigned type." << endl;
                                exit(EXIT_FAILURE);
                            }
                            degenerated_motif_positive_count += neighbor_motifs[nuc].second->get_positive_count();

                            if (degenerated_motif_negative_count > ~0 - neighbor_motifs[nuc].second->get_negative_count()) {
                                std::cerr << "Error : an overflow occurred while setting the negative count of a degenerated motif. You should consider switching to a bigger unsigned type." << endl;
                                exit(EXIT_FAILURE);
                            }
                            degenerated_motif_negative_count += neighbor_motifs[nuc].second->get_negative_count();
                        }
                        current_node_ptr->set_positive_count(degenerated_motif_positive_count);
                        current_node_ptr->set_negative_count(degenerated_motif_negative_count);
                        // current_node_ptr->set_motif(degenerated_motif);
                        degenerated_motifs.emplace(make_pair(degenerated_motif, make_pair(-1, current_node_ptr)));
                        if (rc) {
                            degenerated_motifs.emplace(make_pair(reverse_complement(degenerated_motif), make_pair(kmer_size, current_node_ptr)));
                        }
                    }
                    //remembering the node that we created to be able to find them easily
                    //TODO this is not required since lookup in a hash table is O(1)
                    iupac_to_node[iupac] = current_node_ptr;

                    //adding links between nodes

                    //here we create the nodes that depends on the nucleotides first,
                    //then we create the nodes that depends on the previous one, etc.
                    if (degeneration_degree == 0) {
                        for (char nuc : iupacs_dependencies[iupac]) {

                            // std::cout << degenerated_motif  << "->" << neighbor_motifs[nuc].second->get_motif()<< ";" << endl;
                            current_node_ptr->add_successor(neighbor_motifs[nuc].second);
                            neighbor_motifs[nuc].second->add_predecessor(current_node_ptr);
                        }
                    } else {
                        for (char iupac_dependency : iupacs_dependencies[iupac]) {
                            // std::cout << degenerated_motif  << "->" << iupac_to_node[iupac_dependency]->get_motif() << ";" << endl;
                            current_node_ptr->add_successor(iupac_to_node[iupac_dependency]);
                            iupac_to_node[iupac_dependency]->add_predecessor(current_node_ptr);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>[METHOD] Changed the way motif are degenerated : now degenerated motif are only created if each of their successors is present in either file (before we could find one successor in a file, and another successor in another file, that is now forbidden)<commit_after>#include "degenerate.hpp"

//retourne les nucléotides concaténés dans l'ordre (assuré par une itération sur le vecteur nucleotides)
const string find_neighbor_motifs(  sparse_hash_map<string, pair<int, Node *>> &motifs,
                                    sparse_hash_map<char, pair<string, Node *>> &neighbor_motifs,
                                    const string &motif,
                                    unsigned int pos) {

    string neighbor_motif(motif);
    string neighbors_nuc;
    neighbors_nuc.reserve(4);
    //pour tous les nucléotides
    for (auto const &nuc : nucleotides) {
        //on remplace la (pos)ième position du motif de base par ce nucléotide
        neighbor_motif.replace(pos, 1, 1, nuc);

        //on passe au suivant si le voisin n'est pas dans la table
        auto const motif_it = motifs.find(neighbor_motif);
        if(motif_it == motifs.end())
            continue;
        motif_it->second.first = pos;
        //sinon, on insère dans la table des résultats le motif et son compte
        neighbor_motifs[nuc] = make_pair(neighbor_motif, motifs[neighbor_motif].second);
        neighbors_nuc.push_back(nuc);
    }
    return neighbors_nuc;
}

void degenerate(sparse_hash_map<string, pair<int, Node *>> &motifs,
                sparse_hash_map<string, pair<int, Node *>> &degenerated_motifs,
                const unsigned int kmer_size,
                bool rc) {

    //pour chaque position
    for (unsigned int pos = 0; pos < kmer_size; pos++) {

        //pour chaque motif dans la table
        for (auto const &motif_it : motifs) {
            //s'il n'a pas été marqué pour cette position ou si la position a déjà été dégénérée
            if((motif_it.second.first == pos) || (motif_it.second.first == kmer_size) || (!string("ACGT").find(motif_it.first[pos]))) {
                continue;
            }

            sparse_hash_map<char, pair<string, Node *>> neighbor_motifs;
            neighbor_motifs.reserve(4);
            //on trouve les voisins du kmer par rapport à la position courante
            const string neighbors_nuc = find_neighbor_motifs(motifs, neighbor_motifs, motif_it.first, pos);

            if (neighbors_nuc.size() <= 1) {
                continue;
            }
            //this is where things can explode if the string is not sorted alphabetically
            auto iupacs = nucs_to_iupacs.find(neighbors_nuc);
            assert(iupacs != nucs_to_iupacs.end());

            //string that will be transformed into the degenerated motif later
            string degenerated_motif(motif_it.first);

            //TODO not required since lookup in a hashtable is O(1)
            sparse_hash_map<char, Node *> iupac_to_node;
            iupac_to_node.reserve(11);

            // pour tous les iupacs dérivant des nucléotides
            for (unsigned int degeneration_degree = 0; degeneration_degree < iupacs->second.size(); degeneration_degree++) {
                for (auto const iupac : iupacs->second[degeneration_degree]) {

                    degenerated_motif.replace(pos, 1, 1, iupac);
                    Node *current_node_ptr;

                    //checks if the node has already been created
                    auto entry_ptr = degenerated_motifs.find(degenerated_motif);
                    if(entry_ptr != degenerated_motifs.end()) {
                        current_node_ptr = entry_ptr->second.second;
                    }
                    else {
                        //node creation
                        bool missing_successor_positive = false;
                        bool missing_successor_negative = false;
                        unsigned int degenerated_motif_positive_count = 0;
                        unsigned int degenerated_motif_negative_count = 0;

                        for (auto const &nuc : iupac_to_nucs[iupac]) {

                            unsigned int successor_positive_count = neighbor_motifs[nuc].second->get_positive_count();
                            unsigned int successor_negative_count = neighbor_motifs[nuc].second->get_negative_count();

                            //add positive successor count or raise flag
                            if (degenerated_motif_positive_count > ~0 - successor_positive_count) {
                                std::cerr << "Error : an overflow occurred while setting the positive count of a degenerated motif. You should consider switching to a bigger unsigned type." << endl;
                                exit(EXIT_FAILURE);
                            }
                            if (successor_positive_count == 0)
                                missing_successor_positive = true;
                            else
                                degenerated_motif_positive_count += successor_positive_count;

                            //add negative successor count or raise flag
                            if (degenerated_motif_negative_count > ~0 - successor_negative_count) {
                                std::cerr << "Error : an overflow occurred while setting the negative count of a degenerated motif. You should consider switching to a bigger unsigned type." << endl;
                                exit(EXIT_FAILURE);
                            }
                            if (successor_negative_count == 0)
                                missing_successor_negative = true;
                            else
                                degenerated_motif_negative_count += successor_negative_count;
                        }
                        //if a successor is missing in each datasets, then the motif should not be created
                        if (missing_successor_positive && missing_successor_negative)
                            continue;

                        current_node_ptr = new Node(degenerated_motif_positive_count, degenerated_motif_negative_count);
                        // current_node_ptr->set_motif(degenerated_motif);
                        degenerated_motifs.emplace(make_pair(degenerated_motif, make_pair(-1, current_node_ptr)));
                        if (rc) {
                            degenerated_motifs.emplace(make_pair(reverse_complement(degenerated_motif), make_pair(kmer_size, current_node_ptr)));
                        }
                    }
                    //remembering the node that we created to be able to find them easily
                    //TODO this is not required since lookup in a hash table is O(1)
                    iupac_to_node[iupac] = current_node_ptr;

                    //adding links between nodes

                    //here we create the nodes that depends on the nucleotides first,
                    //then we create the nodes that depends on the previous one, etc.
                    if (degeneration_degree == 0) {
                        for (char nuc : iupacs_dependencies[iupac]) {
                            current_node_ptr->add_successor(neighbor_motifs[nuc].second);
                            neighbor_motifs[nuc].second->add_predecessor(current_node_ptr);
                        }
                    } else {
                        for (char iupac_dependency : iupacs_dependencies[iupac]) {
                            if (iupac_to_node.find(iupac_dependency) == iupac_to_node.end()) {
                                std::cerr << "Tried to link a node to an non-existing one" << std::endl;
                                exit(EXIT_FAILURE);
                            }
                            current_node_ptr->add_successor(iupac_to_node[iupac_dependency]);
                            iupac_to_node[iupac_dependency]->add_predecessor(current_node_ptr);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>