1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into txhfid

This commit is contained in:
sowle 2024-12-24 22:16:36 +01:00
commit 8e2c70de93
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
18 changed files with 1223 additions and 15 deletions

View file

@ -973,6 +973,57 @@ bool blockchain_storage::get_block_by_hash(const crypto::hash &h, block &blk) c
return false;
}
//------------------------------------------------------------------
bool blockchain_storage::get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX;
if (height >= m_db_blocks.size())
return false;
boost::multiprecision::uint128_t reward_with_fee_mp{};
if (height != 0)
reward_with_fee_mp = m_db_blocks[height]->already_generated_coins - m_db_blocks[height - 1]->already_generated_coins;
else
reward_with_fee_mp = m_db_blocks[height]->already_generated_coins;
if (reward_with_fee_mp > amount_max_mp)
return false;
reward_with_fee = reward_with_fee_mp.convert_to<uint64_t>();
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX;
block_extended_info bei{};
if (!get_block_extended_info_by_hash(h, bei))
return false;
boost::multiprecision::uint128_t reward_with_fee_mp{};
if (bei.height != 0)
{
block_extended_info bei_prev{};
if (!get_block_extended_info_by_hash(bei.bl.prev_id, bei_prev))
return false;
reward_with_fee_mp = bei.already_generated_coins - bei_prev.already_generated_coins;
}
else
{
reward_with_fee_mp = bei.already_generated_coins;
}
if (reward_with_fee_mp > amount_max_mp)
return false;
reward_with_fee = reward_with_fee_mp.convert_to<uint64_t>();
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::is_tx_related_to_altblock(crypto::hash tx_id) const
{
CRITICAL_REGION_LOCAL1(m_alternative_chains_lock);

View file

@ -233,6 +233,8 @@ namespace currency
size_t get_alternative_blocks_count() const;
crypto::hash get_block_id_by_height(uint64_t height) const;
bool get_block_by_hash(const crypto::hash &h, block &blk) const;
bool get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const; // only for main chain blocks
bool get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const; // works for main chain and alt chain blocks
bool get_block_extended_info_by_height(uint64_t h, block_extended_info &blk) const;
bool get_block_extended_info_by_hash(const crypto::hash &h, block_extended_info &blk) const;
bool get_block_by_height(uint64_t h, block &blk) const;

View file

@ -959,7 +959,12 @@ bool MainWindow::init_backend(int argc, char* argv[])
QString MainWindow::is_remnotenode_mode_preconfigured(const QString& param)
{
TRY_ENTRY();
return API_RETURN_CODE_FALSE;
view::api_response ar{};
if (m_backend.is_remote_node_mode())
ar.error_code = API_RETURN_CODE_TRUE;
else
ar.error_code = API_RETURN_CODE_FALSE;
return MAKE_RESPONSE(ar);
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}

@ -1 +1 @@
Subproject commit f6e3e0611f2100c6d9e76631a9fcfeb60e82d6d6
Subproject commit 638f98f9e25fa3c2f88338b7efe4b1c45ea0e23c

View file

@ -1156,16 +1156,22 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
uint64_t core_rpc_server::get_block_reward(const block& blk)
uint64_t core_rpc_server::get_block_reward(const block& blk, const crypto::hash& h)
{
if (blk.miner_tx.version >= TRANSACTION_VERSION_POST_HF4)
{
uint64_t reward_with_fee = 0;
m_core.get_blockchain_storage().get_block_reward_by_hash(h, reward_with_fee);
return reward_with_fee;
}
// legacy version, pre HF4
uint64_t reward = 0;
BOOST_FOREACH(const auto& out, blk.miner_tx.vout)
{
VARIANT_SWITCH_BEGIN(out);
VARIANT_CASE_CONST(tx_out_bare, out)
reward += out.amount;
VARIANT_CASE_CONST(tx_out_zarcanum, out)
//@#@
VARIANT_SWITCH_END();
}
return reward;
@ -1173,6 +1179,7 @@ namespace currency
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response)
{
crypto::hash block_hash = get_block_hash(blk);
response.major_version = blk.major_version;
response.minor_version = blk.minor_version;
response.timestamp = blk.timestamp;
@ -1181,9 +1188,9 @@ namespace currency
response.orphan_status = orphan_status;
response.height = get_block_height(blk);
response.depth = m_core.get_current_blockchain_size() - response.height - 1;
response.hash = string_tools::pod_to_hex(get_block_hash(blk));
response.hash = string_tools::pod_to_hex(block_hash);
response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to<std::string>();
response.reward = get_block_reward(blk);
response.reward = get_block_reward(blk, block_hash);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------

View file

@ -182,7 +182,7 @@ namespace currency
bool check_core_ready_(const std::string& calling_method);
//utils
uint64_t get_block_reward(const block& blk);
uint64_t get_block_reward(const block& blk, const crypto::hash& h);
bool fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response);
void set_session_blob(const std::string& session_id, const currency::block& blob);
bool get_session_blob(const std::string& session_id, currency::block& blob);

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "1"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 369
#define PROJECT_VERSION_BUILD_NO 372
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -3756,6 +3756,10 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
if (!td.is_zc())
m_has_bare_unspent_outputs = true;
e.outs_amount_min = (e.outs_count == 0) ? td.amount() : std::min(e.outs_amount_min, td.amount());
e.outs_amount_max = (e.outs_count == 0) ? td.amount() : std::max(e.outs_amount_max, td.amount());
e.outs_count += 1;
}
}

