Skip to content

Commit

Permalink
core_tests: check service node registration and expiration (#195)
Browse files Browse the repository at this point in the history
* core_tests: check service node registration and deregistration

* core_tests for service nodes:

- include service nodes rewards when calculating account's balance
- check that service nodes rewards have been received

* fixed namespace error; reduced the scope of staking requirement constants
  • Loading branch information
msgmaxim authored and Doy-lee committed Sep 4, 2018
1 parent 06081b7 commit dfae876
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 59 deletions.
2 changes: 0 additions & 2 deletions src/cryptonote_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE 10

#define STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS 20
#define STAKING_REQUIREMENT_LOCK_BLOCKS (30*24*30)
#define STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET (30*24*2)
#define STAKING_PORTIONS UINT64_C(0xfffffffffffffffc)
#define MAX_NUMBER_OF_CONTRIBUTORS 4
#define MIN_PORTIONS (STAKING_PORTIONS / MAX_NUMBER_OF_CONTRIBUTORS)
Expand Down
23 changes: 16 additions & 7 deletions src/cryptonote_core/service_node_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ namespace service_nodes
if (tx.version >= cryptonote::transaction::version_3_per_output_unlock_times)
unlock_time = tx.output_unlock_times[i];

return unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && unlock_time >= block_height + get_staking_requirement_lock_blocks();
return unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && unlock_time >= block_height + get_staking_requirement_lock_blocks(m_blockchain.nettype());
}

bool service_node_list::reg_tx_extract_fields(const cryptonote::transaction& tx, std::vector<cryptonote::account_public_address>& addresses, uint64_t& portions_for_operator, std::vector<uint64_t>& portions, uint64_t& expiration_timestamp, crypto::public_key& service_node_key, crypto::signature& signature, crypto::public_key& tx_pub_key) const
Expand Down Expand Up @@ -582,7 +582,7 @@ namespace service_nodes
{
std::vector<crypto::public_key> expired_nodes;

const uint64_t lock_blocks = get_staking_requirement_lock_blocks();
const uint64_t lock_blocks = get_staking_requirement_lock_blocks(m_blockchain.nettype());

if (block_height < lock_blocks)
return expired_nodes;
Expand Down Expand Up @@ -802,11 +802,6 @@ namespace service_nodes
}
}

uint64_t service_node_list::get_staking_requirement_lock_blocks() const
{
return m_blockchain.nettype() == cryptonote::TESTNET || m_blockchain.nettype() == cryptonote::FAKECHAIN ? STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET : STAKING_REQUIREMENT_LOCK_BLOCKS;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

service_node_list::rollback_event::rollback_event(uint64_t block_height, rollback_type type) : m_block_height(block_height), type(type)
Expand Down Expand Up @@ -1156,6 +1151,20 @@ namespace service_nodes
cmd = stream.str();
return true;
}

uint64_t get_staking_requirement_lock_blocks(cryptonote::network_type nettype)
{
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS = 30*24*30;
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET = 30*24*2;
constexpr static uint32_t STAKING_REQUIREMENT_LOCK_BLOCKS_FAKENET = 30;

switch(nettype) {
case cryptonote::TESTNET: return STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET;
case cryptonote::FAKECHAIN: return STAKING_REQUIREMENT_LOCK_BLOCKS_FAKENET;
default: return STAKING_REQUIREMENT_LOCK_BLOCKS;
}
}

