aboutsummaryrefslogtreecommitdiff
path: root/tests/core_tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/core_tests')
-rw-r--r--tests/core_tests/CMakeLists.txt6
-rw-r--r--tests/core_tests/chaingen.cpp11
-rw-r--r--tests/core_tests/chaingen.h9
-rw-r--r--tests/core_tests/chaingen_main.cpp27
-rw-r--r--tests/core_tests/chaingen_tests_list.h1
-rw-r--r--tests/core_tests/rct.cpp469
-rw-r--r--tests/core_tests/rct.h251
7 files changed, 764 insertions, 10 deletions
diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt
index c34039c17..6f07fbd25 100644
--- a/tests/core_tests/CMakeLists.txt
+++ b/tests/core_tests/CMakeLists.txt
@@ -39,7 +39,8 @@ set(core_tests_sources
ring_signature_1.cpp
transaction_tests.cpp
tx_validation.cpp
- v2_tests.cpp)
+ v2_tests.cpp
+ rct.cpp)
set(core_tests_headers
block_reward.h
@@ -54,7 +55,8 @@ set(core_tests_headers
ring_signature_1.h
transaction_tests.h
tx_validation.h
- v2_tests.h)
+ v2_tests.h
+ rct.h)
add_executable(coretests
${core_tests_sources}
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index a181c1d16..b7a1c3dec 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -94,11 +94,11 @@ uint64_t test_generator::get_already_generated_coins(const cryptonote::block& bl
return get_already_generated_coins(blk_hash);
}
-void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins)
+void test_generator::add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins, uint8_t hf_version)
{
const size_t block_size = tsx_size + get_object_blobsize(blk.miner_tx);
uint64_t block_reward;
- get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, 1);
+ get_block_reward(misc_utils::median(block_sizes), block_size, already_generated_coins, block_reward, hf_version);
m_blocks_info[get_block_hash(blk)] = block_info(blk.prev_id, already_generated_coins + block_reward, block_size);
}
@@ -215,7 +215,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc
const crypto::hash& prev_id/* = crypto::hash()*/, const difficulty_type& diffic/* = 1*/,
const transaction& miner_tx/* = transaction()*/,
const std::vector<crypto::hash>& tx_hashes/* = std::vector<crypto::hash>()*/,
- size_t txs_sizes/* = 0*/, size_t max_outs/* = 0*/)
+ size_t txs_sizes/* = 0*/, size_t max_outs/* = 0*/, uint8_t hf_version/* = 1*/)
{
blk.major_version = actual_params & bf_major_ver ? major_ver : CURRENT_BLOCK_MAJOR_VERSION;
blk.minor_version = actual_params & bf_minor_ver ? minor_ver : CURRENT_BLOCK_MINOR_VERSION;
@@ -223,6 +223,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc
blk.prev_id = actual_params & bf_prev_id ? prev_id : get_block_hash(prev_block);
blk.tx_hashes = actual_params & bf_tx_hashes ? tx_hashes : std::vector<crypto::hash>();
max_outs = actual_params & bf_max_outs ? max_outs : 9999;
+ hf_version = actual_params & bf_hf_version ? hf_version : 1;
size_t height = get_block_height(prev_block) + 1;
uint64_t already_generated_coins = get_already_generated_coins(prev_block);
@@ -236,7 +237,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc
{
size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx);
// TODO: This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE
- if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs))
+ if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), max_outs, hf_version))
return false;
}
@@ -245,7 +246,7 @@ bool test_generator::construct_block_manually(block& blk, const block& prev_bloc
difficulty_type a_diffic = actual_params & bf_diffic ? diffic : get_test_difficulty();
fill_nonce(blk, a_diffic, height);
- add_block(blk, txs_sizes, block_sizes, already_generated_coins);
+ add_block(blk, txs_sizes, block_sizes, already_generated_coins, hf_version);
return true;
}
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 0e5dbb0e4..81cbc2b6a 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -221,7 +221,8 @@ public:
bf_miner_tx = 1 << 4,
bf_tx_hashes = 1 << 5,
bf_diffic = 1 << 6,
- bf_max_outs = 1 << 7
+ bf_max_outs = 1 << 7,
+ bf_hf_version= 1 << 8
};
void get_block_chain(std::vector<block_info>& blockchain, const crypto::hash& head, size_t n) const;
@@ -229,7 +230,8 @@ public:
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<size_t>& block_sizes, uint64_t already_generated_coins);
+ void add_block(const cryptonote::block& blk, size_t tsx_size, std::vector<size_t>& block_sizes, uint64_t already_generated_coins,
+ uint8_t hf_version = 1);
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<size_t>& block_sizes, const std::list<cryptonote::transaction>& tx_list);
@@ -241,7 +243,8 @@ public:
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 max_outs = 999);
+ const std::vector<crypto::hash>& tx_hashes = std::vector<crypto::hash>(), size_t txs_sizes = 0, size_t max_outs = 999,
+ uint8_t hf_version = 1);
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);
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index e20f7a152..fc93b2e74 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -173,6 +173,33 @@ int main(int argc, char* argv[])
// GENERATE_AND_PLAY(gen_v2_tx_unmixable_two);
GENERATE_AND_PLAY(gen_v2_tx_dust);
+ GENERATE_AND_PLAY(gen_rct_tx_valid_from_pre_rct);
+ GENERATE_AND_PLAY(gen_rct_tx_valid_from_rct);
+ GENERATE_AND_PLAY(gen_rct_tx_valid_from_mixed);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_dest);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_mask);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_dest);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_mask);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_dest);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_mask);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_dest);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_mask);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_spend_with_zero_commit);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_zero_vin_amount);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_non_zero_vin_amount);
+ GENERATE_AND_PLAY(gen_rct_tx_non_zero_vout_amount);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_duplicate_key_image);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_duplicate_key_image);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_key_image);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_key_image);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_fee);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_fee);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_remove_vin);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_remove_vin);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_add_vout);
+ GENERATE_AND_PLAY(gen_rct_tx_rct_add_vout);
+ GENERATE_AND_PLAY(gen_rct_tx_pre_rct_increase_vin_and_fee);
+
std::cout << (failed_tests.empty() ? concolor::green : concolor::magenta);
std::cout << "\nREPORT:\n";
std::cout << " Test run: " << tests_count << '\n';
diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h
index 4da87a973..1b9ebd756 100644
--- a/tests/core_tests/chaingen_tests_list.h
+++ b/tests/core_tests/chaingen_tests_list.h
@@ -40,6 +40,7 @@
#include "ring_signature_1.h"
#include "tx_validation.h"
#include "v2_tests.h"
+#include "rct.h"
/************************************************************************/
/* */
/************************************************************************/
diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp
new file mode 100644
index 000000000..465d2036f
--- /dev/null
+++ b/tests/core_tests/rct.cpp
@@ -0,0 +1,469 @@
+// Copyright (c) 2014-2016, 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
+
+#include "ringct/rctSigs.h"
+#include "chaingen.h"
+#include "chaingen_tests_list.h"
+
+using namespace epee;
+using namespace crypto;
+using namespace cryptonote;
+
+//----------------------------------------------------------------------------------------------------------------------
+// Tests
+
+bool gen_rct_tx_validation_base::generate_with(std::vector<test_event_entry>& events,
+ const int *out_idx, int mixin, uint64_t amount_paid, bool valid,
+ const std::function<void(std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations)> &pre_tx,
+ const std::function<void(transaction &tx)> &post_tx) const
+{
+ uint64_t ts_start = 1338224400;
+
+ GENERATE_ACCOUNT(miner_account);
+ MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start);
+
+ // create 4 miner accounts, and have them mine the next 4 blocks
+ cryptonote::account_base miner_accounts[4];
+ const cryptonote::block *prev_block = &blk_0;
+ cryptonote::block blocks[4];
+ for (size_t n = 0; n < 4; ++n) {
+ miner_accounts[n].generate();
+ CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n],
+ test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version,
+ 3, 3, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
+ crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 3),
+ false, "Failed to generate block");
+ events.push_back(blocks[n]);
+ prev_block = blocks + n;
+ LOG_PRINT_L0("Initial miner tx " << n << ": " << obj_to_json_str(blocks[n].miner_tx));
+ }
+
+ // rewind
+ cryptonote::block blk_r, blk_last;
+ {
+ blk_last = blocks[3];
+ for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i)
+ {
+ cryptonote::block blk;
+ CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
+ test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version,
+ 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
+ crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 3),
+ false, "Failed to generate block");
+ events.push_back(blk);
+ blk_last = blk;
+ }
+ blk_r = blk_last;
+ }
+
+ // create 4 txes from these miners in another block, to generate some rct outputs
+ transaction rct_txes[4];
+ rct::key rct_tx_masks[16];
+ cryptonote::block blk_txes[4];
+ for (size_t n = 0; n < 4; ++n)
+ {
+ std::vector<crypto::hash> starting_rct_tx_hashes;
+ std::vector<tx_source_entry> sources;
+
+ sources.resize(1);
+ tx_source_entry& src = sources.back();
+
+ const size_t index_in_tx = 5;
+ src.amount = 30000000000000;
+ for (int m = 0; m < 4; ++m) {
+ src.push_output(m, boost::get<txout_to_key>(blocks[m].miner_tx.vout[index_in_tx].target).key, src.amount);
+ }
+ src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[n].miner_tx);
+ src.real_output = n;
+ src.real_output_in_tx_index = index_in_tx;
+ src.mask = rct::identity();
+
+ //fill outputs entry
+ tx_destination_entry td;
+ td.addr = miner_accounts[n].get_keys().m_account_address;
+ td.amount = 7390000000000;
+ std::vector<tx_destination_entry> destinations;
+ destinations.push_back(td);
+ destinations.push_back(td);
+ destinations.push_back(td);
+ destinations.push_back(td); // 30 -> 7.39 * 4
+
+ crypto::secret_key tx_key;
+ bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), sources, destinations, std::vector<uint8_t>(), rct_txes[n], 0, tx_key, true);
+ CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
+ events.push_back(rct_txes[n]);
+ starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n]));
+
+ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(rct_txes[n]);
+ for (size_t o = 0; o < 4; ++o)
+ {
+ cryptonote::keypair in_ephemeral;
+ crypto::key_image ki;
+ cryptonote::generate_key_image_helper(miner_accounts[n].get_keys(), tx_pub_key, o, in_ephemeral, ki);
+ rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(in_ephemeral.sec), o, rct_tx_masks[o+n*4]);
+ }
+
+ CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account,
+ test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version,
+ 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
+ crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 0, 3),
+ false, "Failed to generate block");
+ events.push_back(blk_txes[n]);
+ blk_last = blk_txes[n];
+ }
+
+ // rewind
+ {
+ for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i)
+ {
+ cryptonote::block blk;
+ CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account,
+ test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version,
+ 3, 3, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long
+ crypto::hash(), 0, transaction(), std::vector<crypto::hash>(), 0, 0, 3),
+ false, "Failed to generate block");
+ events.push_back(blk);
+ blk_last = blk;
+ }
+ blk_r = blk_last;
+ }
+
+ // create a tx from the requested ouputs
+ std::vector<tx_source_entry> sources;
+ size_t rct_idx = 0, pre_rct_idx = 0;
+ for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) {
+ sources.resize(sources.size()+1);
+ tx_source_entry& src = sources.back();
+
+ src.real_output = 0;
+ if (out_idx[out_idx_idx]) {
+ // rct
+ src.amount = 7390000000000;
+ src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]);
+ src.real_output_in_tx_index = rct_idx&3;
+ src.mask = rct_tx_masks[rct_idx];
+ for (int m = 0; m <= mixin; ++m) {
+ rct::ctkey ctkey;
+ ctkey.dest = rct::pk2rct(boost::get<txout_to_key>(rct_txes[rct_idx/4].vout[rct_idx&3].target).key);
+ ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask;
+ src.outputs.push_back(std::make_pair(rct_idx, ctkey));
+ ++rct_idx;
+ }
+ }
+ else
+ {
+ // pre rct
+ src.amount = 5000000000000;
+ src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx);
+ src.real_output_in_tx_index = 4;
+ src.mask = rct::identity();
+ for (int m = 0; m <= mixin; ++m) {
+ src.push_output(m, boost::get<txout_to_key>(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount);
+ ++pre_rct_idx;
+ }
+ }
+ }
+
+ //fill outputs entry
+ tx_destination_entry td;
+ td.addr = miner_account.get_keys().m_account_address;
+ td.amount = amount_paid;
+ std::vector<tx_destination_entry> destinations;
+ destinations.push_back(td);
+
+ if (pre_tx)
+ pre_tx(sources, destinations);
+
+ transaction tx;
+ crypto::secret_key tx_key;
+ bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), sources, destinations, std::vector<uint8_t>(), tx, 0, tx_key, true);
+ CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction");
+
+ if (post_tx)
+ post_tx(tx);
+
+ if (!valid)
+ DO_CALLBACK(events, "mark_invalid_tx");
+ events.push_back(tx);
+ LOG_PRINT_L0("Test tx: " << obj_to_json_str(tx));
+
+ return true;
+}
+
+bool gen_rct_tx_valid_from_pre_rct::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL);
+}
+
+bool gen_rct_tx_valid_from_rct::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL);
+}
+
+bool gen_rct_tx_valid_from_mixed::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, 0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL);
+}
+
+bool gen_rct_tx_pre_rct_bad_real_dest::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ bool tx_creation_succeeded = false;
+ // in the case, the tx will fail to create, due to mismatched sk/pk
+ bool ret = generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);},
+ [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;});
+ return !ret && !tx_creation_succeeded;
+}
+
+bool gen_rct_tx_pre_rct_bad_real_mask::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);},
+ NULL);
+}
+
+bool gen_rct_tx_pre_rct_bad_fake_dest::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);},
+ NULL);
+}
+
+bool gen_rct_tx_pre_rct_bad_fake_mask::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);},
+ NULL);
+}
+
+bool gen_rct_tx_rct_bad_real_dest::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ bool tx_creation_succeeded = false;
+ // in the case, the tx will fail to create, due to mismatched sk/pk
+ bool ret = generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);},
+ [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;});
+ return !ret && !tx_creation_succeeded;
+}
+
+bool gen_rct_tx_rct_bad_real_mask::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);},
+ NULL);
+}
+
+bool gen_rct_tx_rct_bad_fake_dest::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);},
+ NULL);
+}
+
+bool gen_rct_tx_rct_bad_fake_mask::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);},
+ NULL);
+}
+
+bool gen_rct_tx_rct_spend_with_zero_commit::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ [](std::vector<tx_source_entry> &sources, std::vector<tx_destination_entry> &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(sources[0].amount); sources[0].mask = rct::identity();},
+ [](transaction &tx){boost::get<txin_to_key>(tx.vin[0]).amount = 0;});
+}
+
+bool gen_rct_tx_pre_rct_zero_vin_amount::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {boost::get<txin_to_key>(tx.vin[0]).amount = 0;});
+}
+
+bool gen_rct_tx_rct_non_zero_vin_amount::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {boost::get<txin_to_key>(tx.vin[0]).amount = 5000000000000;}); // one that we know exists
+}
+
+bool gen_rct_tx_non_zero_vout_amount::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.vout[0].amount = 5000000000000;}); // one that we know exists
+}
+
+bool gen_rct_tx_pre_rct_duplicate_key_image::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [&events](transaction &tx) {boost::get<txin_to_key>(tx.vin[0]).k_image = boost::get<txin_to_key>(boost::get<transaction>(events[67]).vin[0]).k_image;});
+}
+
+bool gen_rct_tx_rct_duplicate_key_image::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [&events](transaction &tx) {boost::get<txin_to_key>(tx.vin[0]).k_image = boost::get<txin_to_key>(boost::get<transaction>(events[67]).vin[0]).k_image;});
+}
+
+bool gen_rct_tx_pre_rct_wrong_key_image::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ // some random key image from the monero blockchain, so we get something that is a valid key image
+ static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07";
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {memcpy(&boost::get<txin_to_key>(tx.vin[0]).k_image, k_image, 32);});
+}
+
+bool gen_rct_tx_rct_wrong_key_image::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ // some random key image from the monero blockchain, so we get something that is a valid key image
+ static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07";
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {memcpy(&boost::get<txin_to_key>(tx.vin[0]).k_image, k_image, 32);});
+}
+
+bool gen_rct_tx_pre_rct_wrong_fee::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;});
+}
+
+bool gen_rct_tx_rct_wrong_fee::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;});
+}
+
+bool gen_rct_tx_pre_rct_increase_vin_and_fee::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {0, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {boost::get<txin_to_key>(tx.vin[0]).amount++;tx.rct_signatures.txnFee++;});
+}
+
+bool gen_rct_tx_pre_rct_remove_vin::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.vin.pop_back();});
+}
+
+bool gen_rct_tx_rct_remove_vin::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.vin.pop_back();});
+}
+
+bool gen_rct_tx_pre_rct_add_vout::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());});
+}
+
+bool gen_rct_tx_rct_add_vout::generate(std::vector<test_event_entry>& events) const
+{
+ const int mixin = 2;
+ const int out_idx[] = {1, -1};
+ const uint64_t amount_paid = 10000;
+ return generate_with(events, out_idx, mixin, amount_paid, false,
+ NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());});
+}
+
diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h
new file mode 100644
index 000000000..1b79cbd8f
--- /dev/null
+++ b/tests/core_tests/rct.h
@@ -0,0 +1,251 @@
+// Copyright (c) 2014-2016, 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 "chaingen.h"
+
+struct gen_rct_tx_validation_base : public test_chain_unit_base
+{
+ gen_rct_tx_validation_base()
+ : m_invalid_tx_index(0)
+ , m_invalid_block_index(0)
+ {
+ REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_tx);
+ REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_block);
+ }
+
+ bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/)
+ {
+ if (m_invalid_tx_index == event_idx)
+ return tvc.m_verifivation_failed;
+ else
+ return !tvc.m_verifivation_failed && tx_added;
+ }
+
+ bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/)
+ {
+ if (m_invalid_block_index == event_idx)
+ return bvc.m_verifivation_failed;
+ else
+ return !bvc.m_verifivation_failed;
+ }
+
+ bool mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
+ {
+ m_invalid_block_index = ev_index + 1;
+ return true;
+ }
+
+ bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector<test_event_entry>& /*events*/)
+ {
+ m_invalid_tx_index = ev_index + 1;
+ return true;
+ }
+
+ bool generate_with(std::vector<test_event_entry>& events, const int *out_idx, int mixin,
+ uint64_t amount_paid, bool valid,
+ const std::function<void(std::vector<cryptonote::tx_source_entry> &sources, std::vector<cryptonote::tx_destination_entry> &destinations)> &pre_tx,
+ const std::function<void(cryptonote::transaction &tx)> &post_tx) const;
+
+private:
+ size_t m_invalid_tx_index;
+ size_t m_invalid_block_index;
+};
+
+template<>
+struct get_test_options<gen_rct_tx_validation_base> {
+ const std::pair<uint8_t, uint64_t> hard_forks[2] = {std::make_pair(1, 0), std::make_pair(3, 1)};
+ const cryptonote::test_options test_options = {
+ hard_forks
+ };
+};
+
+// valid
+struct gen_rct_tx_valid_from_pre_rct : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_valid_from_pre_rct>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_valid_from_rct : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_valid_from_rct>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_valid_from_mixed : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_valid_from_mixed>: public get_test_options<gen_rct_tx_validation_base> {};
+
+// altered commitment/dest
+struct gen_rct_tx_pre_rct_bad_real_dest : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_bad_real_dest>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_bad_real_mask : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_bad_real_mask>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_bad_fake_dest : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_bad_fake_dest>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_bad_fake_mask : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_bad_fake_mask>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_bad_real_dest : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_bad_real_dest>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_bad_real_mask : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_bad_real_mask>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_bad_fake_dest : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_bad_fake_dest>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_bad_fake_mask : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_bad_fake_mask>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_spend_with_zero_commit : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_spend_with_zero_commit>: public get_test_options<gen_rct_tx_validation_base> {};
+
+// altered amounts
+struct gen_rct_tx_pre_rct_zero_vin_amount : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_zero_vin_amount>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_non_zero_vin_amount : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_non_zero_vin_amount>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_non_zero_vout_amount : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_non_zero_vout_amount>: public get_test_options<gen_rct_tx_validation_base> {};
+
+// key image
+struct gen_rct_tx_pre_rct_duplicate_key_image : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_duplicate_key_image>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_duplicate_key_image : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_duplicate_key_image>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_wrong_key_image : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_wrong_key_image>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_wrong_key_image : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_wrong_key_image>: public get_test_options<gen_rct_tx_validation_base> {};
+
+// fee
+struct gen_rct_tx_pre_rct_wrong_fee : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_wrong_fee>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_wrong_fee : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_wrong_fee>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_increase_vin_and_fee : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_increase_vin_and_fee>: public get_test_options<gen_rct_tx_validation_base> {};
+
+// modify vin/vout
+struct gen_rct_tx_pre_rct_remove_vin : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_remove_vin>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_remove_vin : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_remove_vin>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_pre_rct_add_vout : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_pre_rct_add_vout>: public get_test_options<gen_rct_tx_validation_base> {};
+
+struct gen_rct_tx_rct_add_vout : public gen_rct_tx_validation_base
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<> struct get_test_options<gen_rct_tx_rct_add_vout>: public get_test_options<gen_rct_tx_validation_base> {};
+