View file

@ -321,13 +321,21 @@ namespace wallet_public
uint64_t unlocked = 0;
uint64_t awaiting_in = 0;
uint64_t awaiting_out = 0;
uint64_t outs_count = 0;
uint64_t outs_amount_min = 0;
uint64_t outs_amount_max = 0;
//v2
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total) DOC_DSCR("Total coins available(including locked)") DOC_EXMP(100000000000000) DOC_END
KV_SERIALIZE(unlocked) DOC_DSCR("Unlocked coins available(the ones that could be used right now)") DOC_EXMP(50000000000000) DOC_END
KV_SERIALIZE(awaiting_in) DOC_DSCR("Unconfirmed amount for receive") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(awaiting_out) DOC_DSCR("Unconfirmed amount for send") DOC_EXMP(2000000000000) DOC_END
KV_SERIALIZE(total) DOC_DSCR("Total coins available(including locked)") DOC_EXMP(100000000000000) DOC_END
KV_SERIALIZE(unlocked) DOC_DSCR("Unlocked coins available(the ones that could be used right now)") DOC_EXMP(50000000000000) DOC_END
KV_SERIALIZE(awaiting_in) DOC_DSCR("Unconfirmed amount for receive") DOC_EXMP(1000000000000) DOC_END
KV_SERIALIZE(awaiting_out) DOC_DSCR("Unconfirmed amount for send") DOC_EXMP(2000000000000) DOC_END
KV_SERIALIZE(outs_count) DOC_DSCR("Number of total unspent outputs (including locked)") DOC_EXMP(7) DOC_END
KV_SERIALIZE(outs_amount_min) DOC_DSCR("Output's minimum amount") DOC_EXMP(2000000000000) DOC_END
KV_SERIALIZE(outs_amount_max) DOC_DSCR("Output's maximum amount") DOC_EXMP(2000000000000) DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -178,6 +178,7 @@ public:
std::string add_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor);
std::string delete_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id);
bool is_core_initialized() { return m_core_initialized;}
bool is_remote_node_mode() const { return m_remote_node_mode; }
private:
void main_worker(const po::variables_map& vm);

View file

@ -692,4 +692,41 @@ bool gen_block_wrong_version_agains_hardfork::generate(std::vector<test_event_en
BLOCK_VALIDATION_INIT_GENERATE();
DO_CALLBACK(events, "c1");
return true;
}
}
block_with_correct_prev_id_on_wrong_height::block_with_correct_prev_id_on_wrong_height()
{
REGISTER_CALLBACK("assert_blk_2_has_wrong_height", block_with_correct_prev_id_on_wrong_height::assert_blk_2_has_wrong_height);
}
bool block_with_correct_prev_id_on_wrong_height::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure that a block with correct previous block identifier that is at the wrong height won't be accepted by the core.
GENERATE_ACCOUNT(miner);
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_TX(events, tx_0, miner, miner, MK_TEST_COINS(2), blk_0r);
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner);
m_blk_2.prev_id = currency::get_block_hash(blk_1);
m_blk_2.miner_tx = blk_0r.miner_tx;
m_blk_2.major_version = blk_0r.major_version;
// blk_1 is the previous for blk_2, but height(blk_2) < height(blk_1).
CHECK_AND_ASSERT_EQ(currency::get_block_height(blk_1), 11);
CHECK_AND_ASSERT_EQ(currency::get_block_height(m_blk_2), 10);
DO_CALLBACK(events, "assert_blk_2_has_wrong_height");
return true;
}
bool block_with_correct_prev_id_on_wrong_height::assert_blk_2_has_wrong_height(currency::core& c, [[maybe_unused]] size_t ev_index, [[maybe_unused]] const std::vector<test_event_entry>& events) const
{
currency::block_verification_context context_blk_2{};
CHECK_AND_ASSERT_EQ(boost::get<txin_gen>(m_blk_2.miner_tx.vin.front()).height, 10);
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().add_new_block(m_blk_2, context_blk_2), false);
return true;
}

