1
0
Fork 0
forked from lthn/blockchain

coretests: improve of the test "tx_pool_semantic_validation" (#465)

* Coretests: implement the test "tx_pool_semantic_validation"

* Play the test "tx_pool_semantic_validation" on the HF 3

* Delete an extra space after the ":"

* Remove an extra adding of objects to the transaction

* Create the input objects of the specified type in the "unsupported input type" case

* Modify the function bodies "inputs_sum", "outputs_sum" to be short

* Remove adding output to the transaction in the cases "inputs amount overflow", "two entries of the same type in extra"

* Get rid of use the object "image" of the type key_image in the case "equal key images in inputs"
This commit is contained in:
Stёpa Dolgorukov 2024-10-15 05:30:05 +05:00 committed by GitHub
parent c344739de9
commit b836742f66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 212 additions and 19 deletions

View file

@ -1218,7 +1218,9 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(tx_expiration_time_and_chain_switching);
GENERATE_AND_PLAY(tx_key_image_pool_conflict);
//GENERATE_AND_PLAY_HF(tx_version_against_hardfork, "4-*");
GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "4-*");
/* 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");
// Double spend
GENERATE_AND_PLAY(gen_double_spend_in_tx<false>);

View file

@ -1728,7 +1728,7 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
{
transaction tx{};
tx.vin.emplace_back();
tx.vin.emplace_back(txin_gen{});
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
@ -1750,7 +1750,6 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
point_t point_public_key{};
txout_to_key target{};
std::array<txin_to_key, 2> inputs{};
tx_out_bare output{};
transaction tx{};
CHECK_AND_ASSERT_EQ(point_public_key.from_string("499790c3302b9f0514e2db09b390679283d43d971383d33dc24c7991ea4cf6d7"), true);
@ -1763,10 +1762,6 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
tx.vin.push_back(input);
}
output.amount = 1;
output.target = target;
tx.vout.push_back(output);
CHECK_AND_ASSERT_GREATER(inputs.at(0).amount, inputs.at(0).amount + inputs.at(1).amount);
CHECK_AND_ASSERT_GREATER(inputs.at(1).amount, inputs.at(0).amount + inputs.at(1).amount);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
@ -1803,41 +1798,38 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
// Equal key images in inputs.
{
tx_out_bare output;
tx_out_bare output{};
transaction tx{};
std::array<txin_to_key, 2> inputs{};
point_t key_image_point{};
key_image image{};
output.amount = 1;
tx.vout.push_back(output);
CHECK_AND_ASSERT_EQ(key_image_point.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true);
image = key_image_point.to_key_image();
for (int position{}; position < 2; ++position)
{
inputs.at(position).k_image = image;
tx.vin.push_back(inputs.at(position));
auto& input{inputs.at(position)};
input.k_image = key_image_point.to_key_image();
tx.vin.push_back(input);
}
CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), typeid(txin_to_key));
CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), tx.vin.at(1).type());
CHECK_AND_ASSERT_EQ(boost::get<txin_to_key>(tx.vin.at(0)).k_image, boost::get<txin_to_key>(tx.vin.at(1)).k_image);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Two entries of the same type in extra.
{
tx_out_bare output;
transaction tx{};
std::array<txin_to_key, 2> inputs{};
std::array<point_t, 2> key_image_points{};
key_image image{};
output.amount = 1;
tx.vout.push_back(output);
CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("de3c22a62f15e6de8abe6b217085b2aead196daf5ddd67d9c4b366330736fbeb"), true);
CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("9f3eef913921ca35239e696725595e3686bb0d69e3e805791c5aa93d5754aa5c"), true);
@ -1859,8 +1851,8 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
// tx.version <= TRANSACTION_VERSION_PRE_HF4. Balance check fail: sum of inputs <= sum of outputs.
{
tx_out_bare output{};
transaction tx{};
tx_out_bare output;
std::array<point_t, 2> key_image_points{};
std::array<txin_to_key, 2> inputs{};
@ -1879,7 +1871,10 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
tx.vin.push_back(input);
}
CHECK_AND_ASSERT_GREATER(output.amount, std::accumulate(inputs.begin(), inputs.end(), std::uint64_t{}, [](uint64_t sum, const txin_to_key& input) { return sum + input.amount; }));
const uint64_t sum_inputs{std::accumulate(inputs.begin(), inputs.end(), std::uint64_t{}, [](uint64_t sum, const txin_to_key& input) { return sum + input.amount; })};
CHECK_AND_ASSERT_LESS(sum_inputs, output.amount);
CHECK_AND_ASSERT_EQ(output.amount - sum_inputs, 1);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
@ -1911,5 +1906,201 @@ bool tx_pool_semantic_validation::generate(std::vector<test_event_entry>& events
ADD_CUSTOM_EVENT(events, tx);
}
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// Construct a valid transaction and then modify it so that the transaction is no longer semantically correct.
// No inputs.
{
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
tx.vin = {};
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Unsupported input type.
{
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
tx.vin.emplace_back(txin_gen{});
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Unsupported output type.
{
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
tx.vout.emplace_back();
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Inputs amount overflow.
{
point_t point_public_key{};
txout_to_key target{};
std::array<txin_to_key, 2> inputs{};
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
CHECK_AND_ASSERT_EQ(point_public_key.from_string("499790c3302b9f0514e2db09b390679283d43d971383d33dc24c7991ea4cf6d7"), true);
target.key = point_public_key.to_public_key();
inputs.at(0).amount = 1;
inputs.at(1).amount = UINT64_MAX;
for (const auto& input : inputs)
{
tx.vin.push_back(input);
}
CHECK_AND_ASSERT_GREATER(inputs.at(0).amount, inputs.at(0).amount + inputs.at(1).amount);
CHECK_AND_ASSERT_GREATER(inputs.at(1).amount, inputs.at(0).amount + inputs.at(1).amount);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Outputs amount overflow.
{
point_t point_public_key{};
txout_to_key target{};
std::array<tx_out_bare, 2> outputs{};
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
CHECK_AND_ASSERT_EQ(point_public_key.from_string("78ef3d9af7b5e3d09556d57820cf68c2b3553a9d8205c01fe40fc70aae86bb4f"), true);
target.key = point_public_key.to_public_key();
outputs.at(0).amount = 1;
outputs.at(1).amount = UINT64_MAX;
for (auto& output : outputs)
{
output.target = target;
tx.vout.push_back(output);
}
tx.vin.push_back(txin_to_key{});
CHECK_AND_ASSERT_GREATER(outputs.at(0).amount, outputs.at(0).amount + outputs.at(1).amount);
CHECK_AND_ASSERT_GREATER(outputs.at(1).amount, outputs.at(0).amount + outputs.at(1).amount);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Equal key images in inputs.
{
tx_out_bare output{};
std::array<txin_to_key, 2> inputs{};
point_t key_image_point{};
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
output.amount = 1;
tx.vout.push_back(output);
CHECK_AND_ASSERT_EQ(key_image_point.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true);
for (int position{}; position < 2; ++position)
{
inputs.at(position).k_image = key_image_point.to_key_image();
tx.vin.push_back(inputs.at(position));
}
{
const auto& input_preceding_last{tx.vin.at(tx.vin.size() - 2u)};
CHECK_AND_ASSERT_EQ(tx.vin.back().type(), typeid(txin_to_key));
CHECK_AND_ASSERT_EQ(tx.vin.back().type(), input_preceding_last.type());
CHECK_AND_ASSERT_EQ(boost::get<txin_to_key>(tx.vin.back()).k_image, boost::get<txin_to_key>(input_preceding_last).k_image);
}
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// Two entries of the same type in extra.
{
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
tx.extra.push_back(null_pkey);
tx.extra.push_back(null_pkey);
CHECK_AND_ASSERT_GREATER(tx.extra.size(), 2);
CHECK_AND_ASSERT_EQ(typeid(tx.extra.back()), typeid(tx.extra.at(tx.extra.size() - 2)));
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
// tx.version <= TRANSACTION_VERSION_PRE_HF4. Balance check fail: sum of inputs <= sum of outputs.
{
tx_out_bare output{};
std::array<point_t, 2> key_image_points{};
std::array<txin_to_key, 2> inputs{};
MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, blk_0r);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true);
output.amount = 10'000'000'003;
tx.vout.push_back(output);
tx.version = 0;
CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true);
CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("dc48b741dacda5ac026ad0a7d193b816049eb08724907a1ff6f95839cfb0efa5"), true);
for (int position{}; position < 2; ++position)
{
auto& input{inputs.at(position)};
input.amount = 1;
input.k_image = key_image_points.at(position).to_key_image();
tx.vin.push_back(input);
}
const auto inputs_sum{[](const uint64_t sum, const txin_v& input) -> uint64_t
{
if (input.type() == typeid(txin_to_key))
{
return sum + boost::get<txin_to_key>(input).amount;
}
if (input.type() == typeid(txin_multisig))
{
return sum + boost::get<txin_multisig>(input).amount;
}
}
};
const auto outputs_sum{[](const uint64_t sum, const tx_out_v& output) -> uint64_t
{
if (output.type() == typeid(tx_out_bare))
{
return sum + boost::get<tx_out_bare>(output).amount;
}
}
};
const uint64_t inputs_amount{std::accumulate(tx.vin.begin(), tx.vin.end(), std::uint64_t{}, inputs_sum)};
const uint64_t outputs_amount{std::accumulate(tx.vout.begin(), tx.vout.end(), std::uint64_t{}, outputs_sum)};
CHECK_AND_ASSERT_LESS(inputs_amount, outputs_amount);
CHECK_AND_ASSERT_EQ(outputs_amount - inputs_amount, 1);
CHECK_AND_ASSERT(tx.version <= TRANSACTION_VERSION_PRE_HF4, false);
CHECK_AND_ASSERT_EQ(get_block_height(blk_0r), 10);
CHECK_AND_ASSERT_EQ(m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_03, 10), true);
CHECK_AND_ASSERT_EQ(m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 10), false);
CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false);
DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx);
}
return true;
}

View file

@ -161,7 +161,7 @@ struct tx_version_against_hardfork : public test_chain_unit_enchanced
bool generate(std::vector<test_event_entry>& events) const;
};
struct tx_pool_semantic_validation : public test_chain_unit_enchanced
struct tx_pool_semantic_validation : public test_chain_unit_enchanced
{
bool generate(std::vector<test_event_entry>& events) const;
};