oxen-core/tests/core_tests/chaingen.h

1530 lines
75 KiB
C
Raw Normal View History

// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <vector>
#include <iostream>
2020-06-01 20:32:18 +02:00
#include <cstdint>
2020-06-02 00:30:19 +02:00
#include <optional>
2020-06-01 20:32:18 +02:00
#include <regex>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/program_options.hpp>
#include <boost/serialization/vector.hpp>
#include "cryptonote_protocol/quorumnet.h"
#include "common/boost_serialization_helper.h"
#include "common/command_line.h"
#include "common/threadpool.h"
#include "cryptonote_basic/account_boost_serialization.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
2021-07-06 04:48:18 +02:00
#include "cryptonote_basic/hardfork.h"
#include "cryptonote_config.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
2020-09-17 02:38:07 +02:00
#include "cryptonote_protocol/quorumnet.h"
#include "serialization/boost_std_variant.h"
#include "serialization/boost_std_optional.h"
#include "blockchain_db/testdb.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "tests.core"
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
#define TESTS_DEFAULT_FEE ((uint64_t)200000000) // 2 * pow(10, 8)
#define TEST_DEFAULT_DIFFICULTY 1
2019-10-10 02:56:10 +02:00
#if defined(__GNUG__) && !defined(__clang__) && __GNUC__ < 6
namespace service_nodes {
const std::vector<payout_entry> dummy; // help GCC 5 realize it needs to generate a default constructor
}
#endif
2021-01-04 03:09:59 +01:00
struct oxen_block_with_checkpoint
{
cryptonote::block block;
bool has_checkpoint;
cryptonote::checkpoint_t checkpoint;
};
2021-01-04 03:09:59 +01:00
struct oxen_transaction
{
cryptonote::transaction tx;
bool kept_by_block;
};
2021-01-04 03:09:59 +01:00
// TODO(oxen): Deperecate other methods of doing polymorphism for items to be
// added to test_event_entry. Right now, adding a block and checking for
// failure requires you to add a member field to mark the event index that
// should of failed, and you must add a member function that checks at run-time
// if at the marked index the block failed or not.
// Doing this way lets you write the failure case inline to when you create the
// test_event_entry, which means less book-keeping and boilerplate code of
// tracking event indexes and making member functions to detect the failure cases.
template <typename T>
2021-01-04 03:09:59 +01:00
struct oxen_blockchain_addable
{
2021-01-04 03:09:59 +01:00
oxen_blockchain_addable() = default;
oxen_blockchain_addable(T const &data, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {})
: data(data)
, can_be_added_to_blockchain(can_be_added_to_blockchain)
, fail_msg(fail_msg)
{
}
T data;
bool can_be_added_to_blockchain;
std::string fail_msg;
private: // TODO(doyle): Not implemented properly. Just copy pasta. Do we even need serialization?
friend class boost::serialization::access;
template<class Archive> void serialize(Archive & /*ar*/, const unsigned int /*version*/) { }
};
2021-01-04 03:09:59 +01:00
typedef std::function<bool (cryptonote::core& c, size_t ev_index)> oxen_callback;
struct oxen_callback_entry
{
std::string name;
2021-01-04 03:09:59 +01:00
oxen_callback callback;
private: // TODO(doyle): Not implemented properly. Just copy pasta. Do we even need serialization?
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/) { ar & name; }
};
//
// NOTE: Monero
//
struct callback_entry
{
std::string callback_name;
BEGIN_SERIALIZE_OBJECT()
FIELD(callback_name)
END_SERIALIZE()
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & callback_name;
}
};
template<typename T>
struct serialized_object
{
serialized_object() { }
serialized_object(const cryptonote::blobdata& a_data)
: data(a_data)
{
}
cryptonote::blobdata data;
BEGIN_SERIALIZE_OBJECT()
FIELD(data)
END_SERIALIZE()
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & data;
}
};
typedef serialized_object<cryptonote::block> serialized_block;
typedef serialized_object<cryptonote::transaction> serialized_transaction;
struct event_visitor_settings
{
int valid_mask;
bool txs_keeped_by_block;
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
crypto::secret_key service_node_key;
enum settings
{
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
set_txs_keeped_by_block = 1 << 0,
};
event_visitor_settings(int a_valid_mask = 0, bool a_txs_keeped_by_block = false)
: valid_mask(a_valid_mask)
, txs_keeped_by_block(a_txs_keeped_by_block)
{
}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & valid_mask;
ar & txs_keeped_by_block;
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
ar & service_node_key;
}
};
struct event_replay_settings
{
event_replay_settings() = default;
2021-07-06 04:48:18 +02:00
std::optional<std::vector<cryptonote::hard_fork>> hard_forks;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & hard_forks;
}
};
2020-06-02 05:08:48 +02:00
BINARY_VARIANT_TAG(callback_entry, 0xcb);
BINARY_VARIANT_TAG(cryptonote::account_base, 0xcc);
BINARY_VARIANT_TAG(serialized_block, 0xcd);
BINARY_VARIANT_TAG(serialized_transaction, 0xce);
BINARY_VARIANT_TAG(event_visitor_settings, 0xcf);
BINARY_VARIANT_TAG(event_replay_settings, 0xda);
typedef std::variant<cryptonote::block,
cryptonote::transaction,
std::vector<cryptonote::transaction>,
cryptonote::account_base,
callback_entry,
serialized_block,
serialized_transaction,
event_visitor_settings,
event_replay_settings,
std::string,
2021-01-04 03:09:59 +01:00
oxen_callback_entry,
oxen_blockchain_addable<oxen_block_with_checkpoint>,
oxen_blockchain_addable<cryptonote::block>,
oxen_blockchain_addable<oxen_transaction>,
oxen_blockchain_addable<service_nodes::quorum_vote_t>,
oxen_blockchain_addable<serialized_block>,
oxen_blockchain_addable<cryptonote::checkpoint_t>
> test_event_entry;
typedef std::unordered_map<crypto::hash, const cryptonote::transaction*> map_hash2tx_t;
class test_chain_unit_base
{
public:
2020-06-03 05:14:12 +02:00
typedef std::function<bool (cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events)> verify_callback;
typedef std::map<std::string, verify_callback> callbacks_map;
void register_callback(const std::string& cb_name, verify_callback cb);
bool verify(const std::string& cb_name, cryptonote::core& c, size_t ev_index, const std::vector<test_event_entry> &events);
2019-05-01 08:01:17 +02:00
bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*blk*/);
bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool /*tx_added*/, size_t /*event_index*/, const cryptonote::transaction& /*tx*/);
bool check_tx_verification_context_array(const std::vector<cryptonote::tx_verification_context>& tvcs, size_t /*tx_added*/, size_t /*event_index*/, const std::vector<cryptonote::transaction>& /*txs*/);
bool was_vote_meant_to_be_successfully_added(size_t event_index, bool vote_was_added) { (void)event_index; return vote_was_added; }
2019-05-01 08:01:17 +02:00
private:
callbacks_map m_callbacks;
};
class test_generator
{
public:
struct block_info
{
2014-03-03 23:07:58 +01:00
block_info()
: prev_id()
, already_generated_coins(0)
, block_weight(0)
2014-03-03 23:07:58 +01:00
{
}
block_info(crypto::hash a_prev_id, uint64_t an_already_generated_coins, size_t a_block_weight, cryptonote::block a_block)
: prev_id(a_prev_id)
, already_generated_coins(an_already_generated_coins)
, block_weight(a_block_weight)
, block(a_block)
{
}
crypto::hash prev_id;
uint64_t already_generated_coins;
size_t block_weight;
cryptonote::block block;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & prev_id;
ar & already_generated_coins;
ar & block_weight;
ar & block;
}
};
enum block_fields
{
bf_none = 0,
bf_major_ver = 1 << 0,
bf_minor_ver = 1 << 1,
bf_timestamp = 1 << 2,
bf_prev_id = 1 << 3,
bf_miner_tx = 1 << 4,
bf_tx_hashes = 1 << 5,
bf_diffic = 1 << 6,
bf_hf_version= 1 << 8
};
explicit test_generator(int hf_version = 7) : m_hf_version(hf_version) {}
void get_block_chain(std::vector<block_info>& blockchain, const crypto::hash& head, size_t n) const;
void get_block_chain(std::vector<cryptonote::block>& blockchain, const crypto::hash& head, size_t n) const;
void get_last_n_block_weights(std::vector<uint64_t>& block_weights, const crypto::hash& head, size_t n) const;
uint64_t get_already_generated_coins(const crypto::hash& blk_id) const;
uint64_t get_already_generated_coins(const cryptonote::block& blk) const;
void add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<uint64_t>& block_weights, uint64_t already_generated_coins);
bool 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<uint64_t>& block_weights, const std::list<cryptonote::transaction>& tx_list, const service_nodes::payout &block_leader = {});
bool construct_block(cryptonote::block& blk, const cryptonote::account_base& miner_acc, uint64_t timestamp);
bool construct_block(cryptonote::block& blk, const cryptonote::block& blk_prev, const cryptonote::account_base& miner_acc,
const std::list<cryptonote::transaction>& tx_list = std::list<cryptonote::transaction>(), const service_nodes::payout &block_leader = {});
bool construct_block_manually(cryptonote::block& blk, const cryptonote::block& prev_block,
const cryptonote::account_base& miner_acc, int actual_params = bf_none, uint8_t major_ver = 0,
uint8_t minor_ver = 0, uint64_t timestamp = 0, const crypto::hash& prev_id = crypto::hash(),
const cryptonote::difficulty_type& diffic = 1, const cryptonote::transaction& miner_tx = cryptonote::transaction(),
const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0, size_t txn_fee = 0);
bool construct_block_manually_tx(cryptonote::block& blk, const cryptonote::block& prev_block,
const cryptonote::account_base& miner_acc, const std::vector<crypto::hash>& tx_hashes, size_t txs_size);
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
int m_hf_version;
std::unordered_map<crypto::hash, block_info> m_blocks_info;
2020-06-02 04:09:22 +02:00
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & m_blocks_info;
}
};
template<typename T>
std::string dump_keys(T * buff32)
{
std::ostringstream ss;
char buff[10];
ss << "[";
for(int i = 0; i < 32; i++)
{
snprintf(buff, 10, "0x%02x", ((uint8_t)buff32[i] & 0xff));
ss << buff;
if (i < 31)
ss << ",";
}
ss << "]";
return ss.str();
}
struct output_index {
cryptonote::txout_target_v out;
uint64_t amount;
size_t blk_height; // block height
size_t tx_no; // index of transaction in block
size_t out_no; // index of out in transaction
size_t idx;
uint64_t unlock_time;
bool is_coin_base;
bool deterministic_key_pair;
bool spent;
bool rct;
rct::key comm;
2021-01-04 03:09:59 +01:00
rct::key mask; // TODO(oxen): I dont know if this is still meant to be here. Monero removed and replaced with commitment, whereas we use the mask in our tests?
cryptonote::block const *p_blk;
cryptonote::transaction const *p_tx;
output_index() = default;
output_index(const cryptonote::txout_target_v &_out, uint64_t _a, size_t _h, size_t tno, size_t ono, const cryptonote::block *_pb, const cryptonote::transaction *_pt)
{
*this = {};
out = _out;
amount = _a;
blk_height = _h;
tx_no = tno;
out_no = ono;
p_blk = _pb;
p_tx = _pt;
}
#if 0
output_index(const output_index &other)
: out(other.out), amount(other.amount), blk_height(other.blk_height), tx_no(other.tx_no), rct(other.rct),
out_no(other.out_no), idx(other.idx), unlock_time(other.unlock_time), is_coin_base(other.is_coin_base),
spent(other.spent), comm(other.comm), p_blk(other.p_blk), p_tx(other.p_tx) { }
#endif
void set_rct(bool arct) {
rct = arct;
if (rct && p_tx->rct_signatures.outPk.size() > out_no)
comm = p_tx->rct_signatures.outPk[out_no].mask;
else
comm = rct::commit(amount, rct::identity());
}
rct::key commitment() const {
return comm;
}
const std::string toString() const {
std::stringstream ss;
ss << "output_index{blk_height=" << blk_height
<< " tx_no=" << tx_no
<< " out_no=" << out_no
<< " amount=" << amount
<< " idx=" << idx
<< " unlock_time=" << unlock_time
<< " spent=" << spent
<< " is_coin_base=" << is_coin_base
<< " rct=" << rct
<< " comm=" << dump_keys(comm.bytes)
<< "}";
return ss.str();
}
output_index(const output_index &) = default;
output_index& operator=(const output_index& other)
{
new(this) output_index(other);
return *this;
}
};
typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry;
typedef std::pair<crypto::hash, size_t> output_hasher;
2019-11-06 08:18:44 +01:00
struct output_hasher_hasher { size_t operator()(const output_hasher &h) const { return *reinterpret_cast<const size_t *>(h.first.data) + h.second; } };
typedef std::map<uint64_t, std::vector<size_t> > map_output_t;
typedef std::map<uint64_t, std::vector<output_index> > map_output_idx_t;
typedef std::unordered_map<crypto::hash, cryptonote::block> map_block_t;
typedef std::unordered_map<output_hasher, output_index, output_hasher_hasher> map_txid_output_t;
typedef std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses_t;
typedef std::pair<uint64_t, size_t> outloc_t;
typedef std::variant<cryptonote::account_public_address, cryptonote::account_keys, cryptonote::account_base, cryptonote::tx_destination_entry> var_addr_t;
cryptonote::account_public_address get_address(const var_addr_t& inp);
typedef struct {
const var_addr_t addr;
bool is_subaddr;
uint64_t amount;
} dest_wrapper_t;
// Daemon functionality
class block_tracker
{
public:
map_output_idx_t m_outs;
map_txid_output_t m_map_outs; // mapping (txid, out) -> output_index
map_block_t m_blocks;
block_tracker() = default;
block_tracker(const block_tracker &bt): m_outs(bt.m_outs), m_map_outs(bt.m_map_outs), m_blocks(bt.m_blocks) {};
map_txid_output_t::iterator find_out(const crypto::hash &txid, size_t out);
map_txid_output_t::iterator find_out(const output_hasher &id);
void process(const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
void process(const std::vector<const cryptonote::block*>& blockchain, const map_hash2tx_t& mtx);
void process(const cryptonote::block* blk, const cryptonote::transaction * tx, size_t i);
void global_indices(const cryptonote::transaction *tx, std::vector<uint64_t> &indices);
void get_fake_outs(size_t num_outs, uint64_t amount, uint64_t global_index, uint64_t cur_height, std::vector<get_outs_entry> &outs);
std::string dump_data();
void dump_data(const std::string & fname);
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /*version*/)
{
ar & m_outs;
ar & m_map_outs;
ar & m_blocks;
}
};
std::string dump_data(const cryptonote::transaction &tx);
2014-03-03 23:07:58 +01:00
cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr=false, uint64_t amount=0);
std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1=false, uint64_t am1=0);
std::vector<cryptonote::tx_destination_entry> build_dsts(std::initializer_list<dest_wrapper_t> inps);
uint64_t sum_amount(const std::vector<cryptonote::tx_destination_entry>& destinations);
uint64_t sum_amount(const std::vector<cryptonote::tx_source_entry>& sources);
2014-03-03 23:07:58 +01:00
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx,
const cryptonote::block& blk_head, const cryptonote::account_base& from, const var_addr_t& to, uint64_t amount,
uint64_t fee, size_t nmix, rct::RangeProofType range_proof_type=rct::RangeProofType::Borromean, int bp_version = 0);
bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head,
const cryptonote::account_base& from, std::vector<cryptonote::tx_destination_entry> destinations,
uint64_t fee, size_t nmix, rct::RangeProofType range_proof_type=rct::RangeProofType::Borromean, int bp_version = 0);
bool construct_tx_to_key(cryptonote::transaction& tx, const cryptonote::account_base& from, const var_addr_t& to, uint64_t amount,
std::vector<cryptonote::tx_source_entry> &sources,
uint64_t fee, rct::RangeProofType range_proof_type=rct::RangeProofType::Borromean, int bp_version = 0);
bool construct_tx_to_key(cryptonote::transaction& tx, const cryptonote::account_base& from, const std::vector<cryptonote::tx_destination_entry>& destinations,
std::vector<cryptonote::tx_source_entry> &sources,
uint64_t fee, rct::RangeProofType range_proof_type, int bp_version = 0);
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
cryptonote::transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const cryptonote::block& blk_head,
const cryptonote::account_base& acc_from, const cryptonote::account_base& acc_to,
uint64_t amount, uint64_t fee);
bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys,
std::vector<cryptonote::tx_source_entry>& sources,
const std::vector<cryptonote::tx_destination_entry>& destinations,
2020-06-02 00:30:19 +02:00
const std::optional<cryptonote::tx_destination_entry>& change_addr,
std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time,
rct::RangeProofType range_proof_type=rct::RangeProofType::Borromean, int bp_version = 0);
uint64_t num_blocks(const std::vector<test_event_entry>& events);
cryptonote::block get_head_block(const std::vector<test_event_entry>& events);
void get_confirmed_txs(const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs);
bool trim_block_chain(std::vector<cryptonote::block>& blockchain, const crypto::hash& tail);
bool trim_block_chain(std::vector<const cryptonote::block*>& blockchain, const crypto::hash& tail);
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<cryptonote::block>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head);
void fill_tx_sources_and_multi_destinations(const std::vector<test_event_entry>& events,
const cryptonote::block& blk_head,
const cryptonote::account_base& from,
const cryptonote::account_public_address& to,
uint64_t const *amount,
int num_amounts,
uint64_t fee,
size_t nmix,
std::vector<cryptonote::tx_source_entry>& sources,
std::vector<cryptonote::tx_destination_entry>& destinations,
bool always_add_change_output = false,
uint64_t *change_amount = nullptr);
bool find_block_chain(const std::vector<test_event_entry>& events, std::vector<const cryptonote::block*>& blockchain, map_hash2tx_t& mtx, const crypto::hash& head);
void fill_tx_destinations(const var_addr_t& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee,
const std::vector<cryptonote::tx_source_entry> &sources,
std::vector<cryptonote::tx_destination_entry>& destinations, bool always_change=false);
void fill_tx_destinations(const var_addr_t& from, const std::vector<cryptonote::tx_destination_entry>& dests,
uint64_t fee,
const std::vector<cryptonote::tx_source_entry> &sources,
std::vector<cryptonote::tx_destination_entry>& destinations,
bool always_change);
void fill_tx_destinations(const var_addr_t& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee,
const std::vector<cryptonote::tx_source_entry> &sources,
std::vector<cryptonote::tx_destination_entry>& destinations,
std::vector<cryptonote::tx_destination_entry>& destinations_pure,
bool always_change=false);
void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& events, const cryptonote::block& blk_head,
const cryptonote::account_base& from, const cryptonote::account_public_address& to,
uint64_t amount, uint64_t fee, size_t nmix,
std::vector<cryptonote::tx_source_entry>& sources,
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
std::vector<cryptonote::tx_destination_entry>& destinations, uint64_t *change_amount = nullptr);
/// Get the amount transferred to `account` in `tx` as output `i`
uint64_t get_amount(const cryptonote::account_base& account, const cryptonote::transaction& tx, int i);
uint64_t get_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
uint64_t get_unlocked_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
2021-07-06 04:48:18 +02:00
bool extract_hard_forks(const std::vector<test_event_entry>& events, std::vector<cryptonote::hard_fork>& hard_forks);
/************************************************************************/
/* */
/************************************************************************/
template<class t_test_class>
struct push_core_event_visitor
{
private:
cryptonote::core& m_c;
const std::vector<test_event_entry>& m_events;
t_test_class& m_validator;
size_t m_ev_index;
bool m_txs_keeped_by_block;
public:
push_core_event_visitor(cryptonote::core& c, const std::vector<test_event_entry>& events, t_test_class& validator)
: m_c(c)
, m_events(events)
, m_validator(validator)
, m_ev_index(0)
, m_txs_keeped_by_block(false)
{
}
void event_index(size_t ev_index)
{
m_ev_index = ev_index;
}
bool operator()(const event_replay_settings& settings)
{
log_event("event_replay_settings");
return true;
}
bool operator()(const event_visitor_settings& settings)
{
log_event("event_visitor_settings");
if (settings.valid_mask & event_visitor_settings::set_txs_keeped_by_block)
{
m_txs_keeped_by_block = settings.txs_keeped_by_block;
}
return true;
}
bool operator()(const cryptonote::transaction& tx) const
{
log_event("cryptonote::transaction");
cryptonote::tx_verification_context tvc{};
size_t pool_size = m_c.get_pool().get_transactions_count();
Generic burn fee checking + blink burn fee checking This adds the ability for check_fee() to also check the burn amount. This requires passing extra info through `add_tx()` (and the various things that call it), so I took the: bool keeped_by_block, bool relayed, bool do_not_relay argument triplet, moved it into a struct in tx_pool.h, then added the other fee options there (along with some static factory functions for generating the typical sets of option). The majority of this commit is chasing that change through the codebase and test suite. This is used by blink but should also help LNS and other future burn transactions to verify a burn amount simply when adding the transation to the mempool. It supports a fixed burn amount, a burn amount as a multiple of the minimum tx fee, and also allows you to increase the minimum tx fee (so that, for example, we could require blink txes to pay miners 250% of the usual minimum (unimportant) priority tx fee. - Removed a useless core::add_new_tx() overload that wasn't used anywhere. Blink-specific changes: (I'd normally separate these into a separate commit, but they got interwoven fairly heavily with the above change). - changed the way blink burning is specified so that we have three knobs for fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee). The fixed amount is currently 0, base fee is 400%, and require miner tx fee is simply 100% (i.e. no different than a normal transaction). This is the same as before this commit, but is changing how they are being specified in cryptonote_config.h. - blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked before signing a blink tx. (These fee checks don't apply to anyone else -- when propagating over the network only the miner tx fee is checked). - Added a couple of checks for blink quorums: 1) make sure they have reached the blink hf; 2) make sure the submitted tx version conforms to the current hf min/max tx version. - print blink fee information in simplewallet's `fee` output - add "typical" fee calculations in the `fee` output: [wallet T6SCwL (has locked stakes)]: fee Current fee is 0.000000850 loki per byte + 0.020000000 loki per output No backlog at priority 1 No backlog at priority 2 No backlog at priority 3 No backlog at priority 4 Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink) where "small" here is the same tx size (2500 bytes + 2 outputs) used to estimate backlogs.
2019-11-09 04:14:15 +01:00
cryptonote::tx_pool_options opts;
opts.kept_by_block = m_txs_keeped_by_block;
m_c.handle_incoming_tx(t_serializable_object_to_blob(tx), tvc, opts);
bool tx_added = pool_size + 1 == m_c.get_pool().get_transactions_count();
2019-05-01 08:01:17 +02:00
bool r = m_validator.check_tx_verification_context(tvc, tx_added, m_ev_index, tx);
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
return true;
}
bool operator()(const std::vector<cryptonote::transaction>& txs) const
{
log_event("cryptonote::transaction");
std::vector<cryptonote::blobdata> tx_blobs;
for (const auto &tx: txs)
tx_blobs.push_back(t_serializable_object_to_blob(tx));
size_t pool_size = m_c.get_pool().get_transactions_count();
Generic burn fee checking + blink burn fee checking This adds the ability for check_fee() to also check the burn amount. This requires passing extra info through `add_tx()` (and the various things that call it), so I took the: bool keeped_by_block, bool relayed, bool do_not_relay argument triplet, moved it into a struct in tx_pool.h, then added the other fee options there (along with some static factory functions for generating the typical sets of option). The majority of this commit is chasing that change through the codebase and test suite. This is used by blink but should also help LNS and other future burn transactions to verify a burn amount simply when adding the transation to the mempool. It supports a fixed burn amount, a burn amount as a multiple of the minimum tx fee, and also allows you to increase the minimum tx fee (so that, for example, we could require blink txes to pay miners 250% of the usual minimum (unimportant) priority tx fee. - Removed a useless core::add_new_tx() overload that wasn't used anywhere. Blink-specific changes: (I'd normally separate these into a separate commit, but they got interwoven fairly heavily with the above change). - changed the way blink burning is specified so that we have three knobs for fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee). The fixed amount is currently 0, base fee is 400%, and require miner tx fee is simply 100% (i.e. no different than a normal transaction). This is the same as before this commit, but is changing how they are being specified in cryptonote_config.h. - blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked before signing a blink tx. (These fee checks don't apply to anyone else -- when propagating over the network only the miner tx fee is checked). - Added a couple of checks for blink quorums: 1) make sure they have reached the blink hf; 2) make sure the submitted tx version conforms to the current hf min/max tx version. - print blink fee information in simplewallet's `fee` output - add "typical" fee calculations in the `fee` output: [wallet T6SCwL (has locked stakes)]: fee Current fee is 0.000000850 loki per byte + 0.020000000 loki per output No backlog at priority 1 No backlog at priority 2 No backlog at priority 3 No backlog at priority 4 Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink) where "small" here is the same tx size (2500 bytes + 2 outputs) used to estimate backlogs.
2019-11-09 04:14:15 +01:00
cryptonote::tx_pool_options opts;
opts.kept_by_block = m_txs_keeped_by_block;
auto parsed = m_c.handle_incoming_txs(tx_blobs, opts);
std::vector<cryptonote::tx_verification_context> tvcs;
tvcs.reserve(parsed.size());
for (auto &i : parsed)
tvcs.push_back(i.tvc);
size_t tx_added = m_c.get_pool().get_transactions_count() - pool_size;
2019-05-01 08:01:17 +02:00
bool r = m_validator.check_tx_verification_context_array(tvcs, tx_added, m_ev_index, txs);
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
return true;
}
bool operator()(const cryptonote::block& b) const
{
log_event("cryptonote::block");
cryptonote::block_verification_context bvc{};
cryptonote::blobdata bd = t_serializable_object_to_blob(b);
std::vector<cryptonote::block> pblocks;
if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {bd, {}, {}}), pblocks))
{
m_c.handle_incoming_block(bd, &b, bvc, nullptr);
m_c.cleanup_handle_incoming_blocks();
}
else
bvc.m_verifivation_failed = true;
2019-05-01 08:01:17 +02:00
bool r = m_validator.check_block_verification_context(bvc, m_ev_index, b);
CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed");
return r;
}
2021-01-04 03:09:59 +01:00
// TODO(oxen): Deprecate callback_entry for oxen_callback_entry, why don't you
// just include the callback routine in the callback entry instead of going
// down into the validator and then have to do a string->callback (map) lookup
// for the callback?
bool operator()(const callback_entry& cb) const
{
log_event(std::string("callback_entry ") + cb.callback_name);
return m_validator.verify(cb.callback_name, m_c, m_ev_index, m_events);
}
bool operator()(const cryptonote::account_base& ab) const
{
log_event("cryptonote::account_base");
return true;
}
bool operator()(const serialized_block& sr_block) const
{
log_event("serialized_block");
cryptonote::block_verification_context bvc{};
std::vector<cryptonote::block> pblocks;
if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {sr_block.data, {}, {}}), pblocks))
{
m_c.handle_incoming_block(sr_block.data, NULL, bvc, nullptr);
m_c.cleanup_handle_incoming_blocks();
}
else
bvc.m_verifivation_failed = true;
cryptonote::block blk;
2020-06-02 05:08:48 +02:00
serialization::binary_string_unarchiver ba{sr_block.data};
try {
serialization::serialize(ba, blk);
} catch (...) {
blk = cryptonote::block();
}
2019-05-01 08:01:17 +02:00
bool r = m_validator.check_block_verification_context(bvc, m_ev_index, blk);
CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed");
return true;
}
bool operator()(const serialized_transaction& sr_tx) const
{
log_event("serialized_transaction");
cryptonote::tx_verification_context tvc{};
size_t pool_size = m_c.get_pool().get_transactions_count();
Generic burn fee checking + blink burn fee checking This adds the ability for check_fee() to also check the burn amount. This requires passing extra info through `add_tx()` (and the various things that call it), so I took the: bool keeped_by_block, bool relayed, bool do_not_relay argument triplet, moved it into a struct in tx_pool.h, then added the other fee options there (along with some static factory functions for generating the typical sets of option). The majority of this commit is chasing that change through the codebase and test suite. This is used by blink but should also help LNS and other future burn transactions to verify a burn amount simply when adding the transation to the mempool. It supports a fixed burn amount, a burn amount as a multiple of the minimum tx fee, and also allows you to increase the minimum tx fee (so that, for example, we could require blink txes to pay miners 250% of the usual minimum (unimportant) priority tx fee. - Removed a useless core::add_new_tx() overload that wasn't used anywhere. Blink-specific changes: (I'd normally separate these into a separate commit, but they got interwoven fairly heavily with the above change). - changed the way blink burning is specified so that we have three knobs for fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee). The fixed amount is currently 0, base fee is 400%, and require miner tx fee is simply 100% (i.e. no different than a normal transaction). This is the same as before this commit, but is changing how they are being specified in cryptonote_config.h. - blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked before signing a blink tx. (These fee checks don't apply to anyone else -- when propagating over the network only the miner tx fee is checked). - Added a couple of checks for blink quorums: 1) make sure they have reached the blink hf; 2) make sure the submitted tx version conforms to the current hf min/max tx version. - print blink fee information in simplewallet's `fee` output - add "typical" fee calculations in the `fee` output: [wallet T6SCwL (has locked stakes)]: fee Current fee is 0.000000850 loki per byte + 0.020000000 loki per output No backlog at priority 1 No backlog at priority 2 No backlog at priority 3 No backlog at priority 4 Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink) where "small" here is the same tx size (2500 bytes + 2 outputs) used to estimate backlogs.
2019-11-09 04:14:15 +01:00
cryptonote::tx_pool_options opts;
opts.kept_by_block = m_txs_keeped_by_block;
m_c.handle_incoming_tx(sr_tx.data, tvc, opts);
bool tx_added = pool_size + 1 == m_c.get_pool().get_transactions_count();
cryptonote::transaction tx;
2020-06-02 05:08:48 +02:00
serialization::binary_string_unarchiver ba{sr_tx.data};
try {
serialization::serialize(ba, tx);
} catch (...) {
tx = cryptonote::transaction();
}
2019-05-01 08:01:17 +02:00
bool r = m_validator.check_tx_verification_context(tvc, tx_added, m_ev_index, tx);
CHECK_AND_NO_ASSERT_MES(r, false, "transaction verification context check failed");
return true;
}
//
// NOTE: Loki
//
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<cryptonote::checkpoint_t> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<cryptonote::checkpoint_t>");
cryptonote::Blockchain &blockchain = m_c.get_blockchain_storage();
bool added = blockchain.update_checkpoint(entry.data);
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg : "Failed to add checkpoint (no reason given)"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<service_nodes::quorum_vote_t> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<service_nodes::quorum_vote_t>");
cryptonote::vote_verification_context vvc = {};
bool added = m_c.add_service_node_vote(entry.data, vvc);
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg : "Failed to add service node vote (no reason given)"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<oxen_block_with_checkpoint> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<oxen_block_with_checkpoint>");
cryptonote::block const &block = entry.data.block;
2021-01-04 03:09:59 +01:00
// TODO(oxen): Need to make a copy because we still need modify checkpoints
// in handle_incoming_blocks but that is because of temporary forking code
cryptonote::checkpoint_t checkpoint_copy = entry.data.checkpoint;
cryptonote::block_verification_context bvc = {};
cryptonote::blobdata bd = t_serializable_object_to_blob(block);
std::vector<cryptonote::block> pblocks;
if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {bd, {}, {}}), pblocks))
{
m_c.handle_incoming_block(bd, &block, bvc, &checkpoint_copy);
m_c.cleanup_handle_incoming_blocks();
}
else
bvc.m_verifivation_failed = true;
bool added = !bvc.m_verifivation_failed;
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg : "Failed to add block with checkpoint (no reason given)"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<cryptonote::block> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<cryptonote::block>");
2020-06-23 04:35:56 +02:00
cryptonote::block const &block = entry.data;
cryptonote::block_verification_context bvc = {};
cryptonote::blobdata bd = t_serializable_object_to_blob(block);
std::vector<cryptonote::block> pblocks;
if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {bd, {}, {}}), pblocks))
{
m_c.handle_incoming_block(bd, &block, bvc, nullptr);
m_c.cleanup_handle_incoming_blocks();
}
else
bvc.m_verifivation_failed = true;
bool added = !bvc.m_verifivation_failed;
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg : "Failed to add block (no reason given)"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<serialized_block> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<serialized_block>");
serialized_block const &block = entry.data;
cryptonote::block_verification_context bvc = {};
std::vector<cryptonote::block> pblocks;
if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {block.data, {}, {}}), pblocks))
{
m_c.handle_incoming_block(block.data, nullptr, bvc, nullptr);
m_c.cleanup_handle_incoming_blocks();
}
else
bvc.m_verifivation_failed = true;
bool added = !bvc.m_verifivation_failed;
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg : "Failed to add block (no reason given)"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_blockchain_addable<oxen_transaction> &entry) const
{
2021-01-04 03:09:59 +01:00
log_event("oxen_blockchain_addable<oxen_transaction>");
cryptonote::tx_verification_context tvc = {};
size_t pool_size = m_c.get_pool().get_transactions_count();
Generic burn fee checking + blink burn fee checking This adds the ability for check_fee() to also check the burn amount. This requires passing extra info through `add_tx()` (and the various things that call it), so I took the: bool keeped_by_block, bool relayed, bool do_not_relay argument triplet, moved it into a struct in tx_pool.h, then added the other fee options there (along with some static factory functions for generating the typical sets of option). The majority of this commit is chasing that change through the codebase and test suite. This is used by blink but should also help LNS and other future burn transactions to verify a burn amount simply when adding the transation to the mempool. It supports a fixed burn amount, a burn amount as a multiple of the minimum tx fee, and also allows you to increase the minimum tx fee (so that, for example, we could require blink txes to pay miners 250% of the usual minimum (unimportant) priority tx fee. - Removed a useless core::add_new_tx() overload that wasn't used anywhere. Blink-specific changes: (I'd normally separate these into a separate commit, but they got interwoven fairly heavily with the above change). - changed the way blink burning is specified so that we have three knobs for fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee). The fixed amount is currently 0, base fee is 400%, and require miner tx fee is simply 100% (i.e. no different than a normal transaction). This is the same as before this commit, but is changing how they are being specified in cryptonote_config.h. - blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked before signing a blink tx. (These fee checks don't apply to anyone else -- when propagating over the network only the miner tx fee is checked). - Added a couple of checks for blink quorums: 1) make sure they have reached the blink hf; 2) make sure the submitted tx version conforms to the current hf min/max tx version. - print blink fee information in simplewallet's `fee` output - add "typical" fee calculations in the `fee` output: [wallet T6SCwL (has locked stakes)]: fee Current fee is 0.000000850 loki per byte + 0.020000000 loki per output No backlog at priority 1 No backlog at priority 2 No backlog at priority 3 No backlog at priority 4 Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink) where "small" here is the same tx size (2500 bytes + 2 outputs) used to estimate backlogs.
2019-11-09 04:14:15 +01:00
cryptonote::tx_pool_options opts;
opts.kept_by_block = entry.data.kept_by_block;
m_c.handle_incoming_tx(t_serializable_object_to_blob(entry.data.tx), tvc, opts);
bool added = (pool_size + 1) == m_c.get_pool().get_transactions_count();
CHECK_AND_NO_ASSERT_MES(added == entry.can_be_added_to_blockchain, false, (entry.fail_msg.size() ? entry.fail_msg :
entry.can_be_added_to_blockchain ? "Failed to add transaction that should have been accepted" : "TX adding should have failed, but didn't"));
return true;
}
2021-01-04 03:09:59 +01:00
bool operator()(const oxen_callback_entry& entry) const
{
2021-01-04 03:09:59 +01:00
log_event(std::string("oxen_callback_entry ") + entry.name);
bool result = entry.callback(m_c, m_ev_index);
return result;
}
bool operator()(const std::string &msg) const
{
log_event("event_msgevent_marker");
MGINFO_MAGENTA(msg);
return true;
}
private:
void log_event(const std::string& event_type) const
{
2020-09-15 02:20:36 +02:00
if (LOG_ENABLED(Info))
MGINFO_YELLOW("=== EVENT # " << m_ev_index << ": " << event_type);
}
};
//--------------------------------------------------------------------------
template<class t_test_class>
inline bool replay_events_through_core_plain(cryptonote::core& cr, const std::vector<test_event_entry>& events, t_test_class& validator, bool reinit=true)
{
TRY_ENTRY();
// start with a clean pool
std::vector<crypto::hash> pool_txs;
cr.get_pool().get_transaction_hashes(pool_txs);
cr.get_blockchain_storage().flush_txes_from_pool(pool_txs);
//init core here
if (reinit) {
CHECK_AND_ASSERT_MES(std::holds_alternative<cryptonote::block>(events[0]), false,
"First event must be genesis block creation");
cr.set_genesis_block(var::get<cryptonote::block>(events[0]));
}
bool r = true;
push_core_event_visitor<t_test_class> visitor(cr, events, validator);
for(size_t i = 1; i < events.size() && r; ++i)
{
visitor.event_index(i);
r = var::visit(visitor, events[i]);
}
return r;
CATCH_ENTRY_L0("replay_events_through_core", false);
}
//--------------------------------------------------------------------------
template<typename t_test_class>
struct get_test_options {
2021-07-06 04:48:18 +02:00
const std::vector<cryptonote::hard_fork> hard_forks = {{7, 0, 0, 0}};
const cryptonote::test_options test_options = {
hard_forks, 0
};
};
//--------------------------------------------------------------------------
template<class t_test_class>
inline bool do_replay_events_get_core(std::vector<test_event_entry>& events, cryptonote::core *core, t_test_class &validator)
{
boost::program_options::options_description desc("Allowed options");
cryptonote::core::init_options(desc);
Replace epee http rpc server with uWebSockets This replaces the NIH epee http server which does not work all that well with an external C++ library called uWebSockets. Fundamentally this gives the following advantages: - Much less code to maintain - Just one thread for handling HTTP connections versus epee's pool of threads - Uses existing LokiMQ job server and existing thread pool for handling the actual tasks; they are processed/scheduled in the same "rpc" or "admin" queues as lokimq rpc calls. One notable benefit is that "admin" rpc commands get their own queue (and thus cannot be delayed by long rpc commands). Currently the lokimq threads and the http rpc thread pool and the p2p thread pool and the job queue thread pool and the dns lookup thread pool and... are *all* different thread pools; this is a step towards consolidating them. - Very little mutex contention (which has been a major problem with epee RPC in the past): there is one mutex (inside uWebSockets) for putting responses back into the thread managing the connection; everything internally gets handled through (lock-free) lokimq inproc sockets. - Faster RPC performance on average, and much better worst case performance. Epee's http interface seems to have some race condition that ocassionally stalls a request (even a very simple one) for a dozen or more seconds for no good reason. - Long polling gets redone here to no longer need threads; instead we just store the request and respond when the thread pool, or else in a timer (that runs once/second) for timing out long polls. --- The basic idea of how this works from a high level: We launch a single thread to handle HTTP RPC requests and response data. This uWebSockets thread is essentially running an event loop: it never actually handles any logic; it only serves to shuttle data that arrives in a request to some other thread, and then, at some later point, to send some reply back to that waiting connection. Everything is asynchronous and non-blocking here: the basic uWebSockets event loop just operates as things arrive, passes it off immediately, and goes back to waiting for the next thing to arrive. The basic flow is like this: 0. uWS thread -- listens on localhost:22023 1. uWS thread -- incoming request on localhost:22023 2. uWS thread -- fires callback, which injects the task into the LokiMQ job queue 3. LMQ main loop -- schedules it as an RPC job 4. LMQ rpc thread -- Some LokiMQ thread runs it, gets the result 5. LMQ rpc thread -- Result gets queued up for the uWS thread 6. uWS thread -- takes the request and starts sending it (asynchronously) back to the requestor. In more detail: uWebSockets has registered has registered handlers for non-jsonrpc requests (legacy JSON or binary). If the port is restricted then admin commands get mapped to a "Access denied" response handler, otherwise public commands (and admin commands on an unrestricted port) go to the rpc command handler. POST requests to /json_rpc have their own handler; this is a little different than the above because it has to parse the request before it can determine whether it is allowed or not, but once this is done it continues roughly the same as legacy/binary requests. uWebSockets then listens on the given IP/port for new incoming requests, and starts listening for requests in a thread (we own this thread). When a request arrives, it fires the event handler for that request. (This may happen multiple times, if the client is sending a bunch of data in a POST request). Once we have the full request, we then queue the job in LokiMQ, putting it in the "rpc" or "admin" command categories. (The one practical different here is that "admin" is configured to be allowed to start up its own thread if all other threads are busy, while "rpc" commands are prioritized along with everything else.) LokiMQ then schedules this, along with native LokiMQ "rpc." or "admin." requests. When a LMQ worker thread becomes available, the RPC command gets called in it and runs. Whatever output it produces (or error message, if it throws) then gets wrapped up in jsonrpc boilerplate (if necessary), and delivered to the uWebSockets thread to be sent in reply to that request. uWebSockets picks up the data and sends whatever it can without blocking, then buffers whatever it couldn't send to be sent again in a later event loop iteration once the requestor can accept more data. (This part is outside lokid; we only have to give uWS the data and let it worry about delivery). --- PR specifics: Things removed from this PR: 1. ssl settings; with this PR the HTTP RPC interface is plain-text. The previous default generated a self-signed certificate for the server on startup and then the client accepted any certificate. This is actually *worse* than unencrypted because it is entirely MITM-readable and yet might make people think that their RPC communication is encrypted, and setting up actual certificates is difficult enough that I think most people don't bother. uWebSockets *does* support HTTPS, and we could glue the existing options into it, but I'm not convinced it's worthwhile: it works much better to put HTTPS in a front-end proxy holding the certificate that proxies requests to the backend (which can then listen in restricted mode on some localhost port). One reason this is better is that it is much easier to reload and/or restart such a front-end server, while certificate updates with lokid require a full restart. Another reason is that you get an error page instead of a timeout if something is wrong with the backend. Finally we also save having to generate a temporary certificate on *every* lokid invocation. 2. HTTP Digest authentication. Digest authentication is obsolete (and was already obsolete when it got added to Monero). HTTP-Digest was originally an attempt to provide a password authentication mechanism that does not leak the password in transit, but still required that the server know the password. It only has marginal value against replay attacks, and is made entirely obsolete by sending traffic over HTTPS instead. No client out there supports Digest but *not* Basic auth, and so given the limited usefulness it seems pointless to support more than Basic auth for HTTP RPC login. What's worse is that epee's HTTP Digest authentication is a terrible implementation: it uses boost::spirit -- a recursive descent parser meant for building complex language grammars -- just to parse a single HTTP header for Digest auth. This is a big load of crap that should never have been accepted upstream, and that we should get rid of (even if we wanted to support Digest auth it takes less than 100 lines of code to do it when *not* using a recursive descent parser).
2020-06-29 01:23:06 +02:00
cryptonote::long_poll_trigger = [](cryptonote::tx_memory_pool&) {};
boost::program_options::variables_map vm;
bool r = command_line::handle_error_helper(desc, [&]()
{
boost::program_options::store(boost::program_options::basic_parsed_options<char>(&desc), vm);
boost::program_options::notify(vm);
return true;
});
if (!r)
return false;
auto & c = *core;
quorumnet::init_core_callbacks();
2021-01-04 03:09:59 +01:00
// TODO(oxen): Deprecate having to specify hardforks in a templated struct. This
// puts an unecessary level of indirection that makes it hard to follow the
// code. Hardforks should just be declared next to the testing code in the
// generate function. Inlining code and localizing declarations so that we read
// as much as possible top-to-bottom in linear sequences makes things easier to
// follow
// But changing this now means that all the other tests would break.
get_test_options<t_test_class> gto;
2021-01-04 03:09:59 +01:00
// TODO(oxen): Hard forks should always be specified in events OR do replay
// events should be passed a testing context which should have this specific
// testing situation
// Hardforks can be specified in events.
2021-07-06 04:48:18 +02:00
std::vector<cryptonote::hard_fork> derived_hardforks;
bool use_derived_hardforks = extract_hard_forks(events, derived_hardforks);
const cryptonote::test_options derived_test_options =
{
derived_hardforks,
gto.test_options.long_term_block_weight_window,
};
// FIXME: make sure that vm has arg_testnet_on set to true or false if
// this test needs for it to be so.
cryptonote::test_options const *testing_options = (use_derived_hardforks) ? &derived_test_options : &gto.test_options;
if (!c.init(vm, testing_options))
{
MERROR("Failed to init core");
return false;
}
c.get_blockchain_storage().get_db().set_batch_transactions(true);
bool ret = replay_events_through_core_plain<t_test_class>(c, events, validator, true);
tools::threadpool::getInstance().recycle();
return ret;
}
//--------------------------------------------------------------------------
template<class t_test_class>
inline bool do_replay_file(const std::string& filename)
{
std::vector<test_event_entry> events;
if (!tools::unserialize_obj_from_file(events, filename))
{
MERROR("Failed to deserialize data from file: ");
return false;
}
cryptonote::core core;
t_test_class validator;
bool result = do_replay_events_get_core<t_test_class>(events, &core, validator);
core.deinit();
return result;
}
//--------------------------------------------------------------------------
#define DEFAULT_HARDFORKS(HARDFORKS) do { \
HARDFORKS.push_back(std::make_pair((uint8_t)1, (uint64_t)0)); \
} while(0)
#define ADD_HARDFORK(HARDFORKS, FORK, HEIGHT) HARDFORKS.push_back(std::make_pair((uint8_t)FORK, (uint64_t)HEIGHT))
#define GENERATE_ACCOUNT(account) \
cryptonote::account_base account; \
account.generate();
#define GENERATE_MULTISIG_ACCOUNT(account, threshold, total) \
CHECK_AND_ASSERT_MES(threshold >= 2 && threshold <= total, false, "Invalid multisig scheme"); \
std::vector<cryptonote::account_base> account(total); \
do \
{ \
for (size_t msidx = 0; msidx < total; ++msidx) \
account[msidx].generate(); \
make_multisig_accounts(account, threshold); \
} while(0)
#define MAKE_ACCOUNT(VEC_EVENTS, account) \
cryptonote::account_base account; \
account.generate(); \
VEC_EVENTS.push_back(account);
#define DO_CALLBACK(VEC_EVENTS, CB_NAME) \
{ \
callback_entry CALLBACK_ENTRY; \
CALLBACK_ENTRY.callback_name = CB_NAME; \
VEC_EVENTS.push_back(CALLBACK_ENTRY); \
}
#define REGISTER_CALLBACK(METHOD) \
register_callback(#METHOD, [this](auto&&... x) { return METHOD(std::forward<decltype(x)>(x)...); });
#define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS) \
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
test_generator generator; \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, MINER_ACC, TS); \
VEC_EVENTS.push_back(BLK_NAME);
/// TODO: use hf_ver from test options
#define MAKE_GENESIS_BLOCK_WITH_HF_VERSION(VEC_EVENTS, BLK_NAME, MINER_ACC, TS, HF_VER) \
test_generator generator(HF_VER); \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, MINER_ACC, TS); \
VEC_EVENTS.push_back(BLK_NAME);
#define MAKE_NEXT_BLOCK(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC); \
VEC_EVENTS.push_back(BLK_NAME);
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
#define MAKE_NEXT_BLOCK_V2(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, WINNER, SN_INFO) \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC, {}, WINNER, SN_INFO); \
VEC_EVENTS.push_back(BLK_NAME);
#define MAKE_NEXT_BLOCK_TX1(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TX1) \
cryptonote::block BLK_NAME; \
{ \
std::list<cryptonote::transaction> tx_list; \
tx_list.push_back(TX1); \
generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC, tx_list); \
} \
VEC_EVENTS.push_back(BLK_NAME);
#define MAKE_NEXT_BLOCK_TX_LIST(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST) \
cryptonote::block BLK_NAME; \
generator.construct_block(BLK_NAME, PREV_BLOCK, MINER_ACC, TXLIST); \
VEC_EVENTS.push_back(BLK_NAME);
#define REWIND_BLOCKS_N(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, COUNT) \
cryptonote::block BLK_NAME; \
{ \
cryptonote::block blk_last = PREV_BLOCK; \
for (size_t i = 0; i < COUNT; ++i) \
{ \
MAKE_NEXT_BLOCK(VEC_EVENTS, blk, blk_last, MINER_ACC); \
blk_last = blk; \
} \
BLK_NAME = blk_last; \
}
Version 0.4.0 Release Candidate (#216) * core: submit uptime proof immediately after registering * Increase visibility of autostaking prompts * quorum_cop: changed uptime proof prune timeout to 2 hours 10 minutes * cleanup: removed scope limiting block * check_tx_inputs: fix deregister double spend test to include deregisters from other heights * config: new testnet network id, genesis tx, and version bump * wallet2: fix testnet wallet blockheight approximation * Fix change in address format in RPC which broke parsing and pooling contributors (#184) * Fix service node endpoints for RPC to also use stdout (#185) * fixed some further rct core tests (#180) * Fix service node state by calling detached hooks on failure to switch to alt chain (#188) * fixed block verification core tests (#186) * fixed block verification core tests * core tests: removed gen_block_miner_tx_out_is_small which is only relevant to hardfork version 1 * Don't consider expired deregistrations when filling block template * Add unit tests for getting staking requirement (#191) * First service node test (#190) * core_tests: added service node tests * core_tests: check balance after registration tx * Fix underflow for popping rollback events (#189) * Move deregistration age check into check_tx_inputs * Zero initialise rct_signatures member txnFee is a uint64_t and has uninit values * Enforce that deregisters must be 0 fee since we skip checks * Add unit tests for vote validation (#193) * Add unit tests for deregistration validation (#194) * Mainnet checkpoint 86535, testnet 3591, 4166 * Bump version number * Add print_sr for getting staking requirement (#198) * Misc bugfixes (#203) * removed unnecessary cast to double during txfee+coinbase calculation * simplewallet: increased autostaking interval from 2 minutes to 40 * Fix casting issues from uint to int (#204) * core_tests: check service node registration and expiration (#195) * 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 * On blockchain inc/dec mark deregisters relayble based on age (#201) * Service nodes restore only 1 rollback bug (#206) * Fix restore 1 rollback event, ensure prevent rollback is always added * Remove adding prevent_rollback event at init It gets called in on block added generic anyway. * Log db exception, fix relation operators for vote/deregister lifetime (#207) * Filter relayable deregisters w/ check_tx_inputs instead of blockchain callbacks * Bump version to 0.3.7-beta * fix build with GCC 8.1.0 (#211) * Add temp hardfork rule in testnet for deregister lifetimes (#210) * Update testnet, remove testnet forks, remove checkpoints, update blockheight estimate (#212) * Don't ban peers for a bad vote, just drop their connection (#213) * Update to version 0.3.0 release candidate (#215)
2018-09-07 07:14:28 +02:00
#define REWIND_BLOCKS_N_V2(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, COUNT, WINNER, SN_INFO) \
cryptonote::block BLK_NAME; \
{ \
cryptonote::block blk_last = PREV_BLOCK; \
for (size_t i = 0; i < COUNT; ++i) \
{ \
MAKE_NEXT_BLOCK_V2(VEC_EVENTS, blk, blk_last, MINER_ACC, WINNER, SN_INFO); \
blk_last = blk; \
} \
BLK_NAME = blk_last; \
}
#define REWIND_BLOCKS(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC) REWIND_BLOCKS_N(VEC_EVENTS, BLK_NAME, PREV_BLOCK, MINER_ACC, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW)
2021-01-04 03:09:59 +01:00
// NOTE(oxen): These macros assume hardfork version 7 and are from the old Monero testing code
#define MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
cryptonote::transaction TX_NAME; \
2021-01-04 03:09:59 +01:00
oxen_tx_builder(VEC_EVENTS, TX_NAME, HEAD, FROM, TO.get_keys().m_account_address, AMOUNT, cryptonote::network_version_7).build(); \
VEC_EVENTS.push_back(TX_NAME);
#define MAKE_TX_MIX_RCT(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
cryptonote::transaction TX_NAME; \
construct_tx_to_key(VEC_EVENTS, TX_NAME, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, rct::RangeProofType::PaddedBulletproof); \
VEC_EVENTS.push_back(TX_NAME);
#define MAKE_TX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, HEAD) MAKE_TX_MIX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, 9, HEAD)
#define MAKE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
{ \
cryptonote::transaction t; \
2021-01-04 03:09:59 +01:00
oxen_tx_builder(VEC_EVENTS, t, HEAD, FROM, TO.get_keys().m_account_address, AMOUNT, cryptonote::network_version_7).build(); \
SET_NAME.push_back(t); \
VEC_EVENTS.push_back(t); \
}
#define MAKE_TX_MIX_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
MAKE_TX_MIX_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD, rct::RangeProofType::PaddedBulletproof, 1)
#define MAKE_TX_MIX_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD, RCT_TYPE, BP_VER) \
{ \
cryptonote::transaction t; \
construct_tx_to_key(VEC_EVENTS, t, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, NMIX, RCT_TYPE, BP_VER); \
SET_NAME.push_back(t); \
VEC_EVENTS.push_back(t); \
}
#define MAKE_TX_MIX_DEST_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD) \
MAKE_TX_MIX_DEST_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD, rct::RangeProofType::PaddedBulletproof, 1)
#define MAKE_TX_MIX_DEST_LIST_RCT_EX(VEC_EVENTS, SET_NAME, FROM, TO, NMIX, HEAD, RCT_TYPE, BP_VER) \
{ \
cryptonote::transaction t; \
construct_tx_to_key(VEC_EVENTS, t, HEAD, FROM, TO, TESTS_DEFAULT_FEE, NMIX, RCT_TYPE, BP_VER); \
SET_NAME.push_back(t); \
VEC_EVENTS.push_back(t); \
}
#define MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD) MAKE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, 9, HEAD)
#define MAKE_TX_LIST_START(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD) \
std::list<cryptonote::transaction> SET_NAME; \
MAKE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD);
#define MAKE_MINER_TX_MANUALLY(TX, BLK) \
transaction TX; \
std::optional<std::vector<cryptonote::batch_sn_payment>> sn_rwds; \
uint64_t block_rewards = 0; \
bool r; \
std::tie(r, block_rewards) = construct_miner_tx(get_block_height(BLK) + 1, \
0, \
generator.get_already_generated_coins(BLK), \
0, \
0, \
TX, \
2021-01-04 03:09:59 +01:00
cryptonote::oxen_miner_tx_context::miner_block(cryptonote::FAKECHAIN, miner_account.get_keys().m_account_address), \
sn_rwds, \
{} \
); \
if (!r) \
return false;
#define MAKE_TX_LIST_START_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD) \
std::list<cryptonote::transaction> SET_NAME; \
MAKE_TX_MIX_LIST_RCT(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, NMIX, HEAD);
#define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL));
#define PLAY(filename, generator_class) \
if(!do_replay_file<generator_class>(filename)) \
{ \
MERROR("Failed to pass test : " << #generator_class); \
return 1; \
}
#define CATCH_REPLAY(generator_class) \
catch (const std::exception &ex) { MERROR(#generator_class << " generation failed: what=" << ex.what()); } \
catch (...) { MERROR(#generator_class << " generation failed: generic exception"); }
#define REPLAY_CORE(generator_class, generator_class_instance) \
{ \
cryptonote::core core; \
if (generated && do_replay_events_get_core<generator_class>(events, &core, generator_class_instance)) \
{ \
MGINFO_GREEN("#TEST# Succeeded " << #generator_class); \
} \
else \
{ \
MERROR("#TEST# Failed " << #generator_class); \
failed_tests.push_back(#generator_class); \
} \
core.deinit(); \
}
#define REPLAY_WITH_CORE(generator_class, generator_class_instance, CORE) \
{ \
if (generated && \
replay_events_through_core_plain<generator_class>(events, CORE, generator_class_instance, false /*reinit*/)) \
{ \
MGINFO_GREEN("#TEST# Succeeded " << #generator_class); \
} \
else \
{ \
MERROR("#TEST# Failed " << #generator_class); \
failed_tests.push_back(#generator_class); \
} \
}
#define CATCH_GENERATE_REPLAY(generator_class, generator_class_instance) \
CATCH_REPLAY(generator_class); \
REPLAY_CORE(generator_class, generator_class_instance);
#define CATCH_GENERATE_REPLAY_CORE(generator_class, generator_class_instance, CORE) \
CATCH_REPLAY(generator_class); \
REPLAY_WITH_CORE(generator_class, generator_class_instance, CORE);
#define GENERATE_AND_PLAY(generator_class) \
if (list_tests) \
std::cout << #generator_class << std::endl; \
2020-06-01 20:32:18 +02:00
else if (std::cmatch m; filter.empty() || std::regex_match(#generator_class, m, std::regex(filter))) \
{ \
std::vector<test_event_entry> events; \
++tests_count; \
bool generated = false; \
generator_class generator_class_instance; \
try \
{ \
generated = generator_class_instance.generate(events); \
} \
CATCH_GENERATE_REPLAY(generator_class, generator_class_instance); \
}
#define GENERATE_AND_PLAY_INSTANCE(generator_class, generator_class_instance, CORE) \
2020-06-01 20:32:18 +02:00
if (std::cmatch m; filter.empty() || std::regex_match(#generator_class, m, std::regex(filter))) \
{ \
std::vector<test_event_entry> events; \
++tests_count; \
bool generated = false; \
try \
{ \
generated = ins.generate(events); \
} \
CATCH_GENERATE_REPLAY_CORE(generator_class, generator_class_instance, CORE); \
}
#define QUOTEME(x) #x
#define DEFINE_TESTS_ERROR_CONTEXT(text) const char* perr_context = text;
#define CHECK_TEST_CONDITION(cond) CHECK_AND_ASSERT_MES(cond, false, "[" << perr_context << "] failed: \"" << QUOTEME(cond) << "\"")
#define CHECK_TEST_CONDITION_MSG(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "[" << perr_context << "] failed: \"" << QUOTEME(cond) << "\", msg: " << msg)
#define CHECK_EQ(v1, v2) CHECK_AND_ASSERT_MES(v1 == v2, false, "[" << perr_context << "] failed: \"" << QUOTEME(v1) << " == " << QUOTEME(v2) << "\", " << v1 << " != " << v2)
#define CHECK_NOT_EQ(v1, v2) CHECK_AND_ASSERT_MES(!(v1 == v2), false, "[" << perr_context << "] failed: \"" << QUOTEME(v1) << " != " << QUOTEME(v2) << "\", " << v1 << " == " << v2)
#define MK_COINS(amount) (UINT64_C(amount) * COIN)
2021-07-06 04:48:18 +02:00
inline std::string make_junk() {
std::string junk;
junk.reserve(1024);
for (size_t i = 0; i < 256; i++)
junk += (char) i;
junk += junk;
junk += junk;
return junk;
}
//
// NOTE: Loki
//
2021-01-04 03:09:59 +01:00
class oxen_tx_builder {
/// required fields
const std::vector<test_event_entry>& m_events;
cryptonote::transaction& m_tx;
const cryptonote::block& m_head;
const cryptonote::account_base& m_from;
const cryptonote::account_public_address& m_to;
uint64_t m_amount;
uint64_t m_fee;
uint64_t m_unlock_time;
uint64_t m_junk_size = 0;
std::vector<uint8_t> m_extra;
2021-01-04 03:09:59 +01:00
cryptonote::oxen_construct_tx_params m_tx_params;
/// this makes sure we didn't forget to build it
bool m_finished = false;
public:
2021-01-04 03:09:59 +01:00
oxen_tx_builder(const std::vector<test_event_entry>& events,
cryptonote::transaction& tx,
const cryptonote::block& head,
const cryptonote::account_base& from,
const cryptonote::account_public_address& to,
uint64_t amount,
uint8_t hf_version)
: m_events(events)
, m_tx(tx)
, m_head(head)
, m_from(from)
, m_to(to)
, m_amount(amount)
, m_fee(TESTS_DEFAULT_FEE)
, m_unlock_time(0)
{
m_tx_params.hf_version = hf_version;
}
2021-01-04 03:09:59 +01:00
oxen_tx_builder&& with_fee(uint64_t fee) {
m_fee = fee;
return std::move(*this);
}
2021-01-04 03:09:59 +01:00
oxen_tx_builder&& with_extra(const std::vector<uint8_t>& extra) {
m_extra = extra;
return std::move(*this);
}
2021-01-04 03:09:59 +01:00
oxen_tx_builder&& with_unlock_time(uint64_t val) {
m_unlock_time = val;
return std::move(*this);
}
2021-01-04 03:09:59 +01:00
oxen_tx_builder&& with_tx_type(cryptonote::txtype val) {
m_tx_params.tx_type = val;
return std::move(*this);
}
2021-01-04 03:09:59 +01:00
oxen_tx_builder&& with_junk(size_t size) {
m_junk_size = size;
return std::move(*this);
}
2021-01-04 03:09:59 +01:00
~oxen_tx_builder() {
if (!m_finished) {
std::cerr << "Tx building not finished\n";
abort();
}
}
inline static const std::string junk1k = make_junk();
bool build()
{
m_finished = true;
std::vector<cryptonote::tx_source_entry> sources;
std::vector<cryptonote::tx_destination_entry> destinations;
uint64_t change_amount;
constexpr size_t nmix = 9;
2021-02-12 05:19:30 +01:00
if (m_tx_params.tx_type == cryptonote::txtype::oxen_name_system) // ONS txes only have change
{
fill_tx_sources_and_multi_destinations(
m_events, m_head, m_from, m_to, nullptr /*amounts*/, 0 /*num_amounts*/, m_fee, nmix, sources, destinations, true /*add change*/, &change_amount);
}
else
{
2021-01-04 03:09:59 +01:00
// TODO(oxen): Eww we still depend on monero land test code
fill_tx_sources_and_destinations(
m_events, m_head, m_from, m_to, m_amount, m_fee, nmix, sources, destinations, &change_amount);
}
if (m_junk_size > 0) {
std::string junk;
junk.reserve(m_junk_size + 10);
tools::write_varint(std::back_inserter(junk), m_junk_size);
m_junk_size += junk.size(); // we just added some bytes for the varint
std::string_view junk_piece{junk1k};
while (junk.size() < m_junk_size) {
if (junk.size() + junk_piece.size() > m_junk_size)
junk_piece = junk_piece.substr(0, m_junk_size - junk.size());
junk += junk_piece;
}
cryptonote::add_tagged_data_to_tx_extra(m_extra, cryptonote::TX_EXTRA_MYSTERIOUS_MINERGATE_TAG, junk);
}
cryptonote::tx_destination_entry change_addr{ change_amount, m_from.get_keys().m_account_address, false /*is_subaddr*/ };
bool result = cryptonote::construct_tx(
m_from.get_keys(), sources, destinations, change_addr, m_extra, m_tx, m_unlock_time, m_tx_params);
return result;
}
};
2021-01-04 03:09:59 +01:00
void fill_nonce_with_oxen_generator(struct oxen_chain_generator const *generator, cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height);
void oxen_register_callback(std::vector<test_event_entry> &events, std::string const &callback_name, oxen_callback callback);
2021-07-06 04:48:18 +02:00
std::vector<cryptonote::hard_fork> oxen_generate_hard_fork_table(uint8_t hf_version = cryptonote::network_version_count - 1, uint64_t pos_delay = 60);
2021-01-04 03:09:59 +01:00
struct oxen_blockchain_entry
{
cryptonote::block block;
std::vector<cryptonote::transaction> txs;
uint64_t block_weight;
uint64_t already_generated_coins;
service_nodes::service_node_list::state_t service_node_state{nullptr};
bool checkpointed;
cryptonote::checkpoint_t checkpoint;
};
2021-01-04 03:09:59 +01:00
struct oxen_chain_generator_db : public cryptonote::BaseTestDB
{
2021-01-04 03:09:59 +01:00
std::vector<oxen_blockchain_entry> blocks;
std::unordered_map<crypto::hash, cryptonote::transaction> tx_table;
2021-01-04 03:09:59 +01:00
std::unordered_map<crypto::hash, oxen_blockchain_entry> block_table;
Pulse: Handle alternative block reorg with Pulse blocks - Alternative pulse blocks must be verified against the quorum they belong to. This updates alt_block_added hook in Service Node List to check the new Pulse invariants and on passing allow the alt block to be stored into the DB until enough blocks have been checkpointed. - New reorganization behaviour for the Pulse hard fork. Currently reorganization rules work by preferring chains with greater cumulative difficulty and or a chain with more checkpoints. Pulse blocks introduces a 'fake' difficulty to allow falling back to PoW and continuing the chain with reasonable difficulty. If we fall into a position where we have an alt chain of mixed Pulse blocks and PoW blocks, difficulty is no longer a valid metric to compare blocks (a completely PoW chain could have much higher cumulative difficulty if hash power is thrown at it vs Pulse chain with fixed difficulty). So starting in HF16 we only reorganize when 2 consecutive checkpoints prevail on one chain. This aligns with the idea of a PoS network that is governed by the Service Nodes. The chain doesn't essentially recover until Pulse is re-enabled and Service Nodes on that chain checkpoint the chain again, causing the PoW chain to switch over. - Generating Pulse Entropy no longer does a confusing +-1 to the height dance and always begins from the top block. It now takes a block instead of a height since the blocks may be on an alternative chain or the main chain. In the former case, we have to query the alternative DB table to grab the blocks to work. - Removes the developer debug hashes in code for entropy. - Adds core tests to check reorganization works
2020-09-04 10:09:17 +02:00
uint64_t get_block_height(crypto::hash const &hash) const override;
cryptonote::block_header get_block_header_from_height(uint64_t height) const override;
cryptonote::block get_block_from_height(uint64_t height) const override;
bool get_tx(const crypto::hash& h, cryptonote::transaction &tx) const override;
std::vector<cryptonote::checkpoint_t> get_checkpoints_range(uint64_t start, uint64_t end, size_t num_desired_checkpoints) const override;
std::vector<cryptonote::block> get_blocks_range(const uint64_t& h1, const uint64_t& h2) const override;
uint64_t height() const override { return blocks.size(); }
};
2021-01-04 03:09:59 +01:00
struct oxen_service_node_contribution
{
cryptonote::account_public_address contributor;
uint64_t portions;
};
2021-01-04 03:09:59 +01:00
enum struct oxen_create_block_type
{
automatic,
pulse,
miner,
};
2021-01-04 03:09:59 +01:00
struct oxen_create_block_params
{
2021-01-04 03:09:59 +01:00
oxen_create_block_type type;
uint8_t hf_version;
2021-01-04 03:09:59 +01:00
oxen_blockchain_entry prev;
cryptonote::account_base miner_acc;
uint64_t timestamp;
std::vector<uint64_t> block_weights;
std::vector<cryptonote::transaction> tx_list;
service_nodes::payout block_leader;
uint64_t total_fee;
uint8_t pulse_round;
};
2021-01-04 03:09:59 +01:00
struct oxen_chain_generator
{
2021-01-04 03:09:59 +01:00
// TODO(oxen): I want to store pointers to transactions but I get some memory corruption somewhere. Pls fix.
// We already store blockchain_entries in block_ vector which stores the actual backing transaction entries.
std::unordered_map<crypto::hash, cryptonote::transaction> tx_table_;
mutable std::unordered_map<crypto::public_key, crypto::secret_key> service_node_keys_;
service_nodes::service_node_list::state_set state_history_;
uint64_t last_cull_height_ = 0;
2021-02-12 05:19:30 +01:00
std::shared_ptr<ons::name_system_db> ons_db_ = std::make_shared<ons::name_system_db>();
std::unique_ptr<cryptonote::BlockchainSQLiteTest> sqlite_db_;
2021-01-04 03:09:59 +01:00
oxen_chain_generator_db db_;
uint8_t hf_version_ = cryptonote::network_version_7;
std::vector<test_event_entry>& events_;
2021-07-06 04:48:18 +02:00
const std::vector<cryptonote::hard_fork> hard_forks_;
cryptonote::account_base first_miner_;
oxen_chain_generator(std::vector<test_event_entry>& events, const std::vector<cryptonote::hard_fork>& hard_forks, std::string first_miner_seed = "");
oxen_chain_generator(const oxen_chain_generator &other)
:tx_table_(other.tx_table_), service_node_keys_(other.service_node_keys_), state_history_(other.state_history_), last_cull_height_(other.last_cull_height_), sqlite_db_(std::make_unique<cryptonote::BlockchainSQLiteTest>(*other.sqlite_db_)),
ons_db_(other.ons_db_ ), db_(other.db_), hf_version_(other.hf_version_), events_(other.events_), hard_forks_(other.hard_forks_), first_miner_(other.first_miner_) {};
uint64_t height() const { return cryptonote::get_block_height(db_.blocks.back().block); }
uint64_t chain_height() const { return height() + 1; }
2021-01-04 03:09:59 +01:00
const std::vector<oxen_blockchain_entry>& blocks() const { return db_.blocks; }
size_t event_index() const { return events_.size() - 1; }
uint8_t hardfork() const { return get_hf_version_at(height()); }
2021-01-04 03:09:59 +01:00
const oxen_blockchain_entry& top() const { return db_.blocks.back(); }
service_nodes::quorum_manager top_quorum() const;
service_nodes::quorum_manager quorum(uint64_t height) const;
2019-11-06 08:18:44 +01:00
std::shared_ptr<const service_nodes::quorum> get_quorum(service_nodes::quorum_type type, uint64_t height) const;
service_nodes::service_node_keys get_cached_keys(const crypto::public_key &pubkey) const;
cryptonote::account_base add_account();
2021-01-04 03:09:59 +01:00
oxen_blockchain_entry &add_block(oxen_blockchain_entry const &entry, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {});
void add_blocks_until_version(uint8_t hf_version);
void add_n_blocks(int n);
bool add_blocks_until_next_checkpointable_height();
void add_service_node_checkpoint(uint64_t block_height, size_t num_votes);
void add_mined_money_unlock_blocks(); // NOTE: Unlock all Loki generated from mining prior to this call i.e. CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW
Lokinet LNS Revamps how .loki LNS registrations work: - Enable lokinet registrations beginning at HF16. - rework renewal so that you can renew at any time and it simply adds to the end of the current expiry. Previously there was only a window in which you could renew. - Renewals are a new type of LNS transaction, distinct from buys and updates. (Internally it is an update with no fields, which cannot be produced in the existing code). - Add optional "type=" parameter to lns commands. Commands default to trying to auto-detect (i.e. if the name ends with .loki it is lokinet), but the type allows you to be explicit *and* allows select non-default registration lengths for lokinet buys/renewals. - change .loki naming requirements: we now require <= 32 chars if it doesn't contain a -, and 63 if it does. We also reserve names starting "??--" for any ?? other than xn-- (punycode), as this is a DNS restriction. "loki.loki" and "snode.loki" are also now reserved (just in case someone sticks .loki as a DNS search domain). - Tweak LNS registration times to consider "a year" to be 368 days worth of blocks (to allow for leap years and some minor block time drift). - Overhaul how LNS registrations are displayed in the cli wallet. For example: [wallet L6QPcD]: lns_print_name_to_owners jasonv.loki jason.loki jasonz.loki Error: jasonv.loki not found Name: jason.loki Type: lokinet Value: azfoj73snr9f3neh5c6sf7rtbaeabyxhr1m4un5aydsmsrxo964o.loki Owner: L6QPcDVp6Fu7HwtXrXjtfvWvgBPvvMQ9FiyquMWn2BBEDsk2vydwu1A3BrK2uQcCo94G7HA5xiKvpZ4CMQva6pxW2GXkCG9 Last updated height: 46 Expiration height: 75 Encrypted value: 870e42cd172a(snip) Error: jasonz.loki not found - Add an RPC end-point to do simple LNS resolution; you can get the same info out of names-to-owners, but the new lns_resolve end-point is considerably simpler for doing simple lookups (e.g. for lokinet), and allows for a simpler SQL query + processing. Code changes: - Rename mapping_type::lokinet_1year to mapping_type::lokinet (see next point). - Don't store lokinet_2y, etc. in the database, but instead always store as type=2/::lokinet. The LNS extra data can still specify different lengths, but this now just affects the expiration_height value that we set. - Reworked some binding code to use std::variant's and add a bind_container() to simplify passing in a variable list of bind parameters of different types. - Accept both base64 and hex inputs for binary LNS parameters in the RPC interface. - This commit adds some (incomplete) expiry adjustment code, but ignore it as it all gets replaced with the following commit to overhaul record updating. - Updated a bunch of test suite code, mainly related to lokinet. - Some random C++17 niceties (string_view, variant, structured binding returns) in the related code. - Tweaked the test suite to generate a bit fewer blocks in some cases where we just need to confirm/unlock a transfers rather than a coinbase tx.
2020-09-15 04:52:03 +02:00
void add_transfer_unlock_blocks(); // Unlock funds from (standard) transfers prior to this call, i.e. CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
// NOTE: Add an event that is just a user specified message to signify progress in the test
void add_event_msg(std::string const &msg) { events_.push_back(msg); }
void add_tx(cryptonote::transaction const &tx, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {}, bool kept_by_block = false);
2021-01-04 03:09:59 +01:00
oxen_create_block_params next_block_params() const;
// NOTE: Add constructed TX to events_ and assume that it is valid to add to the blockchain. If the TX is meant to be unaddable to the blockchain use the individual create + add functions to
// be able to mark the add TX event as something that should trigger a failure.
2021-02-12 05:19:30 +01:00
cryptonote::transaction create_and_add_oxen_name_system_tx(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, ons::mapping_value const &value, ons::generic_owner const *owner = nullptr, ons::generic_owner const *backup_owner = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_oxen_name_system_tx_update(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, ons::mapping_value const *value, ons::generic_owner const *owner = nullptr, ons::generic_owner const *backup_owner = nullptr, ons::generic_signature *signature = nullptr, bool kept_by_block = false);
cryptonote::transaction create_and_add_oxen_name_system_tx_renew(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, bool kept_by_block = false);
cryptonote::transaction create_and_add_tx (const cryptonote::account_base& src, const cryptonote::account_public_address& dest, uint64_t amount, uint64_t fee = TESTS_DEFAULT_FEE, bool kept_by_block = false);
cryptonote::transaction create_and_add_state_change_tx(service_nodes::new_state state, const crypto::public_key& pub_key, uint16_t reasons_all, uint16_t reasons_any, uint64_t height = -1, const std::vector<uint64_t>& voters = {}, uint64_t fee = 0, bool kept_by_block = false);
cryptonote::transaction create_and_add_registration_tx(const cryptonote::account_base& src, const cryptonote::keypair& sn_keys = cryptonote::keypair{hw::get_device("default")}, bool kept_by_block = false);
cryptonote::transaction create_and_add_staking_tx (const crypto::public_key &pub_key, const cryptonote::account_base &src, uint64_t amount, bool kept_by_block = false);
2021-01-04 03:09:59 +01:00
oxen_blockchain_entry &create_and_add_next_block (const std::vector<cryptonote::transaction>& txs = {}, cryptonote::checkpoint_t const *checkpoint = nullptr, bool can_be_added_to_blockchain = true, std::string const &fail_msg = {});
// Same as create_and_add_tx, but also adds 95kB of junk into tx_extra to bloat up the tx size.
cryptonote::transaction create_and_add_big_tx(const cryptonote::account_base& src, const cryptonote::account_public_address& dest, uint64_t amount, uint64_t junk_size = 95000, uint64_t fee = TESTS_DEFAULT_FEE, bool kept_by_block = false);
// NOTE: Create transactions but don't add to events_
cryptonote::transaction create_tx(const cryptonote::account_base &src, const cryptonote::account_public_address &dest, uint64_t amount, uint64_t fee) const;
cryptonote::transaction create_registration_tx(const cryptonote::account_base &src,
const cryptonote::keypair &service_node_keys = cryptonote::keypair{hw::get_device("default")},
uint64_t src_portions = STAKING_PORTIONS,
uint64_t src_operator_cut = 0,
2021-01-04 03:09:59 +01:00
std::array<oxen_service_node_contribution, 3> const &contributors = {},
int num_contributors = 0) const;
cryptonote::transaction create_staking_tx (const crypto::public_key& pub_key, const cryptonote::account_base &src, uint64_t amount) const;
cryptonote::transaction create_state_change_tx(service_nodes::new_state state, const crypto::public_key& pub_key, uint16_t reasons_all, uint16_t reasons_any, uint64_t height = -1, const std::vector<uint64_t>& voters = {}, uint64_t fee = 0) const;
cryptonote::checkpoint_t create_service_node_checkpoint(uint64_t block_height, size_t num_votes) const;
// value: Takes the binary value NOT the human readable version, of the name->value mapping
2021-02-12 05:19:30 +01:00
static const uint64_t ONS_AUTO_BURN = static_cast<uint64_t>(-1);
cryptonote::transaction create_oxen_name_system_tx(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, ons::mapping_value const &value, ons::generic_owner const *owner = nullptr, ons::generic_owner const *backup_owner = nullptr, std::optional<uint64_t> burn_override = std::nullopt) const;
cryptonote::transaction create_oxen_name_system_tx_update(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, ons::mapping_value const *value, ons::generic_owner const *owner = nullptr, ons::generic_owner const *backup_owner = nullptr, ons::generic_signature *signature = nullptr, bool use_asserts = false) const;
cryptonote::transaction create_oxen_name_system_tx_update_w_extra(cryptonote::account_base const &src, uint8_t hf_version, cryptonote::tx_extra_oxen_name_system const &ons_extra) const;
cryptonote::transaction create_oxen_name_system_tx_renew(cryptonote::account_base const &src, uint8_t hf_version, ons::mapping_type type, std::string const &name, std::optional<uint64_t> burn_override = std::nullopt) const;
2021-01-04 03:09:59 +01:00
oxen_blockchain_entry create_genesis_block(const cryptonote::account_base &miner, uint64_t timestamp);
oxen_blockchain_entry create_next_block(const std::vector<cryptonote::transaction>& txs = {}, cryptonote::checkpoint_t const *checkpoint = nullptr);
bool create_block(oxen_blockchain_entry &entry, oxen_create_block_params &params, const std::vector<cryptonote::transaction> &tx_list) const;
bool block_begin(oxen_blockchain_entry &entry, oxen_create_block_params &params, const std::vector<cryptonote::transaction> &tx_list) const;
void block_fill_pulse_data(oxen_blockchain_entry &entry, oxen_create_block_params const &params, uint8_t round) const;
void block_end(oxen_blockchain_entry &entry, oxen_create_block_params const &params) const;
bool process_registration_tx(cryptonote::transaction& tx, uint64_t block_height, uint8_t hf_version);
uint8_t get_hf_version_at(uint64_t height) const;
std::vector<uint64_t> last_n_block_weights(uint64_t height, uint64_t num) const;
const cryptonote::account_base& first_miner() const { return first_miner_; }
oxen_chain_generator& operator=(const oxen_chain_generator& other)
{
new(this) oxen_chain_generator(other);
return *this;
}
};