View file

@ -187,3 +187,13 @@ struct gen_block_invalid_binary_format : public test_chain_unit_base
private:
size_t m_corrupt_blocks_begin_idx;
};
struct block_with_correct_prev_id_on_wrong_height : public gen_block_verification_base<1 + CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3>
{
block_with_correct_prev_id_on_wrong_height();
bool generate(std::vector<test_event_entry>& events) const;
bool assert_blk_2_has_wrong_height(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const;
private:
mutable currency::block m_blk_2{};
};

View file

@ -1154,6 +1154,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(one_block);
GENERATE_AND_PLAY(gen_ring_signature_1);
GENERATE_AND_PLAY(gen_ring_signature_2);
GENERATE_AND_PLAY(fill_tx_rpc_inputs);
//GENERATE_AND_PLAY(gen_ring_signature_big); // Takes up to XXX hours (if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10)
// tests for outputs mixing in
@ -1177,6 +1178,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY_HF(gen_block_unlock_time_is_timestamp_in_future, "0,3");
GENERATE_AND_PLAY_HF(gen_block_height_is_low, "0,3");
GENERATE_AND_PLAY_HF(gen_block_height_is_high, "0,3");
GENERATE_AND_PLAY_HF(block_with_correct_prev_id_on_wrong_height, "3-*");
GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_tx_gen_in, "0,3");
GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_in, "0,3");
GENERATE_AND_PLAY_HF(gen_block_miner_tx_with_txin_to_key, "0,3");
@ -1221,6 +1223,7 @@ int main(int argc, char* argv[])
/* To execute the check of bare balance (function "check_tx_bare_balance") we need to run the test "tx_pool_semantic_validation" on the HF 3. By default behaviour bare outputs are disallowed on
the heights >= 10. */
GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3");
GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output);
// Double spend
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);

View file

@ -46,4 +46,5 @@
#include "multiassets_test.h"
#include "ionic_swap_tests.h"
#include "attachment_isolation_encryption_test.h"
#include "pos_fuse_test.h"
#include "pos_fuse_test.h"
#include "daemon_rpc.h"

View file

