Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fireice-uk committed Mar 22, 2024
1 parent 53b65b0 commit f39a6eb
Show file tree
Hide file tree
Showing 15 changed files with 423 additions and 283 deletions.
5 changes: 5 additions & 0 deletions src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ namespace cn
const char P2P_NET_DATA_FILENAME[] = "p2pstate.bin";
const char CRYPTONOTE_BLOCKCHAIN_INDICES_FILENAME[] = "blockchainindices.dat";
const char MINER_CONFIG_FILE_NAME[] = "miner_conf.json";
const char CRYPTONOTE_CHECKPOINT_FILENAME[] = "checkpoint.dat";

} // namespace parameters

Expand Down Expand Up @@ -191,6 +192,7 @@ namespace cn

// This defines the minimum P2P version required for lite blocks propogation
const uint8_t P2P_LITE_BLOCKS_PROPOGATION_VERSION = 3;
const uint8_t P2P_CHECKPOINT_LIST_VERSION = 3;

const size_t P2P_LOCAL_WHITE_PEERLIST_LIMIT = 1000;
const size_t P2P_LOCAL_GRAY_PEERLIST_LIMIT = 5000;
Expand Down Expand Up @@ -230,6 +232,9 @@ namespace cn
__attribute__((unused))
#endif

const char DNS_CHECKPOINT_DOMAIN[] = "checkpoints.conceal.id";
const char TESTNET_DNS_CHECKPOINT_DOMAIN[] = "testpoints.conceal.gq";

// Blockchain Checkpoints:
// {<block height>, "<block hash>"},
const std::initializer_list<CheckpointData>
Expand Down
86 changes: 58 additions & 28 deletions src/CryptoNoteCore/Blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,6 @@ namespace cn
m_blockchainIndexesEnabled(blockchainIndexesEnabled),
m_blockchainAutosaveEnabled(blockchainAutosaveEnabled),
logger(logger, "Blockchain")

{
}

