Revamp core_tests linear_chain_generator to support state_t

Remove using crypto, using cryptonote, using epee in chaingen

Add loki prefix to data structures, cleanup warts

Remove the need for get_static_keys(), remove useless functions and
attempt to remove some pointless function overloading that puts too many
levels of indirection and makes it harder to follow code execution.

Rehaul tests further, persist test generator when replaying through core

The class used to generate the testing events to replay through core is
now preserved. This subtle change simplifies a big chunk of core testing
in that we can remove the need for using callbacks to track events in
the events vector.

Add preliminary checkpoint/alt service node tests

Allow inlining of fail cases for test conditions

Add more checkpoint core tests

add_block in generator is parameterised with checkpoints

Add test to check chain with equal checkpoints

Add test for chain reorging when recieving enough votes for checkpoint
This commit is contained in:
Doyle 2019-09-02 20:18:54 +10:00
parent 35c84359d4
commit d2b619ea9a
18 changed files with 2150 additions and 1971 deletions

View File

@ -39,6 +39,8 @@
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "string_tools.h"
#include <boost/serialization/base_object.hpp>
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
#define JSON_HASH_FILE_NAME "checkpoints.json"
@ -80,6 +82,12 @@ namespace cryptonote
FIELD(signatures)
FIELD(prev_height)
END_SERIALIZE()
// TODO(loki): idk exactly if I want to implement this, but need for core tests to compile. Not sure I care about serializing for core tests at all.
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int /*version*/) { }
};
struct height_to_hash

View File

@ -4327,10 +4327,10 @@ bool Blockchain::update_checkpoint(cryptonote::checkpoint_t const &checkpoint)
}
else
{
// roll back to a couple of blocks before the checkpoint
LOG_ERROR("Local blockchain failed to pass a checkpoint in: " << __func__ << ", rolling back!");
std::list<block> empty;
rollback_blockchain_switching(empty, checkpoint.height - 2);
uint64_t blocks_to_pop = m_db->height() - checkpoint.height + 2;
crypto::hash const reorg_hash = m_db->get_block_hash_from_height(checkpoint.height - 2);
MGINFO_GREEN("###### CHECKPOINTING REORGANIZE from height: " << m_db->height() << " to before checkpoint height: " << (checkpoint.height - 2) << " id: " << reorg_hash);
pop_blocks(blocks_to_pop);
}
}

View File

@ -56,8 +56,8 @@ DISABLE_VS_WARNINGS(4355)
namespace cryptonote
{
struct test_options {
const std::vector<std::pair<uint8_t, uint64_t>> hard_forks;
const size_t long_term_block_weight_window;
std::vector<std::pair<uint8_t, uint64_t>> hard_forks;
size_t long_term_block_weight_window;
};
extern const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir;

View File

@ -190,18 +190,6 @@ namespace service_nodes
return sort_and_filter(service_nodes_infos, [](const service_node_info &info) { return info.is_decommissioned() && info.is_fully_funded(); }, /*reserve=*/ false);
}
static std::shared_ptr<const testing_quorum> get_quorum_from_manager(quorum_manager const &manager, quorum_type type)
{
if (type == quorum_type::obligations)
return manager.obligations;
else if (type == quorum_type::checkpointing)
return manager.checkpointing;
MERROR("Developer error: Unhandled quorum enum with value: " << (size_t)type);
assert(!"Developer error: Unhandled quorum enum");
return nullptr;
}
std::shared_ptr<const testing_quorum> service_node_list::get_testing_quorum(quorum_type type, uint64_t height, bool include_old, std::vector<std::shared_ptr<const testing_quorum>> *alt_quorums) const
{
if (type == quorum_type::checkpointing) {
@ -249,13 +237,13 @@ namespace service_nodes
state_t const &alt_state = hash_to_state.second;
if (alt_state.height == height)
{
std::shared_ptr<const testing_quorum> alt_result = get_quorum_from_manager(alt_state.quorums, type);
std::shared_ptr<const testing_quorum> alt_result = alt_state.quorums.get(type);
if (alt_result) alt_quorums->push_back(alt_result);
}
}
}
std::shared_ptr<const testing_quorum> result = get_quorum_from_manager(*quorums, type);
std::shared_ptr<const testing_quorum> result = quorums->get(type);
return result;
}