@ -0,0 +1,573 @@
#include "chaingen.h"
#include "daemon_rpc.h"
fill_tx_rpc_inputs::fill_tx_rpc_inputs()
{
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c1);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c2);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c3);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c4);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c5);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c6);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c7);
REGISTER_CALLBACK_METHOD(fill_tx_rpc_inputs, c8);
}
bool fill_tx_rpc_inputs::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure that the function "blockchain_storage::fill_tx_rpc_inputs" works as expected.
GENERATE_ACCOUNT(miner);
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
// A transaction in the default state.
DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(currency::transaction{}));
// A transaction with an input of the type "txin_to_key" in the default state.
{
currency::transaction tx{};
tx.vin.push_back(std::move(currency::txin_to_key{}));
DO_CALLBACK_PARAMS_STR(events, "c2", t_serializable_object_to_blob(tx));
}
// A transaction with an input of the type "txin_zc_input".
{
currency::transaction tx{};
{
currency::txin_zc_input input{};
input.k_image = {};
tx.vin.push_back(std::move(input));
}
DO_CALLBACK_PARAMS_STR(events, "c6", t_serializable_object_to_blob(tx));
}
// A transaction with several "txin_to_key" inputs those have different .amount values.
{
currency::transaction tx{};
tx.vin.reserve(3);
{
currency::txin_to_key input{};
CHECK_AND_ASSERT_EQ(input.amount, 0);
tx.vin.push_back(std::move(input));
}
{
currency::txin_to_key input{};
input.amount = UINT64_MAX;
tx.vin.push_back(std::move(input));
}
{
currency::txin_to_key input{};
input.amount = 16730018105294876523ull;
tx.vin.push_back(std::move(input));
}
DO_CALLBACK_PARAMS_STR(events, "c3", t_serializable_object_to_blob(tx));
}
// A transaction with inputs of all possible types.
{
currency::transaction tx{};
tx.vin.reserve(5);
tx.vin.push_back(std::move(currency::txin_gen{}));
tx.vin.push_back(std::move(currency::txin_to_key{}));
tx.vin.push_back(std::move(currency::txin_htlc{}));
{
currency::txin_zc_input input{};
input.k_image = {};
tx.vin.push_back(std::move(input));
}
tx.vin.push_back(std::move(currency::txin_multisig{}));
DO_CALLBACK_PARAMS_STR(events, "c4", t_serializable_object_to_blob(tx));
}
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0);
// A transaction with inputs of all possible types.
{
currency::transaction tx{};
tx.vin.reserve(5);
tx.vin.push_back(std::move(currency::txin_gen{/* .height = */ 7137406440025745250}));
{
currency::txin_to_key input{};
input.key_offsets.push_back(5350230927837587142ull);
input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 0u}));
input.amount = 2341818593703234797ull;
input.k_image = crypto::point_t{{0x62, 0xd9, 0xa0, 0xff, 0xb1, 0x89, 0x06, 0xbe, 0xbd, 0xe9, 0xce, 0xd5, 0xc2, 0x04, 0x5b, 0x6b, 0xb4, 0x5f, 0x9c, 0x3b, 0x31, 0xcc, 0x72, 0xc7, 0x55, 0x25, 0x0f,
0xa2, 0xb2, 0xbf, 0xb1, 0x0c}}.to_key_image();
input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 2613407258u, /* .n_extras = */ 347754399u}));
input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 5559118977069213037ull, /* .hsh = */ currency::null_hash, /* cnt = */ 8106306627691316520ull}));
tx.vin.push_back(std::move(input));
}
{
currency::txin_htlc input{};
input.key_offsets.push_back(9536097715806449708ull);
input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 9u}));
input.amount = 11357119244607763967ull;
input.k_image = crypto::point_t{{0xcb, 0xec, 0xfb, 0x36, 0x02, 0x1c, 0xe5, 0x64, 0xee, 0x6a, 0xb8, 0x67, 0xb2, 0x8e, 0xe9, 0xef, 0x80, 0x17, 0x34, 0x6f, 0xa8, 0x67, 0x3e, 0x45, 0x3a, 0xe0, 0xd4,
0x8b, 0x1a, 0x13, 0x75, 0xe2}}.to_key_image();
input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u}));
input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull}));
input.hltc_origin = "htlc-origin";
tx.vin.push_back(std::move(input));
}
{
currency::txin_zc_input input{};
input.key_offsets.push_back(16540286509618649069ull);
input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 4}));
input.k_image = crypto::point_t{{0x53, 0xcf, 0xaf, 0x48, 0x4d, 0xf8, 0xfb, 0x09, 0x4c, 0x01, 0x59, 0x9f, 0xe2, 0x2d, 0x3c, 0x23, 0x96, 0x2d, 0x8c, 0x24, 0x09, 0xf9, 0xd3, 0xe6, 0xf3, 0x27, 0xe8,
0x7c, 0x7a, 0x90, 0x9c, 0xab}}.to_key_image();
input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u}));
input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull}));
tx.vin.push_back(std::move(input));
}
{
currency::txin_multisig input{};
input.amount = 14073369620052150183ull;
input.multisig_out_id = crypto::cn_fast_hash("multisig-out-id", 15);
input.sigs_count = 3497547654u;
input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 1801772931u, /* .n_extras = */ 167800219u}));
input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 12438971857615319230ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 13515222808659969031ull}));
tx.vin.push_back(std::move(input));
}
DO_CALLBACK_PARAMS_STR(events, "c5", t_serializable_object_to_blob(tx));
}
/* A wrong reference by an object of the type "ref_by_id": a value of the attribute ".n" representing an offset is greater than a length of a container of outputs.The function "fill_tx_rpc_inputs"
returns false. */
{
currency::transaction tx{};
{
currency::txin_to_key input{};
CHECK_AND_ASSERT_GREATER(1968482779, tx_0.vout.size() - 1);
input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 1968482779u}));
tx.vin.push_back(std::move(input));
}
DO_CALLBACK_PARAMS_STR(events, "c7", t_serializable_object_to_blob(tx));
}
// A wrong reference by an object of the type "ref_by_id": hashcode of non-existent transaction is specified. The function "fill_tx_rpc_inputs" returns false.
{
currency::transaction tx{};
{
currency::txin_to_key input{};
input.key_offsets.push_back(std::move(currency::ref_by_id{currency::null_hash, 0u}));
tx.vin.push_back(std::move(input));
}
DO_CALLBACK_PARAMS_STR(events, "c8", t_serializable_object_to_blob(tx));
}
return true;
}
bool fill_tx_rpc_inputs::c1(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.empty(), true);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c2(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
{
CHECK_AND_ASSERT_EQ(info.ins.size(), 1);
{
CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true);
}
}
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c3(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
{
CHECK_AND_ASSERT_EQ(info.ins.size(), 3);
{
CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true);
}
{
CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, UINT64_MAX);
CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.empty(), true);
}
{
CHECK_AND_ASSERT_EQ(info.ins.back().amount, 16730018105294876523ull);
CHECK_AND_ASSERT_EQ(info.ins.back().multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.back().htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.back().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
CHECK_AND_ASSERT_EQ(info.ins.back().global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.back().etc_options.empty(), true);
}
}
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c4(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
{
CHECK_AND_ASSERT_EQ(info.ins.size(), 5);
for (size_t position{}; position < info.ins.size(); ++position)
{
CHECK_AND_ASSERT_EQ(info.ins.at(position).amount, 0);
CHECK_AND_ASSERT_EQ(info.ins.at(position).multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.at(position).htlc_origin.empty(), true);
if (position == 0)
{
CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id.empty(), true);
}
else
{
CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
}
CHECK_AND_ASSERT_EQ(info.ins.at(position).global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(position).etc_options.empty(), true);
}
}
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c5(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
{
CHECK_AND_ASSERT_EQ(info.ins.size(), 5);
{
CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true);
}
{
CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, 2341818593703234797ull);
CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, "8172e80b8da3bcbce2ee7df42466627bb3559b80bb504f1fd56b460eedbc2ce9");
CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.front(), 5350230927837587142ull);
CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.back(), 0ull);
}
CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.front(), "n_outs: 2613407258, n_extras: 347754399");
CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.back(), "cnt: 8106306627691316520, sz: 5559118977069213037, hsh: " + std::string(64, '0'));
}
}
{
CHECK_AND_ASSERT_EQ(info.ins.at(2).amount, 11357119244607763967ull);
CHECK_AND_ASSERT_EQ(info.ins.at(2).multisig_count, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(2).htlc_origin, epee::string_tools::buff_to_hex_nodelimer(std::string{"htlc-origin"}));
CHECK_AND_ASSERT_EQ(info.ins.at(2).kimage_or_ms_id, "f15201980333d6ca8fda90c73814baea0864eb56597e40c38061ec77644585ea");
CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.front(), 9536097715806449708ull);
CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.back(), 0ull);
}
CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888");
CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0'));
}
}
{
CHECK_AND_ASSERT_EQ(info.ins.at(3).amount, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(3).multisig_count, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(3).htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(3).kimage_or_ms_id, "c08b36a7f77185f31a570a7f51aa550122026985e5de7941218510a1e973202e");
CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.front(), 16540286509618649069ull);
CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.back(), 0ull);
}
CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888");
CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0'));
}
}
{
CHECK_AND_ASSERT_EQ(info.ins.at(4).amount, 14073369620052150183ull);
CHECK_AND_ASSERT_EQ(info.ins.at(4).multisig_count, 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(4).htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.at(4).kimage_or_ms_id, "aacdff6018af0aae84d7a836a7f0b4309b51a28bfc4f566657c67b903a3ccba5");
CHECK_AND_ASSERT_EQ(info.ins.at(4).global_indexes.size(), 0ull);
CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.size(), 2ull);
{
CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.front(), "n_outs: 1801772931, n_extras: 167800219");
CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.back(), "cnt: 13515222808659969031, sz: 12438971857615319230, hsh: " + std::string(64, '0'));
}
}
}
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c6(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true);
CHECK_AND_ASSERT_EQ(info.blob.empty(), true);
CHECK_AND_ASSERT_EQ(info.blob_size, 0);
CHECK_AND_ASSERT_EQ(info.fee, 0);
CHECK_AND_ASSERT_EQ(info.amount, 0);
CHECK_AND_ASSERT_EQ(info.timestamp, 0);
CHECK_AND_ASSERT_EQ(info.keeper_block, 0);
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true);
CHECK_AND_ASSERT_EQ(info.outs.empty(), true);
{
CHECK_AND_ASSERT_EQ(info.ins.size(), 1);
{
CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0);
CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki));
CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true);
CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true);
}
}
CHECK_AND_ASSERT_EQ(info.id.empty(), true);
CHECK_AND_ASSERT_EQ(info.extra.empty(), true);
CHECK_AND_ASSERT_EQ(info.attachments.empty(), true);
CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true);
return true;
}
bool fill_tx_rpc_inputs::c7(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.size(), 1);
{
const auto& input{boost::get<currency::txin_to_key>(tx.vin.front())};
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
{
const auto& reference{boost::get<currency::ref_by_id>(input.key_offsets.front())};
CHECK_AND_ASSERT_EQ(reference.n, 1968482779u);
{
const auto pointer_entry{core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id)};
CHECK_AND_ASSERT_NEQ(pointer_entry, nullptr);
CHECK_AND_ASSERT(reference.n >= pointer_entry->m_global_output_indexes.size(), false);
}
}
}
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false);
return true;
}
bool fill_tx_rpc_inputs::c8(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const
{
currency::transaction tx{};
currency::tx_rpc_extended_info info{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(event_position)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.size(), 1);
{
const auto& input{boost::get<currency::txin_to_key>(tx.vin.front())};
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
{
const auto& reference{boost::get<currency::ref_by_id>(input.key_offsets.front())};
CHECK_AND_ASSERT_EQ(reference.tx_id, currency::null_hash);
CHECK_AND_ASSERT_EQ(reference.n, 0u);
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id), nullptr);
}
}
CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false);
return true;
}