uint64_t get_staking_requirement(cryptonote::network_type m_nettype, uint64_t height)
{
if (m_nettype == cryptonote::TESTNET || m_nettype == cryptonote::FAKECHAIN)
Expand Down
4 changes: 2 additions & 2 deletions src/cryptonote_core/service_node_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ namespace service_nodes

std::vector<crypto::public_key> get_service_nodes_pubkeys() const;

uint64_t get_staking_requirement_lock_blocks() const;

template<typename T>
void block_added_generic(const cryptonote::block& block, const T& txs);

Expand Down Expand Up @@ -284,6 +282,8 @@ namespace service_nodes
bool make_registration_cmd(cryptonote::network_type nettype, const std::vector<std::string> args, const crypto::public_key& service_node_pubkey,
const crypto::secret_key service_node_key, std::string &cmd, bool make_friendly);

uint64_t get_staking_requirement_lock_blocks(cryptonote::network_type m_nettype);

uint64_t get_staking_requirement(cryptonote::network_type nettype, uint64_t height);

uint64_t portions_to_amount(uint64_t portions, uint64_t staking_requirement);
Expand Down
2 changes: 1 addition & 1 deletion src/daemon/rpc_command_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2037,7 +2037,7 @@ static void print_service_node_list_state(cryptonote::network_type nettype, uint
// Print Expiry Info
{
uint64_t expiry_height = entry.registration_height;
expiry_height += (nettype == cryptonote::TESTNET) ? STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET : STAKING_REQUIREMENT_LOCK_BLOCKS;
expiry_height += service_nodes::get_staking_requirement_lock_blocks(nettype);

if (curr_height)
{
Expand Down
4 changes: 2 additions & 2 deletions src/simplewallet/simplewallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4740,7 +4740,7 @@ bool simple_wallet::register_service_node_main(
return true;
}

uint64_t staking_requirement_lock_blocks = (m_wallet->nettype() == cryptonote::TESTNET ? STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET : STAKING_REQUIREMENT_LOCK_BLOCKS);
uint64_t staking_requirement_lock_blocks = service_nodes::get_staking_requirement_lock_blocks(m_wallet->nettype());
uint64_t locked_blocks = staking_requirement_lock_blocks + STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS;

std::string err, err2;
Expand Down Expand Up @@ -5089,7 +5089,7 @@ bool simple_wallet::stake_main(
uint64_t fetched_blocks;
m_wallet->refresh(0, fetched_blocks);

uint64_t staking_requirement_lock_blocks = (m_wallet->nettype() == cryptonote::TESTNET ? STAKING_REQUIREMENT_LOCK_BLOCKS_TESTNET : STAKING_REQUIREMENT_LOCK_BLOCKS);
uint64_t staking_requirement_lock_blocks = service_nodes::get_staking_requirement_lock_blocks(m_wallet->nettype());
uint64_t locked_blocks = staking_requirement_lock_blocks + STAKING_REQUIREMENT_LOCK_BLOCKS_EXCESS;

std::string err, err2;
Expand Down
77 changes: 61 additions & 16 deletions tests/core_tests/chaingen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, st
const size_t block_size = tsx_size + get_object_blobsize(blk.miner_tx);
uint64_t block_reward;
cryptonote::get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, hf_version_, 0);
m_blocks_info[get_block_hash(blk)] = block_info(blk.prev_id, already_generated_coins + block_reward, block_size);
m_blocks_info.insert({get_block_hash(blk), block_info(blk.prev_id, already_generated_coins + block_reward, block_size)});
}

bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, const crypto::hash& prev_id,
const cryptonote::account_base& miner_acc, uint64_t timestamp, uint64_t already_generated_coins,
std::vector<size_t>& block_sizes, const std::list<cryptonote::transaction>& tx_list)
std::vector<size_t>& block_sizes, const std::list<cryptonote::transaction>& tx_list,
const crypto::public_key& sn_pub_key /* = crypto::null_key */, const std::vector<sn_contributor_t>& sn_infos)
{
/// a temporary workaround
blk.major_version = hf_version_;
Expand Down Expand Up @@ -137,7 +138,8 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co
size_t target_block_size = txs_size + get_object_blobsize(blk.miner_tx);
while (true)
{
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, target_block_size, total_fee, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), hf_version_))

if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, target_block_size, total_fee, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), hf_version_, cryptonote::MAINNET, sn_pub_key, sn_infos))
return false;

