Make hooks use exceptions on error rather than bool returns

bool returns suck in general, but in most cases here they are also a
pain in the ass because *each* place that returns false is also issuing
a log statement.  If only there were a way to return error information
to the common caller to have the common caller handle it... oh wait,
there is!
This commit is contained in:
Jason Rhinelander 2022-07-27 15:10:52 -03:00
parent f382c1971e
commit 9c9552380d
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
10 changed files with 121 additions and 178 deletions

View File

@ -167,11 +167,11 @@ namespace cryptonote
return result;
}
//---------------------------------------------------------------------------
bool checkpoints::block_added(const block_added_info& info)
void checkpoints::block_added(const block_added_info& info)
{
uint64_t const height = get_block_height(info.block);
if (height < service_nodes::CHECKPOINT_STORE_PERSISTENTLY_INTERVAL || info.block.major_version < hf::hf12_checkpointing)
return true;
return;
uint64_t end_cull_height = 0;
{
@ -205,8 +205,6 @@ namespace cryptonote
if (info.checkpoint)
update_checkpoint(*info.checkpoint);
return true;
}
//---------------------------------------------------------------------------
void checkpoints::blockchain_detached(uint64_t height)

View File

@ -113,7 +113,7 @@ namespace cryptonote
class checkpoints
{
public:
bool block_added(const block_added_info& info);
void block_added(const block_added_info& info);
void blockchain_detached(uint64_t height);
bool get_checkpoint(uint64_t height, checkpoint_t &checkpoint) const;

View File

@ -42,7 +42,7 @@ namespace cryptonote {
const std::vector<transaction>& txs;
const checkpoint_t* const checkpoint;
};
using BlockAddedHook = std::function<bool(const block_added_info& info)>;
using BlockAddedHook = std::function<void(const block_added_info& info)>;
struct detached_info {
uint64_t height;
bool by_pop_blocks;
@ -56,7 +56,7 @@ namespace cryptonote {
const block_reward_parts& reward_parts;
const std::vector<cryptonote::batch_sn_payment>& batched_sn_payments;
};
using ValidateMinerTxHook = std::function<bool(const miner_tx_info& info)>;
using ValidateMinerTxHook = std::function<void(const miner_tx_info& info)>;
struct address_parse_info
{

View File

@ -401,9 +401,10 @@ bool Blockchain::load_missing_blocks_into_oxen_subsystems()
if (blk.major_version >= hf::hf13_enforce_checkpoints && get_checkpoint(block_height, checkpoint))
checkpoint_ptr = &checkpoint;
if (!m_service_node_list.block_added(blk, txs, checkpoint_ptr))
{
MFATAL("Unable to process block for updating service node list: " << cryptonote::get_block_hash(blk));
try {
m_service_node_list.block_added(blk, txs, checkpoint_ptr);
} catch (const std::exception& e) {
MFATAL("Unable to process block {} for updating service node list: " << e.what());
return false;
}
snl_iteration_duration += clock::now() - snl_start;
@ -604,7 +605,7 @@ bool Blockchain::init(BlockchainDB* db, sqlite3 *ons_db, std::shared_ptr<crypton
}
hook_block_added([this] (const auto& info) { return m_checkpoints.block_added(info); });
hook_block_added([this] (const auto& info) { m_checkpoints.block_added(info); });
hook_blockchain_detached([this] (const auto& info) { m_checkpoints.blockchain_detached(info.height); });
for (const auto& hook : m_init_hooks)
hook();
@ -1384,8 +1385,12 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
miner_tx_info hook_data{b, reward_parts, batched_sn_payments};
for (const auto& hook : m_validate_miner_tx_hooks)
{
if (!hook(hook_data))
try {
hook(hook_data);
} catch (const std::exception& e) {
MGINFO_RED("Miner tx failed validation: " << e.what());
return false;
}
}
if (already_generated_coins != 0 && block_has_governance_output(nettype(), b) && version < hf::hf19_reward_batching)
@ -2100,8 +2105,12 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
block_added_info hook_data{b, txs, checkpoint};
for (const auto& hook : m_alt_block_added_hooks)
{
if (!hook(hook_data))
return false;
try {
hook(hook_data);
} catch (const std::exception& e) {
LOG_PRINT_L1("Failed to add alt block: " << e.what());
return false;
}
}
}
@ -4522,9 +4531,10 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
for (std::pair<transaction, std::string> const &tx_pair : txs)
only_txs.push_back(tx_pair.first);
if (!m_service_node_list.block_added(bl, only_txs, checkpoint))
{
MGINFO_RED("Failed to add block to Service Node List.");
try {
m_service_node_list.block_added(bl, only_txs, checkpoint);
} catch (const std::exception& e) {
MGINFO_RED("Failed to add block to Service Node List: " << e.what());
bvc.m_verifivation_failed = true;
return false;
}
@ -4551,9 +4561,10 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
block_added_info hook_data{bl, only_txs, checkpoint};
for (const auto& hook : m_block_added_hooks)
{
if (!hook(hook_data))
{
MGINFO_RED("Block added hook signalled failure");
try {
hook(hook_data);
} catch (const std::exception& e) {
MGINFO_RED("Block added hook failed with exception: " << e.what());
bvc.m_verifivation_failed = true;
return false;
}

View File

@ -978,23 +978,26 @@ namespace cryptonote
void on_new_tx_from_block(const cryptonote::transaction &tx);
/**
* @brief add a hook for processing new blocks and rollbacks for reorgs
* @brief add a hook called during new block handling; should throw to abort adding the block.
*/
void hook_block_added(BlockAddedHook hook) {
m_block_added_hooks.push_back(std::move(hook));
}
void hook_blockchain_detached(BlockchainDetachedHook hook) {
m_blockchain_detached_hooks.push_back(std::move(hook));
}
void hook_init(InitHook hook) {
m_init_hooks.push_back(std::move(hook));
}
void hook_validate_miner_tx(ValidateMinerTxHook hook) {
m_validate_miner_tx_hooks.push_back(std::move(hook));
}
void hook_alt_block_added(BlockAddedHook hook) {
m_alt_block_added_hooks.push_back(std::move(hook));
}
void hook_block_added(BlockAddedHook hook) { m_block_added_hooks.push_back(std::move(hook)); }
/**
* @brief add a hook called when blocks are removed from the chain.
*/
void hook_blockchain_detached(BlockchainDetachedHook hook) { m_blockchain_detached_hooks.push_back(std::move(hook)); }
/**
* @brief add a hook called during startup and re-initialization
*/
void hook_init(InitHook hook) { m_init_hooks.push_back(std::move(hook)); }
/**
* @brief add a hook to be called to validate miner txes; should throw if the miner tx is
* invalid.
*/
void hook_validate_miner_tx(ValidateMinerTxHook hook) { m_validate_miner_tx_hooks.push_back(std::move(hook)); }
/**
* @brief add a hook to be called when adding an alt-chain block; should throw to abort adding.
*/
void hook_alt_block_added(BlockAddedHook hook) { m_alt_block_added_hooks.push_back(std::move(hook)); }
/**
* @brief returns the timestamps of the last N blocks

View File

@ -768,14 +768,14 @@ namespace cryptonote
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_blockchain_detached([this] (const auto& info) { return m_service_node_list.blockchain_detached(info.height); });
m_blockchain_storage.hook_blockchain_detached([this] (const auto& info) { m_service_node_list.blockchain_detached(info.height); });
m_blockchain_storage.hook_init([this] { m_service_node_list.init(); });
m_blockchain_storage.hook_validate_miner_tx([this] (const auto& info) { return m_service_node_list.validate_miner_tx(info); });
m_blockchain_storage.hook_alt_block_added([this] (const auto& info) { return m_service_node_list.alt_block_added(info); });
m_blockchain_storage.hook_validate_miner_tx([this] (const auto& info) { m_service_node_list.validate_miner_tx(info); });
m_blockchain_storage.hook_alt_block_added([this] (const auto& info) { m_service_node_list.alt_block_added(info); });
// NOTE: There is an implicit dependency on service node lists being hooked first!
m_blockchain_storage.hook_init([this] { m_quorum_cop.init(); });
m_blockchain_storage.hook_block_added([this] (const auto& info) { return m_quorum_cop.block_added(info.block, info.txs); });
m_blockchain_storage.hook_block_added([this] (const auto& info) { m_quorum_cop.block_added(info.block, info.txs); });
m_blockchain_storage.hook_blockchain_detached([this] (const auto& info) { m_quorum_cop.blockchain_detached(info.height, info.by_pop_blocks); });
}

View File

@ -1542,12 +1542,12 @@ namespace service_nodes
}
bool service_node_list::verify_block(const cryptonote::block &block, bool alt_block, cryptonote::checkpoint_t const *checkpoint)
void service_node_list::verify_block(const cryptonote::block &block, bool alt_block, cryptonote::checkpoint_t const *checkpoint)
{
if (block.major_version < hf::hf9_service_nodes)
return true;
return;
std::string_view block_type = alt_block ? "alt block "sv : "block "sv;
std::string_view block_type = alt_block ? "alt block"sv : "block"sv;
//
// NOTE: Verify the checkpoint given on this height that locks in a block in the past.
@ -1558,10 +1558,7 @@ namespace service_nodes
std::shared_ptr<const quorum> quorum = get_quorum(quorum_type::checkpointing, checkpoint->height, false, alt_block ? &alt_quorums : nullptr);
if (!quorum)
{
MGINFO("Failed to get testing quorum checkpoint for " << block_type << cryptonote::get_block_hash(block));
return false;
}
throw std::runtime_error{fmt::format("Failed to get testing quorum checkpoint for {} {}", block_type, cryptonote::get_block_hash(block))};
bool failed_checkpoint_verify = !service_nodes::verify_checkpoint(block.major_version, *checkpoint, *quorum);
if (alt_block && failed_checkpoint_verify)
@ -1577,10 +1574,7 @@ namespace service_nodes
}
if (failed_checkpoint_verify)
{
MGINFO("Service node checkpoint failed verification for " << block_type << cryptonote::get_block_hash(block));
return false;
}
throw std::runtime_error{fmt::format("Service node checkpoint failed verification for {} {}", block_type, cryptonote::get_block_hash(block))};
}
//
@ -1595,10 +1589,9 @@ namespace service_nodes
{
cryptonote::block prev_block;
if (!find_block_in_db(m_blockchain.get_db(), block.prev_id, prev_block))
{
MGINFO("Alt block " << cryptonote::get_block_hash(block) << " references previous block " << block.prev_id << " not available in DB.");
return false;
}
throw std::runtime_error{fmt::format(
"Alt block {} references previous block {} not available in DB.",
cryptonote::get_block_hash(block), block.prev_id)};
prev_timestamp = prev_block.timestamp;
}
@ -1609,10 +1602,9 @@ namespace service_nodes
}
if (!pulse::get_round_timings(m_blockchain, height, prev_timestamp, timings))
{
MGINFO("Failed to query the block data for Pulse timings to validate incoming " << block_type << "at height " << height);
return false;
}
throw std::runtime_error{fmt::format(
"Failed to query the block data for Pulse timings to validate incoming {} at height {}",
block_type, height)};
}
//
@ -1670,18 +1662,20 @@ namespace service_nodes
alt_pulse_quorums);
}
return result;
if (!result)
throw std::runtime_error{fmt::format("Failed to verify block components for incoming {} at height {}",
block_type, height)};
}
bool service_node_list::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint)
void service_node_list::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, cryptonote::checkpoint_t const *checkpoint)
{
if (block.major_version < hf::hf9_service_nodes)
return true;
return;
std::lock_guard lock(m_sn_mutex);
process_block(block, txs);
bool result = verify_block(block, false /*alt_block*/, checkpoint);
if (result && cryptonote::block_has_pulse_components(block))
verify_block(block, false /*alt_block*/, checkpoint);
if (cryptonote::block_has_pulse_components(block))
{
// NOTE: Only record participation if its a block we recently received.
// Otherwise processing blocks in retrospect/re-loading on restart seeds
@ -1697,10 +1691,8 @@ namespace service_nodes
{
std::shared_ptr<const quorum> quorum = get_quorum(quorum_type::pulse, block_height, false, nullptr);
if (!quorum || quorum->validators.empty())
{
MFATAL("Unexpected Pulse error " << (quorum ? " quorum was not generated" : " quorum was empty"));
return false;
}
throw std::runtime_error{fmt::format(
"Unexpected Pulse error: {}", quorum ? " quorum was not generated" : " quorum was empty")};
for (size_t validator_index = 0; validator_index < service_nodes::PULSE_QUORUM_NUM_VALIDATORS; validator_index++)
{
@ -1710,7 +1702,6 @@ namespace service_nodes
}
}
}
return result;
}
void service_node_list::reset_batching_to_latest_height()
@ -2442,17 +2433,15 @@ namespace service_nodes
}
// NOTE: Verify queued service node coinbase or pulse block producer rewards
static bool verify_coinbase_tx_output(cryptonote::transaction const &miner_tx,
static void verify_coinbase_tx_output(cryptonote::transaction const &miner_tx,
uint64_t height,
size_t output_index,
cryptonote::account_public_address const &receiver,
uint64_t reward)
{
if (output_index >= miner_tx.vout.size())
{
MGINFO_RED("Output Index: " << output_index << ", indexes out of bounds in vout array with size: " << miner_tx.vout.size());
return false;
}
throw std::out_of_range{fmt::format("Output Index: {} , indexes out of bounds in vout array with size: ",
output_index, miner_tx.vout.size())};
cryptonote::tx_out const &output = miner_tx.vout[output_index];
@ -2461,16 +2450,10 @@ namespace service_nodes
// 1 ULP difference in the reward calculations.
// TODO(oxen): eliminate all FP math from reward calculations
if (!within_one(output.amount, reward))
{
MGINFO_RED("Service node reward amount incorrect. Should be " << cryptonote::print_money(reward) << ", is: " << cryptonote::print_money(output.amount));
return false;
}
throw std::runtime_error{fmt::format("Service node reward amount incorrect. Should be {}, is: {}", cryptonote::print_money(reward), cryptonote::print_money(output.amount))};
if (!std::holds_alternative<cryptonote::txout_to_key>(output.target))
{
MGINFO_RED("Service node output target type should be txout_to_key");
return false;
}
throw std::runtime_error{"Service node output target type should be txout_to_key"};
// NOTE: Loki uses the governance key in the one-time ephemeral key
// derivation for both Pulse Block Producer/Queued Service Node Winner rewards
@ -2478,28 +2461,23 @@ namespace service_nodes
crypto::public_key out_eph_public_key{};
cryptonote::keypair gov_key = cryptonote::get_deterministic_keypair_from_height(height);
bool r = crypto::generate_key_derivation(receiver.m_view_public_key, gov_key.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << receiver.m_view_public_key << ", " << gov_key.sec << ")");
r = crypto::derive_public_key(derivation, output_index, receiver.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< receiver.m_spend_public_key << ")");
if (!crypto::generate_key_derivation(receiver.m_view_public_key, gov_key.sec, derivation))
throw std::runtime_error{"Failed to generate key derivation"};
if (!crypto::derive_public_key(derivation, output_index, receiver.m_spend_public_key, out_eph_public_key))
throw std::runtime_error{"Failed derive public key"};
if (var::get<cryptonote::txout_to_key>(output.target).key != out_eph_public_key)
{
MGINFO_RED("Invalid service node reward at output: " << output_index << ", output key, specifies wrong key");
return false;
}
return true;
throw std::runtime_error{fmt::format("Invalid service node reward at output: {}, output key, specifies wrong key", output_index)};
}
bool service_node_list::validate_miner_tx(const cryptonote::miner_tx_info& info) const
void service_node_list::validate_miner_tx(const cryptonote::miner_tx_info& info) const
{
const auto& block = info.block;
const auto& reward_parts = info.reward_parts;
const auto& batched_sn_payments = info.batched_sn_payments;
const auto hf_version = block.major_version;
if (hf_version < hf::hf9_service_nodes)
return true;
return;
std::lock_guard lock(m_sn_mutex);
uint64_t const height = cryptonote::get_block_height(block);
@ -2514,10 +2492,7 @@ namespace service_nodes
{
auto const check_block_leader_pubkey = cryptonote::get_service_node_winner_from_tx_extra(miner_tx.extra);
if (block_leader.key != check_block_leader_pubkey)
{
MGINFO_RED("Service node reward winner is incorrect! Expected " << block_leader.key << ", block has " << check_block_leader_pubkey);
return false;
}
throw std::runtime_error{fmt::format("Service node reward winner is incorrect! Expected {}, block has {}", block_leader.key, check_block_leader_pubkey)};
}
enum struct verify_mode
@ -2539,20 +2514,14 @@ namespace service_nodes
std::vector<crypto::hash> entropy = get_pulse_entropy_for_next_block(m_blockchain.get_db(), block.prev_id, block.pulse.round);
quorum pulse_quorum = generate_pulse_quorum(m_blockchain.nettype(), block_leader.key, hf_version, m_state.active_service_nodes_infos(), entropy, block.pulse.round);
if (!verify_pulse_quorum_sizes(pulse_quorum))
{
MGINFO_RED("Pulse block received but Pulse has insufficient nodes for quorum, block hash " << cryptonote::get_block_hash(block) << ", height " << height);
return false;
}
throw std::runtime_error{fmt::format("Pulse block received but Pulse has insufficient nodes for quorum, block hash {}, height {}", cryptonote::get_block_hash(block), height)};
block_producer_key = pulse_quorum.workers[0];
mode = (block_producer_key == block_leader.key) ? verify_mode::pulse_block_leader_is_producer
: verify_mode::pulse_different_block_producer;
if (block.pulse.round == 0 && (mode == verify_mode::pulse_different_block_producer))
{
MGINFO_RED("The block producer in pulse round 0 should be the same node as the block leader: " << block_leader.key << ", actual producer: " << block_producer_key);
return false;
}
throw std::runtime_error{fmt::format("The block producer in pulse round 0 should be the same node as the block leader: {}, actual producer: {}", block_leader.key, block_producer_key)};
}
// NOTE: Verify miner tx vout composition
@ -2588,10 +2557,7 @@ namespace service_nodes
{
auto info_it = m_state.service_nodes_infos.find(block_producer_key);
if (info_it == m_state.service_nodes_infos.end())
{
MGINFO_RED("The pulse block producer for round: " << +block.pulse.round << " is not currently a Service Node: " << block_producer_key);
return false;
}
throw std::runtime_error{fmt::format("The pulse block producer for round {:d} is not current a Service Node: {}", block.pulse.round, block_producer_key)};
block_producer = info_it->second;
expected_vouts_size = mode == verify_mode::pulse_different_block_producer && reward_parts.miner_fee > 0
@ -2613,20 +2579,16 @@ namespace service_nodes
}
if (miner_tx.vout.size() != expected_vouts_size)
{
auto type =
mode == verify_mode::miner ? "miner"sv :
mode == verify_mode::batched_sn_rewards ? "batch reward"sv :
mode == verify_mode::pulse_block_leader_is_producer ? "pulse"sv : "pulse alt round"sv;
MGINFO_RED("Expected " << type << " block, the miner TX specifies a different amount of outputs vs the expected: " << expected_vouts_size << ", miner tx outputs: " << miner_tx.vout.size());
return false;
}
throw std::runtime_error{fmt::format("Expected {} block, the miner TX specifies a different amount of outputs vs the expected: {}, miner tx outputs: {}",
mode == verify_mode::miner ? "miner"sv :
mode == verify_mode::batched_sn_rewards ? "batch reward"sv :
mode == verify_mode::pulse_block_leader_is_producer ? "pulse"sv :
"pulse alt round"sv,
expected_vouts_size,
miner_tx.vout.size())};
if (hf_version >= hf::hf16_pulse && reward_parts.base_miner != 0)
{
MGINFO_RED("Miner reward is incorrect expected 0 reward, block specified " << cryptonote::print_money(reward_parts.base_miner));
return false;
}
throw std::runtime_error{fmt::format("Miner reward is incorrect expected 0 reward, block specified {}", cryptonote::print_money(reward_parts.base_miner))};
// NOTE: Verify Coinbase Amounts
switch(mode)
@ -2649,8 +2611,7 @@ namespace service_nodes
const auto& payout = block_leader.payouts[i];
if (split_rewards[i])
{
if (!verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]))
return false;
verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]);
vout_index++;
}
}
@ -2669,8 +2630,7 @@ namespace service_nodes
const auto& payout = block_leader.payouts[i];
if (split_rewards[i])
{
if (!verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]))
return false;
verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]);
vout_index++;
}
}
@ -2688,8 +2648,7 @@ namespace service_nodes
const auto& payout = block_producer_payouts.payouts[i];
if (split_rewards[i])
{
if (!verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]))
return false;
verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]);
vout_index++;
}
}
@ -2701,8 +2660,7 @@ namespace service_nodes
const auto& payout = block_leader.payouts[i];
if (split_rewards[i])
{
if (!verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]))
return false;
verify_coinbase_tx_output(miner_tx, height, vout_index, payout.address, split_rewards[i]);
vout_index++;
}
}
@ -2726,52 +2684,33 @@ namespace service_nodes
const auto& batch_payment = batched_sn_payments[vout_index];
if (!std::holds_alternative<cryptonote::txout_to_key>(vout.target))
{
MGINFO_RED("Service node output target type should be txout_to_key");
return false;
}
throw std::runtime_error{"Service node output target type should be txout_to_key"};
constexpr uint64_t max_amount = std::numeric_limits<uint64_t>::max() / cryptonote::BATCH_REWARD_FACTOR;
if (vout.amount > max_amount)
{
// We should never actually hit this limit unless someone is trying something nefarious
MGINFO_RED("Batched reward payout invalid: exceeds maximum possible payout size");
return false;
}
throw std::runtime_error{"Batched reward payout invalid: exceeds maximum possible payout size"};
auto paid_amount = vout.amount * cryptonote::BATCH_REWARD_FACTOR;
total_payout_in_vouts += paid_amount;
if (paid_amount != batch_payment.amount)
{
MGINFO_RED(fmt::format("Batched reward payout incorrect: expected {}, not {}", batch_payment.amount, paid_amount));
return false;
}
throw std::runtime_error{fmt::format("Batched reward payout incorrect: expected {}, not {}", batch_payment.amount, paid_amount)};
crypto::public_key out_eph_public_key{};
if (!cryptonote::get_deterministic_output_key(batch_payment.address_info.address, deterministic_keypair, vout_index, out_eph_public_key))
{
MGINFO_RED("Failed to generate output one-time public key");
return false;
}
throw std::runtime_error{"Failed to generate output one-time public key"};
const auto& out_to_key = var::get<cryptonote::txout_to_key>(vout.target);
if (tools::view_guts(out_to_key) != tools::view_guts(out_eph_public_key))
{
MGINFO_RED("Output Ephermeral Public Key does not match (payment to wrong recipient)");
return false;
}
throw std::runtime_error{"Output Ephermeral Public Key does not match (payment to wrong recipient)"};
}
if (total_payout_in_vouts != total_payout_in_our_db)
{
MGINFO_RED(fmt::format("Total service node reward amount incorrect: expected {}, not {}", total_payout_in_our_db, total_payout_in_vouts));
return false;
}
throw std::runtime_error{fmt::format("Total service node reward amount incorrect: expected {}, not {}", total_payout_in_our_db, total_payout_in_vouts)};
}
break;
}
return true;
}
bool service_node_list::alt_block_added(const cryptonote::block_added_info& info)
void service_node_list::alt_block_added(const cryptonote::block_added_info& info)
{
// NOTE: The premise is to search the main list and the alternative list for
// the parent of the block we just received, generate the new Service Node
@ -2784,14 +2723,14 @@ namespace service_nodes
auto& block = info.block;
if (block.major_version < hf::hf9_service_nodes)
return true;
return;
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_transient.alt_state.find(block_hash);
if (it != m_transient.alt_state.end()) return true; // NOTE: Already processed alt-state for this block
if (it != m_transient.alt_state.end()) return; // NOTE: Already processed alt-state for this block
// NOTE: Check if alt block forks off some historical state on the canonical chain
if (!starting_state)
@ -2809,17 +2748,11 @@ namespace service_nodes
}
if (!starting_state)
{
LOG_PRINT_L1("Received alt block but couldn't find parent state in historical state");
return false;
}
throw std::runtime_error{"Received alt block but couldn't find parent state in historical 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 false;
}
throw std::runtime_error{fmt::format("Unexpected state_t's hash: {}, does not match the block prev hash: {}",
starting_state->block_hash, block.prev_id)};
// NOTE: Generate the next Service Node list state from this Alt block.
state_t alt_state = *starting_state;
@ -2830,7 +2763,7 @@ namespace service_nodes
else
m_transient.alt_state.emplace(block_hash, std::move(alt_state));
return verify_block(block, true /*alt_block*/, info.checkpoint);
verify_block(block, true /*alt_block*/, info.checkpoint);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -455,15 +455,15 @@ namespace service_nodes
service_node_list(const service_node_list &) = delete;
service_node_list &operator=(const service_node_list &) = delete;
bool block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, const cryptonote::checkpoint_t* checkpoint);
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, const cryptonote::checkpoint_t* checkpoint);
void reset_batching_to_latest_height();
bool state_history_exists(uint64_t height);
bool process_batching_rewards(const cryptonote::block& block);
bool pop_batching_rewards_block(const cryptonote::block& block);
void blockchain_detached(uint64_t height);
void init();
bool validate_miner_tx(const cryptonote::miner_tx_info& info) const;
bool alt_block_added(const cryptonote::block_added_info& info);
void validate_miner_tx(const cryptonote::miner_tx_info& info) const;
void alt_block_added(const cryptonote::block_added_info& info);
payout get_block_leader() const { std::lock_guard lock{m_sn_mutex}; return m_state.get_block_leader(); }
bool is_service_node(const crypto::public_key& pubkey, bool require_active = true) const;
bool is_key_image_locked(crypto::key_image const &check_image, uint64_t *unlock_height = nullptr, service_node_info::contribution_t *the_locked_contribution = nullptr) const;
@ -739,7 +739,7 @@ namespace service_nodes
void record_pulse_participation(crypto::public_key const &pubkey, uint64_t height, uint8_t round, bool participated);
// Verify block against Service Node state that has just been called with 'state.update_from_block(block)'.
bool verify_block(const cryptonote::block& block, bool alt_block, cryptonote::checkpoint_t const *checkpoint);
void verify_block(const cryptonote::block& block, bool alt_block, cryptonote::checkpoint_t const *checkpoint);
void reset(bool delete_db_entry = false);
bool load(uint64_t current_height);

View File

@ -510,7 +510,7 @@ namespace service_nodes
}
}
bool quorum_cop::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
void quorum_cop::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs)
{
process_quorums(block);
uint64_t const height = cryptonote::get_block_height(block) + 1; // chain height = new top block height + 1
@ -520,8 +520,6 @@ namespace service_nodes
// These feels out of place here because the hook system sucks: TODO replace it with
// std::function hooks instead.
m_core.update_omq_sns();
return true;
}
static bool handle_obligations_vote(cryptonote::core &core, const quorum_vote_t& vote, const std::vector<pool_vote_entry>& votes, const quorum& quorum)

View File

@ -115,7 +115,7 @@ namespace service_nodes
explicit quorum_cop(cryptonote::core& core);
void init();
bool block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs);
void block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs);
void blockchain_detached(uint64_t height, bool by_pop_blocks);
void set_votes_relayed (std::vector<quorum_vote_t> const &relayed_votes);