View File

@ -329,8 +329,7 @@ namespace service_nodes
}
}
quorum_vote_t vote = service_nodes::make_state_change_vote(
m_obligations_height, static_cast<uint16_t>(index_in_group), node_index, vote_for_state, my_pubkey, my_seckey);
quorum_vote_t vote = service_nodes::make_state_change_vote(m_obligations_height, static_cast<uint16_t>(index_in_group), node_index, vote_for_state, my_pubkey, my_seckey);
cryptonote::vote_verification_context vvc;
if (!handle_vote(vote, vvc))
LOG_ERROR("Failed to add state change vote; reason: " << print_vote_verification_context(vvc, &vote));
@ -373,22 +372,8 @@ namespace service_nodes
//
// NOTE: I am in the quorum, handle checkpointing
//
quorum_vote_t vote = {};
vote.type = quorum_type::checkpointing;
vote.checkpoint.block_hash = m_core.get_block_id_by_height(m_last_checkpointed_height);
if (vote.checkpoint.block_hash == crypto::null_hash)
{
// TODO(loki): Fatal error
LOG_ERROR("Could not get block hash for block on height: " << m_last_checkpointed_height);
continue;
}
vote.block_height = m_last_checkpointed_height;
vote.group = quorum_group::worker;
vote.index_in_group = static_cast<uint16_t>(index_in_group);
vote.signature = make_signature_from_vote(vote, my_pubkey, my_seckey);
crypto::hash block_hash = m_core.get_block_id_by_height(m_last_checkpointed_height);
quorum_vote_t vote = make_checkpointing_vote(block_hash, m_last_checkpointed_height, static_cast<uint16_t>(index_in_group), my_pubkey, my_seckey);
cryptonote::vote_verification_context vvc = {};
if (!handle_vote(vote, vvc))
LOG_ERROR("Failed to add checkpoint vote; reason: " << print_vote_verification_context(vvc, &vote));
@ -562,30 +547,18 @@ namespace service_nodes
if (it == checkpoint.signatures.end() ||
pool_vote.vote.index_in_group != it->voter_index)
{
update_checkpoint = true;
voter_to_signature vts = {};
vts.voter_index = pool_vote.vote.index_in_group;
vts.signature = pool_vote.vote.signature;
checkpoint.signatures.insert(it, vts);
update_checkpoint = true;
checkpoint.signatures.insert(it, vote_to_voter_to_signature(pool_vote.vote));
}
}
}
}
else
{
checkpoint = {};
checkpoint.type = cryptonote::checkpoint_type::service_node;
checkpoint.height = vote.block_height;
checkpoint.block_hash = vote.checkpoint.block_hash;
checkpoint = make_empty_service_node_checkpoint(vote.checkpoint.block_hash, vote.block_height);
checkpoint.signatures.reserve(votes.size());
for (pool_vote_entry const &pool_vote : votes)
{
voter_to_signature vts = {};
vts.voter_index = pool_vote.vote.index_in_group;
vts.signature = pool_vote.vote.signature;
checkpoint.signatures.push_back(vts);
}
checkpoint.signatures.push_back(vote_to_voter_to_signature(pool_vote.vote));
}
if (update_checkpoint)

View File

