mirror of https://github.com/oxen-io/oxen-core.git
Incorporate checkpoint validation into syncing step
Fix checkpoint verification check and add messages
This commit is contained in:
parent
15ff209db0
commit
4724a7436f
|
@ -167,12 +167,12 @@ namespace cryptonote
|
|||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void checkpoints::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
|
||||
bool checkpoints::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, checkpoint_t const *checkpoint)
|
||||
{
|
||||
uint64_t const height = get_block_height(block);
|
||||
if (height < service_nodes::CHECKPOINT_STORE_PERSISTENTLY_INTERVAL ||
|
||||
block.major_version < network_version_12_checkpointing)
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (m_nettype == MAINNET && height == HF_VERSION_12_CHECKPOINTING_SOFT_FORK_HEIGHT)
|
||||
{
|
||||
|
@ -200,6 +200,9 @@ namespace cryptonote
|
|||
}
|
||||
}
|
||||
|
||||
if (checkpoint)
|
||||
update_checkpoint(*checkpoint);
|
||||
|
||||
uint64_t end_cull_height = 0;
|
||||
{
|
||||
checkpoint_t immutable_checkpoint;
|
||||
|
@ -229,6 +232,8 @@ namespace cryptonote
|
|||
MERROR("Pruning block checkpoint on block added failed non-trivially at height: " << m_last_cull_height << ", what = " << e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void checkpoints::blockchain_detached(uint64_t height)
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace cryptonote
|
|||
public cryptonote::BlockchainDetachedHook
|
||||
{
|
||||
public:
|
||||
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs) override;
|
||||
bool block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, checkpoint_t const *checkpoint) override;
|
||||
void blockchain_detached(uint64_t height) override;
|
||||
|
||||
bool get_checkpoint(uint64_t height, checkpoint_t &checkpoint) const;
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace cryptonote {
|
|||
class BlockAddedHook
|
||||
{
|
||||
public:
|
||||
virtual void block_added(const block& block, const std::vector<transaction>& txs) = 0;
|
||||
virtual bool block_added(const block& block, const std::vector<transaction>& txs, struct checkpoint_t const *checkpoint) = 0;
|
||||
};
|
||||
|
||||
class BlockchainDetachedHook
|
||||
|
@ -63,7 +63,7 @@ namespace cryptonote {
|
|||
class AltBlockAddedHook
|
||||
{
|
||||
public:
|
||||
virtual void alt_block_added(const block &block, const std::vector<transaction>& txs) = 0;
|
||||
virtual bool alt_block_added(const block &block, const std::vector<transaction>& txs, struct checkpoint_t const *checkpoint) = 0;
|
||||
};
|
||||
/************************************************************************/
|
||||
/* */
|
||||
|
|
|
@ -1124,7 +1124,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
|
|||
for (auto& old_ch_ent : disconnected_chain)
|
||||
{
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc, false /*has_checkpoint*/);
|
||||
bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc, nullptr /*checkpoint*/);
|
||||
if(!r)
|
||||
{
|
||||
MERROR("Failed to push ex-main chain blocks to alternative chain ");
|
||||
|
@ -1774,7 +1774,7 @@ bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<block_ex
|
|||
// if that chain is long enough to become the main chain and re-org accordingly
|
||||
// if so. If not, we need to hang on to the block in case it becomes part of
|
||||
// a long forked chain eventually.
|
||||
bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc, bool has_checkpoint)
|
||||
bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc, checkpoint_t const *checkpoint)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
@ -1899,20 +1899,9 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
|
|||
}
|
||||
bei.cumulative_difficulty += current_diff;
|
||||
|
||||
// add block to alternate blocks storage,
|
||||
// as well as the current "alt chain" container
|
||||
CHECK_AND_ASSERT_MES(!m_db->get_alt_block(id, NULL, NULL), false, "insertion of new alternative block returned as it already exists");
|
||||
cryptonote::alt_block_data_t data;
|
||||
data.height = bei.height;
|
||||
data.cumulative_weight = bei.block_cumulative_weight;
|
||||
data.cumulative_difficulty = bei.cumulative_difficulty;
|
||||
data.already_generated_coins = bei.already_generated_coins;
|
||||
m_db->add_alt_block(id, data, cryptonote::block_to_blob(bei.bl));
|
||||
alt_chain.push_back(bei);
|
||||
|
||||
bool rejected_by_service_node = false;
|
||||
bool is_a_checkpoint = false;
|
||||
if(!has_checkpoint && !m_checkpoints.check_block(bei.height, id, &is_a_checkpoint, &rejected_by_service_node))
|
||||
if(!checkpoint && !m_checkpoints.check_block(bei.height, id, &is_a_checkpoint, &rejected_by_service_node))
|
||||
{
|
||||
if (rejected_by_service_node && nettype() == MAINNET && block_height < HF_VERSION_12_CHECKPOINTING_SOFT_FORK_HEIGHT)
|
||||
{
|
||||
|
@ -1926,7 +1915,34 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
|
|||
}
|
||||
}
|
||||
|
||||
bool checkpointed = has_checkpoint || is_a_checkpoint;
|
||||
{
|
||||
std::vector<transaction> txs;
|
||||
std::vector<crypto::hash> missed;
|
||||
if (!get_transactions(b.tx_hashes, txs, missed))
|
||||
{
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AltBlockAddedHook *hook : m_alt_block_added_hooks)
|
||||
{
|
||||
if (!hook->alt_block_added(b, txs, checkpoint))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// add block to alternate blocks storage,
|
||||
// as well as the current "alt chain" container
|
||||
CHECK_AND_ASSERT_MES(!m_db->get_alt_block(id, NULL, NULL), false, "insertion of new alternative block returned as it already exists");
|
||||
cryptonote::alt_block_data_t data;
|
||||
data.height = bei.height;
|
||||
data.cumulative_weight = bei.block_cumulative_weight;
|
||||
data.cumulative_difficulty = bei.cumulative_difficulty;
|
||||
data.already_generated_coins = bei.already_generated_coins;
|
||||
m_db->add_alt_block(id, data, cryptonote::block_to_blob(bei.bl));
|
||||
alt_chain.push_back(bei);
|
||||
|
||||
bool checkpointed = checkpoint || is_a_checkpoint;
|
||||
if (checkpointed || (main_chain_cumulative_difficulty < bei.cumulative_difficulty)) // check if difficulty bigger then in main chain
|
||||
{
|
||||
if (checkpointed)
|
||||
|
@ -1956,17 +1972,6 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
|
|||
}
|
||||
else
|
||||
{
|
||||
std::vector<transaction> txs;
|
||||
std::vector<crypto::hash> missed;
|
||||
if (!get_transactions(b.tx_hashes, txs, missed))
|
||||
{
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AltBlockAddedHook *hook : m_alt_block_added_hooks)
|
||||
hook->alt_block_added(b, txs);
|
||||
|
||||
MGINFO_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "difficulty:\t" << current_diff);
|
||||
return true;
|
||||
}
|
||||
|
@ -2625,7 +2630,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_
|
|||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
crypto::hash id = get_block_hash(bl);
|
||||
return handle_block_to_main_chain(bl, id, bvc);
|
||||
return handle_block_to_main_chain(bl, id, bvc, nullptr /*checkpoint*/);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
size_t Blockchain::get_total_transactions() const
|
||||
|
@ -3675,7 +3680,7 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
|
|||
// Needs to validate the block and acquire each transaction from the
|
||||
// transaction mem_pool, then pass the block and transactions to
|
||||
// m_db->add_block()
|
||||
bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc)
|
||||
bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc, checkpoint_t const *checkpoint)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
|
@ -4024,7 +4029,14 @@ leave:
|
|||
only_txs.push_back(tx_pair.first);
|
||||
|
||||
for (BlockAddedHook* hook : m_block_added_hooks)
|
||||
hook->block_added(bl, only_txs);
|
||||
{
|
||||
if (!hook->block_added(bl, only_txs, checkpoint))
|
||||
{
|
||||
MERROR("Block added hook signalled failure");
|
||||
pop_block_from_blockchain();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TIME_MEASURE_FINISH(addblock);
|
||||
|
||||
|
@ -4220,22 +4232,19 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc,
|
|||
|
||||
bool result = false;
|
||||
rtxn_guard.stop();
|
||||
//check that block refers to chain tail
|
||||
if(!(bl.prev_id == get_tail_id()))
|
||||
if(bl.prev_id == get_tail_id()) //check that block refers to chain tail
|
||||
{
|
||||
//chain switching or wrong block
|
||||
bvc.m_added_to_main_chain = false;
|
||||
result = handle_alternative_block(bl, id, bvc, (checkpoint != nullptr));
|
||||
m_blocks_txs_check.clear();
|
||||
//never relay alternative blocks
|
||||
result = handle_block_to_main_chain(bl, id, bvc, checkpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = handle_block_to_main_chain(bl, id, bvc);
|
||||
//chain switching or wrong block
|
||||
bvc.m_added_to_main_chain = false;
|
||||
result = handle_alternative_block(bl, id, bvc, checkpoint);
|
||||
m_blocks_txs_check.clear();
|
||||
//never relay alternative blocks
|
||||
}
|
||||
|
||||
if (result && checkpoint)
|
||||
update_checkpoint(*checkpoint);
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -1224,7 +1224,7 @@ namespace cryptonote
|
|||
*
|
||||
* @return true if the block was added successfully, otherwise false
|
||||
*/
|
||||
bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc);
|
||||
bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc, checkpoint_t const *checkpoint);
|
||||
|
||||
/**
|
||||
* @brief validate and add a new block to an alternate blockchain
|
||||
|
@ -1239,7 +1239,7 @@ namespace cryptonote
|
|||
*
|
||||
* @return true if the block was added successfully, otherwise false
|
||||
*/
|
||||
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc, bool has_checkpoint);
|
||||
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc, checkpoint_t const *checkpoint);
|
||||
|
||||
/**
|
||||
* @brief builds a list of blocks connecting a block to the main chain
|
||||
|
|
|
@ -713,9 +713,9 @@ namespace cryptonote
|
|||
// Service Nodes
|
||||
{
|
||||
m_service_node_list.set_db_pointer(initialized_db);
|
||||
|
||||
m_service_node_list.set_quorum_history_storage(command_line::get_arg(vm, arg_store_quorum_history));
|
||||
|
||||
// NOTE: Implicit dependency. Service node list needs to be hooked before checkpoints.
|
||||
m_blockchain_storage.hook_block_added(m_service_node_list);
|
||||
m_blockchain_storage.hook_blockchain_detached(m_service_node_list);
|
||||
m_blockchain_storage.hook_init(m_service_node_list);
|
||||
|
@ -1662,25 +1662,7 @@ namespace cryptonote
|
|||
// quorums are implemented and merged
|
||||
if (checkpoint)
|
||||
{
|
||||
if (b->major_version >= network_version_13)
|
||||
{
|
||||
if (checkpoint->signatures.size() > 1)
|
||||
{
|
||||
for (size_t i = 0; i < (checkpoint->signatures.size() - 1); i++)
|
||||
{
|
||||
auto curr = checkpoint->signatures[i].voter_index;
|
||||
auto next = checkpoint->signatures[i + 1].voter_index;
|
||||
|
||||
if (curr >= next)
|
||||
{
|
||||
LOG_PRINT_L1("Voters in checkpoints are not given in ascending order, block failed");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (b->major_version < network_version_13)
|
||||
{
|
||||
std::sort(checkpoint->signatures.begin(),
|
||||
checkpoint->signatures.end(),
|
||||
|
|
|
@ -462,7 +462,10 @@ namespace service_nodes
|
|||
|
||||
auto it = state_history.find(state_change.block_height);
|
||||
if (it == state_history.end())
|
||||
{
|
||||
LOG_PRINT_L1("Transaction: " << cryptonote::get_transaction_hash(tx) << ", references quorum at height: " << cryptonote::get_block_hash(block) << ", that is not stored");
|
||||
return false;
|
||||
}
|
||||
|
||||
quorum_manager const *quorums = &it->quorums;
|
||||
cryptonote::tx_verification_context tvc = {};
|
||||
|
@ -680,7 +683,7 @@ namespace service_nodes
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool get_contribution(cryptonote::network_type nettype, int hard_fork_version, const cryptonote::transaction& tx, uint64_t block_height, parsed_tx_contribution &parsed_contribution)
|
||||
static bool get_contribution(cryptonote::network_type nettype, int hf_version, const cryptonote::transaction& tx, uint64_t block_height, parsed_tx_contribution &parsed_contribution)
|
||||
{
|
||||
if (!cryptonote::get_service_node_contributor_from_tx_extra(tx.extra, parsed_contribution.address))
|
||||
return false;
|
||||
|
@ -1104,11 +1107,32 @@ namespace service_nodes
|
|||
return false;
|
||||
}
|
||||
|
||||
void service_node_list::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
|
||||
bool service_node_list::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint)
|
||||
{
|
||||
if (block.major_version < cryptonote::network_version_9_service_nodes)
|
||||
return true;
|
||||
|
||||
std::lock_guard<boost::recursive_mutex> lock(m_sn_mutex);
|
||||
process_block(block, txs);
|
||||
|
||||
if (checkpoint)
|
||||
{
|
||||
std::shared_ptr<const testing_quorum> quorum = get_testing_quorum(quorum_type::checkpointing, checkpoint->height);
|
||||
if (!quorum)
|
||||
{
|
||||
LOG_PRINT_L1("Failed to get testing quorum checkpoint for block: " << cryptonote::get_block_hash(block));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!service_nodes::verify_checkpoint(block.major_version, *checkpoint, *quorum))
|
||||
{
|
||||
LOG_PRINT_L1("Service node checkpoint failed verification for block: " << cryptonote::get_block_hash(block));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
store();
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<size_t> generate_shuffled_service_node_index_list(
|
||||
|
@ -1364,16 +1388,16 @@ namespace service_nodes
|
|||
void service_node_list::process_block(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
|
||||
{
|
||||
uint64_t block_height = cryptonote::get_block_height(block);
|
||||
int hard_fork_version = m_blockchain.get_hard_fork_version(block_height);
|
||||
uint8_t hf_version = m_blockchain.get_hard_fork_version(block_height);
|
||||
|
||||
if (hard_fork_version < 9)
|
||||
if (hf_version < 9)
|
||||
return;
|
||||
|
||||
//
|
||||
// Cull old history
|
||||
//
|
||||
{
|
||||
uint64_t cull_height = short_term_state_cull_height(m_db, block_height);
|
||||
uint64_t cull_height = short_term_state_cull_height(hf_version, m_db, block_height);
|
||||
auto end_it = m_state_history.upper_bound(cull_height);
|
||||
for (auto it = m_state_history.begin(); it != end_it; it++)
|
||||
{
|
||||
|
@ -1653,14 +1677,17 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
void service_node_list::alt_block_added(cryptonote::block const &block, std::vector<cryptonote::transaction> const &txs)
|
||||
bool service_node_list::alt_block_added(cryptonote::block const &block, std::vector<cryptonote::transaction> const &txs, cryptonote::checkpoint_t const *checkpoint)
|
||||
{
|
||||
if (block.major_version < cryptonote::network_version_9_service_nodes)
|
||||
return true;
|
||||
|
||||
uint64_t block_height = cryptonote::get_block_height(block);
|
||||
state_t const *starting_state = nullptr;
|
||||
crypto::hash const block_hash = get_block_hash(block);
|
||||
|
||||
auto it = m_alt_state.find(block_hash);
|
||||
if (it != m_alt_state.end()) return; // NOTE: Already processed alt-state for this block
|
||||
if (it != m_alt_state.end()) return true; // NOTE: Already processed alt-state for this block
|
||||
|
||||
// NOTE: Check if alt block forks off current state
|
||||
if ((block_height == m_state.height) && (block.prev_id == m_state.block_hash))
|
||||
|
@ -1681,24 +1708,48 @@ namespace service_nodes
|
|||
if (it != m_alt_state.end()) starting_state = &it->second;
|
||||
}
|
||||
|
||||
if (starting_state)
|
||||
if (!starting_state)
|
||||
{
|
||||
if (starting_state->block_hash != block.prev_id)
|
||||
{
|
||||
LOG_PRINT_L1("Unexpected state_t's hash: " << starting_state->block_hash
|
||||
<< ", does not match the block prev hash: " << block.prev_id);
|
||||
return;
|
||||
}
|
||||
LOG_PRINT_L1("Received alt block but couldn't find parent state in historical state");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
if (starting_state->block_hash != block.prev_id)
|
||||
{
|
||||
// TODO(loki): Fatal
|
||||
return;
|
||||
LOG_PRINT_L1("Unexpected state_t's hash: " << starting_state->block_hash
|
||||
<< ", does not match the block prev hash: " << block.prev_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
state_t alt_state = *starting_state;
|
||||
alt_state.update_from_block(m_blockchain, m_state_history, m_alt_state, block, txs, m_service_node_pubkey);
|
||||
m_alt_state[block_hash] = std::move(alt_state);
|
||||
|
||||
if (checkpoint)
|
||||
{
|
||||
std::vector<std::shared_ptr<const service_nodes::testing_quorum>> alt_quorums;
|
||||
std::shared_ptr<const testing_quorum> quorum = get_testing_quorum(quorum_type::checkpointing, checkpoint->height, false, &alt_quorums);
|
||||
if (!quorum)
|
||||
return false;
|
||||
|
||||
if (!service_nodes::verify_checkpoint(block.major_version, *checkpoint, *quorum))
|
||||
{
|
||||
bool verified_on_alt_quorum = false;
|
||||
for (std::shared_ptr<const service_nodes::testing_quorum> alt_quorum : alt_quorums)
|
||||
{
|
||||
if (service_nodes::verify_checkpoint(block.major_version, *checkpoint, *alt_quorum))
|
||||
{
|
||||
verified_on_alt_quorum = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!verified_on_alt_quorum)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2069,7 +2120,7 @@ namespace service_nodes
|
|||
size_t const last_index = data_in.states.size() - 1;
|
||||
for (size_t i = 0; i < last_index; i++)
|
||||
{
|
||||
state_serialized &entry = data_in.states[last_index];
|
||||
state_serialized &entry = data_in.states[i];
|
||||
if (entry.block_hash == crypto::null_hash) entry.block_hash = m_blockchain.get_block_id_by_height(entry.height);
|
||||
m_state_history.emplace_hint(m_state_history.end(), std::move(entry));
|
||||
}
|
||||
|
|
|
@ -35,7 +35,12 @@
|
|||
#include "cryptonote_core/service_node_voting.h"
|
||||
#include "cryptonote_core/service_node_quorum_cop.h"
|
||||
|
||||
namespace cryptonote { class Blockchain; class BlockchainDB; }
|
||||
namespace cryptonote
|
||||
{
|
||||
class Blockchain;
|
||||
class BlockchainDB;
|
||||
struct checkpoint_t;
|
||||
}; // namespace cryptonote
|
||||
|
||||
namespace service_nodes
|
||||
{
|
||||
|
@ -218,7 +223,7 @@ namespace service_nodes
|
|||
}
|
||||
}
|
||||
|
||||
using block_height = uint64_t;
|
||||
using block_height = uint64_t;
|
||||
class service_node_list
|
||||
: public cryptonote::BlockAddedHook,
|
||||
public cryptonote::BlockchainDetachedHook,
|
||||
|
@ -228,11 +233,11 @@ namespace service_nodes
|
|||
{
|
||||
public:
|
||||
service_node_list(cryptonote::Blockchain& blockchain);
|
||||
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs) override;
|
||||
bool block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint) override;
|
||||
void blockchain_detached(uint64_t height) override;
|
||||
void init() override;
|
||||
bool validate_miner_tx(const crypto::hash& prev_id, const cryptonote::transaction& miner_tx, uint64_t height, int hard_fork_version, cryptonote::block_reward_parts const &base_reward) const override;
|
||||
void alt_block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs) override;
|
||||
bool alt_block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint) override;
|
||||
std::vector<std::pair<cryptonote::account_public_address, uint64_t>> get_winner_addresses_and_portions() const;
|
||||
crypto::public_key select_winner() const;
|
||||
|
||||
|
|
|
@ -399,7 +399,7 @@ namespace service_nodes
|
|||
}
|
||||
}
|
||||
|
||||
void quorum_cop::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
|
||||
bool quorum_cop::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const * /*checkpoint*/)
|
||||
{
|
||||
process_quorums(block);
|
||||
|
||||
|
@ -412,6 +412,7 @@ namespace service_nodes
|
|||
|
||||
m_vote_pool.remove_expired_votes(height);
|
||||
m_vote_pool.remove_used_votes(txs, block.major_version);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool quorum_cop::handle_vote(quorum_vote_t const &vote, cryptonote::vote_verification_context &vvc)
|
||||
|
@ -438,7 +439,7 @@ namespace service_nodes
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!verify_vote_against_quorum(vote, vvc, *quorum))
|
||||
if (!verify_vote_signature(vote, vvc, *quorum))
|
||||
return false;
|
||||
|
||||
std::vector<pool_vote_entry> votes = m_vote_pool.add_pool_vote_if_unique(vote, vvc);
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace cryptonote
|
|||
{
|
||||
class core;
|
||||
struct vote_verification_context;
|
||||
struct checkpoint_t;
|
||||
};
|
||||
|
||||
namespace service_nodes
|
||||
|
@ -81,7 +82,7 @@ namespace service_nodes
|
|||
explicit quorum_cop(cryptonote::core& core);
|
||||
|
||||
void init() override;
|
||||
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs) override;
|
||||
bool block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const * /*checkpoint*/) override;
|
||||
void blockchain_detached(uint64_t height) override;
|
||||
|
||||
void set_votes_relayed (std::vector<quorum_vote_t> const &relayed_votes);
|
||||
|
|
|
@ -238,37 +238,56 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
bool verify_checkpoint(cryptonote::checkpoint_t const &checkpoint, service_nodes::testing_quorum const &quorum)
|
||||
bool verify_checkpoint(uint8_t hf_version, cryptonote::checkpoint_t const &checkpoint, service_nodes::testing_quorum const &quorum)
|
||||
{
|
||||
if (checkpoint.type == cryptonote::checkpoint_type::service_node)
|
||||
{
|
||||
if ((checkpoint.height % service_nodes::CHECKPOINT_INTERVAL) != 0)
|
||||
{
|
||||
LOG_PRINT_L1("Checkpoint given but not expecting a checkpoint at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkpoint.signatures.size() < service_nodes::CHECKPOINT_MIN_VOTES)
|
||||
{
|
||||
LOG_PRINT_L1("Checkpoint has insufficient signatures to be considered");
|
||||
LOG_PRINT_L1("Checkpoint has insufficient signatures to be considered at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkpoint.signatures.size() > service_nodes::CHECKPOINT_QUORUM_SIZE)
|
||||
{
|
||||
LOG_PRINT_L1("Checkpoint has too many signatures to be considered");
|
||||
LOG_PRINT_L1("Checkpoint has too many signatures to be considered at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<size_t, service_nodes::CHECKPOINT_QUORUM_SIZE> unique_vote_set = {};
|
||||
for (service_nodes::voter_to_signature const &voter_to_signature : checkpoint.signatures)
|
||||
for (size_t i = 0; i < checkpoint.signatures.size(); i++)
|
||||
{
|
||||
service_nodes::voter_to_signature const &voter_to_signature = checkpoint.signatures[i];
|
||||
if (hf_version >= cryptonote::network_version_13 && i < (checkpoint.signatures.size() - 1))
|
||||
{
|
||||
auto curr = checkpoint.signatures[i].voter_index;
|
||||
auto next = checkpoint.signatures[i + 1].voter_index;
|
||||
|
||||
if (curr >= next)
|
||||
{
|
||||
LOG_PRINT_L1("Voters in checkpoints are not given in ascending order, checkpoint failed verification at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bounds_check_worker_index(quorum, voter_to_signature.voter_index, nullptr)) return false;
|
||||
|
||||
crypto::public_key const &key = quorum.workers[voter_to_signature.voter_index];
|
||||
if (unique_vote_set[voter_to_signature.voter_index]++)
|
||||
{
|
||||
LOG_PRINT_L1("Voter quorum index is duplicated: " << voter_to_signature.voter_index);
|
||||
LOG_PRINT_L1("Voter: " << epee::string_tools::pod_to_hex(key) << ", quorum index is duplicated: " << voter_to_signature.voter_index << ", checkpoint failed verification at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto::public_key const &key = quorum.workers[voter_to_signature.voter_index];
|
||||
if (!crypto::check_signature(checkpoint.block_hash, key, voter_to_signature.signature))
|
||||
{
|
||||
LOG_PRINT_L1("Invalid signatures for votes");
|
||||
LOG_PRINT_L1("Invalid signatures for votes, checkpoint failed verification at height: " << checkpoint.height << " for voter: " << epee::string_tools::pod_to_hex(key));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +296,7 @@ namespace service_nodes
|
|||
{
|
||||
if (checkpoint.signatures.size() != 0)
|
||||
{
|
||||
LOG_PRINT_L1("Non service-node checkpoints should have no signatures");
|
||||
LOG_PRINT_L1("Non service-node checkpoints should have no signatures, checkpoint failed at height: " << checkpoint.height);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +345,7 @@ namespace service_nodes
|
|||
return result;
|
||||
}
|
||||
|
||||
bool verify_vote_against_quorum(const quorum_vote_t &vote, cryptonote::vote_verification_context &vvc, const service_nodes::testing_quorum &quorum)
|
||||
bool verify_vote_signature(const quorum_vote_t &vote, cryptonote::vote_verification_context &vvc, const service_nodes::testing_quorum &quorum)
|
||||
{
|
||||
bool result = true;
|
||||
if (vote.type >= quorum_type::count)
|
||||
|
|
|
@ -103,10 +103,10 @@ namespace service_nodes
|
|||
|
||||
quorum_vote_t make_state_change_vote(uint64_t block_height, uint16_t index_in_group, uint16_t worker_index, new_state state, crypto::public_key const &pub_key, crypto::secret_key const &secret_key);
|
||||
|
||||
bool verify_checkpoint (cryptonote::checkpoint_t const &checkpoint, service_nodes::testing_quorum const &quorum);
|
||||
bool verify_checkpoint (uint8_t hf_version, cryptonote::checkpoint_t const &checkpoint, service_nodes::testing_quorum const &quorum);
|
||||
bool verify_tx_state_change (const cryptonote::tx_extra_service_node_state_change& state_change, uint64_t latest_height, cryptonote::tx_verification_context& vvc, const service_nodes::testing_quorum &quorum, uint8_t hf_version);
|
||||
bool verify_vote_age (const quorum_vote_t& vote, uint64_t latest_height, cryptonote::vote_verification_context &vvc);
|
||||
bool verify_vote_against_quorum (const quorum_vote_t& vote, cryptonote::vote_verification_context &vvc, const service_nodes::testing_quorum &quorum);
|
||||
bool verify_vote_signature (const quorum_vote_t& vote, cryptonote::vote_verification_context &vvc, const service_nodes::testing_quorum &quorum);
|
||||
crypto::signature make_signature_from_vote (quorum_vote_t const &vote, const crypto::public_key& pub, const crypto::secret_key& sec);
|
||||
crypto::signature make_signature_from_tx_state_change(cryptonote::tx_extra_service_node_state_change const &state_change, crypto::public_key const &pub, crypto::secret_key const &sec);
|
||||
|
||||
|
|
|
@ -1317,39 +1317,7 @@ namespace cryptonote
|
|||
return false;
|
||||
}
|
||||
|
||||
checkpoint = &checkpoint_allocated_on_stack_;
|
||||
bool maybe_has_checkpoint = (checkpoint->height % service_nodes::CHECKPOINT_INTERVAL == 0);
|
||||
|
||||
if (!maybe_has_checkpoint)
|
||||
{
|
||||
MERROR("Checkpoint blob given but not expecting a checkpoint at this height");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(doyle): If we are receiving alternative blocks, we won't
|
||||
// have the quorum for the alternative chain meaning we will not
|
||||
// be able to verify the checkpoint. For now always accept
|
||||
// whatever checkpoint we receive
|
||||
#if 1
|
||||
std::vector<std::shared_ptr<const service_nodes::testing_quorum>> alt_states;
|
||||
std::shared_ptr<const service_nodes::testing_quorum> quorum = m_core.get_testing_quorum(
|
||||
service_nodes::quorum_type::checkpointing, checkpoint->height, false /*include_old*/, &alt_states);
|
||||
if (!quorum)
|
||||
{
|
||||
MERROR("Failed to get service node quorum for height: "
|
||||
<< checkpoint->height
|
||||
<< ", quorum should be available as we are syncing the chain and deriving the current "
|
||||
"relevant quorum");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(doyle): add reasoning, important for sync failures
|
||||
if (!service_nodes::verify_checkpoint(*checkpoint, *quorum))
|
||||
{
|
||||
MERROR("Failed to verify checkpoint at height: " << checkpoint->height);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
checkpoint = &checkpoint_allocated_on_stack_;
|
||||
}
|
||||
|
||||
// process block
|
||||
|
|
|
@ -125,7 +125,7 @@ static bool verify_vote(service_nodes::quorum_vote_t const &vote,
|
|||
service_nodes::testing_quorum const &quorum)
|
||||
{
|
||||
bool result = service_nodes::verify_vote_age(vote, latest_height, vvc);
|
||||
result &= service_nodes::verify_vote_against_quorum(vote, vvc, quorum);
|
||||
result &= service_nodes::verify_vote_signature(vote, vvc, quorum);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue