/* * This file is part of the Flowee project * Copyright (C) 2020-2022 Tom Zander * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BLOCKCHAIN_H #define BLOCKCHAIN_H #include "BlockHeader.h" #include "P2PNet.h" #include #include #include #include #include #include #include class DownloadManager; namespace Streaming { class P2PBuilder; } class Blockchain { public: Blockchain(DownloadManager *downloadManager, const boost::filesystem::path &basedir, P2PNet::Chain chain); Message createGetHeadersRequest(Streaming::P2PBuilder &builder); void processBlockHeaders(Message message, int peerId); /** * Set a raw mapped blockchain data, a simple list of headers. * Block headers, as they are stored in the blockchain, at 80 bytes each can be provided * here as a lost in order to avoid downloading them from peers. * We require that the blocks are in-order (will not be checked), starting with the * geneesis block (which is checked). * * This setter should be used BEFORE the creation of the Blockchain instance, which means * before the creation of the DownloadManager instance. * * Notice that after setting this, the save() will skip saving any headers provided by * the static data. */ static void setStaticChain(const unsigned char *data, int64_t size, const std::string &infoFile); /** * In order to promote a standard blockheaders file to be useful as a static chain, * we need to create an extra metadata file by doing the expensive operations on them * and saving the results. * This method is meant to create the file 'meta' as a result of the input 'blockchain' file. */ static bool createStaticHeaders(const std::string &blockchain, const std::string &meta); /** * Return the chain-height that we actually are at, based on validated headers. */ int height() const; /** * Return the chain-height that based on the date/time we expect to be at. */ int expectedBlockHeight() const; /** * Returns true if the block-id is part of the main chain (so far). */ bool isKnown(const uint256 &blockId) const; /** * Returns the block height for a certain block. * Please notice the isKnown which is a cheaper version if all you need is a yes/no. */ int blockHeightFor(const uint256 &blockId) const; /** * This returns the block that was created just after the requested timestamp. * * If the timestamp is further in the future than 'Tip' then tip's height + 1 is given. */ int blockHeightAtTime(uint32_t timestamp) const; /** * Return the block header for a block at a certain height. * Height 0 is the genesis block. */ BlockHeader block(int height) const; /// re-load the chain. Also called from the constructor. void load(); /// save the chain void save(); private: void createMainchainGenesis(); void loadMainchainCheckpoints(); void createTestnet4Genesis(); void loadTestnet4Checkpoints(); void loadStaticChain(const unsigned char *data, int64_t dataSize, std::ifstream &infoFile); void createGenericGenesis(BlockHeader genesis); /// replace all the saved files with one that has all the data. void compressSaveFiles(const boost::system::error_code &error); void startSaveTimer(); mutable std::mutex m_lock; const boost::filesystem::path m_basedir; std::vector m_longestChain; struct ChainTip { uint256 tip; int height; arith_uint256 chainWork; }; ChainTip m_tip; typedef std::unordered_map BlockHeightMap; BlockHeightMap m_blockHeight; DownloadManager *m_dlmanager; boost::asio::deadline_timer m_saveTimer; bool m_saveTimerStarted = false; // consensus const uint256 powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); std::map checkpoints; const unsigned char *m_staticChain = nullptr; int m_numStaticHeaders = 0; // including genesis, so this is height + 1 int m_fileCount = 0; // number of 'blockchainN' files we own int m_lastSavedHeader = 0; }; #endif