@ -63,6 +63,15 @@ namespace service_nodes
// TODO(doyle): Validators aren't used, but I kept this as a testing_quorum
// to avoid drastic changes for now to a lot of the service node API
std::shared_ptr<const testing_quorum> checkpointing;
std::shared_ptr<const testing_quorum> get(quorum_type type) const
{
if (type == quorum_type::obligations) return obligations;
else if (type == quorum_type::checkpointing) return checkpointing;
MERROR("Developer error: Unhandled quorum enum with value: " << (size_t)type);
assert(!"Developer error: Unhandled quorum enum with value: ");
return nullptr;
}
};
struct service_node_test_results {

View File

@ -317,6 +317,35 @@ namespace service_nodes
return result;
}
quorum_vote_t make_checkpointing_vote(crypto::hash const &block_hash, uint64_t block_height, uint16_t index_in_quorum, crypto::public_key const &pub_key, crypto::secret_key const &sec_key)
{
quorum_vote_t result = {};
result.type = quorum_type::checkpointing;
result.checkpoint.block_hash = block_hash;
result.block_height = block_height;
result.group = quorum_group::worker;
result.index_in_group = index_in_quorum;
result.signature = make_signature_from_vote(result, pub_key, sec_key);
return result;
}
cryptonote::checkpoint_t make_empty_service_node_checkpoint(crypto::hash const &block_hash, uint64_t height)
{
cryptonote::checkpoint_t result = {};
result.type = cryptonote::checkpoint_type::service_node;
result.height = height;
result.block_hash = block_hash;
return result;
}
voter_to_signature vote_to_voter_to_signature(quorum_vote_t const &vote)
{
voter_to_signature result = {};
result.voter_index = vote.index_in_group;
result.signature = vote.signature;
return result;
}
bool verify_vote_age(const quorum_vote_t& vote, uint64_t latest_height, cryptonote::vote_verification_context &vvc)
{
bool result = true;

View File

@ -41,6 +41,8 @@
#include "math_helper.h"
#include "syncobj.h"
#include <boost/serialization/base_object.hpp>
namespace cryptonote
{
struct tx_verification_context;
@ -99,16 +101,25 @@ namespace service_nodes
state_change_vote state_change;
checkpoint_vote checkpoint;
};
// TODO(loki): idk exactly if I want to implement this, but need for core tests to compile. Not sure I care about serializing for core tests at all.
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int /*version*/) { }
};
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);
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);
quorum_vote_t make_checkpointing_vote(crypto::hash const &block_hash, uint64_t block_height, uint16_t index_in_quorum, crypto::public_key const &pub_key, crypto::secret_key const &sec_key);
cryptonote::checkpoint_t make_empty_service_node_checkpoint(crypto::hash const &block_hash, uint64_t height);
voter_to_signature vote_to_voter_to_signature(quorum_vote_t const &vote);
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_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);
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_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);
// NOTE: This preserves the deregister vote format pre-checkpointing so that
// up to the hardfork, we can still deserialize and serialize until we switch

View File

