Files
thehub/libs/p2p/Blockchain.h
T
tomFlowee 06b3d3d491 Save the downloaded block headers into multiple files
This change makes it so that we rely less on the downloaded
blockheader data being only in memory and us saving it when
the client shuts down.
Instead, we save more regularly and we save smaller files
instead of always overwriting the complete downloaded headers.

Having less to save at shutdown is then a happy side-effect.
2022-11-12 23:42:59 +01:00

146 lines
4.9 KiB
C++

/*
* This file is part of the Flowee project
* Copyright (C) 2020-2022 Tom Zander <tom@flowee.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef BLOCKCHAIN_H
#define BLOCKCHAIN_H
#include "BlockHeader.h"
#include "P2PNet.h"
#include <Message.h>
#include <arith_uint256.h>
#include <boost/asio/deadline_timer.hpp>
#include <uint256.h>
#include <boost/filesystem.hpp>
#include <mutex>
#include <unordered_map>
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<BlockHeader> m_longestChain;
struct ChainTip {
uint256 tip;
int height;
arith_uint256 chainWork;
};
ChainTip m_tip;
typedef std::unordered_map<uint256, int, HashShortener, HashComparison> 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<int, uint256> 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