size_t actual_block_size = txs_size + get_object_blobsize(blk.miner_tx);
Expand Down Expand Up @@ -199,7 +201,8 @@ bool test_generator::construct_block(cryptonote::block& blk, const cryptonote::a

bool test_generator::construct_block(cryptonote::block& blk, const cryptonote::block& blk_prev,
const cryptonote::account_base& miner_acc,
const std::list<cryptonote::transaction>& tx_list/* = {}*/)
const std::list<cryptonote::transaction>& tx_list/* = {}*/,
const crypto::public_key& sn_pub_key /* = crypto::null_key */, const std::vector<sn_contributor_t>& sn_infos)
{
uint64_t height = boost::get<txin_gen>(blk_prev.miner_tx.vin.front()).height + 1;
crypto::hash prev_id = get_block_hash(blk_prev);
Expand All @@ -209,7 +212,7 @@ bool test_generator::construct_block(cryptonote::block& blk, const cryptonote::b
std::vector<size_t> block_sizes;
get_last_n_block_sizes(block_sizes, prev_id, CRYPTONOTE_REWARD_BLOCKS_WINDOW);

return construct_block(blk, height, prev_id, miner_acc, timestamp, already_generated_coins, block_sizes, tx_list);
return construct_block(blk, height, prev_id, miner_acc, timestamp, already_generated_coins, block_sizes, tx_list, sn_pub_key, sn_infos);
}

bool test_generator::construct_block_manually(block& blk, const block& prev_block, const account_base& miner_acc,
Expand Down Expand Up @@ -270,14 +273,14 @@ struct output_index {
size_t out_no; // index of out in transaction
size_t idx;
bool spent;
bool is_sn_reward = false;
const cryptonote::block *p_blk;
const cryptonote::transaction *p_tx;

output_index(const cryptonote::txout_target_v &_out, uint64_t _a, size_t _h, uint64_t ut, size_t tno, size_t ono, const cryptonote::block *_pb, const cryptonote::transaction *_pt)
: out(_out), amount(_a), blk_height(_h), unlock_time(ut), tx_no(tno), out_no(ono), idx(0), spent(false), p_blk(_pb), p_tx(_pt) { }

output_index(const output_index &other)
: out(other.out), amount(other.amount), mask(other.mask), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx), unlock_time(other.unlock_time) { }
output_index(const output_index &other) = default;

const std::string toString() const {
std::stringstream ss;
Expand Down Expand Up @@ -404,13 +407,20 @@ bool init_output_indices(output_index_vec& outs, output_vec& outs_mine, const st
outs[tx_global_idx].idx = tx_global_idx;
outs[tx_global_idx].mask = rct::zeroCommit(out.amount);
// Is out to me?
if (is_out_to_acc(from.get_keys(), boost::get<txout_to_key>(out.target), get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) {
outs_mine.push_back(tx_global_idx);
auto& out = outs.back();
if (out.amount == 0) {
out.amount = get_amount(from, tx, j);
out.mask = tx.rct_signatures.outPk[j].mask;
const auto gov_key = cryptonote::get_deterministic_keypair_from_height(height);

const bool to_acc_regular = is_out_to_acc(from.get_keys(), boost::get<txout_to_key>(out.target), get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j);
const bool to_acc_sn_reward = to_acc_regular ? false : is_out_to_acc(from.get_keys(), boost::get<txout_to_key>(out.target), gov_key.pub, {}, j);

if (to_acc_regular || to_acc_sn_reward) {
outs_mine.push_back(tx_global_idx);
auto& oi = outs.back();
oi.is_sn_reward = to_acc_sn_reward;
if (oi.amount == 0) {
oi.amount = get_amount(from, tx, j);
oi.mask = tx.rct_signatures.outPk[j].mask;
}

}
}
}
Expand All @@ -436,10 +446,14 @@ bool init_spent_output_indices(output_index_vec& outs,
crypto::public_key out_key = boost::get<txout_to_key>(oi.out).key;
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0,0};

const auto tx_pk = oi.is_sn_reward ? get_deterministic_keypair_from_height(oi.blk_height).pub
: get_tx_pub_key_from_extra(*oi.p_tx);

generate_key_image_helper(from.get_keys(),
subaddresses,
out_key,
get_tx_pub_key_from_extra(*oi.p_tx),
tx_pk,
get_additional_tx_pub_keys_from_extra(*oi.p_tx),
oi.out_no,
in_ephemeral,
Expand Down Expand Up @@ -737,7 +751,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events,

bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const block& blk_head,
const cryptonote::account_base& from, const cryptonote::account_base& to, uint64_t amount,
uint64_t fee, size_t nmix, bool stake, uint64_t unlock_time)
uint64_t fee, size_t nmix, bool stake, boost::optional<const register_info> reg_info, uint64_t unlock_time)
{
vector<tx_source_entry> sources;
vector<tx_destination_entry> destinations;
Expand All @@ -746,7 +760,38 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote
fill_tx_sources_and_destinations(events, blk_head, from, to, amount, fee, nmix, sources, destinations, &change_amount);
tx_destination_entry change_addr{change_amount, from.get_keys().m_account_address, false /* is subaddr */ };

return cryptonote::construct_tx(from.get_keys(), sources, destinations, change_addr, {}, tx, unlock_time, stake, true);

std::vector<uint8_t> extra;

if (stake) {

if (!reg_info) {
LOG_ERROR("Stake tx has not registration info");
return false;
}

add_service_node_pubkey_to_tx_extra(extra, reg_info->service_node_keypair.pub);

const uint64_t exp_timestamp = time(nullptr) + STAKING_AUTHORIZATION_EXPIRATION_WINDOW;

crypto::hash hash;
bool hashed = cryptonote::get_registration_hash(reg_info->addresses, reg_info->operator_cut, reg_info->portions, exp_timestamp, hash);
if (!hashed)
{
MERROR("Could not make registration hash from addresses and portions");
return false;
}

crypto::signature signature;
crypto::generate_signature(hash, reg_info->service_node_keypair.pub, reg_info->service_node_keypair.sec, signature);

add_service_node_register_to_tx_extra(extra, reg_info->addresses, reg_info->operator_cut, reg_info->portions, exp_timestamp, signature);
add_service_node_contributor_to_tx_extra(extra, reg_info->addresses.at(0));

}


return cryptonote::construct_tx(from.get_keys(), sources, destinations, change_addr, extra, tx, unlock_time, stake, true);
}

transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head,
Expand Down
Loading

0 comments on commit dfae876

Please sign in to comment.