@ -282,37 +282,44 @@ gen_batched_governance_reward::gen_batched_governance_reward()
}
static uint64_t expected_total_governance_paid = 0;
static uint64_t hf10_height = 0;
bool gen_batched_governance_reward::generate(std::vector<test_event_entry>& events) const
{
const config_t &network = cryptonote::get_config(cryptonote::FAKECHAIN, network_version_10_bulletproofs);
const get_test_options<gen_batched_governance_reward> test_options = {};
linear_chain_generator batched_governance_generator(events, test_options.hard_forks);
loki_chain_generator batched_governance_generator(events, test_options.hard_forks);
{
batched_governance_generator.rewind_until_version(network_version_10_bulletproofs);
batched_governance_generator.add_blocks_until_version(network_version_10_bulletproofs);
hf10_height = batched_governance_generator.height();
uint64_t blocks_to_gen = network.GOVERNANCE_REWARD_INTERVAL_IN_BLOCKS - batched_governance_generator.height();
batched_governance_generator.rewind_blocks_n(blocks_to_gen);
batched_governance_generator.add_n_blocks(blocks_to_gen);
}
assert(hf10_height != 0);
{
// NOTE(loki): Since hard fork 8 we have an emissions curve change, so if
// you don't atleast progress and generate blocks from hf8 you will run into
// problems
const std::vector<std::pair<uint8_t, uint64_t>> other_hard_forks = {
std::make_pair(cryptonote::network_version_7, 0),
std::make_pair(cryptonote::network_version_8, 1),
std::make_pair(cryptonote::network_version_9_service_nodes, hf10_height)};
std::vector<test_event_entry> unused_events;
linear_chain_generator no_batched_governance_generator(unused_events, test_options.hard_forks);
no_batched_governance_generator.rewind_until_version(network_version_9_service_nodes);
loki_chain_generator no_batched_governance_generator(unused_events, other_hard_forks);
no_batched_governance_generator.add_blocks_until_version(network_version_9_service_nodes);
while(no_batched_governance_generator.height() < batched_governance_generator.height())
no_batched_governance_generator.create_block();
no_batched_governance_generator.add_block();
// NOTE(loki): Skip the last block as that is the batched payout height, we
// don't include the governance reward of that height, that gets picked up
// in the next batch.
const std::vector<cryptonote::block>& blockchain = no_batched_governance_generator.blocks();
for (size_t block_height = 1; block_height < blockchain.size() - 1; ++block_height)
const std::vector<loki_blockchain_entry>& blockchain = no_batched_governance_generator.blocks();
for (size_t block_height = hf10_height; block_height < blockchain.size() - 1; ++block_height)
{
const cryptonote::block &block = blockchain[block_height];
const cryptonote::block &block = blockchain[block_height].block;
expected_total_governance_paid += block.miner_tx.vout.back().amount;
}
}
@ -331,7 +338,7 @@ bool gen_batched_governance_reward::check_batched_governance_amount_matches(cryp
return false;
uint64_t governance = 0;
for (size_t block_height = 1; block_height < blockchain.size(); ++block_height)
for (size_t block_height = hf10_height; block_height < blockchain.size(); ++block_height)
{
const cryptonote::block &block = blockchain[block_height];
if (cryptonote::block_has_governance_output(cryptonote::FAKECHAIN, block))

View File

@ -334,7 +334,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events
transaction tmp_tx;
if (!TxBuilder(events, tmp_tx, blk_0r, miner_account, miner_account, blk_0.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
if (!loki_tx_builder(events, tmp_tx, blk_0r, miner_account, miner_account, blk_0.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_0r);
@ -361,7 +361,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry>
REWIND_BLOCKS(events, blk_1r, blk_1, miner_account);
transaction tmp_tx;
if (!TxBuilder(events, tmp_tx, blk_1r, miner_account, miner_account, blk_1.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
if (!loki_tx_builder(events, tmp_tx, blk_1r, miner_account, miner_account, blk_1.miner_tx.vout[0].amount, cryptonote::network_version_7).build())
return false;
MAKE_MINER_TX_MANUALLY(miner_tx, blk_1);
@ -409,6 +409,16 @@ bool gen_block_miner_tx_has_no_out::generate(std::vector<test_event_entry>& even
return true;
}
static crypto::public_key
get_output_key(const cryptonote::keypair &txkey, const cryptonote::account_public_address &addr, size_t output_index)
{
crypto::key_derivation derivation;
crypto::generate_key_derivation(addr.m_view_public_key, txkey.sec, derivation);
crypto::public_key out_eph_public_key;
crypto::derive_public_key(derivation, output_index, addr.m_spend_public_key, out_eph_public_key);
return out_eph_public_key;
}
static bool construct_miner_tx_with_extra_output(cryptonote::transaction& tx,
const cryptonote::account_public_address& miner_address,
size_t height,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -112,7 +112,7 @@ static void make_rct_tx(eventV& events,
{
txs.emplace_back();
bool success = TxBuilder(events, txs.back(), blk_head, from, to, amount, cryptonote::network_version_7).build();
bool success = loki_tx_builder(events, txs.back(), blk_head, from, to, amount, cryptonote::network_version_7).build();
/// TODO: beter error message
if (!success) throw std::exception();
events.push_back(txs.back());

View File

@ -120,12 +120,17 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(test_prefer_deregisters);
GENERATE_AND_PLAY(test_zero_fee_deregister);
GENERATE_AND_PLAY(test_deregister_safety_buffer);
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);
GENERATE_AND_PLAY(gen_service_node_alt_quorum);
GENERATE_AND_PLAY(gen_service_node_checkpoint_from_votes);
GENERATE_AND_PLAY(gen_service_node_checkpoints_check_reorg_windows);
GENERATE_AND_PLAY(gen_alt_chain_more_service_node_checkpoints_less_pow_overtakes);
GENERATE_AND_PLAY(gen_alt_chain_with_increasing_service_node_checkpoints);
GENERATE_AND_PLAY(gen_alt_chain_receive_checkpoint_votes_should_reorg_back);
#else
GENERATE_AND_PLAY(gen_simple_chain_split_1);
GENERATE_AND_PLAY(gen_alt_chain_receive_checkpoint_votes_should_reorg_back);
#endif
}

View File

@ -55,43 +55,42 @@ namespace
bool gen_ring_signature_1::generate(std::vector<test_event_entry>& events) const
{
const get_test_options<gen_ring_signature_1> test_options = {};
linear_chain_generator gen(events, test_options.hard_forks);
gen.create_genesis_block();
loki_chain_generator gen(events, test_options.hard_forks);
const auto miner = gen.first_miner();
const auto bob = gen.create_account(); /// event 1
const auto alice = gen.create_account(); /// event 2
const auto some_account_1 = gen.create_account();
const auto some_account_2 = gen.create_account();
const auto bob = gen.add_account(); /// event 1
const auto alice = gen.add_account(); /// event 2
const auto some_account_1 = gen.add_account();
const auto some_account_2 = gen.add_account();
/// give the miner some outputs to spend and ulock them
gen.rewind_blocks_n(20);
gen.rewind_blocks();
gen.add_n_blocks(20);
gen.add_mined_money_unlock_blocks();
std::vector<cryptonote::transaction> txs;
txs.push_back( gen.create_tx(miner, bob, MK_COINS(1)) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(1)) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_tx(miner, some_account_1, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_tx(miner, some_account_2, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, bob, MK_COINS(29) + rnd_29) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(11) + rnd_11) );
txs.push_back( gen.create_and_add_tx(miner, some_account_1, MK_COINS(20) + rnd_20) );
txs.push_back( gen.create_and_add_tx(miner, some_account_2, MK_COINS(20) + rnd_20) );
gen.create_block(txs);
gen.add_block(txs);
gen.rewind_blocks();
gen.add_mined_money_unlock_blocks();
DO_CALLBACK(events, "check_balances_1");
auto tx = gen.create_tx(bob, alice, MK_COINS(129) + 2 * rnd_11 + rnd_20 + 3 * rnd_29 - TESTS_DEFAULT_FEE);
gen.create_block({tx});
auto tx = gen.create_and_add_tx(bob, alice, MK_COINS(129) + 2 * rnd_11 + rnd_20 + 3 * rnd_29 - TESTS_DEFAULT_FEE);
gen.add_block({tx});
DO_CALLBACK(events, "check_balances_2");
@ -102,8 +101,8 @@ bool gen_ring_signature_1::check_balances_1(cryptonote::core& c, size_t ev_index
{
DEFINE_TESTS_ERROR_CONTEXT("gen_ring_signature_1::check_balances_1");
m_bob_account = boost::get<account_base>(events[1]);
m_alice_account = boost::get<account_base>(events[2]);
m_bob_account = boost::get<account_base>(events[2]);
m_alice_account = boost::get<account_base>(events[3]);
std::vector<block> blocks;
bool r = c.get_blocks(0, 1000, blocks);

File diff suppressed because it is too large Load Diff

View File

@ -35,184 +35,18 @@
/* */
/************************************************************************/
class test_service_nodes_base : public test_chain_unit_base {};
struct gen_service_nodes : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct test_prefer_deregisters : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct test_zero_fee_deregister : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct test_deregister_safety_buffer : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct test_deregisters_on_split : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct deregister_too_old : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct sn_test_rollback : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct test_swarms_basic : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct gen_service_node_alt_quorum : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
struct gen_service_node_checkpoint_from_votes : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct gen_service_node_checkpoints_check_reorg_windows : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct gen_alt_chain_more_service_node_checkpoints_less_pow_overtakes : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct gen_alt_chain_with_increasing_service_node_checkpoints : public test_chain_unit_base { bool generate(std::vector<test_event_entry> &events); };
struct gen_alt_chain_receive_checkpoint_votes_should_reorg_back : public test_chain_unit_base { bool generate(std::vector<test_event_entry>& events); };
template<>
struct get_test_options<test_service_nodes_base>
{
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) };
const cryptonote::test_options test_options = { hard_forks };
};
class gen_service_nodes : public test_service_nodes_base
{
public:
gen_service_nodes();
bool generate(std::vector<test_event_entry> &events) const;
bool check_registered(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
bool check_expired(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
private:
cryptonote::keypair m_alice_service_node_keys;
};
template<> struct get_test_options<gen_service_nodes>: public get_test_options<test_service_nodes_base> {};
class test_prefer_deregisters : public test_service_nodes_base
{
public:
test_prefer_deregisters();
bool generate(std::vector<test_event_entry> &events);
bool check_prefer_deregisters(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
};
template<> struct get_test_options<test_prefer_deregisters>: public get_test_options<test_service_nodes_base> {};
class test_zero_fee_deregister : public test_service_nodes_base
{
size_t m_invalid_tx_index = UINT64_MAX;
public:
test_zero_fee_deregister();
bool generate(std::vector<test_event_entry> &events);
bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
{
m_invalid_tx_index = ev_index + 1;
return true;
}
bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc,
bool tx_added,
size_t event_idx,
const cryptonote::transaction& /*tx*/)
{
if (m_invalid_tx_index == event_idx)
return tvc.m_verifivation_failed;
else
return !tvc.m_verifivation_failed && tx_added;
}
};
template<> struct get_test_options<test_zero_fee_deregister>: public get_test_options<test_service_nodes_base> {};
class test_deregister_safety_buffer : public test_service_nodes_base
{
size_t m_invalid_tx_index = UINT64_MAX;
public:
test_deregister_safety_buffer();
bool generate(std::vector<test_event_entry>& events);
bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
{
m_invalid_tx_index = ev_index + 1;
return true;
}
bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc,
bool tx_added,
size_t event_idx,
const cryptonote::transaction& /*tx*/)
{
if (m_invalid_tx_index == event_idx)
return tvc.m_verifivation_failed;
else
return !tvc.m_verifivation_failed && tx_added;
}
};
template<> struct get_test_options<test_deregister_safety_buffer>: public get_test_options<test_service_nodes_base> {};
class test_deregisters_on_split : public test_service_nodes_base
{
size_t m_invalid_tx_index = UINT64_MAX;
public:
test_deregisters_on_split();
bool generate(std::vector<test_event_entry>& events);
bool test_on_split(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
{
m_invalid_tx_index = ev_index + 1;
return true;
}
bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc,
bool tx_added,
size_t event_idx,
const cryptonote::transaction& /*tx*/)
{
if (m_invalid_tx_index == event_idx)
return tvc.m_verifivation_failed;
else
return !tvc.m_verifivation_failed && tx_added;
}
};
template<> struct get_test_options<test_deregisters_on_split>: public get_test_options<test_service_nodes_base> {};
class deregister_too_old : public test_chain_unit_base
{
size_t m_invalid_block_index = UINT64_MAX;
public:
deregister_too_old();
bool generate(std::vector<test_event_entry>& events);
bool mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
{
m_invalid_block_index = ev_index + 1;
return true;
}
bool check_block_verification_context(const cryptonote::block_verification_context& bvc,
size_t event_idx,
const cryptonote::block& /*blk*/)
{
if (m_invalid_block_index == event_idx)
return bvc.m_verifivation_failed;
else
return !bvc.m_verifivation_failed;
}
};
template<> struct get_test_options<deregister_too_old>: public get_test_options<test_service_nodes_base> {};
//-------------------------------------------------------------------------------------------
class sn_test_rollback : public test_chain_unit_base
{
public:
sn_test_rollback();
bool generate(std::vector<test_event_entry>& events);
bool test_registrations(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
};
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_with_one_more_sn(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
bool test_after_first_deregisters(cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
bool test_after_final_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 };
};

View File

@ -195,7 +195,7 @@ bool gen_tx_big_version::generate(std::vector<test_event_entry>& events) const
fill_tx_sources_and_destinations(events, blk_money_unlocked, miner_account, get_address(miner_account), MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), -1).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), -1).build();
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx);
@ -215,43 +215,43 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const
transaction tx = {};
uint64_t unlock_time = 0;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) - 1;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked);
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) + 1;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = get_block_height(blk_money_unlocked) + 2;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = ts_start - 1;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
tx = {};
unlock_time = time(0) + 60 * 60;
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_unlock_time(unlock_time).build();
events.push_back(tx);
txs_0.push_back(tx);
@ -276,13 +276,13 @@ bool gen_tx_input_is_not_txin_to_key::generate(std::vector<test_event_entry>& ev
DO_CALLBACK(events, "mark_invalid_tx");
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.push_back(txin_to_script());
events.push_back(tx);
DO_CALLBACK(events, "mark_invalid_tx");
tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.push_back(txin_to_scripthash());
events.push_back(tx);
@ -315,7 +315,7 @@ bool gen_tx_no_inputs_has_outputs::generate(std::vector<test_event_entry>& event
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vin.clear();
DO_CALLBACK(events, "mark_invalid_tx");
@ -333,7 +333,7 @@ bool gen_tx_has_inputs_no_outputs::generate(std::vector<test_event_entry>& event
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.clear();
DO_CALLBACK(events, "mark_invalid_tx"); // NOTE(loki): This used to be valid in Monero pre RCT, but not anymore with our transactions because we start with RCT type TXs
@ -379,7 +379,7 @@ bool gen_tx_input_wo_key_offsets::generate(std::vector<test_event_entry>& events
fill_tx_sources_and_destinations(events, blk_money_unlocked, miner_account, get_address(miner_account), MK_COINS(1), TESTS_DEFAULT_FEE, CRYPTONOTE_DEFAULT_TX_MIXIN, sources, destinations);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
while (!in_to_key.key_offsets.empty())
in_to_key.key_offsets.pop_back();
@ -406,7 +406,7 @@ bool gen_tx_key_offset_points_to_foreign_key::generate(std::vector<test_event_en
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction bob_tx = {};
TxBuilder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(15) + 1 - TESTS_DEFAULT_FEE, cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
std::vector<tx_source_entry> sources_alice;
std::vector<tx_destination_entry> destinations_alice;
@ -437,7 +437,7 @@ bool gen_tx_sender_key_offset_not_exist::generate(std::vector<test_event_entry>&
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
in_to_key.key_offsets.front() = std::numeric_limits<uint64_t>::max();
@ -525,7 +525,7 @@ bool gen_tx_key_image_not_derive_from_tx_key::generate(std::vector<test_event_en
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
// Use fake key image
@ -553,7 +553,7 @@ bool gen_tx_key_image_is_invalid::generate(std::vector<test_event_entry>& events
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
txin_to_key& in_to_key = boost::get<txin_to_key>(tx.vin.front());
in_to_key.k_image = generate_invalid_key_image();
@ -637,7 +637,7 @@ bool gen_tx_txout_to_key_has_invalid_key::generate(std::vector<test_event_entry>
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
txout_to_key& out_to_key = boost::get<txout_to_key>(tx.vout.front().target);
out_to_key.key = generate_invalid_pub_key();
@ -654,7 +654,7 @@ bool gen_tx_output_with_zero_amount::generate(std::vector<test_event_entry>& eve
REWIND_BLOCKS_N (events, blk_money_unlocked, blk_tail, miner_account, 40);
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
// TODO(loki): Hmm. Can't use TxBuilder approach because RCT masks amounts
// TODO(loki): Hmm. Can't use loki_tx_builder approach because RCT masks amounts
// after it's constructed, so vout amounts is already zero. It seems to be
// valid to be able to send a transaction whos output is zero, so this test
// might not be valid anymore post RCT.
@ -673,7 +673,7 @@ bool gen_tx_output_with_zero_amount::generate(std::vector<test_event_entry>& eve
#else
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.front().amount = 0;
#endif
@ -692,14 +692,14 @@ bool gen_tx_output_is_not_txout_to_key::generate(std::vector<test_event_entry>&
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.back().target = txout_to_script();
DO_CALLBACK(events, "mark_invalid_tx");
events.push_back(tx);
tx = {};
TxBuilder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
loki_tx_builder(events, tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(1), cryptonote::network_version_7).build();
tx.vout.back().target = txout_to_scripthash();
DO_CALLBACK(events, "mark_invalid_tx");
@ -724,7 +724,7 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
REWIND_BLOCKS (events, blk_head, blk_money_unlocked, miner_account);
transaction miner_tx = {};
TxBuilder(events, miner_tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(60), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, miner_tx, blk_money_unlocked, miner_account, miner_account, MK_COINS(60), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
// TX without signatures
DO_CALLBACK(events, "mark_invalid_tx");
@ -744,7 +744,7 @@ bool gen_tx_signatures_are_invalid::generate(std::vector<test_event_entry>& even
events.push_back(serialized_transaction(sr_tx));
transaction bob_tx = {};
TxBuilder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
loki_tx_builder(events, bob_tx, blk_money_unlocked, bob_account, miner_account, MK_COINS(1), cryptonote::network_version_7).with_fee(TESTS_DEFAULT_FEE).build();
// TX without signatures
DO_CALLBACK(events, "mark_invalid_tx");