View file

@ -0,0 +1,18 @@
#pragma once
#include <vector>
#include "chaingen.h"
struct fill_tx_rpc_inputs : public test_chain_unit_enchanced
{
fill_tx_rpc_inputs();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c2(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c3(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c4(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c5(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c6(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c7(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
bool c8(const currency::core& core, const size_t event_position, const std::vector<test_event_entry>& events) const;
};

View file

@ -2121,3 +2121,481 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
return true;
}
input_refers_to_incompatible_by_type_output::input_refers_to_incompatible_by_type_output()
{
REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_to_key_output_is_wrong);
REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_to_key_input_refers_zarcanum_output_is_wrong);
REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_zarcanum_output_is_wrong);
REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_zc_input_refers_bare_output_is_wrong);
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 14);
}
bool input_refers_to_incompatible_by_type_output::generate(std::vector<test_event_entry>& events) const
{
// Test idea: ensure that input and output compatibility checks work.
GENERATE_ACCOUNT(miner);
MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time());
DO_CALLBACK(events, "configure_core");
REWIND_BLOCKS(events, blk_0r, blk_0, miner);
block& top{blk_0r};
MAKE_TX_FEE(events, tx_00, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk_1, top, miner, tx_00);
top = blk_1;
}
// An input of the type "txin_htlc" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key".
{
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
transaction tx_1{};
top = blk;
{
txin_htlc input{};
{
ref_by_id reference{};
reference.tx_id = get_transaction_hash(tx_0);
reference.n = get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7));
CHECK_AND_ASSERT_NEQ(reference.n, UINT64_MAX);
input.key_offsets.push_back(reference);
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
}
input.k_image = crypto::point_t{{0x59, 0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63,
0x64, 0x3b, 0x3b, 0x47, 0x30}}.to_key_image();
input.amount = MK_TEST_COINS(7);
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
{
tx_out_bare output_bare{};
txout_to_key output_to_key{};
output_bare.amount = MK_TEST_COINS(2);
output_to_key.key = crypto::point_t{{0x2c, 0xdc, 0xc4, 0x7c, 0x38, 0x69, 0xe5, 0xe2, 0x4c, 0x5e, 0x10, 0xb2, 0xbe, 0x57, 0xe9, 0x42, 0x72, 0xd8, 0xf8, 0xb5, 0x97, 0xb9, 0x02, 0x41, 0xba, 0xea,
0x82, 0xb3, 0xaf, 0x0c, 0xf0, 0x09}}.to_public_key();
output_bare.target = output_to_key;
tx_1.vout.push_back(output_bare);
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 1);
}
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
// An input of the type "txin_htlc" refers by a global output index to an output with a target of the type "txout_to_key".
{
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
transaction tx_1{};
top = blk;
{
txin_htlc input{};
{
uint64_t global_output_index{};
CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7)), global_output_index), true);
CHECK_AND_ASSERT_NEQ(global_output_index, UINT64_MAX);
input.key_offsets.push_back(global_output_index);
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
}
input.k_image = crypto::point_t{{0xc6, 0x1c, 0xda, 0xf7, 0x9e, 0xb7, 0xd9, 0xc2, 0x46, 0x90, 0x29, 0xc8, 0x8a, 0x8f, 0xb4, 0x3e, 0x8e, 0xa8, 0x3b, 0x33, 0x4c, 0x75, 0xdf, 0xcb, 0x8b, 0x77, 0xf7,
0x39, 0xa7, 0x17, 0xc9, 0xb4}}.to_key_image();
input.amount = MK_TEST_COINS(7);
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
{
tx_out_bare output_bare{};
txout_to_key output_to_key{};
output_bare.amount = MK_TEST_COINS(2);
output_to_key.key = crypto::point_t{{0xc4, 0x17, 0xc7, 0x7f, 0xb2, 0x5d, 0xcb, 0x4b, 0x29, 0xdf, 0xea, 0x53, 0x70, 0x11, 0xbb, 0x42, 0x33, 0x0d, 0xf1, 0x22, 0x2d, 0xe4, 0x84, 0x24, 0x36, 0xc0,
0x06, 0xd5, 0x8c, 0xf8, 0x23, 0x62}}.to_public_key();
output_bare.target = output_to_key;
tx_1.vout.push_back(output_bare);
}
tx_1.signatures.push_back(NLSAG_sig{{crypto::signature{}}});
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", size_t{ZANO_HARDFORK_04_ZARCANUM});
{
REWIND_BLOCKS_N(events, blk, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
top = blk;
}
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
MAKE_TX_FEE(events, tx_01, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_01);
top = blk;
}
MAKE_TX_FEE(events, tx_02, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_02);
top = blk;
}
// An input of the type "txin_to_key" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum".
{
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
top = blk;
}
{
REWIND_BLOCKS(events, blk_r, top, miner);
top = blk_r;
}
transaction tx_1{};
tx_1.version = 2;
{
txin_to_key input{};
input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_0), 0});
CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get<ref_by_id>(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum));
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
input.k_image = crypto::point_t({0x59,0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63,
0x64, 0x3b, 0x3b, 0x47, 0x30}).to_key_image();
input.amount = MK_TEST_COINS(2);
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
tx_1.vout.push_back(tx_out_zarcanum{});
tx_1.vout.push_back(tx_out_zarcanum{});
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2);
tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE});
CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
// An input of the type "txin_to_key" refers by a global output index to an output of the type "tx_out_zarcanum".
{
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
top = blk;
}
{
REWIND_BLOCKS(events, blk_r, top, miner);
top = blk_r;
}
transaction tx_1{};
tx_1.version = 2;
{
txin_to_key input{};
{
uint64_t global_output_index{};
CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum));
CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true);
input.key_offsets.push_back(global_output_index);
}
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c,
0x92, 0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image();
// A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0.
input.amount = 0;
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
tx_1.vout.push_back(tx_out_zarcanum{});
tx_1.vout.push_back(tx_out_zarcanum{});
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2);
tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE});
CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
// An input of the type "txin_zc_input" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key".
{
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
top = blk;
}
{
REWIND_BLOCKS(events, blk_r, top, miner);
top = blk_r;
}
transaction tx_1{};
tx_1.version = 2;
{
txin_zc_input input{};
input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_00), 0});
{
const auto& output{tx_00.vout.at(boost::get<ref_by_id>(input.key_offsets.front()).n)};
CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_bare));
CHECK_AND_ASSERT_EQ(boost::get<tx_out_bare>(output).target.type(), typeid(txout_to_key));
}
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_01), 0});
{
const auto& output{tx_01.vout.at(boost::get<ref_by_id>(input.key_offsets.at(1)).n)};
CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_zarcanum));
}
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 2);
input.k_image = crypto::point_t{{0x31, 0x31, 0xd0, 0xf7, 0x13, 0x73, 0xff, 0x21, 0x14, 0xe8, 0x17, 0x4d, 0x18, 0x20, 0x12, 0x2d, 0x80, 0x31, 0xd5, 0x11, 0x82, 0xc0, 0x37, 0xad, 0xd2, 0x7b, 0x8c,
0xf2, 0xdd, 0xd4, 0x34, 0x9a}}.to_key_image();
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
tx_1.vout.push_back(tx_out_zarcanum{});
tx_1.vout.push_back(tx_out_zarcanum{});
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2);
tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE});
CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_zc_input_refers_bare_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
// An input of the type "txin_htlc" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum".
{
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
top = blk;
}
{
REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
top = blk_r;
}
transaction tx_1{};
tx_1.version = 2;
{
txin_htlc input{};
input.key_offsets.push_back(ref_by_id{get_transaction_hash(tx_0), 0});
CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get<ref_by_id>(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum));
input.k_image = crypto::point_t{{0x7b, 0xf5, 0x28, 0x09, 0xe8, 0x7e, 0x9c, 0x71, 0x0b, 0xad, 0x24, 0xa1, 0x9d, 0xb4, 0xc8, 0xd7, 0x96, 0x72, 0x18, 0xe6, 0x4b, 0x8f, 0x31, 0x01, 0xb0, 0x43, 0xa0,
0xcc, 0xce, 0x72, 0x8c, 0x7e}}.to_key_image();
input.amount = MK_TEST_COINS(2);
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
tx_1.vout.push_back(tx_out_zarcanum{});
tx_1.vout.push_back(tx_out_zarcanum{});
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2);
tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE});
CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
// An input of the type "txin_htlc" refers by a global output index to an output of the type "tx_out_zarcanum".
{
MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top);
{
MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0);
top = blk;
}
DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM});
{
REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
top = blk_r;
}
transaction tx_1{};
tx_1.version = 2;
{
txin_htlc input{};
uint64_t global_output_index{};
CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum));
CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true);
input.key_offsets.push_back(global_output_index);
CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1);
input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c, 0x92,
0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image();
// A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0.
input.amount = 0;
tx_1.vin.push_back(input);
CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1);
}
tx_1.vout.push_back(tx_out_zarcanum{});
tx_1.vout.push_back(tx_out_zarcanum{});
CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2);
tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE});
CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1));
}
return true;
}
bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events) const
{
transaction tx{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(ev_index)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc));
{
uint64_t max_related_block_height{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get<const txin_htlc>(tx.vin.front()), get_transaction_hash(tx), max_related_block_height), false);
}
{
std::vector<public_key> keys{};
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false);
}
return true;
}
bool input_refers_to_incompatible_by_type_output::assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const
{
transaction tx{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(ev_index)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_to_key));
{
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get<const txin_to_key>(tx.vin.front()), get_transaction_hash(tx), max_related_block_height,
source_max_unlock_time_for_pos_coinbase), false);
}
{
std::vector<public_key> keys{};
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false);
}
return true;
}
bool input_refers_to_incompatible_by_type_output::assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const
{
transaction tx{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(ev_index)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_zc_input));
{
std::vector<public_key> keys{};
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), true);
}
{
bool all_inputs_have_explicit_native_asset_id{};
uint64_t max_related_block_height{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get<const txin_zc_input>(tx.vin.front()), get_transaction_hash(tx), max_related_block_height,
all_inputs_have_explicit_native_asset_id), false);
}
return true;
}
bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const
{
transaction tx{};
CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get<const callback_entry>(events.at(ev_index)).callback_params), true);
CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc));
{
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get<const txin_htlc>(tx.vin.front()), get_transaction_hash(tx), max_related_block_height,
source_max_unlock_time_for_pos_coinbase), false);
}
{
std::vector<public_key> keys{};
uint64_t max_related_block_height{};
uint64_t source_max_unlock_time_for_pos_coinbase{};
CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false);
}
return true;
}

View file

@ -165,3 +165,13 @@ struct tx_pool_semantic_validation : public test_chain_unit_enchanced
{
bool generate(std::vector<test_event_entry>& events) const;
};
struct input_refers_to_incompatible_by_type_output : public test_chain_unit_enchanced
{
input_refers_to_incompatible_by_type_output();
bool generate(std::vector<test_event_entry>& events) const;
bool assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const;
bool assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const;
bool assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const;
bool assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector<test_event_entry>& events) const;
};