Expand Down Expand Up @@ -461,7 +460,6 @@ namespace cn
bool Blockchain::init(const std::string &config_folder, bool load_existing, bool testnet)
{
m_testnet = testnet;
m_checkpoints.set_testnet(testnet);
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
if (!config_folder.empty() && !tools::create_directories_if_necessary(config_folder))
{
Expand All @@ -471,6 +469,9 @@ namespace cn

m_config_folder = config_folder;

m_checkpoints.init_targets(testnet, appendPath(config_folder, m_currency.checkpointFileName()));
m_checkpoints.load_checkpoints_from_file();

if (!m_blocks.open(appendPath(config_folder, m_currency.blocksFileName()), appendPath(config_folder, m_currency.blockIndexesFileName()), 1024))
{
return false;
Expand Down Expand Up @@ -593,25 +594,35 @@ namespace cn

bool Blockchain::checkCheckpoints(uint32_t &lastValidCheckpointHeight)
{
std::vector<uint32_t> checkpointHeights = m_checkpoints.getCheckpointHeights();
for (const auto &checkpointHeight : checkpointHeights)
bool rv = true;
std::vector<std::pair<uint32_t, crypto::Hash>> checkpointHeights = m_checkpoints.get_checkpoint_targets();
lastValidCheckpointHeight = 0;

/* Hashes are in reverse order so if everything is ok we will only do one iteration */
for (const auto &check : checkpointHeights)
{
if (m_blocks.size() <= checkpointHeight)
{
return true;
}
uint32_t height = check.first;
if (m_blocks.size() <= height)
continue;

if (m_checkpoints.check_block(checkpointHeight, getBlockIdByHeight(checkpointHeight)))
crypto::Hash hv = m_blockIndex.getHashOfIds(0, height);
if (hv == check.second)
{
lastValidCheckpointHeight = checkpointHeight;
lastValidCheckpointHeight = height;
break;
}
else
{
return false;
}
rv = false;
}
logger(INFO, BRIGHT_WHITE) << "Checkpoints passed";
return true;

if(rv)
{
logger(INFO, BRIGHT_WHITE) << "Checkpoints passed";
if(m_checkpoints.get_points_height() < lastValidCheckpointHeight)
m_checkpoints.set_checkpoint_list(m_blockIndex.getBlockIds(0, lastValidCheckpointHeight));
}

return rv;
}

void Blockchain::rebuildCache()
Expand Down Expand Up @@ -1403,6 +1414,29 @@ namespace cn
return true;
}

bool Blockchain::is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const {
if (0 == block_height)
return false;

uint32_t lowest_height = blockchain_height - cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;

if (blockchain_height < cn::parameters::CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)
{
lowest_height = 0;
}

if (block_height < lowest_height && !m_checkpoints.is_in_checkpoint_zone(block_height))
{
logger(logging::DEBUGGING, logging::WHITE)
<< "<< Checkpoints.cpp << "
<< "Reorganization depth too deep : " << (blockchain_height - block_height) << ". Block Rejected";
return false;
}

uint32_t checkpoint_height = m_checkpoints.get_greatest_target_height();
return checkpoint_height < block_height;
}

bool Blockchain::handle_alternative_block(const Block &b, const crypto::Hash &id, block_verification_context &bvc, bool sendNewAlternativeBlockMessage)
{
std::lock_guard<decltype(m_blockchain_lock)> lk(m_blockchain_lock);
Expand All @@ -1416,10 +1450,8 @@ namespace cn
return false;
}

/* in the absence of a better solution, we fetch checkpoints from dns records */
m_checkpoints.load_checkpoints_from_dns();

if (!m_checkpoints.is_alternative_block_allowed(getCurrentBlockchainHeight(), block_height))
if (!is_alternative_block_allowed(getCurrentBlockchainHeight(), block_height))
{
logger(DEBUGGING) << "Block with id: " << id << std::endl
<< " can't be accepted for alternative chain, block height: " << block_height << std::endl
Expand Down Expand Up @@ -1514,8 +1546,8 @@ namespace cn
bei.bl = b;
bei.height = alt_chain.size() ? it_prev->second.height + 1 : mainPrevHeight + 1;

bool is_a_checkpoint;
if (!m_checkpoints.check_block(bei.height, id, is_a_checkpoint))
auto checkpoint_status = m_checkpoints.check_checkpoint(bei.height, id);
if ( checkpoint_status == CheckpointList::is_in_zone_failed )
{
logger(ERROR, BRIGHT_RED) << "Checkpoint validaton failure";

Expand Down Expand Up @@ -1581,7 +1613,7 @@ namespace cn

alt_chain.push_back(i_res.first->first);

if (is_a_checkpoint)
if ( checkpoint_status == CheckpointList::is_checkpointed )
{
//do reorganize!
logger(INFO, BRIGHT_GREEN) << "###### REORGANIZE on height: " << m_alternative_chains[alt_chain.front()].height << " of " << m_blocks.size() - 1 << ", checkpoint is found in alternative chain on height " << bei.height;
Expand Down Expand Up @@ -2481,15 +2513,13 @@ namespace cn

auto longhashTimeStart = std::chrono::steady_clock::now();
crypto::Hash proof_of_work = NULL_HASH;
if (m_checkpoints.is_in_checkpoint_zone(getCurrentBlockchainHeight()))
auto checkpoint_status = m_checkpoints.check_checkpoint(getCurrentBlockchainHeight(), blockHash);
if (checkpoint_status == CheckpointList::is_in_zone_failed )
{
if (!m_checkpoints.check_block(getCurrentBlockchainHeight(), blockHash))
{
bvc.m_verification_failed = true;
return false;
}
bvc.m_verification_failed = true;
return false;
}
else
else if(checkpoint_status == CheckpointList::is_out_of_zone )
{
if (!m_currency.checkProofOfWork(m_cn_context, blockData, currentDifficulty, proof_of_work))
{
Expand Down
6 changes: 3 additions & 3 deletions src/CryptoNoteCore/Blockchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "Common/ObserverManager.h"
#include "Common/Util.h"
#include "CryptoNoteCore/BlockIndex.h"
#include "CryptoNoteCore/Checkpoints.h"
#include "CryptoNoteCore/CheckpointList.h"
#include "CryptoNoteCore/Currency.h"
#include "CryptoNoteCore/DepositIndex.h"
#include "CryptoNoteCore/IBlockchainStorageObserver.h"
Expand Down Expand Up @@ -68,7 +68,6 @@ namespace cn
bool getLowerBound(uint64_t timestamp, uint64_t startOffset, uint32_t &height);
std::vector<crypto::Hash> getBlockIds(uint32_t startHeight, uint32_t maxCount);

void setCheckpoints(Checkpoints &&chk_pts) { m_checkpoints = std::move(chk_pts); }
bool getBlocks(uint32_t start_offset, uint32_t count, std::list<Block> &blocks, std::list<Transaction> &txs);
bool getBlocks(uint32_t start_offset, uint32_t count, std::list<Block> &blocks);
bool getAlternativeBlocks(std::list<Block> &blocks);
Expand Down Expand Up @@ -285,7 +284,7 @@ namespace cn
outputs_container m_outputs;

std::string m_config_folder;
Checkpoints m_checkpoints;
CheckpointList m_checkpoints;
std::atomic<bool> m_is_in_checkpoint_zone;

using Blocks = SwappedVector<BlockEntry>;
Expand Down Expand Up @@ -320,6 +319,7 @@ namespace cn


bool switch_to_alternative_blockchain(const std::list<crypto::Hash> &alt_chain, bool discard_disconnected_chain);
bool is_alternative_block_allowed(uint32_t blockchain_height, uint32_t block_height) const;
bool handle_alternative_block(const Block &b, const crypto::Hash &id, block_verification_context &bvc, bool sendNewAlternativeBlockMessage = true);
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<crypto::Hash> &alt_chain, const BlockEntry &bei);
void pushToDepositIndex(const BlockEntry &block, uint64_t interest);
Expand Down
94 changes: 94 additions & 0 deletions src/CryptoNoteCore/CheckpointList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Copyright (c) 2011-2017 The Cryptonote developers
// Copyright (c) 2017-2018 The Circle Foundation & Conceal Devs
// Copyright (c) 2018-2023 Conceal Network & Conceal Devs
//
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#pragma once
#include <vector>
#include <unordered_set>

#include "CryptoNoteBasicImpl.h"
#include <Logging/LoggerRef.h>

namespace cn
{
class CheckpointList
{
public:
explicit CheckpointList(logging::ILogger& log) : logger(log, "checkpoint_list") {}

void init_targets(bool is_testnet, const std::string& save_file);

bool add_checkpoint_list(const std::vector<crypto::Hash>& points);
bool set_checkpoint_list(std::vector<crypto::Hash>&& points);
bool load_checkpoints_from_file();

uint32_t get_points_height() const
{
return m_points.size()-1;
}

uint32_t get_greatest_target_height() const
{
return m_targets.rbegin()->first - 1;
}

bool is_ready() const
{
return m_points.size() > 0;
}

bool is_in_checkpoint_zone(uint32_t height) const
{
return m_points.size() < height;
}

enum check_rt
{
is_out_of_zone,
is_in_zone_failed,
is_checkpointed
};

check_rt check_checkpoint(uint32_t height, const crypto::Hash& hv) const
{
if(m_points.size() >= height)
return is_out_of_zone;
if(m_points[height] == hv)
return is_checkpointed;
else
return is_in_zone_failed;
}

std::vector<std::pair<uint32_t, crypto::Hash>> get_checkpoint_targets()
{
std::vector<std::pair<uint32_t, crypto::Hash>> rv;
rv.reserve(m_targets.size());
for(auto it = m_targets.rbegin(); it != m_targets.rend(); ++it)
rv.emplace_back(it->first-1, it->second);
return rv;
}

private:
bool m_testnet;
logging::LoggerRef logger;
std::string m_save_file;

std::map<uint32_t, crypto::Hash> m_targets; /*NB uint32_t is size not height */
std::unordered_set<uint32_t> m_valid_point_sizes;
std::vector<crypto::Hash> m_points;

bool save_checkpoints();
bool add_checkpoint_target(uint32_t height, const std::string &hash_str);
bool is_fsize_valid(uint32_t fsize)
{
if(fsize % sizeof(crypto::Hash) != 0)
return false;
fsize /= sizeof(crypto::Hash);

return m_valid_point_sizes.find(fsize) != m_valid_point_sizes.end();
}
};
}
Loading

0 comments on commit f39a6eb

Please sign in to comment.