forked from lthn/blockchain
Added PoS grinding attack fuse
This commit is contained in:
parent
7237867f15
commit
10c451f3b7
9 changed files with 201 additions and 33 deletions
|
|
@ -67,6 +67,8 @@ using namespace currency;
|
|||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION 2
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //DON'T CHANGE THIS, if you need to resync db change BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations
|
||||
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE 5 //if not blocks should ever be added with this condition
|
||||
|
||||
|
||||
#define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10
|
||||
|
||||
|
|
@ -96,6 +98,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m
|
|||
m_db_last_worked_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION, m_db_solo_options),
|
||||
m_db_storage_major_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options),
|
||||
m_db_storage_minor_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION, m_db_solo_options),
|
||||
m_db_major_failure(BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE, m_db_solo_options),
|
||||
m_db_per_block_gindex_incs(m_db),
|
||||
m_tx_pool(tx_pool),
|
||||
m_is_in_checkpoint_zone(false),
|
||||
|
|
@ -507,7 +510,8 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
|
|||
<< " last block: " << m_db_blocks.size() - 1 << ", " << misc_utils::get_time_interval_string(timestamp_diff) << " ago" << ENDL
|
||||
<< " current pos difficulty: " << get_next_diff_conditional(true) << ENDL
|
||||
<< " current pow difficulty: " << get_next_diff_conditional(false) << ENDL
|
||||
<< " total transactions: " << m_db_transactions.size(),
|
||||
<< " total transactions: " << m_db_transactions.size() << ENDL
|
||||
<< " major failure: " << (m_db_major_failure ? "true" : "false"),
|
||||
LOG_LEVEL_0);
|
||||
|
||||
return true;
|
||||
|
|
@ -1181,14 +1185,9 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) const
|
||||
void blockchain_storage::collect_timestamps_and_c_difficulties_main(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
std::vector<uint64_t> timestamps;
|
||||
std::vector<wide_difficulty_type> commulative_difficulties;
|
||||
if (!m_db_blocks.size())
|
||||
return DIFFICULTY_POW_STARTER;
|
||||
//skip genesis timestamp
|
||||
TIME_MEASURE_START_PD(target_calculating_enum_blocks);
|
||||
CRITICAL_REGION_BEGIN(m_targetdata_cache_lock);
|
||||
std::list<std::pair<wide_difficulty_type, uint64_t>>& targetdata_cache = pos ? m_pos_targetdata_cache : m_pow_targetdata_cache;
|
||||
|
|
@ -1203,11 +1202,14 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con
|
|||
++count;
|
||||
}
|
||||
CRITICAL_REGION_END();
|
||||
|
||||
wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty;
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_enum_blocks);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::calc_diff_at_h_from_timestamps(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, uint64_t h, bool pos) const
|
||||
{
|
||||
wide_difficulty_type dif;
|
||||
TIME_MEASURE_START_PD(target_calculating_calc);
|
||||
if (m_core_runtime_config.is_hardfork_active_for_height(1, m_db_blocks.size()))
|
||||
if (m_core_runtime_config.is_hardfork_active_for_height(1, h))
|
||||
{
|
||||
dif = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
|
||||
}
|
||||
|
|
@ -1215,22 +1217,36 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con
|
|||
{
|
||||
dif = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
|
||||
}
|
||||
|
||||
|
||||
TIME_MEASURE_FINISH_PD(target_calculating_calc);
|
||||
return dif;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
{
|
||||
//skip genesis timestamp
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
if (!m_db_blocks.size())
|
||||
return DIFFICULTY_POW_STARTER;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> timestamps;
|
||||
std::vector<wide_difficulty_type> commulative_difficulties;
|
||||
size_t count = 0;
|
||||
if (!m_db_blocks.size())
|
||||
return DIFFICULTY_POW_STARTER;
|
||||
collect_timestamps_and_c_difficulties_main(timestamps, commulative_difficulties, pos);
|
||||
|
||||
auto cb = [&](const block_extended_info& bei, bool is_main){
|
||||
|
||||
wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty;
|
||||
dif = calc_diff_at_h_from_timestamps(timestamps, commulative_difficulties, m_db_blocks.size(), pos);
|
||||
|
||||
return dif;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::collect_timestamps_and_c_difficulties_alt(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
size_t count = 0;
|
||||
|
||||
auto cb = [&](const block_extended_info& bei, bool is_main) {
|
||||
if (!bei.height)
|
||||
return false;
|
||||
bool is_pos_bl = is_pos_block(bei.bl);
|
||||
|
|
@ -1242,15 +1258,22 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, co
|
|||
if (count >= DIFFICULTY_WINDOW)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
};
|
||||
enum_blockchain(cb, alt_chain, split_height);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_next_diff_conditional_alt(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const
|
||||
{
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
if (!m_db_blocks.size())
|
||||
return DIFFICULTY_POW_STARTER;
|
||||
}
|
||||
std::vector<uint64_t> timestamps;
|
||||
std::vector<wide_difficulty_type> commulative_difficulties;
|
||||
collect_timestamps_and_c_difficulties_alt(timestamps, commulative_difficulties, pos, alt_chain, split_height);
|
||||
|
||||
wide_difficulty_type diff = 0;
|
||||
if(m_core_runtime_config.is_hardfork_active_for_height(1, abei.height))
|
||||
diff = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
|
||||
else
|
||||
diff = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
|
||||
return diff;
|
||||
return calc_diff_at_h_from_timestamps(timestamps, commulative_difficulties, abei.height, pos);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
wide_difficulty_type blockchain_storage::get_cached_next_difficulty(bool pos) const
|
||||
|
|
@ -1865,7 +1888,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
}
|
||||
|
||||
// PoW / PoS validation (heavy checks)
|
||||
wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height, abei);
|
||||
wide_difficulty_type current_diff = get_next_diff_conditional_alt(pos_block, alt_chain, connection_height, abei);
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(current_diff, false, bvc.m_verification_failed = true, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
|
||||
|
||||
crypto::hash proof_of_work = null_hash;
|
||||
|
|
@ -5751,6 +5774,12 @@ void blockchain_storage::get_pos_mining_estimate(uint64_t amount_coins,
|
|||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id) const
|
||||
{
|
||||
if (m_db_major_failure)
|
||||
{
|
||||
LOG_ERROR("MAJOR FAILURE: POS DIFFICULTY IS GOT TO HIGH! Contact the team immediately if you see this error in logs and watch them having panic attack.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t block_height = m_db_blocks.size();
|
||||
return validate_tx_for_hardfork_specific_terms(tx, tx_id, block_height);
|
||||
}
|
||||
|
|
@ -6780,6 +6809,13 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
<< range_proofs_agregated.size()
|
||||
<< ")"
|
||||
<< "))");
|
||||
if (is_pos_bl && current_diffic > m_core_runtime_config.max_pos_difficulty)
|
||||
{
|
||||
m_db_major_failure = true; //burn safety fuse
|
||||
LOG_ERROR("MAJOR FAILURE: POS DIFFICULTY IS GOT TO HIGH! Contact the team immediately if you see this error in logs and watch them having panic attack."
|
||||
<< ENDL << "Block id:" << id);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
static epee::math_helper::average<uint64_t, 30> blocks_processing_time_avg_pos, blocks_processing_time_avg_pow;
|
||||
|
|
@ -6956,6 +6992,15 @@ bool blockchain_storage::add_new_block(const block& bl, block_verification_conte
|
|||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (m_db_major_failure)
|
||||
{
|
||||
LOG_PRINT_RED_L0("Block processing is stoped due to MAJOR FAILURE fuse burned");
|
||||
bvc.m_added_to_main_chain = false;
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_db.begin_transaction();
|
||||
|
||||
//block bl = bl_;
|
||||
|
|
@ -6979,10 +7024,6 @@ bool blockchain_storage::add_new_block(const block& bl, block_verification_conte
|
|||
m_db.commit_transaction();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//check that block refers to chain tail
|
||||
|
||||
|
||||
if (!(bl.prev_id == get_top_block_id()))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -266,8 +266,12 @@ namespace currency
|
|||
crypto::hash get_top_block_id(uint64_t& height) const;
|
||||
bool get_top_block(block& b) const;
|
||||
wide_difficulty_type get_next_diff_conditional(bool pos) const;
|
||||
wide_difficulty_type get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const;
|
||||
wide_difficulty_type get_next_diff_conditional_alt(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const;
|
||||
wide_difficulty_type get_cached_next_difficulty(bool pos) const;
|
||||
wide_difficulty_type calc_diff_at_h_from_timestamps(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, uint64_t h, bool pos) const;
|
||||
void collect_timestamps_and_c_difficulties_main(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos) const;
|
||||
void collect_timestamps_and_c_difficulties_alt(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const;
|
||||
|
||||
|
||||
|
||||
bool create_block_template(const account_public_address& miner_address, const blobdata& ex_nonce, block& b, wide_difficulty_type& di, uint64_t& height) const;
|
||||
|
|
@ -551,6 +555,8 @@ namespace currency
|
|||
tools::db::solo_db_value<uint64_t, std::string, solo_options_container, true> m_db_last_worked_version;
|
||||
tools::db::solo_db_value<uint64_t, uint64_t, solo_options_container> m_db_storage_major_compatibility_version;
|
||||
tools::db::solo_db_value<uint64_t, uint64_t, solo_options_container> m_db_storage_minor_compatibility_version;
|
||||
tools::db::solo_db_value<uint64_t, bool, solo_options_container> m_db_major_failure; //safety fuse
|
||||
|
||||
outputs_container m_db_outputs;
|
||||
multisig_outs_container m_db_multisig_outs;
|
||||
aliases_container m_db_aliases;
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ namespace currency
|
|||
crypto::public_key alias_validation_pubkey;
|
||||
core_time_func_t get_core_time;
|
||||
uint64_t hf4_minimum_mixins;
|
||||
wide_difficulty_type max_pos_difficulty;
|
||||
|
||||
hard_forks_descriptor hard_forks;
|
||||
|
||||
|
|
@ -129,6 +130,7 @@ namespace currency
|
|||
pc.tx_default_fee = TX_DEFAULT_FEE;
|
||||
pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT;
|
||||
pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
|
||||
pc.max_pos_difficulty = wide_difficulty_type(POS_MAX_DIFFICULTY_ALLOWED);
|
||||
|
||||
// TODO: refactor the following
|
||||
pc.hard_forks.set_hardfork_height(1, ZANO_HARDFORK_01_AFTER_HEIGHT);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,8 @@
|
|||
#define POS_MODFIFIER_INTERVAL 10
|
||||
#define POS_WALLET_MINING_SCAN_INTERVAL POS_SCAN_STEP //seconds
|
||||
#define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count
|
||||
#define POS_MAX_DIFFICULTY_ALLOWED "25000000000000000000000" // maximum expected PoS difficuty (need to change it probaly in 20 years)
|
||||
|
||||
|
||||
#ifndef TESTNET
|
||||
# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 57000
|
||||
|
|
|
|||
|
|
@ -4887,15 +4887,16 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address
|
|||
return true;
|
||||
}, m_core_runtime_config);
|
||||
|
||||
bool res = true;
|
||||
if (ctx.status == API_RETURN_CODE_OK)
|
||||
{
|
||||
build_minted_block(ctx, miner_address);
|
||||
res = build_minted_block(ctx, miner_address);
|
||||
}
|
||||
TIME_MEASURE_FINISH_MS(mining_duration_ms);
|
||||
|
||||
WLT_LOG_L0("PoS mining: " << ctx.iterations_processed << " iterations finished (" << std::fixed << std::setprecision(2) << (mining_duration_ms / 1000.0f) << "s), status: " << ctx.status << ", " << ctx.total_items_checked << " entries with total amount: " << print_money_brief(ctx.total_amount_checked));
|
||||
|
||||
return true;
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void wallet2::do_pos_mining_prepare_entry(mining_context& context, size_t transfer_index)
|
||||
|
|
|
|||
|
|
@ -1274,6 +1274,9 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(zarcanum_block_with_txs);
|
||||
GENERATE_AND_PLAY(asset_depoyment_and_few_zc_utxos);
|
||||
GENERATE_AND_PLAY_HF(assets_and_pos_mining, "4-*");
|
||||
|
||||
GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*");
|
||||
|
||||
|
||||
|
||||
GENERATE_AND_PLAY_HF(attachment_isolation_test, "4-*");
|
||||
|
|
|
|||
|
|
@ -45,3 +45,4 @@
|
|||
#include "multiassets_test.h"
|
||||
#include "ionic_swap_tests.h"
|
||||
#include "attachment_isolation_encryption_test.h"
|
||||
#include "pos_fuse_test.h"
|
||||
98
tests/core_tests/pos_fuse_test.cpp
Normal file
98
tests/core_tests/pos_fuse_test.cpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2014-2022 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "pos_fuse_test.h"
|
||||
#include "wallet_test_core_proxy.h"
|
||||
|
||||
#include "random_helper.h"
|
||||
#include "wallet/wallet_debug_events_definitions.h"
|
||||
using namespace currency;
|
||||
|
||||
|
||||
using namespace currency;
|
||||
pos_fuse_test::pos_fuse_test()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(pos_fuse_test, c1);
|
||||
REGISTER_CALLBACK_METHOD(pos_fuse_test, configure_core);
|
||||
}
|
||||
|
||||
bool pos_fuse_test::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
wallet_test::configure_core(c, ev_index, events);
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.max_pos_difficulty = wide_difficulty_type(1);
|
||||
//currency::core_runtime_config pc2;
|
||||
//pc2 = pc;
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
|
||||
|
||||
currency::core_runtime_config pc2 = c.get_blockchain_storage().get_core_runtime_config();
|
||||
LOG_PRINT_L1("Difficulty: " << pc2.max_pos_difficulty);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pos_fuse_test::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
uint64_t ts = test_core_time::get_time();
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
|
||||
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 10);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pos_fuse_test::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false;
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
miner_wlt->refresh();
|
||||
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
miner_wlt->refresh();
|
||||
wide_difficulty_type pos_diff = c.get_blockchain_storage().get_next_diff_conditional(true);
|
||||
|
||||
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
|
||||
|
||||
bool r = miner_wlt->try_mint_pos();
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed ot mint pos block");
|
||||
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
LOG_PRINT_MAGENTA("POS Difficulty: " << pos_diff << ", max allowed diff: " << pc.max_pos_difficulty, LOG_LEVEL_0);
|
||||
if (pos_diff > pc.max_pos_difficulty)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check that PoW blocks not going
|
||||
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
|
||||
CHECK_AND_ASSERT_MES(!r, false, "PoW block unexpectedly generated");
|
||||
|
||||
//check that PoS blocks not going
|
||||
r = miner_wlt->try_mint_pos();
|
||||
CHECK_AND_ASSERT_MES(!r, false, "PoS block unexpectedly mined");
|
||||
|
||||
try
|
||||
{
|
||||
miner_wlt->transfer(1000000, m_accounts[ALICE_ACC_IDX].get_public_address());
|
||||
CHECK_AND_ASSERT_MES(false, false, "Transaction unexpectedly sent");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L0("Expected exception catched");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
14
tests/core_tests/pos_fuse_test.h
Normal file
14
tests/core_tests/pos_fuse_test.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2014-2024 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#pragma once
|
||||
#include "chaingen.h"
|
||||
#include "wallet_tests_basic.h"
|
||||
|
||||
struct pos_fuse_test : public wallet_test
|
||||
{
|
||||
pos_fuse_test();
|
||||
virtual bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue