mirror of https://github.com/oxen-io/oxen-core.git
add core tests for swarms (#321)
This commit is contained in:
parent
2ba498242e
commit
6d763041e0
|
@ -916,14 +916,17 @@ namespace cryptonote
|
|||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, bool is_staking, bool per_output_unlock)
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, uint8_t hf_version, bool is_staking)
|
||||
{
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
|
||||
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
|
||||
crypto::secret_key tx_key;
|
||||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
std::vector<tx_destination_entry> destinations_copy = destinations;
|
||||
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct::RangeProofBorromean, NULL, is_staking, per_output_unlock);
|
||||
|
||||
const rct::RangeProofType rp_type = (hf_version < network_version_10_bulletproofs) ? rct::RangeProofBorromean : rct::RangeProofPaddedBulletproof;
|
||||
const bool per_output_unlock = (hf_version >= network_version_9_service_nodes);
|
||||
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rp_type, NULL, is_staking, per_output_unlock);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_genesis_block(
|
||||
|
|
|
@ -170,7 +170,7 @@ namespace cryptonote
|
|||
|
||||
//---------------------------------------------------------------
|
||||
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr);
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, bool is_staking = false, bool per_output_unlock = false);
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, uint8_t hf_version = cryptonote::network_version_7, bool is_staking = false);
|
||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, rct::RangeProofType range_proof_type = rct::RangeProofBorromean, rct::multisig_out *msout = NULL, bool per_output_unlock = false, bool shuffle_outs = true);
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::tx_destination_entry>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, rct::RangeProofType range_proof_type = rct::RangeProofBorromean, rct::multisig_out *msout = NULL, bool is_staking_tx = false, bool per_output_unlock = false);
|
||||
|
||||
|
|
|
@ -88,6 +88,32 @@ void linear_chain_generator::create_block(const std::vector<cryptonote::transact
|
|||
blocks_.push_back(blk);
|
||||
}
|
||||
|
||||
|
||||
void linear_chain_generator::continue_until_version(const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks, int hard_fork_version)
|
||||
{
|
||||
assert(gen_.m_hf_version < hard_fork_version);
|
||||
|
||||
for (auto i = 0u; i < hard_forks.size() - 1; ++i) {
|
||||
|
||||
const uint8_t ver = hard_forks[i].first;
|
||||
const uint64_t height = hard_forks[i].second;
|
||||
|
||||
if (ver < get_hf_version()) continue;
|
||||
|
||||
auto cur_height = blocks_.size();
|
||||
uint64_t next_fork_height = hard_forks[i + 1].second;
|
||||
|
||||
uint64_t blocks_till_next_hardfork = next_fork_height - cur_height;
|
||||
|
||||
rewind_blocks_n(blocks_till_next_hardfork);
|
||||
gen_.m_hf_version = hard_forks[i + 1].first;
|
||||
create_block();
|
||||
|
||||
}
|
||||
|
||||
assert(gen_.m_hf_version == hard_fork_version);
|
||||
}
|
||||
|
||||
void linear_chain_generator::rewind_until_version(const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks, int hard_fork_version)
|
||||
{
|
||||
if (hard_forks.size() > 1)
|
||||
|
@ -111,6 +137,10 @@ void linear_chain_generator::rewind_until_version(const std::vector<std::pair<ui
|
|||
}
|
||||
}
|
||||
|
||||
int linear_chain_generator::get_hf_version() const {
|
||||
return gen_.m_hf_version;
|
||||
}
|
||||
|
||||
|
||||
void linear_chain_generator::rewind_until_v9()
|
||||
{
|
||||
|
@ -209,7 +239,7 @@ cryptonote::transaction linear_chain_generator::create_tx(const cryptonote::acco
|
|||
uint64_t fee)
|
||||
{
|
||||
cryptonote::transaction t;
|
||||
TxBuilder(events_, t, blocks_.back(), miner, acc, amount).with_fee(fee).build();
|
||||
TxBuilder(events_, t, blocks_.back(), miner, acc, amount, gen_.m_hf_version).with_fee(fee).build();
|
||||
events_.push_back(t);
|
||||
return t;
|
||||
}
|
||||
|
@ -222,7 +252,7 @@ cryptonote::transaction linear_chain_generator::create_registration_tx(const cry
|
|||
|
||||
const auto reg_idx = registration_buffer_.size();
|
||||
registration_buffer_.push_back({ expires, sn_keys, contr, { height(), reg_idx } });
|
||||
return make_default_registration_tx(events_, acc, sn_keys, blocks_.back());
|
||||
return make_default_registration_tx(events_, acc, sn_keys, blocks_.back(), gen_.m_hf_version);
|
||||
}
|
||||
|
||||
cryptonote::transaction linear_chain_generator::create_registration_tx()
|
||||
|
@ -262,7 +292,7 @@ cryptonote::transaction linear_chain_generator::create_deregister_tx(const crypt
|
|||
deregister.votes.push_back({ signature, (uint32_t)voter.idx_in_quorum });
|
||||
}
|
||||
|
||||
const auto deregister_tx = make_deregistration_tx(events_, first_miner_, blocks_.back(), deregister, fee);
|
||||
const auto deregister_tx = make_deregistration_tx(events_, first_miner_, blocks_.back(), deregister, gen_.m_hf_version, fee);
|
||||
|
||||
events_.push_back(deregister_tx);
|
||||
|
||||
|
@ -619,7 +649,8 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
|
|||
uint64_t operator_cut,
|
||||
const std::vector<cryptonote::account_public_address>& addresses,
|
||||
const std::vector<uint64_t>& portions,
|
||||
const cryptonote::block& head)
|
||||
const cryptonote::block& head,
|
||||
uint8_t hf_version)
|
||||
{
|
||||
const auto new_height = cryptonote::get_block_height(head) + 1;
|
||||
const auto staking_requirement = service_nodes::get_staking_requirement(cryptonote::FAKECHAIN, new_height);
|
||||
|
@ -647,7 +678,7 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
|
|||
add_service_node_register_to_tx_extra(extra, addresses, operator_cut, portions, exp_timestamp, signature);
|
||||
add_service_node_contributor_to_tx_extra(extra, addresses.at(0));
|
||||
|
||||
TxBuilder(events, tx, head, account, account, amount).is_staking(true).with_extra(extra).with_unlock_time(unlock_time).with_per_output_unlock(true).build();
|
||||
TxBuilder(events, tx, head, account, account, amount, hf_version).is_staking(true).with_extra(extra).with_unlock_time(unlock_time).with_per_output_unlock(true).build();
|
||||
events.push_back(tx);
|
||||
return tx;
|
||||
}
|
||||
|
@ -655,7 +686,9 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
|
|||
cryptonote::transaction make_deregistration_tx(const std::vector<test_event_entry>& events,
|
||||
const cryptonote::account_base& account,
|
||||
const cryptonote::block& head,
|
||||
const cryptonote::tx_extra_service_node_deregister& deregister, uint64_t fee)
|
||||
const cryptonote::tx_extra_service_node_deregister& deregister,
|
||||
uint8_t hf_version,
|
||||
uint64_t fee)
|
||||
{
|
||||
cryptonote::transaction tx;
|
||||
|
||||
|
@ -669,7 +702,7 @@ cryptonote::transaction make_deregistration_tx(const std::vector<test_event_entr
|
|||
|
||||
const uint64_t amount = 0;
|
||||
|
||||
if (fee) TxBuilder(events, tx, head, account, account, amount).with_fee(fee).with_extra(extra).with_per_output_unlock(true).build();
|
||||
if (fee) TxBuilder(events, tx, head, account, account, amount, hf_version).with_fee(fee).with_extra(extra).with_per_output_unlock(true).build();
|
||||
|
||||
tx.version = cryptonote::transaction::version_3_per_output_unlock_times;
|
||||
tx.is_deregister = true;
|
||||
|
@ -680,9 +713,10 @@ cryptonote::transaction make_deregistration_tx(const std::vector<test_event_entr
|
|||
cryptonote::transaction make_default_registration_tx(std::vector<test_event_entry>& events,
|
||||
const cryptonote::account_base& account,
|
||||
const cryptonote::keypair& service_node_keys,
|
||||
const cryptonote::block& head)
|
||||
const cryptonote::block& head,
|
||||
uint8_t hf_version)
|
||||
{
|
||||
return make_registration_tx(events, account, service_node_keys, 0, { account.get_keys().m_account_address }, { STAKING_PORTIONS }, head);
|
||||
return make_registration_tx(events, account, service_node_keys, 0, { account.get_keys().m_account_address }, { STAKING_PORTIONS }, head, hf_version);
|
||||
}
|
||||
|
||||
struct output_index {
|
||||
|
|
|
@ -313,7 +313,10 @@ class linear_chain_generator
|
|||
|
||||
cryptonote::block create_block_on_fork(const cryptonote::block& prev, const std::vector<cryptonote::transaction>& txs = {});
|
||||
|
||||
int get_hf_version() const;
|
||||
|
||||
void rewind_until_v9();
|
||||
void continue_until_version(const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks, int hard_fork_version);
|
||||
void rewind_until_version(const std::vector<std::pair<uint8_t, uint64_t>> &hard_forks, int hard_fork_version);
|
||||
void rewind_blocks_n(int n);
|
||||
void rewind_blocks();
|
||||
|
@ -427,6 +430,7 @@ class TxBuilder {
|
|||
|
||||
/// required fields
|
||||
const std::vector<test_event_entry>& m_events;
|
||||
const uint8_t m_hf_version;
|
||||
cryptonote::transaction& m_tx;
|
||||
const cryptonote::block& m_head;
|
||||
const cryptonote::account_base& m_from;
|
||||
|
@ -449,13 +453,15 @@ public:
|
|||
const cryptonote::block& head,
|
||||
const cryptonote::account_base& from,
|
||||
const cryptonote::account_base& to,
|
||||
uint64_t amount)
|
||||
uint64_t amount,
|
||||
uint8_t hf_version = cryptonote::network_version_9_service_nodes)
|
||||
: m_events(events)
|
||||
, m_tx(tx)
|
||||
, m_head(head)
|
||||
, m_from(from)
|
||||
, m_to(to)
|
||||
, m_amount(amount)
|
||||
, m_hf_version(hf_version)
|
||||
, m_fee(TESTS_DEFAULT_FEE)
|
||||
, m_unlock_time(0)
|
||||
{}
|
||||
|
@ -509,7 +515,7 @@ public:
|
|||
cryptonote::tx_destination_entry change_addr{ change_amount, m_from.get_keys().m_account_address, is_subaddr };
|
||||
|
||||
return cryptonote::construct_tx(
|
||||
m_from.get_keys(), sources, destinations, change_addr, m_extra, m_tx, m_unlock_time, m_is_staking, m_per_output_unlock);
|
||||
m_from.get_keys(), sources, destinations, change_addr, m_extra, m_tx, m_unlock_time, m_hf_version, m_is_staking);
|
||||
|
||||
}
|
||||
};
|
||||
|
@ -927,18 +933,20 @@ cryptonote::transaction make_registration_tx(std::vector<test_event_entry>& even
|
|||
uint64_t operator_cut,
|
||||
const std::vector<cryptonote::account_public_address>& addresses,
|
||||
const std::vector<uint64_t>& portions,
|
||||
const cryptonote::block& head);
|
||||
const cryptonote::block& head,
|
||||
uint8_t hf_version);
|
||||
|
||||
cryptonote::transaction make_default_registration_tx(std::vector<test_event_entry>& events,
|
||||
const cryptonote::account_base& account,
|
||||
const cryptonote::keypair& service_node_keys,
|
||||
const cryptonote::block& head);
|
||||
const cryptonote::block& head,
|
||||
uint8_t hf_version);
|
||||
|
||||
|
||||
cryptonote::transaction make_deregistration_tx(const std::vector<test_event_entry>& events,
|
||||
const cryptonote::account_base& account,
|
||||
const cryptonote::block& head,
|
||||
const cryptonote::tx_extra_service_node_deregister& deregister, uint64_t fee = 0);
|
||||
const cryptonote::tx_extra_service_node_deregister& deregister, uint8_t hf_version, uint64_t fee);
|
||||
|
||||
#define MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
|
||||
cryptonote::transaction TX_NAME; \
|
||||
|
|
|
@ -119,6 +119,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(test_deregisters_on_split);
|
||||
GENERATE_AND_PLAY(deregister_too_old);
|
||||
GENERATE_AND_PLAY(sn_test_rollback);
|
||||
GENERATE_AND_PLAY(test_swarms_basic);
|
||||
}
|
||||
|
||||
if (run_all)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "service_nodes.h"
|
||||
#include "cryptonote_core/service_node_list.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -91,6 +92,8 @@ static const std::pair<const char*, const char*> service_node_keys[] = {
|
|||
|
||||
static const auto SN_KEYS_COUNT = sizeof(service_node_keys) / sizeof(service_node_keys[0]);
|
||||
|
||||
static_assert(SN_KEYS_COUNT == 25, "Need to adjust the key count (for readability)");
|
||||
|
||||
cryptonote::keypair get_static_keys(size_t idx) {
|
||||
|
||||
if (idx >= SN_KEYS_COUNT) { MERROR("out of bounds"); throw std::exception(); }
|
||||
|
@ -601,7 +604,8 @@ bool sn_test_rollback::generate(std::vector<test_event_entry>& events)
|
|||
linear_chain_generator gen(events);
|
||||
gen.create_genesis_block();
|
||||
|
||||
gen.rewind_until_v9();
|
||||
const get_test_options<sn_test_rollback> test_options = {};
|
||||
gen.rewind_until_version(test_options.hard_forks, network_version_9_service_nodes);
|
||||
|
||||
/// generate some outputs and unlock them
|
||||
gen.rewind_blocks_n(20);
|
||||
|
@ -711,3 +715,139 @@ bool sn_test_rollback::test_registrations(cryptonote::core& c, size_t ev_index,
|
|||
return true;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
//------------------------------------- Test Swarm Basics ---------------------------------------------
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
||||
test_swarms_basic::test_swarms_basic() {
|
||||
REGISTER_CALLBACK("test_initial_swarms", test_swarms_basic::test_initial_swarms);
|
||||
REGISTER_CALLBACK("test_with_more_sn", test_swarms_basic::test_with_more_sn);
|
||||
REGISTER_CALLBACK("test_after_deregisters", test_swarms_basic::test_after_deregisters);
|
||||
}
|
||||
|
||||
bool test_swarms_basic::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
linear_chain_generator gen(events);
|
||||
|
||||
const get_test_options<test_swarms_basic> test_options = {};
|
||||
gen.rewind_until_version(test_options.hard_forks, network_version_9_service_nodes);
|
||||
|
||||
/// Create some service nodes before hf version 10
|
||||
constexpr size_t init_sn_count = 16;
|
||||
|
||||
gen.rewind_blocks_n(100);
|
||||
gen.rewind_blocks();
|
||||
|
||||
/// register some service nodes
|
||||
std::vector<cryptonote::transaction> reg_txs;
|
||||
for (auto i = 0u; i < init_sn_count; ++i) {
|
||||
const auto sn = get_static_keys(i);
|
||||
const auto tx = gen.create_registration_tx(gen.first_miner(), sn);
|
||||
reg_txs.push_back(tx);
|
||||
}
|
||||
|
||||
gen.create_block(reg_txs);
|
||||
|
||||
/// create a few blocks with active service nodes
|
||||
gen.rewind_blocks_n(5);
|
||||
|
||||
if (gen.get_hf_version() != network_version_9_service_nodes) {
|
||||
std::cerr << "wrong hf version\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
gen.continue_until_version(test_options.hard_forks, network_version_10_bulletproofs);
|
||||
|
||||
/// test that we now have swarms
|
||||
DO_CALLBACK(events, "test_initial_swarms");
|
||||
|
||||
/// rewind some blocks and register more service nodes
|
||||
for (auto i = init_sn_count; i < SN_KEYS_COUNT; ++i) {
|
||||
const auto sn = get_static_keys(i);
|
||||
const auto tx = gen.create_registration_tx(gen.first_miner(), sn);
|
||||
gen.create_block({tx});
|
||||
}
|
||||
|
||||
/// test that another swarm has been created
|
||||
DO_CALLBACK(events, "test_with_more_sn");
|
||||
|
||||
/// deregister a few snodes and test that both swarms are alive
|
||||
std::vector<cryptonote::transaction> dereg_txs;
|
||||
for (auto i = 0u; i < service_nodes::SWARM_BUFFER; ++i) {
|
||||
const auto pk = gen.get_test_pk(i);
|
||||
const auto tx = gen.build_deregister(pk).build();
|
||||
dereg_txs.push_back(tx);
|
||||
}
|
||||
|
||||
gen.create_block(dereg_txs);
|
||||
|
||||
DO_CALLBACK(events, "test_after_deregisters");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_swarms_basic::test_initial_swarms(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events)
|
||||
{
|
||||
DEFINE_TESTS_ERROR_CONTEXT("test_swarms_basic::test_initial_swarms");
|
||||
|
||||
/// Check that there is one active swarm and the swarm queue is not empty
|
||||
const auto sn_list = c.get_service_node_list_state({});
|
||||
|
||||
std::map<service_nodes::swarm_id_t, std::vector<crypto::public_key>> swarms;
|
||||
|
||||
for (const auto& entry : sn_list) {
|
||||
const auto id = entry.info.swarm_id;
|
||||
swarms[id].push_back(entry.pubkey);
|
||||
}
|
||||
|
||||
/// One of the swarms represent a queue
|
||||
CHECK_EQ(swarms.size(), 2);
|
||||
|
||||
const size_t queue_size = swarms.at(service_nodes::QUEUE_SWARM_ID).size();
|
||||
|
||||
/// No deregisters, so the swarms queue should be full
|
||||
CHECK_TEST_CONDITION(queue_size > service_nodes::SWARM_BUFFER);
|
||||
/// We shouldn't have too many nodes in the queue
|
||||
CHECK_TEST_CONDITION(queue_size < service_nodes::SWARM_BUFFER + service_nodes::MAX_SWARM_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_swarms_basic::test_with_more_sn(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events)
|
||||
{
|
||||
DEFINE_TESTS_ERROR_CONTEXT("test_swarms_basic::test_with_more_sn");
|
||||
|
||||
const auto sn_list = c.get_service_node_list_state({});
|
||||
|
||||
std::map<service_nodes::swarm_id_t, std::vector<crypto::public_key>> swarms;
|
||||
|
||||
for (const auto& entry : sn_list) {
|
||||
const auto id = entry.info.swarm_id;
|
||||
swarms[id].push_back(entry.pubkey);
|
||||
}
|
||||
|
||||
CHECK_EQ(swarms.size(), 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_swarms_basic::test_after_deregisters(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events)
|
||||
{
|
||||
DEFINE_TESTS_ERROR_CONTEXT("test_swarms_basic::test_after_deregisters");
|
||||
|
||||
const auto sn_list = c.get_service_node_list_state({});
|
||||
|
||||
std::map<service_nodes::swarm_id_t, std::vector<crypto::public_key>> swarms;
|
||||
|
||||
for (const auto& entry : sn_list) {
|
||||
const auto id = entry.info.swarm_id;
|
||||
swarms[id].push_back(entry.pubkey);
|
||||
}
|
||||
|
||||
/// The two swarms are still active, but the queue in now showing in the swarms
|
||||
CHECK_TEST_CONDITION(swarms.find(service_nodes::QUEUE_SWARM_ID) == swarms.end());
|
||||
CHECK_EQ(swarms.size(), 2);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -191,3 +191,26 @@ public:
|
|||
};
|
||||
|
||||
template<> struct get_test_options<sn_test_rollback>: public get_test_options<test_service_nodes_base> {};
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
|
||||
class test_swarms_basic : public test_service_nodes_base
|
||||
{
|
||||
public:
|
||||
test_swarms_basic();
|
||||
bool generate(std::vector<test_event_entry>& events);
|
||||
|
||||
bool test_initial_swarms(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
|
||||
bool test_with_more_sn(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
|
||||
bool test_after_deregisters(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct get_test_options<test_swarms_basic>
|
||||
{
|
||||
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks = { std::make_pair(7, 0),
|
||||
std::make_pair(8, 1),
|
||||
std::make_pair(9, 2),
|
||||
std::make_pair(10, 150) };
|
||||
const cryptonote::test_options test_options = { hard_forks };
|
||||
};
|
Loading…
Reference in New Issue