tests compiles
This commit is contained in:
+69
-25
@@ -12,9 +12,10 @@ TimingsDatabase::TimingsDatabase()
|
||||
{
|
||||
}
|
||||
|
||||
TimingsDatabase::TimingsDatabase(const std::string &filename):
|
||||
TimingsDatabase::TimingsDatabase(const std::string &filename, const bool load_previous /*=false*/):
|
||||
filename(filename)
|
||||
{
|
||||
if (load_previous)
|
||||
load();
|
||||
}
|
||||
|
||||
@@ -73,53 +74,96 @@ bool TimingsDatabase::load()
|
||||
{
|
||||
i.deciles.push_back(atoi(fields[idx++].c_str()));
|
||||
}
|
||||
instances.insert(std::make_pair(name, i));
|
||||
instances.emplace_back(name, i);
|
||||
}
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimingsDatabase::save()
|
||||
bool TimingsDatabase::save(const bool save_current_time /*=true*/)
|
||||
{
|
||||
if (filename.empty())
|
||||
if (filename.empty() || instances.empty())
|
||||
return true;
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "w");
|
||||
FILE *f = fopen(filename.c_str(), "a"); // append
|
||||
if (!f)
|
||||
{
|
||||
MERROR("Failed to write to file " << filename << ": " << strerror(errno));
|
||||
return false;
|
||||
}
|
||||
for (const auto &i: instances)
|
||||
|
||||
if (save_current_time)
|
||||
{
|
||||
fprintf(f, "%s", i.first.c_str());
|
||||
fprintf(f, "\t%lu", (unsigned long)i.second.t);
|
||||
fprintf(f, " %zu", i.second.npoints);
|
||||
fprintf(f, " %f", i.second.min);
|
||||
fprintf(f, " %f", i.second.max);
|
||||
fprintf(f, " %f", i.second.mean);
|
||||
fprintf(f, " %f", i.second.median);
|
||||
fprintf(f, " %f", i.second.stddev);
|
||||
fprintf(f, " %f", i.second.npskew);
|
||||
for (uint64_t v: i.second.deciles)
|
||||
fprintf(f, " %lu", (unsigned long)v);
|
||||
// save current time in readable format (UTC)
|
||||
std::time_t sys_time{std::time(nullptr)};
|
||||
std::tm *utc_time = std::gmtime(&sys_time); //GMT is equivalent to UTC
|
||||
|
||||
// format: year-month-day : hour:minute:second
|
||||
std::string current_time{};
|
||||
if (utc_time && sys_time != (std::time_t)(-1))
|
||||
{
|
||||
char timeString[22]; //length = std::size("yyyy-mm-dd : hh:mm:ss") (constexpr std::size is C++17)
|
||||
std::strftime(timeString, 22, "%F : %T", utc_time);
|
||||
current_time += timeString;
|
||||
}
|
||||
else
|
||||
{
|
||||
current_time += "TIME_ERROR_";
|
||||
}
|
||||
fputc('\n', f); // add an extra line before each 'print time'
|
||||
fprintf(f, "%s", current_time.c_str());
|
||||
fputc('\n', f);
|
||||
}
|
||||
|
||||
for (const auto &i: instances)
|
||||
{
|
||||
fprintf(f, "%s,", i.first.c_str());
|
||||
|
||||
if (i.second.npoints > 0)
|
||||
{
|
||||
fprintf(f, "%lu,", (unsigned long)i.second.t);
|
||||
fprintf(f, "%zu,", i.second.npoints);
|
||||
fprintf(f, "%f,", i.second.min);
|
||||
fprintf(f, "%f,", i.second.max);
|
||||
fprintf(f, "%f,", i.second.mean);
|
||||
fprintf(f, "%f,", i.second.median);
|
||||
fprintf(f, "%f,", i.second.stddev);
|
||||
fprintf(f, "%f,", i.second.npskew);
|
||||
for (uint64_t v: i.second.deciles)
|
||||
fprintf(f, "%lu,", (unsigned long)v);
|
||||
|
||||
// note: only add a new line if there are points; assume that 'no points' means i.first is a message meant to be
|
||||
// prepended to the next save operation
|
||||
fputc('\n', f);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
// after saving, clear so next save does not append the same stuff over again
|
||||
instances.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<TimingsDatabase::instance> TimingsDatabase::get(const char *name) const
|
||||
const TimingsDatabase::instance* TimingsDatabase::get_most_recent(const char *name) const
|
||||
{
|
||||
std::vector<instance> ret;
|
||||
auto range = instances.equal_range(name);
|
||||
for (auto i = range.first; i != range.second; ++i)
|
||||
ret.push_back(i->second);
|
||||
std::sort(ret.begin(), ret.end(), [](const instance &e0, const instance &e1){ return e0.t < e1.t; });
|
||||
return ret;
|
||||
time_t latest_time = 0;
|
||||
const TimingsDatabase::instance *instance_ptr = nullptr;
|
||||
|
||||
for (const auto &i: instances)
|
||||
{
|
||||
if (i.first != name)
|
||||
continue;
|
||||
if (i.second.t < latest_time)
|
||||
continue;
|
||||
|
||||
latest_time = i.second.t;
|
||||
instance_ptr = &i.second;
|
||||
}
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
void TimingsDatabase::add(const char *name, const instance &i)
|
||||
{
|
||||
instances.insert(std::make_pair(name, i));
|
||||
instances.emplace_back(name, i);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class TimingsDatabase
|
||||
{
|
||||
@@ -18,17 +18,17 @@ public:
|
||||
|
||||
public:
|
||||
TimingsDatabase();
|
||||
TimingsDatabase(const std::string &filename);
|
||||
TimingsDatabase(const std::string &filename, const bool load_previous = false);
|
||||
~TimingsDatabase();
|
||||
|
||||
std::vector<instance> get(const char *name) const;
|
||||
const instance* get_most_recent(const char *name) const;
|
||||
void add(const char *name, const instance &data);
|
||||
bool save(const bool print_current_time = true);
|
||||
|
||||
private:
|
||||
bool load();
|
||||
bool save();
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
std::multimap<std::string, instance> instances;
|
||||
std::vector<std::pair<std::string, instance>> instances;
|
||||
};
|
||||
|
||||
@@ -496,7 +496,7 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine,
|
||||
subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0,0};
|
||||
cryptonote::origin_data od{3, crypto::null_pkey, 0};
|
||||
rct::salvium_input_data_t sid;
|
||||
generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default")), false, od, sid);
|
||||
generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default")));
|
||||
|
||||
// lookup for this key image in the events vector
|
||||
BOOST_FOREACH(auto& tx_pair, mtx) {
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace
|
||||
auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
|
||||
rct::salvium_input_data_t sid;
|
||||
const cryptonote::origin_data od{3, crypto::null_pkey, src_entr.real_output};
|
||||
generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default")), false, od, sid);
|
||||
generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img, hw::get_device(("default")));
|
||||
|
||||
// put key image into tx input
|
||||
txin_to_key input_to_key;
|
||||
|
||||
@@ -56,8 +56,6 @@ set(performance_tests_headers
|
||||
performance_tests.h
|
||||
performance_utils.h
|
||||
single_tx_test_base.h
|
||||
torsion_ops.h
|
||||
zero_commit.h
|
||||
view_scan.h)
|
||||
|
||||
monero_add_minimal_executable(performance_tests
|
||||
|
||||
@@ -51,6 +51,6 @@ public:
|
||||
crypto::public_key out_key = boost::get<cryptonote::txout_to_key>(m_tx.vout[0].target).key;
|
||||
cryptonote::origin_data od{3,crypto::null_pkey,0};
|
||||
rct::salvium_input_data_t sid;
|
||||
return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki, hw::get_device("default"), false, od, sid);
|
||||
return cryptonote::generate_key_image_helper(m_bob.get_keys(), subaddresses, out_key, m_tx_pub_key, m_additional_tx_pub_keys, 0, in_ephemeral, ki, hw::get_device("default"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2024, 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
|
||||
class test_is_valid_decomposed_amount
|
||||
{
|
||||
public:
|
||||
static const size_t loop_count = 3;
|
||||
static const uint64_t max_per_loop = 1000000000; // must be power of 10
|
||||
|
||||
bool init()
|
||||
{
|
||||
m_num_valid_per_loop = 1;
|
||||
uint64_t x = 1;
|
||||
while (x != max_per_loop)
|
||||
{
|
||||
m_num_valid_per_loop += 9;
|
||||
x *= 10;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test()
|
||||
{
|
||||
size_t num_valid = 0;
|
||||
for (uint64_t a = 0; a <= max_per_loop; ++a)
|
||||
num_valid += cryptonote::is_valid_decomposed_amount(a);
|
||||
return num_valid == m_num_valid_per_loop;
|
||||
}
|
||||
|
||||
size_t m_num_valid_per_loop;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2022, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "generate_keypair.h"
|
||||
#include "signature.h"
|
||||
#include "is_out_to_acc.h"
|
||||
#include "is_valid_decomposed_amount.h"
|
||||
#include "out_can_be_to_acc.h"
|
||||
#include "subaddress_expand.h"
|
||||
#include "sc_reduce32.h"
|
||||
@@ -65,9 +66,9 @@
|
||||
#include "multiexp.h"
|
||||
#include "sig_mlsag.h"
|
||||
#include "sig_clsag.h"
|
||||
#include "torsion_ops.h"
|
||||
// #include "torsion_ops.h"
|
||||
#include "view_scan.h"
|
||||
#include "zero_commit.h"
|
||||
// #include "zero_commit.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
@@ -104,12 +105,14 @@ int main(int argc, char** argv)
|
||||
|
||||
const std::string filter = tools::glob_to_regex(command_line::get_arg(vm, arg_filter));
|
||||
const std::string timings_database = command_line::get_arg(vm, arg_timings_database);
|
||||
Params p;
|
||||
Params core_params;
|
||||
if (!timings_database.empty())
|
||||
p.td = TimingsDatabase(timings_database);
|
||||
p.verbose = command_line::get_arg(vm, arg_verbose);
|
||||
p.stats = command_line::get_arg(vm, arg_stats);
|
||||
p.loop_multiplier = command_line::get_arg(vm, arg_loop_multiplier);
|
||||
core_params.td = TimingsDatabase(timings_database);
|
||||
core_params.verbose = command_line::get_arg(vm, arg_verbose);
|
||||
core_params.stats = command_line::get_arg(vm, arg_stats);
|
||||
core_params.loop_multiplier = command_line::get_arg(vm, arg_loop_multiplier);
|
||||
|
||||
ParamsShuttle p{core_params};
|
||||
|
||||
performance_timer timer;
|
||||
timer.start();
|
||||
@@ -171,24 +174,15 @@ int main(int argc, char** argv)
|
||||
TEST_PERFORMANCE4(filter, p, test_check_tx_signature, 2, 10, true, rct::RangeProofBorromean);
|
||||
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 2, 2, true, rct::RangeProofPaddedBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 2, 2, true, rct::RangeProofMultiOutputBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 10, 2, true, rct::RangeProofPaddedBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 10, 2, true, rct::RangeProofMultiOutputBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 100, 2, true, rct::RangeProofPaddedBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 100, 2, true, rct::RangeProofMultiOutputBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 2, 10, true, rct::RangeProofPaddedBulletproof, 2);
|
||||
TEST_PERFORMANCE5(filter, p, test_check_tx_signature, 2, 10, true, rct::RangeProofMultiOutputBulletproof, 2);
|
||||
|
||||
TEST_PERFORMANCE3(filter, p, test_check_tx_signature_aggregated_bulletproofs, 2, 2, 64);
|
||||
TEST_PERFORMANCE3(filter, p, test_check_tx_signature_aggregated_bulletproofs, 10, 2, 64);
|
||||
TEST_PERFORMANCE3(filter, p, test_check_tx_signature_aggregated_bulletproofs, 100, 2, 64);
|
||||
TEST_PERFORMANCE3(filter, p, test_check_tx_signature_aggregated_bulletproofs, 2, 10, 64);
|
||||
|
||||
TEST_PERFORMANCE4(filter, p, test_check_tx_signature_aggregated_bulletproofs, 2, 2, 62, 4);
|
||||
TEST_PERFORMANCE4(filter, p, test_check_tx_signature_aggregated_bulletproofs, 10, 2, 62, 4);
|
||||
TEST_PERFORMANCE4(filter, p, test_check_tx_signature_aggregated_bulletproofs, 2, 2, 56, 16);
|
||||
TEST_PERFORMANCE4(filter, p, test_check_tx_signature_aggregated_bulletproofs, 10, 2, 56, 16);
|
||||
|
||||
TEST_PERFORMANCE4(filter, p, test_check_hash, 0, 1, 0, 1);
|
||||
TEST_PERFORMANCE4(filter, p, test_check_hash, 0, 0xffffffffffffffff, 0, 0xffffffffffffffff);
|
||||
TEST_PERFORMANCE4(filter, p, test_check_hash, 0, 0xffffffffffffffff, 0, 1);
|
||||
@@ -219,6 +213,10 @@ int main(int argc, char** argv)
|
||||
TEST_PERFORMANCE0(filter, p, test_generate_key_image);
|
||||
TEST_PERFORMANCE0(filter, p, test_derive_public_key);
|
||||
TEST_PERFORMANCE0(filter, p, test_derive_secret_key);
|
||||
// TEST_PERFORMANCE1(filter, p, test_fe_batch_invert, true); // batched
|
||||
// TEST_PERFORMANCE1(filter, p, test_fe_batch_invert, false); // individual inversions
|
||||
// TEST_PERFORMANCE1(filter, p, test_torsion_ops, true); // check for torsion
|
||||
// TEST_PERFORMANCE1(filter, p, test_torsion_ops, false); // clear torsion
|
||||
TEST_PERFORMANCE0(filter, p, test_ge_frombytes_vartime);
|
||||
TEST_PERFORMANCE0(filter, p, test_ge_tobytes);
|
||||
TEST_PERFORMANCE0(filter, p, test_generate_keypair);
|
||||
@@ -230,6 +228,8 @@ int main(int argc, char** argv)
|
||||
|
||||
TEST_PERFORMANCE2(filter, p, test_wallet2_expand_subaddresses, 50, 200);
|
||||
|
||||
TEST_PERFORMANCE0(filter, p, test_is_valid_decomposed_amount);
|
||||
|
||||
TEST_PERFORMANCE1(filter, p, test_cn_slow_hash, 0);
|
||||
TEST_PERFORMANCE1(filter, p, test_cn_slow_hash, 1);
|
||||
TEST_PERFORMANCE1(filter, p, test_cn_slow_hash, 2);
|
||||
@@ -613,6 +613,9 @@ int main(int argc, char** argv)
|
||||
TEST_PERFORMANCE3(filter, p, test_multiexp, multiexp_pippenger, 4096, 9);
|
||||
#endif
|
||||
|
||||
// TEST_PERFORMANCE1(filter, p, test_zero_commit, true); // fast
|
||||
// TEST_PERFORMANCE1(filter, p, test_zero_commit, false);
|
||||
|
||||
std::cout << "Tests finished. Elapsed time: " << timer.elapsed_ms() / 1000 << " sec" << std::endl;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2022, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -31,6 +31,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/chrono.hpp>
|
||||
@@ -41,7 +43,7 @@
|
||||
#include "common/perf_timer.h"
|
||||
#include "common/timings.h"
|
||||
|
||||
class performance_timer
|
||||
class performance_timer final
|
||||
{
|
||||
public:
|
||||
typedef boost::chrono::high_resolution_clock clock;
|
||||
@@ -67,7 +69,7 @@ private:
|
||||
clock::time_point m_start;
|
||||
};
|
||||
|
||||
struct Params
|
||||
struct Params final
|
||||
{
|
||||
TimingsDatabase td;
|
||||
bool verbose;
|
||||
@@ -75,45 +77,79 @@ struct Params
|
||||
unsigned loop_multiplier;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class test_runner
|
||||
struct ParamsShuttle
|
||||
{
|
||||
Params core_params;
|
||||
|
||||
ParamsShuttle() = default;
|
||||
|
||||
ParamsShuttle(Params ¶ms) : core_params{params}
|
||||
{}
|
||||
|
||||
virtual ~ParamsShuttle() = default; // virtual for non-final type
|
||||
};
|
||||
|
||||
template <typename T, typename ParamsT,
|
||||
typename std::enable_if<!std::is_same<ParamsT, ParamsShuttle>::value, bool>::type = true>
|
||||
bool init_test(T &test, ParamsT ¶ms_shuttle)
|
||||
{
|
||||
// assume if the params shuttle isn't the base shuttle type, then the test must take the shuttle as an input on init
|
||||
if (!test.init(params_shuttle))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename ParamsT,
|
||||
typename std::enable_if<std::is_same<ParamsT, ParamsShuttle>::value, bool>::type = true>
|
||||
bool init_test(T &test, ParamsT ¶ms_shuttle)
|
||||
{
|
||||
if (!test.init())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename ParamsT>
|
||||
class test_runner final
|
||||
{
|
||||
public:
|
||||
test_runner(const Params ¶ms)
|
||||
test_runner(const ParamsT ¶ms_shuttle)
|
||||
: m_elapsed(0)
|
||||
, m_params(params)
|
||||
, m_per_call_timers(T::loop_count * params.loop_multiplier, {true})
|
||||
, m_params_shuttle(params_shuttle)
|
||||
, m_core_params(params_shuttle.core_params)
|
||||
, m_per_call_timers(T::loop_count * params_shuttle.core_params.loop_multiplier, {true})
|
||||
{
|
||||
}
|
||||
|
||||
bool run()
|
||||
int run()
|
||||
{
|
||||
static_assert(0 < T::loop_count, "T::loop_count must be greater than 0");
|
||||
|
||||
T test;
|
||||
if (!test.init())
|
||||
return false;
|
||||
if (!init_test(test, m_params_shuttle))
|
||||
return -1;
|
||||
|
||||
performance_timer timer;
|
||||
timer.start();
|
||||
warm_up();
|
||||
if (m_params.verbose)
|
||||
if (m_core_params.verbose)
|
||||
std::cout << "Warm up: " << timer.elapsed_ms() << " ms" << std::endl;
|
||||
|
||||
timer.start();
|
||||
for (size_t i = 0; i < T::loop_count * m_params.loop_multiplier; ++i)
|
||||
for (size_t i = 0; i < T::loop_count * m_core_params.loop_multiplier; ++i)
|
||||
{
|
||||
if (m_params.stats)
|
||||
if (m_core_params.stats)
|
||||
m_per_call_timers[i].resume();
|
||||
if (!test.test())
|
||||
return false;
|
||||
if (m_params.stats)
|
||||
return i + 1;
|
||||
if (m_core_params.stats)
|
||||
m_per_call_timers[i].pause();
|
||||
}
|
||||
m_elapsed = timer.elapsed_ms();
|
||||
m_stats.reset(new Stats<tools::PerformanceTimer, uint64_t>(m_per_call_timers));
|
||||
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int elapsed_time() const { return m_elapsed; }
|
||||
@@ -122,7 +158,7 @@ public:
|
||||
int time_per_call(int scale = 1) const
|
||||
{
|
||||
static_assert(0 < T::loop_count, "T::loop_count must be greater than 0");
|
||||
return m_elapsed * scale / (T::loop_count * m_params.loop_multiplier);
|
||||
return m_elapsed * scale / (T::loop_count * m_core_params.loop_multiplier);
|
||||
}
|
||||
|
||||
uint64_t get_min() const { return m_stats->get_min(); }
|
||||
@@ -156,20 +192,25 @@ private:
|
||||
private:
|
||||
volatile uint64_t m_warm_up; ///<! This field is intended for preclude compiler optimizations
|
||||
int m_elapsed;
|
||||
Params m_params;
|
||||
Params m_core_params;
|
||||
ParamsT m_params_shuttle;
|
||||
std::vector<tools::PerformanceTimer> m_per_call_timers;
|
||||
std::unique_ptr<Stats<tools::PerformanceTimer, uint64_t>> m_stats;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void run_test(const std::string &filter, Params ¶ms, const char* test_name)
|
||||
template <typename T, typename ParamsT>
|
||||
bool run_test(const std::string &filter, ParamsT ¶ms_shuttle, const char* test_name)
|
||||
{
|
||||
static_assert(std::is_base_of<ParamsShuttle, ParamsT>::value, "Must use a ParamsShuttle.");
|
||||
Params ¶ms = params_shuttle.core_params;
|
||||
|
||||
boost::smatch match;
|
||||
if (!filter.empty() && !boost::regex_match(std::string(test_name), match, boost::regex(filter)))
|
||||
return;
|
||||
return true;
|
||||
|
||||
test_runner<T> runner(params);
|
||||
if (runner.run())
|
||||
test_runner<T, ParamsT> runner(params_shuttle);
|
||||
int run_result{runner.run()};
|
||||
if (run_result == 0)
|
||||
{
|
||||
if (params.verbose)
|
||||
{
|
||||
@@ -208,7 +249,7 @@ void run_test(const std::string &filter, Params ¶ms, const char* test_name)
|
||||
double stddev = runner.get_stddev();
|
||||
double npskew = runner.get_non_parametric_skew();
|
||||
|
||||
std::vector<TimingsDatabase::instance> prev_instances = params.td.get(test_name);
|
||||
const TimingsDatabase::instance* prev_instance = params.td.get_most_recent(test_name);
|
||||
params.td.add(test_name, {time(NULL), runner.get_size(), min, max, mean, med, stddev, npskew, quantiles});
|
||||
|
||||
std::cout << (params.verbose ? " time per call: " : " ") << time_per_call << " " << unit << "/call" << (params.verbose ? "\n" : "");
|
||||
@@ -219,24 +260,31 @@ void run_test(const std::string &filter, Params ¶ms, const char* test_name)
|
||||
uint64_t p95s = quantiles[9] / scale;
|
||||
uint64_t stddevs = stddev / scale;
|
||||
std::string cmp;
|
||||
if (!prev_instances.empty())
|
||||
if (prev_instance)
|
||||
{
|
||||
const TimingsDatabase::instance &prev_instance = prev_instances.back();
|
||||
if (!runner.is_same_distribution(prev_instance.npoints, prev_instance.mean, prev_instance.stddev))
|
||||
if (!runner.is_same_distribution(prev_instance->npoints, prev_instance->mean, prev_instance->stddev))
|
||||
{
|
||||
double pc = fabs(100. * (prev_instance.mean - runner.get_mean()) / prev_instance.mean);
|
||||
cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance.mean ? "slower" : "faster");
|
||||
double pc = fabs(100. * (prev_instance->mean - runner.get_mean()) / prev_instance->mean);
|
||||
cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance->mean ? "slower" : "faster");
|
||||
}
|
||||
cmp += " -- " + std::to_string(prev_instance.mean);
|
||||
cmp += " -- " + std::to_string(prev_instance->mean);
|
||||
}
|
||||
std::cout << " (min " << mins << " " << unit << ", 90th " << p95s << " " << unit << ", median " << meds << " " << unit << ", std dev " << stddevs << " " << unit << ")" << cmp;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
else if (run_result == -1)
|
||||
{
|
||||
std::cout << test_name << " - FAILED ON INIT" << std::endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << test_name << " - FAILED" << std::endl;
|
||||
std::cout << test_name << " - FAILED ON TEST LOOP " << run_result << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define QUOTEME(x) #x
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2022, The Monero Project
|
||||
// Copyright (c) 2017-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
|
||||
@@ -57,7 +57,6 @@ set(unit_tests_sources
|
||||
epee_utils.cpp
|
||||
expect.cpp
|
||||
fee.cpp
|
||||
fake_pruned_blockchain.cpp
|
||||
json_serialization.cpp
|
||||
check_output_types.cpp
|
||||
protocol_tx.cpp
|
||||
|
||||
@@ -119,7 +119,7 @@ TEST(account, derive_output_key)
|
||||
hw::device *hw = &hw::get_device("default");
|
||||
|
||||
ASSERT_TRUE(hw->generate_key_derivation(txkey.first, secret_view_key, derivation));
|
||||
ASSERT_TRUE(is_out_to_acc_precomp(subaddresses, txkey.second, derivation, {}, 0, *hw, boost::none));
|
||||
ASSERT_TRUE(is_out_to_acc_precomp(subaddresses, txkey.second, derivation, std::vector<crypto::key_derivation>(), 0, *hw, boost::none));
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
@@ -1559,7 +1559,7 @@ static void get_coinbase_output_proposal_janus_attack_v1(const JanusAttackPropos
|
||||
s_sender_receiver);
|
||||
|
||||
// 8. C_a = G + a H
|
||||
const rct::key amount_commitment = rct::zeroCommitVartime(proposal.normal.amount);
|
||||
const rct::key amount_commitment = rct::zeroCommit(proposal.normal.amount);
|
||||
|
||||
// 9. Ko = K^i_s + K^o_ext = K^i_s + (k^o_g G + k^o_t T)
|
||||
make_carrot_onetime_address(proposal.readjusted_opening_subaddress_spend_pubkey,
|
||||
|
||||
@@ -61,11 +61,6 @@ TEST(check_output_types, check_all)
|
||||
tx.vout.clear();
|
||||
|
||||
// should only allow txout_to_key or txout_to_tagged_key output types
|
||||
txout_to_script tx_out_script;
|
||||
tx.vout.push_back(tx_out {0, tx_out_script});
|
||||
EXPECT_FALSE(check_output_types(tx, hf_version));
|
||||
tx.vout.clear();
|
||||
|
||||
txout_to_scripthash tx_out_scripthash;
|
||||
tx.vout.push_back(tx_out {0, tx_out_scripthash});
|
||||
EXPECT_FALSE(check_output_types(tx, hf_version));
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/merge_mining.h"
|
||||
#include "string_tools.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
+160
-42
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2022, The Monero Project
|
||||
// Copyright (c) 2017-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -43,24 +43,24 @@ static const struct
|
||||
} test_addresses[] =
|
||||
{
|
||||
{
|
||||
"SaLvTyLhZmEeWVwtKBH6j5Fpmanj1t3ah1qQ2tScWFyqDFg6i1bEDw7eMP2NGbNthmS7v8jUK1riz2Sh6R6PEK2kTHGxpcFJb6B2f",
|
||||
"468f7d5b698a6b14292be554886c0161416e241343f87b73786bb93a90d4a30d"
|
||||
"9uvjbU54ZJb8j7Dcq1h3F1DnBRkxXdYUX4pbJ7mE3ghM8uF3fKzqRKRNAKYZXcNLqMg7MxjVVD2wKC2PALUwEveGSC3YSWD",
|
||||
"2dd6e34a234c3e8b5d29a371789e4601e96dee4ea6f7ef79224d1a2d91164c01"
|
||||
},
|
||||
{
|
||||
"SaLvTyLmuEiATd9jLTjBkKAaapqEgn1JqTHkri8m9g4oT35TbQyi5vjjaX31j1szBtErUDHE9HG3JC4wQEx7k84QMGyAMms6tUp3m",
|
||||
"d11819f2dd837c901371aaba30392a7014d1b634dfbf2d0c24ee302fee60f004"
|
||||
"9ywDBAyDbb6QKFiZxDJ4hHZqZEQXXCR5EaYNcndUpqPDeE7rEgs6neQdZnhcDrWbURYK8xUjhuG2mVjJdmknrZbcG7NnbaB",
|
||||
"fac47aecc948ce9d3531aa042abb18235b1df632087c55a361b632ffdd6ede0c"
|
||||
},
|
||||
{
|
||||
"SaLvTyLBwuJ1EPjNJ86Ezv1PDo5bLAbFcSobs9LU9it88nHNsd7XTtWMBxLNAgERE7Lz5CxyhYfeRK2TZs5AGpW7XoTZT3TAioR37",
|
||||
"27d90aad7db5026751c3fb12c7b7ddc137844b720ed446bca91092704456950f"
|
||||
"9t6Hn946u3eah5cuncH1hB5hGzsTUoevtf4SY7MHN5NgJZh2SFWsyVt3vUhuHyRKyrCQvr71Lfc1AevG3BXE11PQFoXDtD8",
|
||||
"bbd3175ef9fd9f5eefdc43035f882f74ad14c4cf1799d8b6f9001bc197175d02"
|
||||
},
|
||||
{
|
||||
"SaLvTyLVzqUUo2RdEWLX8jZgif7wJL5SWg4PvkBmkynFR6sqc3kNmAtjjzVUH8J73yfjceR5ZhbDmhRQYtrrej4KJLGMSAgS8t236",
|
||||
"113c262c9621ded1a55a2ff4d22d7a26cd25a444532daa018795ff257b690b0a"
|
||||
"9zmAWoNyNPbgnYSm3nJNpAKHm6fCcs3MR94gBWxp9MCDUiMUhyYFfyQETUDLPF7DP6ZsmNo6LRxwPP9VmhHNxKrER9oGigT",
|
||||
"f2efae45bef1917a7430cda8fcffc4ee010e3178761aa41d4628e23b1fe2d501"
|
||||
},
|
||||
{
|
||||
"SaLvTyLQAH4U9sgB7vT5Na9X5UrHsf5Fp6eFpkQQ1wQyg7gRyKoiXCQ4HA8Fmg6xqdhtDWcWmrbfyTcGNPRJokqiJpkMsVpicdK1R",
|
||||
"5c3f39f8a5f05c928cddcadcdd56854e2068be7020450a5f3404ae4782e5f907"
|
||||
"9ue8NJMg3WzKxTtmjeXzWYF5KmU6dC7LHEt9wvYdPn2qMmoFUa8hJJHhSHvJ46UEwpDyy5jSboNMRaDBKwU54NT42YcNUp5",
|
||||
"a4cef54ed3fd61cd78a2ceb82ecf85a903ad2db9a86fb77ff56c35c56016280a"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -149,6 +149,7 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
|
||||
std::unordered_set<crypto::secret_key> unique_privkeys;
|
||||
rct::key composite_pubkey = rct::identity();
|
||||
|
||||
ASSERT_TRUE(wallets.size() > 0);
|
||||
wallets[0].decrypt_keys("");
|
||||
crypto::public_key spend_pubkey = wallets[0].get_account().get_keys().m_account_address.m_spend_public_key;
|
||||
crypto::secret_key view_privkey = wallets[0].get_account().get_keys().m_view_secret_key;
|
||||
@@ -156,32 +157,48 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
|
||||
EXPECT_TRUE(crypto::secret_key_to_public_key(view_privkey, view_pubkey));
|
||||
wallets[0].encrypt_keys("");
|
||||
|
||||
for (size_t i = 0; i < wallets.size(); ++i)
|
||||
// at the end of multisig kex, all wallets should emit a post-kex message with the same two pubkeys
|
||||
std::vector<crypto::public_key> post_kex_msg_pubkeys;
|
||||
ASSERT_TRUE(intermediate_infos.size() == wallets.size());
|
||||
for (const std::string &intermediate_info : intermediate_infos)
|
||||
{
|
||||
EXPECT_TRUE(!intermediate_infos[i].empty());
|
||||
bool ready;
|
||||
uint32_t threshold, total;
|
||||
EXPECT_TRUE(wallets[i].multisig(&ready, &threshold, &total));
|
||||
EXPECT_TRUE(ready);
|
||||
EXPECT_TRUE(threshold == M);
|
||||
EXPECT_TRUE(total == wallets.size());
|
||||
multisig::multisig_kex_msg post_kex_msg;
|
||||
EXPECT_TRUE(!intermediate_info.empty());
|
||||
EXPECT_NO_THROW(post_kex_msg = intermediate_info);
|
||||
|
||||
wallets[i].decrypt_keys("");
|
||||
if (post_kex_msg_pubkeys.size() != 0)
|
||||
EXPECT_TRUE(post_kex_msg_pubkeys == post_kex_msg.get_msg_pubkeys()); //assumes sorting is always the same
|
||||
else
|
||||
post_kex_msg_pubkeys = post_kex_msg.get_msg_pubkeys();
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
// "equals" is transitive relation so we need only to compare first wallet's address to each others' addresses.
|
||||
// no need to compare 0's address with itself.
|
||||
EXPECT_TRUE(wallets[0].get_account().get_public_address_str(cryptonote::TESTNET) ==
|
||||
wallets[i].get_account().get_public_address_str(cryptonote::TESTNET));
|
||||
|
||||
EXPECT_EQ(spend_pubkey, wallets[i].get_account().get_keys().m_account_address.m_spend_public_key);
|
||||
EXPECT_EQ(view_privkey, wallets[i].get_account().get_keys().m_view_secret_key);
|
||||
EXPECT_EQ(view_pubkey, wallets[i].get_account().get_keys().m_account_address.m_view_public_key);
|
||||
EXPECT_TRUE(post_kex_msg_pubkeys.size() == 2);
|
||||
}
|
||||
|
||||
// the post-kex pubkeys should equal the account's public view and spend keys
|
||||
EXPECT_TRUE(std::find(post_kex_msg_pubkeys.begin(), post_kex_msg_pubkeys.end(), spend_pubkey) != post_kex_msg_pubkeys.end());
|
||||
EXPECT_TRUE(std::find(post_kex_msg_pubkeys.begin(), post_kex_msg_pubkeys.end(), view_pubkey) != post_kex_msg_pubkeys.end());
|
||||
|
||||
// each wallet should have the same state (private view key, public spend key), and the public spend key should be
|
||||
// reproducible from the private spend keys found in each account
|
||||
for (tools::wallet2 &wallet : wallets)
|
||||
{
|
||||
wallet.decrypt_keys("");
|
||||
const multisig::multisig_account_status ms_status{wallet.get_multisig_status()};
|
||||
EXPECT_TRUE(ms_status.multisig_is_active);
|
||||
EXPECT_TRUE(ms_status.kex_is_done);
|
||||
EXPECT_TRUE(ms_status.is_ready);
|
||||
EXPECT_TRUE(ms_status.threshold == M);
|
||||
EXPECT_TRUE(ms_status.total == wallets.size());
|
||||
|
||||
EXPECT_TRUE(wallets[0].get_account().get_public_address_str(cryptonote::TESTNET) ==
|
||||
wallet.get_account().get_public_address_str(cryptonote::TESTNET));
|
||||
|
||||
EXPECT_EQ(spend_pubkey, wallet.get_account().get_keys().m_account_address.m_spend_public_key);
|
||||
EXPECT_EQ(view_privkey, wallet.get_account().get_keys().m_view_secret_key);
|
||||
EXPECT_EQ(view_pubkey, wallet.get_account().get_keys().m_account_address.m_view_public_key);
|
||||
|
||||
// sum together unique multisig keys
|
||||
for (const auto &privkey : wallets[i].get_account().get_keys().m_multisig_keys)
|
||||
for (const auto &privkey : wallet.get_account().get_keys().m_multisig_keys)
|
||||
{
|
||||
EXPECT_NE(privkey, crypto::null_skey);
|
||||
|
||||
@@ -189,17 +206,17 @@ static void check_results(const std::vector<std::string> &intermediate_infos,
|
||||
{
|
||||
unique_privkeys.insert(privkey);
|
||||
crypto::public_key pubkey;
|
||||
crypto::secret_key_to_public_key(privkey, pubkey);
|
||||
EXPECT_TRUE(crypto::secret_key_to_public_key(privkey, pubkey));
|
||||
EXPECT_NE(privkey, crypto::null_skey);
|
||||
EXPECT_NE(pubkey, crypto::null_pkey);
|
||||
EXPECT_NE(pubkey, rct::rct2pk(rct::identity()));
|
||||
rct::addKeys(composite_pubkey, composite_pubkey, rct::pk2rct(pubkey));
|
||||
}
|
||||
}
|
||||
wallets[i].encrypt_keys("");
|
||||
wallet.encrypt_keys("");
|
||||
}
|
||||
|
||||
// final key via sums should equal the wallets' public spend key
|
||||
// final key via sum of privkeys should equal the wallets' public spend key
|
||||
wallets[0].decrypt_keys("");
|
||||
EXPECT_EQ(wallets[0].get_account().get_keys().m_account_address.m_spend_public_key, rct::rct2pk(composite_pubkey));
|
||||
wallets[0].encrypt_keys("");
|
||||
@@ -226,10 +243,8 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool
|
||||
}
|
||||
|
||||
// wallets should not be multisig yet
|
||||
for (const auto &wallet: wallets)
|
||||
{
|
||||
ASSERT_FALSE(wallet.multisig());
|
||||
}
|
||||
for (const auto& wallet: wallets)
|
||||
ASSERT_FALSE(wallet.get_multisig_status().multisig_is_active);
|
||||
|
||||
// make wallets multisig, get second round kex messages (if appropriate)
|
||||
std::vector<std::string> intermediate_infos(wallets.size());
|
||||
@@ -242,16 +257,15 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool
|
||||
++rounds_complete;
|
||||
|
||||
// perform kex rounds until kex is complete
|
||||
bool ready;
|
||||
wallets[0].multisig(&ready);
|
||||
while (!ready)
|
||||
multisig::multisig_account_status ms_status{wallets[0].get_multisig_status()};
|
||||
while (!ms_status.is_ready)
|
||||
{
|
||||
if (force_update)
|
||||
intermediate_infos = exchange_round_force_update(wallets, intermediate_infos, rounds_complete + 1);
|
||||
else
|
||||
intermediate_infos = exchange_round(wallets, intermediate_infos);
|
||||
|
||||
wallets[0].multisig(&ready);
|
||||
ms_status = wallets[0].get_multisig_status();
|
||||
++rounds_complete;
|
||||
}
|
||||
|
||||
@@ -260,6 +274,104 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool
|
||||
check_results(intermediate_infos, wallets, M);
|
||||
}
|
||||
|
||||
static void make_wallets_boosting(std::vector<tools::wallet2>& wallets, unsigned int M)
|
||||
{
|
||||
ASSERT_TRUE(wallets.size() > 1 && wallets.size() <= KEYS_COUNT);
|
||||
ASSERT_TRUE(M <= wallets.size());
|
||||
std::uint32_t kex_rounds_required = multisig::multisig_kex_rounds_required(wallets.size(), M);
|
||||
std::uint32_t rounds_required = multisig::multisig_setup_rounds_required(wallets.size(), M);
|
||||
std::uint32_t rounds_complete{0};
|
||||
|
||||
// initialize wallets, get first round multisig kex msgs
|
||||
std::vector<std::string> initial_infos(wallets.size());
|
||||
|
||||
for (size_t i = 0; i < wallets.size(); ++i)
|
||||
{
|
||||
make_wallet(i, wallets[i]);
|
||||
|
||||
wallets[i].decrypt_keys("");
|
||||
initial_infos[i] = wallets[i].get_multisig_first_kex_msg();
|
||||
wallets[i].encrypt_keys("");
|
||||
}
|
||||
|
||||
// wallets should not be multisig yet
|
||||
for (const auto &wallet: wallets)
|
||||
{
|
||||
const multisig::multisig_account_status ms_status{wallet.get_multisig_status()};
|
||||
ASSERT_FALSE(ms_status.multisig_is_active);
|
||||
}
|
||||
|
||||
// get round 2 booster messages for wallet0 (if appropriate)
|
||||
auto initial_infos_truncated = initial_infos;
|
||||
initial_infos_truncated.erase(initial_infos_truncated.begin());
|
||||
|
||||
std::vector<std::string> wallet0_booster_infos;
|
||||
wallet0_booster_infos.reserve(wallets.size() - 1);
|
||||
|
||||
if (rounds_complete + 1 < kex_rounds_required)
|
||||
{
|
||||
for (size_t i = 1; i < wallets.size(); ++i)
|
||||
{
|
||||
wallet0_booster_infos.push_back(
|
||||
wallets[i].get_multisig_key_exchange_booster("", initial_infos_truncated, M, wallets.size())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// make wallets multisig
|
||||
std::vector<std::string> intermediate_infos(wallets.size());
|
||||
|
||||
for (size_t i = 0; i < wallets.size(); ++i)
|
||||
intermediate_infos[i] = wallets[i].make_multisig("", initial_infos, M);
|
||||
|
||||
++rounds_complete;
|
||||
|
||||
// perform all kex rounds
|
||||
// boost wallet0 each round, so wallet0 is always 1 round ahead
|
||||
std::string wallet0_intermediate_info;
|
||||
std::vector<std::string> new_infos(intermediate_infos.size());
|
||||
multisig::multisig_account_status ms_status{wallets[0].get_multisig_status()};
|
||||
while (!ms_status.is_ready)
|
||||
{
|
||||
// use booster infos to update wallet0 'early'
|
||||
if (rounds_complete < kex_rounds_required)
|
||||
new_infos[0] = wallets[0].exchange_multisig_keys("", wallet0_booster_infos);
|
||||
else
|
||||
{
|
||||
// force update the post-kex round with wallet0's post-kex message since wallet0 is 'ahead' of the other wallets
|
||||
wallet0_booster_infos = {wallets[0].exchange_multisig_keys("", {})};
|
||||
new_infos[0] = wallets[0].exchange_multisig_keys("", wallet0_booster_infos, true);
|
||||
}
|
||||
|
||||
// get wallet0 booster infos for next round
|
||||
if (rounds_complete + 1 < kex_rounds_required)
|
||||
{
|
||||
// remove wallet0 info for this round (so boosters have incomplete kex message set)
|
||||
auto intermediate_infos_truncated = intermediate_infos;
|
||||
intermediate_infos_truncated.erase(intermediate_infos_truncated.begin());
|
||||
|
||||
// obtain booster messages from all other wallets
|
||||
for (size_t i = 1; i < wallets.size(); ++i)
|
||||
{
|
||||
wallet0_booster_infos[i-1] =
|
||||
wallets[i].get_multisig_key_exchange_booster("", intermediate_infos_truncated, M, wallets.size());
|
||||
}
|
||||
}
|
||||
|
||||
// update other wallets
|
||||
for (size_t i = 1; i < wallets.size(); ++i)
|
||||
new_infos[i] = wallets[i].exchange_multisig_keys("", intermediate_infos);
|
||||
|
||||
intermediate_infos = new_infos;
|
||||
++rounds_complete;
|
||||
ms_status = wallets[0].get_multisig_status();
|
||||
}
|
||||
|
||||
EXPECT_EQ(rounds_required, rounds_complete);
|
||||
|
||||
check_results(intermediate_infos, wallets, M);
|
||||
}
|
||||
|
||||
TEST(multisig, make_1_2)
|
||||
{
|
||||
make_wallets(1, 2, false);
|
||||
@@ -296,6 +408,12 @@ TEST(multisig, make_2_4)
|
||||
make_wallets(2, 4, true);
|
||||
}
|
||||
|
||||
TEST(multisig, make_2_4_boosting)
|
||||
{
|
||||
std::vector<tools::wallet2> wallets(4);
|
||||
make_wallets_boosting(wallets, 2);
|
||||
}
|
||||
|
||||
TEST(multisig, multisig_kex_msg)
|
||||
{
|
||||
using namespace multisig;
|
||||
|
||||
@@ -120,7 +120,7 @@ bool construct_miner_tx_fake_reward_1out(const size_t height,
|
||||
crypto::derive_view_tag(derivation, local_output_index, view_tag);
|
||||
|
||||
cryptonote::tx_out out;
|
||||
cryptonote::set_tx_out(reward, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
cryptonote::set_tx_out(reward, "SAL", 0, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
@@ -171,7 +171,7 @@ cryptonote::tx_source_entry gen_tx_source_entry_fake_members(
|
||||
continue;
|
||||
used_indices.insert(global_output_index);
|
||||
const rct::ctkey output_pair{rct::pkGen(),
|
||||
in.is_rct ? rct::pkGen() : rct::zeroCommitVartime(in.amount)};
|
||||
in.is_rct ? rct::pkGen() : rct::zeroCommit(in.amount)};
|
||||
res.outputs.push_back({global_output_index, output_pair});
|
||||
}
|
||||
// sort by index
|
||||
@@ -214,29 +214,6 @@ cryptonote::transaction construct_pre_carrot_tx_with_fake_inputs(
|
||||
switch (hf_version)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case HF_VERSION_DYNAMIC_FEE:
|
||||
case 5:
|
||||
case HF_VERSION_MIN_MIXIN_4:
|
||||
case 7:
|
||||
rct_config = { rct::RangeProofBorromean, 0 };
|
||||
break;
|
||||
case HF_VERSION_PER_BYTE_FEE:
|
||||
case 9:
|
||||
rct_config = { rct::RangeProofPaddedBulletproof, 1 };
|
||||
break;
|
||||
case HF_VERSION_SMALLER_BP:
|
||||
case 11:
|
||||
case HF_VERSION_MIN_2_OUTPUTS:
|
||||
rct_config = { rct::RangeProofPaddedBulletproof, 2 };
|
||||
break;
|
||||
case HF_VERSION_CLSAG:
|
||||
case 14:
|
||||
rct_config = { rct::RangeProofPaddedBulletproof, 3 };
|
||||
break;
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case 16:
|
||||
rct_config = { rct::RangeProofPaddedBulletproof, 4 };
|
||||
break;
|
||||
default:
|
||||
@@ -334,18 +311,23 @@ cryptonote::transaction construct_pre_carrot_tx_with_fake_inputs(
|
||||
"failed to add nonce to tx_extra");
|
||||
}
|
||||
|
||||
fcmp_pp::ProofParams dummy_fcmp_params;
|
||||
// fcmp_pp::ProofParams dummy_fcmp_params;
|
||||
const bool r = cryptonote::construct_tx_and_get_tx_key(
|
||||
sender_account_keys,
|
||||
sender_subaddress_map,
|
||||
sources,
|
||||
destinations,
|
||||
1,
|
||||
"SAL",
|
||||
"SAL",
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_addr,
|
||||
extra,
|
||||
tx,
|
||||
0,
|
||||
main_tx_privkey_out,
|
||||
additional_tx_privkeys_out,
|
||||
dummy_fcmp_params,
|
||||
// dummy_fcmp_params,
|
||||
rct,
|
||||
rct_config,
|
||||
use_view_tags);
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#include "carrot_impl/address_device_ram_borrowed.h"
|
||||
#include "carrot_mock_helpers.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "fake_pruned_blockchain.h"
|
||||
#include "fcmp_pp/prove.h"
|
||||
// #include "fake_pruned_blockchain.h"
|
||||
// #include "fcmp_pp/prove.h"
|
||||
#include "tx_construction_helpers.h"
|
||||
#include "wallet/tx_builder.h"
|
||||
|
||||
@@ -54,7 +54,7 @@ TEST(wallet_scanning, view_scan_as_sender_mainaddr)
|
||||
|
||||
const rct::xmr_amount fee = 565678;
|
||||
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_FCMP_PLUS_PLUS; ++hf_version)
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_CARROT; ++hf_version)
|
||||
{
|
||||
MDEBUG("view_scan_as_sender_mainaddr: hf_version=" << static_cast<int>(hf_version));
|
||||
|
||||
@@ -123,7 +123,7 @@ TEST(wallet_scanning, view_scan_long_payment_id)
|
||||
|
||||
const crypto::hash payment_id = crypto::rand<crypto::hash>();
|
||||
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_FCMP_PLUS_PLUS; ++hf_version)
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_CARROT; ++hf_version)
|
||||
{
|
||||
MDEBUG("view_scan_as_sender_mainaddr: hf_version=" << static_cast<int>(hf_version));
|
||||
|
||||
@@ -201,7 +201,7 @@ TEST(wallet_scanning, view_scan_short_payment_id)
|
||||
ASSERT_FALSE(tools::wallet::is_long_payment_id(payment_id));
|
||||
ASSERT_NE(crypto::null_hash, payment_id);
|
||||
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_FCMP_PLUS_PLUS; ++hf_version)
|
||||
for (uint8_t hf_version = 1; hf_version < HF_VERSION_CARROT; ++hf_version)
|
||||
{
|
||||
MDEBUG("view_scan_as_sender_mainaddr: hf_version=" << static_cast<int>(hf_version));
|
||||
|
||||
@@ -257,416 +257,416 @@ TEST(wallet_scanning, view_scan_short_payment_id)
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_scanning, positive_smallout_main_addr_all_types_outputs)
|
||||
{
|
||||
// Test that wallet can scan and recover enotes of following type:
|
||||
// a. pre-ringct coinbase
|
||||
// b. pre-ringct
|
||||
// c. ringct coinbase
|
||||
// d. ringct long-amount
|
||||
// e. ringct short-amount
|
||||
// f. view-tagged ringct coinbase
|
||||
// g. view-tagged pre-ringct (only possible in unmixable sweep txs)
|
||||
// h. view-tagged ringct
|
||||
// i. carrot v1 coinbase
|
||||
// j. carrot v1 normal
|
||||
// k. carrot v1 special
|
||||
// l. carrot v1 internal (@TODO)
|
||||
//
|
||||
// All enotes are addressed to the main address in 2-out noin-coinbase txs or 1-out coinbase txs.
|
||||
// We also don't test reorgs here.
|
||||
// TEST(wallet_scanning, positive_smallout_main_addr_all_types_outputs)
|
||||
// {
|
||||
// // Test that wallet can scan and recover enotes of following type:
|
||||
// // a. pre-ringct coinbase
|
||||
// // b. pre-ringct
|
||||
// // c. ringct coinbase
|
||||
// // d. ringct long-amount
|
||||
// // e. ringct short-amount
|
||||
// // f. view-tagged ringct coinbase
|
||||
// // g. view-tagged pre-ringct (only possible in unmixable sweep txs)
|
||||
// // h. view-tagged ringct
|
||||
// // i. carrot v1 coinbase
|
||||
// // j. carrot v1 normal
|
||||
// // k. carrot v1 special
|
||||
// // l. carrot v1 internal (@TODO)
|
||||
// //
|
||||
// // All enotes are addressed to the main address in 2-out noin-coinbase txs or 1-out coinbase txs.
|
||||
// // We also don't test reorgs here.
|
||||
|
||||
// init blockchain
|
||||
mock::fake_pruned_blockchain bc(0);
|
||||
// // init blockchain
|
||||
// mock::fake_pruned_blockchain bc(0);
|
||||
|
||||
// generate wallet
|
||||
tools::wallet2 w(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
w.generate("", "");
|
||||
const cryptonote::account_keys &acc_keys = w.get_account().get_keys();
|
||||
const cryptonote::account_public_address main_addr = w.get_account().get_keys().m_account_address;
|
||||
ASSERT_EQ(0, w.balance(0, true));
|
||||
bc.init_wallet_for_starting_block(w); // needed b/c internal logic
|
||||
// // generate wallet
|
||||
// tools::wallet2 w(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
// w.generate("", "");
|
||||
// const cryptonote::account_keys &acc_keys = w.get_account().get_keys();
|
||||
// const cryptonote::account_public_address main_addr = w.get_account().get_keys().m_account_address;
|
||||
// ASSERT_EQ(0, w.balance(0, true));
|
||||
// bc.init_wallet_for_starting_block(w); // needed b/c internal logic
|
||||
|
||||
uint64_t refresh_height = 0;
|
||||
const auto wallet_process_new_blocks = [&w, &bc, &refresh_height]() -> boost::multiprecision::int128_t
|
||||
{
|
||||
const boost::multiprecision::int128_t old_balance = w.balance(0, true);
|
||||
// uint64_t refresh_height = 0;
|
||||
// const auto wallet_process_new_blocks = [&w, &bc, &refresh_height]() -> boost::multiprecision::int128_t
|
||||
// {
|
||||
// const boost::multiprecision::int128_t old_balance = w.balance(0, true);
|
||||
|
||||
// note: doesn't handle reorgs
|
||||
std::vector<cryptonote::block_complete_entry> block_entries;
|
||||
std::vector<tools::wallet2::parsed_block> parsed_blocks;
|
||||
bc.get_blocks_data(0, bc.height()-1, block_entries, parsed_blocks); //! @TODO: figure out why starting from refresh_height doesn't work
|
||||
uint64_t blocks_added{};
|
||||
auto output_tracker_cache = w.create_output_tracker_cache();
|
||||
w.process_parsed_blocks(0, block_entries, parsed_blocks, blocks_added, output_tracker_cache);
|
||||
// // note: doesn't handle reorgs
|
||||
// std::vector<cryptonote::block_complete_entry> block_entries;
|
||||
// std::vector<tools::wallet2::parsed_block> parsed_blocks;
|
||||
// bc.get_blocks_data(0, bc.height()-1, block_entries, parsed_blocks); //! @TODO: figure out why starting from refresh_height doesn't work
|
||||
// uint64_t blocks_added{};
|
||||
// auto output_tracker_cache = w.create_output_tracker_cache();
|
||||
// w.process_parsed_blocks(0, block_entries, parsed_blocks, blocks_added, output_tracker_cache);
|
||||
|
||||
// update refresh_height
|
||||
refresh_height = bc.height();
|
||||
// // update refresh_height
|
||||
// refresh_height = bc.height();
|
||||
|
||||
// return amount of money received
|
||||
return boost::multiprecision::int128_t(w.balance(0, true)) - old_balance;
|
||||
};
|
||||
// // return amount of money received
|
||||
// return boost::multiprecision::int128_t(w.balance(0, true)) - old_balance;
|
||||
// };
|
||||
|
||||
// a. push block containing a pre-ringct coinbase output to wallet
|
||||
bc.add_block(1, {}, main_addr);
|
||||
// // a. push block containing a pre-ringct coinbase output to wallet
|
||||
// bc.add_block(1, {}, main_addr);
|
||||
|
||||
// a. scan pre-ringct coinbase tx
|
||||
auto balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
// // a. scan pre-ringct coinbase tx
|
||||
// auto balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
// EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
|
||||
// b. construct and push a pre-ringct tx
|
||||
const rct::xmr_amount amount_b = rct::randXmrAmount(COIN);
|
||||
{
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_b, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
acc_keys,
|
||||
w.m_subaddresses,
|
||||
/*stripped_sources=*/{},
|
||||
dests,
|
||||
acc_keys.m_account_address,
|
||||
fee,
|
||||
/*hf_version=*/1);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(1, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeNull, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(amount_b, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(1, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // b. construct and push a pre-ringct tx
|
||||
// const rct::xmr_amount amount_b = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_b, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// /*stripped_sources=*/{},
|
||||
// dests,
|
||||
// acc_keys.m_account_address,
|
||||
// fee,
|
||||
// /*hf_version=*/1);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(1, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeNull, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(amount_b, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(1, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// b. scan pre-ringct tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_b, balance_diff);
|
||||
// // b. scan pre-ringct tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_b, balance_diff);
|
||||
|
||||
// c. construct and push a ringct coinbase tx
|
||||
bc.add_block(HF_VERSION_DYNAMIC_FEE, {}, main_addr);
|
||||
{
|
||||
auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
ASSERT_EQ(2, top_miner_tx.version);
|
||||
ASSERT_NE(0, top_miner_tx.vout.size());
|
||||
ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
}
|
||||
// // c. construct and push a ringct coinbase tx
|
||||
// bc.add_block(HF_VERSION_DYNAMIC_FEE, {}, main_addr);
|
||||
// {
|
||||
// auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
// const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
// ASSERT_EQ(2, top_miner_tx.version);
|
||||
// ASSERT_NE(0, top_miner_tx.vout.size());
|
||||
// ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
// ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
// }
|
||||
|
||||
// c. scan ringct coinbase tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
// // c. scan ringct coinbase tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
// EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
|
||||
// d. construct and push a ringct long-amount tx
|
||||
const rct::xmr_amount amount_d = rct::randXmrAmount(COIN);
|
||||
{
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_d, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
acc_keys,
|
||||
w.m_subaddresses,
|
||||
/*stripped_sources=*/{},
|
||||
dests,
|
||||
acc_keys.m_account_address,
|
||||
fee,
|
||||
HF_VERSION_DYNAMIC_FEE);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(2, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeFull, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_DYNAMIC_FEE, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // d. construct and push a ringct long-amount tx
|
||||
// const rct::xmr_amount amount_d = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_d, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// /*stripped_sources=*/{},
|
||||
// dests,
|
||||
// acc_keys.m_account_address,
|
||||
// fee,
|
||||
// HF_VERSION_DYNAMIC_FEE);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(2, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeFull, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_DYNAMIC_FEE, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// d. scan ringct long-amount tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_d, balance_diff);
|
||||
// // d. scan ringct long-amount tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_d, balance_diff);
|
||||
|
||||
// e. construct and push a ringct short-amount tx
|
||||
const rct::xmr_amount amount_e = rct::randXmrAmount(COIN);
|
||||
{
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_e, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
acc_keys,
|
||||
w.m_subaddresses,
|
||||
/*stripped_sources=*/{},
|
||||
dests,
|
||||
acc_keys.m_account_address,
|
||||
fee,
|
||||
HF_VERSION_SMALLER_BP);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(2, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeBulletproof2, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_SMALLER_BP, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // e. construct and push a ringct short-amount tx
|
||||
// const rct::xmr_amount amount_e = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_e, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// /*stripped_sources=*/{},
|
||||
// dests,
|
||||
// acc_keys.m_account_address,
|
||||
// fee,
|
||||
// HF_VERSION_SMALLER_BP);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(2, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeBulletproof2, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_key), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_SMALLER_BP, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// e. scan ringct short-amount tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_e, balance_diff);
|
||||
// // e. scan ringct short-amount tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_e, balance_diff);
|
||||
|
||||
// f. construct and push a view-tagged ringct coinbase tx
|
||||
bc.add_block(HF_VERSION_VIEW_TAGS, {}, main_addr);
|
||||
{
|
||||
auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
ASSERT_EQ(2, top_miner_tx.version);
|
||||
ASSERT_EQ(1, top_miner_tx.vout.size());
|
||||
ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), top_miner_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
}
|
||||
// // f. construct and push a view-tagged ringct coinbase tx
|
||||
// bc.add_block(HF_VERSION_VIEW_TAGS, {}, main_addr);
|
||||
// {
|
||||
// auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
// const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
// ASSERT_EQ(2, top_miner_tx.version);
|
||||
// ASSERT_EQ(1, top_miner_tx.vout.size());
|
||||
// ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), top_miner_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
// }
|
||||
|
||||
// f. scan view-tagged ringct coinbase tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
// // f. scan view-tagged ringct coinbase tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
// EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
|
||||
// g. construct and push a view-tagged pre-ringct (only possible in unmixable sweep txs) tx
|
||||
const rct::xmr_amount amount_g = rct::randXmrAmount(COIN);
|
||||
{
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_g, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
acc_keys,
|
||||
w.m_subaddresses,
|
||||
/*stripped_sources=*/{},
|
||||
dests,
|
||||
acc_keys.m_account_address,
|
||||
fee,
|
||||
HF_VERSION_VIEW_TAGS,
|
||||
/*sweep_unmixable_override=*/true);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(1, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeNull, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(amount_g, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_VIEW_TAGS, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // g. construct and push a view-tagged pre-ringct (only possible in unmixable sweep txs) tx
|
||||
// const rct::xmr_amount amount_g = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_g, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// /*stripped_sources=*/{},
|
||||
// dests,
|
||||
// acc_keys.m_account_address,
|
||||
// fee,
|
||||
// HF_VERSION_VIEW_TAGS,
|
||||
// /*sweep_unmixable_override=*/true);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(1, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeNull, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(amount_g, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_VIEW_TAGS, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// g. scan view-tagged pre-ringct (only possible in unmixable sweep txs) tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_g, balance_diff);
|
||||
// // g. scan view-tagged pre-ringct (only possible in unmixable sweep txs) tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_g, balance_diff);
|
||||
|
||||
// h. construct and push a view-tagged ringct tx
|
||||
const rct::xmr_amount amount_h = rct::randXmrAmount(COIN);
|
||||
{
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_h, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
acc_keys,
|
||||
w.m_subaddresses,
|
||||
/*stripped_sources=*/{},
|
||||
dests,
|
||||
acc_keys.m_account_address,
|
||||
fee,
|
||||
HF_VERSION_VIEW_TAGS);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(2, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeBulletproofPlus, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_VIEW_TAGS, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // h. construct and push a view-tagged ringct tx
|
||||
// const rct::xmr_amount amount_h = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_h, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// /*stripped_sources=*/{},
|
||||
// dests,
|
||||
// acc_keys.m_account_address,
|
||||
// fee,
|
||||
// HF_VERSION_VIEW_TAGS);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(2, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeBulletproofPlus, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_tagged_key), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_VIEW_TAGS, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// h. scan ringct view-tagged ringct tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_h, balance_diff);
|
||||
// // h. scan ringct view-tagged ringct tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_h, balance_diff);
|
||||
|
||||
// i. construct and push a carrot v1 coinbase tx
|
||||
bc.add_block(HF_VERSION_CARROT, {}, main_addr);
|
||||
{
|
||||
auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
ASSERT_EQ(2, top_miner_tx.version);
|
||||
ASSERT_EQ(1, top_miner_tx.vout.size());
|
||||
ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), top_miner_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
}
|
||||
// // i. construct and push a carrot v1 coinbase tx
|
||||
// bc.add_block(HF_VERSION_CARROT, {}, main_addr);
|
||||
// {
|
||||
// auto top_block = bc.get_parsed_block(bc.height() - 1);
|
||||
// const cryptonote::transaction &top_miner_tx = top_block.block.miner_tx;
|
||||
// ASSERT_EQ(2, top_miner_tx.version);
|
||||
// ASSERT_EQ(1, top_miner_tx.vout.size());
|
||||
// ASSERT_EQ(rct::RCTTypeNull, top_miner_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(0, top_miner_tx.signatures.size());
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), top_miner_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(mock::fake_pruned_blockchain::miner_reward, top_miner_tx.vout.at(0).amount);
|
||||
// }
|
||||
|
||||
// i. scan carrot v1 coinbase tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
// // i. scan carrot v1 coinbase tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(mock::fake_pruned_blockchain::miner_reward, balance_diff);
|
||||
// EXPECT_TRUE(verify_sals_of_recent_transfers());
|
||||
|
||||
// j. construct and push a carrot v1 normal tx
|
||||
const rct::xmr_amount amount_j = rct::randXmrAmount(COIN);
|
||||
{
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_j, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_carrot_pruned_transaction_fake_inputs(
|
||||
{carrot::mock::convert_normal_payment_proposal_v1(dests.front())},
|
||||
/*selfsend_payment_proposals=*/{},
|
||||
acc_keys);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(2, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeFcmpPlusPlus, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_CARROT, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // j. construct and push a carrot v1 normal tx
|
||||
// const rct::xmr_amount amount_j = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_j, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_carrot_pruned_transaction_fake_inputs(
|
||||
// {carrot::mock::convert_normal_payment_proposal_v1(dests.front())},
|
||||
// /*selfsend_payment_proposals=*/{},
|
||||
// acc_keys);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(2, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeFcmpPlusPlus, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_CARROT, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// j. scan carrot v1 normal tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_j, balance_diff);
|
||||
// // j. scan carrot v1 normal tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_j, balance_diff);
|
||||
|
||||
// k. construct and push a carrot v1 special tx
|
||||
const rct::xmr_amount amount_k = rct::randXmrAmount(COIN);
|
||||
{
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_k, acc_keys.m_account_address, false)};
|
||||
cryptonote::transaction curr_tx = mock::construct_carrot_pruned_transaction_fake_inputs(
|
||||
/*normal_payment_proposals=*/{},
|
||||
{{carrot::mock::convert_selfsend_payment_proposal_v1(dests.front()), {/*main*/}}},
|
||||
acc_keys);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
ASSERT_EQ(2, curr_tx.version);
|
||||
ASSERT_EQ(rct::RCTTypeFcmpPlusPlus, curr_tx.rct_signatures.type);
|
||||
ASSERT_EQ(2, curr_tx.vout.size());
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), curr_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
bc.add_block(HF_VERSION_CARROT, {std::move(curr_tx)}, mock::null_addr);
|
||||
}
|
||||
// // k. construct and push a carrot v1 special tx
|
||||
// const rct::xmr_amount amount_k = rct::randXmrAmount(COIN);
|
||||
// {
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_k, acc_keys.m_account_address, false)};
|
||||
// cryptonote::transaction curr_tx = mock::construct_carrot_pruned_transaction_fake_inputs(
|
||||
// /*normal_payment_proposals=*/{},
|
||||
// {{carrot::mock::convert_selfsend_payment_proposal_v1(dests.front()), {/*main*/}}},
|
||||
// acc_keys);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(curr_tx));
|
||||
// ASSERT_EQ(2, curr_tx.version);
|
||||
// ASSERT_EQ(rct::RCTTypeFcmpPlusPlus, curr_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(2, curr_tx.vout.size());
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_carrot_v1), curr_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(0, curr_tx.vout.at(0).amount);
|
||||
// bc.add_block(HF_VERSION_CARROT, {std::move(curr_tx)}, mock::null_addr);
|
||||
// }
|
||||
|
||||
// k. scan carrot v1 special tx
|
||||
balance_diff = wallet_process_new_blocks();
|
||||
EXPECT_EQ(amount_k, balance_diff);
|
||||
}
|
||||
// // k. scan carrot v1 special tx
|
||||
// balance_diff = wallet_process_new_blocks();
|
||||
// EXPECT_EQ(amount_k, balance_diff);
|
||||
// }
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_scanning, burned_zombie)
|
||||
{
|
||||
// Check that a wallet which receives attempted burn outputs counts all outputs of the same key
|
||||
// image spent when that key image is spent. Those with the same key image which aren't marked
|
||||
// as spent are "burned zombies": they aren't burn and not usable, but they shuffle around in
|
||||
// the internal state and inflate the balance or attract input selection.
|
||||
// TEST(wallet_scanning, burned_zombie)
|
||||
// {
|
||||
// // Check that a wallet which receives attempted burn outputs counts all outputs of the same key
|
||||
// // image spent when that key image is spent. Those with the same key image which aren't marked
|
||||
// // as spent are "burned zombies": they aren't burn and not usable, but they shuffle around in
|
||||
// // the internal state and inflate the balance or attract input selection.
|
||||
|
||||
// init blockchain
|
||||
mock::fake_pruned_blockchain bc(0);
|
||||
// // init blockchain
|
||||
// mock::fake_pruned_blockchain bc(0);
|
||||
|
||||
// generate wallet
|
||||
tools::wallet2 w(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
w.set_offline(true);
|
||||
w.generate("", "");
|
||||
const cryptonote::account_keys &acc_keys = w.get_account().get_keys();
|
||||
const cryptonote::account_public_address main_addr = w.get_account().get_keys().m_account_address;
|
||||
ASSERT_EQ(0, w.balance(0, true));
|
||||
bc.init_wallet_for_starting_block(w); // needed b/c internal logic
|
||||
// // generate wallet
|
||||
// tools::wallet2 w(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
// w.set_offline(true);
|
||||
// w.generate("", "");
|
||||
// const cryptonote::account_keys &acc_keys = w.get_account().get_keys();
|
||||
// const cryptonote::account_public_address main_addr = w.get_account().get_keys().m_account_address;
|
||||
// ASSERT_EQ(0, w.balance(0, true));
|
||||
// bc.init_wallet_for_starting_block(w); // needed b/c internal logic
|
||||
|
||||
const rct::xmr_amount amount_a = rct::randXmrAmount(COIN) + 1;
|
||||
const rct::xmr_amount amount_b = rct::randXmrAmount(amount_a - 1);
|
||||
const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
// const rct::xmr_amount amount_a = rct::randXmrAmount(COIN) + 1;
|
||||
// const rct::xmr_amount amount_b = rct::randXmrAmount(amount_a - 1);
|
||||
// const rct::xmr_amount fee = rct::randXmrAmount(COIN);
|
||||
|
||||
// make incoming pre-ringct tx to wallet with amount a
|
||||
cryptonote::transaction incoming_tx_a;
|
||||
{
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(amount_a, main_addr, false)};
|
||||
incoming_tx_a = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
dests,
|
||||
fee,
|
||||
/*hf_version=*/1);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(incoming_tx_a));
|
||||
ASSERT_EQ(1, incoming_tx_a.version);
|
||||
ASSERT_EQ(rct::RCTTypeNull, incoming_tx_a.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_key), incoming_tx_a.vout.at(0).target.type());
|
||||
ASSERT_EQ(amount_a, incoming_tx_a.vout.at(0).amount);
|
||||
}
|
||||
// // make incoming pre-ringct tx to wallet with amount a
|
||||
// cryptonote::transaction incoming_tx_a;
|
||||
// {
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(amount_a, main_addr, false)};
|
||||
// incoming_tx_a = mock::construct_pre_carrot_tx_with_fake_inputs(
|
||||
// dests,
|
||||
// fee,
|
||||
// /*hf_version=*/1);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(incoming_tx_a));
|
||||
// ASSERT_EQ(1, incoming_tx_a.version);
|
||||
// ASSERT_EQ(rct::RCTTypeNull, incoming_tx_a.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_key), incoming_tx_a.vout.at(0).target.type());
|
||||
// ASSERT_EQ(amount_a, incoming_tx_a.vout.at(0).amount);
|
||||
// }
|
||||
|
||||
// make a burn transaction with amount b < a
|
||||
cryptonote::transaction incoming_tx_b = incoming_tx_a;
|
||||
boost::get<cryptonote::txin_to_key>(incoming_tx_b.vin.at(0)).k_image = rct::rct2ki(rct::pkGen());
|
||||
incoming_tx_b.vout[0].amount = amount_b;
|
||||
// // make a burn transaction with amount b < a
|
||||
// cryptonote::transaction incoming_tx_b = incoming_tx_a;
|
||||
// boost::get<cryptonote::txin_to_key>(incoming_tx_b.vin.at(0)).k_image = rct::rct2ki(rct::pkGen());
|
||||
// incoming_tx_b.vout[0].amount = amount_b;
|
||||
|
||||
// submit burning transaction first
|
||||
bc.add_block(1, {incoming_tx_b}, mock::null_addr);
|
||||
// // submit burning transaction first
|
||||
// bc.add_block(1, {incoming_tx_b}, mock::null_addr);
|
||||
|
||||
// then submit original transaction
|
||||
bc.add_block(1, {incoming_tx_a}, mock::null_addr);
|
||||
// // then submit original transaction
|
||||
// bc.add_block(1, {incoming_tx_a}, mock::null_addr);
|
||||
|
||||
// add 10 blocks to put space between sending outgoing tx
|
||||
const cryptonote::tx_out dummy_output{.amount = 5, .target = cryptonote::txout_to_key(rct::rct2pk(rct::pkGen()))};
|
||||
cryptonote::transaction dummy_tx; //! @TODO: remove dummy as prop fixing another bug
|
||||
dummy_tx.version = 1;
|
||||
dummy_tx.unlock_time = 0;
|
||||
dummy_tx.vout.push_back(dummy_output);
|
||||
for (size_t i = 0; i <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE; ++i)
|
||||
bc.add_block(1, {dummy_tx}, mock::null_addr);
|
||||
// // add 10 blocks to put space between sending outgoing tx
|
||||
// const cryptonote::tx_out dummy_output{.amount = 5, .target = cryptonote::txout_to_key(rct::rct2pk(rct::pkGen()))};
|
||||
// cryptonote::transaction dummy_tx; //! @TODO: remove dummy as prop fixing another bug
|
||||
// dummy_tx.version = 1;
|
||||
// dummy_tx.unlock_time = 0;
|
||||
// dummy_tx.vout.push_back(dummy_output);
|
||||
// for (size_t i = 0; i <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE; ++i)
|
||||
// bc.add_block(1, {dummy_tx}, mock::null_addr);
|
||||
|
||||
// scan, assert balance is amount a, (NOT a + b) and get key image to received output
|
||||
bc.refresh_wallet(w, 0);
|
||||
ASSERT_EQ(amount_a, w.balance_all(true));
|
||||
uint64_t key_image_offset;
|
||||
std::vector<std::pair<crypto::key_image, crypto::signature>> exported_key_images;
|
||||
std::tie(key_image_offset, exported_key_images) = w.export_key_images(/*all=*/true);
|
||||
ASSERT_EQ(0, key_image_offset);
|
||||
ASSERT_EQ(2, exported_key_images.size());
|
||||
const crypto::key_image &received_key_image = exported_key_images.at(0).first;
|
||||
ASSERT_EQ(received_key_image, exported_key_images.at(1).first);
|
||||
// // scan, assert balance is amount a, (NOT a + b) and get key image to received output
|
||||
// bc.refresh_wallet(w, 0);
|
||||
// ASSERT_EQ(amount_a, w.balance_all(true));
|
||||
// uint64_t key_image_offset;
|
||||
// std::vector<std::pair<crypto::key_image, crypto::signature>> exported_key_images;
|
||||
// std::tie(key_image_offset, exported_key_images) = w.export_key_images(/*all=*/true);
|
||||
// ASSERT_EQ(0, key_image_offset);
|
||||
// ASSERT_EQ(2, exported_key_images.size());
|
||||
// const crypto::key_image &received_key_image = exported_key_images.at(0).first;
|
||||
// ASSERT_EQ(received_key_image, exported_key_images.at(1).first);
|
||||
|
||||
// make "outgoing" transaction by including this key image in an input
|
||||
cryptonote::transaction outgoing_tx;
|
||||
{
|
||||
const rct::xmr_amount outgoing_amount = rct::randXmrAmount(amount_a);
|
||||
const rct::xmr_amount outgoing_fee = amount_a - outgoing_amount;
|
||||
std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
cryptonote::tx_destination_entry(outgoing_amount, mock::null_addr, false)};
|
||||
crypto::secret_key main_tx_privkey;
|
||||
std::vector<crypto::secret_key> additional_tx_privkeys;
|
||||
tools::wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
ASSERT_EQ(2, transfers.size());
|
||||
const tools::wallet2::transfer_details &input_td = transfers.at(1);
|
||||
const mock::stripped_down_tx_source_entry_t input_src{
|
||||
.is_rct = false,
|
||||
.global_output_index = input_td.m_global_output_index,
|
||||
.onetime_address = input_td.get_public_key(),
|
||||
.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(input_td.m_tx, input_td.m_pk_index),
|
||||
.local_output_index = 0,
|
||||
.amount = amount_a,
|
||||
.mask = rct::I
|
||||
};
|
||||
outgoing_tx = mock::construct_pre_carrot_tx_with_fake_inputs(acc_keys,
|
||||
w.m_subaddresses,
|
||||
{input_src},
|
||||
dests,
|
||||
/*change_addr=*/{},
|
||||
crypto::null_hash,
|
||||
outgoing_fee,
|
||||
/*hf_version=*/1,
|
||||
main_tx_privkey,
|
||||
additional_tx_privkeys);
|
||||
ASSERT_FALSE(cryptonote::is_coinbase(outgoing_tx));
|
||||
ASSERT_EQ(1, outgoing_tx.version);
|
||||
ASSERT_EQ(1, outgoing_tx.vin.size());
|
||||
ASSERT_EQ(1, outgoing_tx.vout.size());
|
||||
ASSERT_EQ(received_key_image, boost::get<cryptonote::txin_to_key>(outgoing_tx.vin.at(0)).k_image);
|
||||
ASSERT_EQ(rct::RCTTypeNull, outgoing_tx.rct_signatures.type);
|
||||
ASSERT_EQ(typeid(cryptonote::txout_to_key), outgoing_tx.vout.at(0).target.type());
|
||||
ASSERT_EQ(amount_a, boost::get<cryptonote::txin_to_key>(outgoing_tx.vin.at(0)).amount);
|
||||
ASSERT_EQ(outgoing_amount, outgoing_tx.vout.at(0).amount);
|
||||
ASSERT_EQ(outgoing_fee, cryptonote::get_tx_fee(outgoing_tx));
|
||||
}
|
||||
// // make "outgoing" transaction by including this key image in an input
|
||||
// cryptonote::transaction outgoing_tx;
|
||||
// {
|
||||
// const rct::xmr_amount outgoing_amount = rct::randXmrAmount(amount_a);
|
||||
// const rct::xmr_amount outgoing_fee = amount_a - outgoing_amount;
|
||||
// std::vector<cryptonote::tx_destination_entry> dests = {
|
||||
// cryptonote::tx_destination_entry(outgoing_amount, mock::null_addr, false)};
|
||||
// crypto::secret_key main_tx_privkey;
|
||||
// std::vector<crypto::secret_key> additional_tx_privkeys;
|
||||
// tools::wallet2::transfer_container transfers;
|
||||
// w.get_transfers(transfers);
|
||||
// ASSERT_EQ(2, transfers.size());
|
||||
// const tools::wallet2::transfer_details &input_td = transfers.at(1);
|
||||
// const mock::stripped_down_tx_source_entry_t input_src{
|
||||
// .is_rct = false,
|
||||
// .global_output_index = input_td.m_global_output_index,
|
||||
// .onetime_address = input_td.get_public_key(),
|
||||
// .real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(input_td.m_tx, input_td.m_pk_index),
|
||||
// .local_output_index = 0,
|
||||
// .amount = amount_a,
|
||||
// .mask = rct::I
|
||||
// };
|
||||
// outgoing_tx = mock::construct_pre_carrot_tx_with_fake_inputs(acc_keys,
|
||||
// w.m_subaddresses,
|
||||
// {input_src},
|
||||
// dests,
|
||||
// /*change_addr=*/{},
|
||||
// crypto::null_hash,
|
||||
// outgoing_fee,
|
||||
// /*hf_version=*/1,
|
||||
// main_tx_privkey,
|
||||
// additional_tx_privkeys);
|
||||
// ASSERT_FALSE(cryptonote::is_coinbase(outgoing_tx));
|
||||
// ASSERT_EQ(1, outgoing_tx.version);
|
||||
// ASSERT_EQ(1, outgoing_tx.vin.size());
|
||||
// ASSERT_EQ(1, outgoing_tx.vout.size());
|
||||
// ASSERT_EQ(received_key_image, boost::get<cryptonote::txin_to_key>(outgoing_tx.vin.at(0)).k_image);
|
||||
// ASSERT_EQ(rct::RCTTypeNull, outgoing_tx.rct_signatures.type);
|
||||
// ASSERT_EQ(typeid(cryptonote::txout_to_key), outgoing_tx.vout.at(0).target.type());
|
||||
// ASSERT_EQ(amount_a, boost::get<cryptonote::txin_to_key>(outgoing_tx.vin.at(0)).amount);
|
||||
// ASSERT_EQ(outgoing_amount, outgoing_tx.vout.at(0).amount);
|
||||
// ASSERT_EQ(outgoing_fee, cryptonote::get_tx_fee(outgoing_tx));
|
||||
// }
|
||||
|
||||
// add outgoing tx to chain and wallet scans it
|
||||
bc.add_block(1, {outgoing_tx}, mock::null_addr);
|
||||
bc.refresh_wallet(w, 0);
|
||||
// // add outgoing tx to chain and wallet scans it
|
||||
// bc.add_block(1, {outgoing_tx}, mock::null_addr);
|
||||
// bc.refresh_wallet(w, 0);
|
||||
|
||||
// check that the balance drops to 0 and that all transfers are marked spent
|
||||
ASSERT_EQ(0, w.balance_all(true));
|
||||
tools::wallet2::transfer_container post_spend_transfers;
|
||||
w.get_transfers(post_spend_transfers);
|
||||
ASSERT_EQ(2, post_spend_transfers.size());
|
||||
for (const tools::wallet2::transfer_details &td : post_spend_transfers)
|
||||
ASSERT_TRUE(td.m_spent);
|
||||
}
|
||||
// // check that the balance drops to 0 and that all transfers are marked spent
|
||||
// ASSERT_EQ(0, w.balance_all(true));
|
||||
// tools::wallet2::transfer_container post_spend_transfers;
|
||||
// w.get_transfers(post_spend_transfers);
|
||||
// ASSERT_EQ(2, post_spend_transfers.size());
|
||||
// for (const tools::wallet2::transfer_details &td : post_spend_transfers)
|
||||
// ASSERT_TRUE(td.m_spent);
|
||||
// }
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
// Copyright (c) 2023-2024, 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.
|
||||
|
||||
#include "unit_tests_utils.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#include "file_io_utils.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "common/util.h"
|
||||
|
||||
using namespace boost::filesystem;
|
||||
using namespace epee::file_io_utils;
|
||||
|
||||
static constexpr const char WALLET_00fd416a_PRIMARY_ADDRESS[] =
|
||||
"45p2SngJAPSJbqSiUvYfS3BfhEdxZmv8pDt25oW1LzxrZv9Uq6ARagiFViMGUE3gJk5VPWingCXVf1p2tyAy6SUeSHPhbve";
|
||||
|
||||
// https://github.com/monero-project/monero/blob/67d190ce7c33602b6a3b804f633ee1ddb7fbb4a1/src/wallet/wallet2.cpp#L156
|
||||
static constexpr const char WALLET2_ASCII_OUTPUT_MAGIC[] = "MoneroAsciiDataV1";
|
||||
|
||||
TEST(wallet_storage, store_to_file2file)
|
||||
{
|
||||
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_file2file";
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_file2file";
|
||||
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||
|
||||
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
||||
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
||||
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
epee::wipeable_string password("beepbeep");
|
||||
|
||||
const auto files_are_expected = [&]()
|
||||
{
|
||||
EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
|
||||
EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
};
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(interm_wallet_file.string(), password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
w.store_to(target_wallet_file.string(), password);
|
||||
files_are_expected();
|
||||
}
|
||||
|
||||
files_are_expected();
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(target_wallet_file.string(), password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
w.store_to("", "");
|
||||
files_are_expected();
|
||||
}
|
||||
|
||||
files_are_expected();
|
||||
}
|
||||
|
||||
TEST(wallet_storage, store_to_mem2file)
|
||||
{
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_mem2file";
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
epee::wipeable_string password("beepbeep2");
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.generate("", password);
|
||||
w.store_to(target_wallet_file.string(), password);
|
||||
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(target_wallet_file.string(), password);
|
||||
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
}
|
||||
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
}
|
||||
|
||||
TEST(wallet_storage, change_password_same_file)
|
||||
{
|
||||
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_same";
|
||||
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||
|
||||
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
||||
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
||||
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||
|
||||
epee::wipeable_string old_password("beepbeep");
|
||||
epee::wipeable_string new_password("meepmeep");
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(interm_wallet_file.string(), old_password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
w.change_password(w.get_wallet_file(), old_password, new_password);
|
||||
}
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(interm_wallet_file.string(), new_password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
}
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
EXPECT_THROW(w.load(interm_wallet_file.string(), old_password), tools::error::invalid_password);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(wallet_storage, change_password_different_file)
|
||||
{
|
||||
const path source_wallet_file = unit_test::data_dir / "wallet_00fd416a";
|
||||
const path interm_wallet_file = unit_test::data_dir / "wallet_00fd416a_copy_change_password_diff";
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_00fd416a_new_change_password_diff";
|
||||
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(source_wallet_file.string() + ".keys"));
|
||||
|
||||
tools::copy_file(source_wallet_file.string(), interm_wallet_file.string());
|
||||
tools::copy_file(source_wallet_file.string() + ".keys", interm_wallet_file.string() + ".keys");
|
||||
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
epee::wipeable_string old_password("beepbeep");
|
||||
epee::wipeable_string new_password("meepmeep");
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(interm_wallet_file.string(), old_password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
w.change_password(target_wallet_file.string(), old_password, new_password);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(is_file_exist(interm_wallet_file.string()));
|
||||
EXPECT_FALSE(is_file_exist(interm_wallet_file.string() + ".keys"));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(target_wallet_file.string(), new_password);
|
||||
const std::string primary_address = w.get_address_as_str();
|
||||
EXPECT_EQ(WALLET_00fd416a_PRIMARY_ADDRESS, primary_address);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(wallet_storage, change_password_in_memory)
|
||||
{
|
||||
const epee::wipeable_string password1("monero");
|
||||
const epee::wipeable_string password2("means money");
|
||||
const epee::wipeable_string password_wrong("is traceable");
|
||||
|
||||
tools::wallet2 w;
|
||||
w.generate("", password1);
|
||||
const std::string primary_address_1 = w.get_address_as_str();
|
||||
w.change_password("", password1, password2);
|
||||
const std::string primary_address_2 = w.get_address_as_str();
|
||||
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||
|
||||
EXPECT_THROW(w.change_password("", password_wrong, password1), tools::error::invalid_password);
|
||||
}
|
||||
|
||||
TEST(wallet_storage, change_password_mem2file)
|
||||
{
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_change_password_mem2file";
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
const epee::wipeable_string password1("https://safecurves.cr.yp.to/rigid.html");
|
||||
const epee::wipeable_string password2(
|
||||
"https://csrc.nist.gov/csrc/media/projects/crypto-standards-development-process/documents/dualec_in_x982_and_sp800-90.pdf");
|
||||
|
||||
std::string primary_address_1, primary_address_2;
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.generate("", password1);
|
||||
primary_address_1 = w.get_address_as_str();
|
||||
w.change_password(target_wallet_file.string(), password1, password2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
EXPECT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.load(target_wallet_file.string(), password2);
|
||||
primary_address_2 = w.get_address_as_str();
|
||||
}
|
||||
|
||||
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||
}
|
||||
|
||||
TEST(wallet_storage, gen_ascii_format)
|
||||
{
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_gen_ascii_format";
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
const epee::wipeable_string password("https://safecurves.cr.yp.to/rigid.html");
|
||||
|
||||
std::string primary_address_1, primary_address_2;
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.set_export_format(tools::wallet2::Ascii);
|
||||
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
||||
w.generate(target_wallet_file.string(), password);
|
||||
primary_address_1 = w.get_address_as_str();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
// Assert that we store keys in ascii format
|
||||
{
|
||||
std::string key_file_contents;
|
||||
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
||||
EXPECT_NE(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
||||
for (const char c : key_file_contents)
|
||||
ASSERT_TRUE(std::isprint(c) || c == '\n' || c == '\r');
|
||||
}
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.set_export_format(tools::wallet2::Ascii);
|
||||
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
||||
w.load(target_wallet_file.string(), password);
|
||||
primary_address_2 = w.get_address_as_str();
|
||||
}
|
||||
|
||||
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||
}
|
||||
|
||||
TEST(wallet_storage, change_export_format)
|
||||
{
|
||||
const path target_wallet_file = unit_test::data_dir / "wallet_change_export_format";
|
||||
|
||||
if (is_file_exist(target_wallet_file.string()))
|
||||
remove(target_wallet_file);
|
||||
if (is_file_exist(target_wallet_file.string() + ".keys"))
|
||||
remove(target_wallet_file.string() + ".keys");
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_FALSE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
const epee::wipeable_string password("https://safecurves.cr.yp.to/rigid.html");
|
||||
|
||||
std::string primary_address_1, primary_address_2;
|
||||
{
|
||||
tools::wallet2 w;
|
||||
ASSERT_EQ(tools::wallet2::Binary, w.export_format());
|
||||
w.generate(target_wallet_file.string(), password);
|
||||
primary_address_1 = w.get_address_as_str();
|
||||
w.store();
|
||||
|
||||
// Assert that we initially store keys in binary format
|
||||
{
|
||||
std::string key_file_contents;
|
||||
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
||||
EXPECT_EQ(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
||||
bool only_printable = true;
|
||||
for (const char c : key_file_contents)
|
||||
{
|
||||
if (!std::isprint(c) && c != '\n' && c != '\r')
|
||||
{
|
||||
only_printable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_FALSE(only_printable);
|
||||
}
|
||||
|
||||
// switch formats and store
|
||||
w.set_export_format(tools::wallet2::Ascii);
|
||||
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
||||
w.store_to("", password, /*force_rewrite_keys=*/ true);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(is_file_exist(target_wallet_file.string()));
|
||||
ASSERT_TRUE(is_file_exist(target_wallet_file.string() + ".keys"));
|
||||
|
||||
// Assert that we store keys in ascii format
|
||||
{
|
||||
std::string key_file_contents;
|
||||
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(target_wallet_file.string() + ".keys", key_file_contents));
|
||||
EXPECT_NE(std::string::npos, key_file_contents.find(WALLET2_ASCII_OUTPUT_MAGIC));
|
||||
for (const char c : key_file_contents)
|
||||
ASSERT_TRUE(std::isprint(c) || c == '\n' || c == '\r');
|
||||
}
|
||||
|
||||
{
|
||||
tools::wallet2 w;
|
||||
w.set_export_format(tools::wallet2::Ascii);
|
||||
ASSERT_EQ(tools::wallet2::Ascii, w.export_format());
|
||||
w.load(target_wallet_file.string(), password);
|
||||
primary_address_2 = w.get_address_as_str();
|
||||
}
|
||||
|
||||
EXPECT_EQ(primary_address_1, primary_address_2);
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "carrot_core/config.h"
|
||||
#include "carrot_mock_helpers.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
@@ -171,7 +172,7 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_transfer_1)
|
||||
/*ignore_below=*/0,
|
||||
{},
|
||||
top_block_index,
|
||||
alice);
|
||||
alice.get_keys());
|
||||
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 tx_proposal = tx_proposals.at(0);
|
||||
@@ -651,147 +652,147 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_6)
|
||||
ASSERT_NE(enote_type_0, enote_type_1);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_tx_builder, wallet2_scan_propose_sign_prove_member_and_scan_1)
|
||||
{
|
||||
// 1. create fake blockchain
|
||||
// 2. create Alice, Bob wallet2 instance
|
||||
// 3. send a mix of fake-input legacy and carrot txs to Alice
|
||||
// 4. step blockchain forward 10 blocks
|
||||
// 5. scan blockchain with Alice wallet
|
||||
// 6. create carrot transaction proposal
|
||||
// 7. construct proofs for transaction
|
||||
// 8. serialize tx
|
||||
// 9. deserialize tx
|
||||
// 10. check ver_non_input_consensus()
|
||||
// 11. check verRctNonSemanticsSimple()
|
||||
// 12. add Alice's transaction to blockchain
|
||||
// 13. scan blockchain with Bob's wallet and assert money received
|
||||
// 14. scan blockchain with Alice's wallet and assert money left
|
||||
// TEST(wallet_tx_builder, wallet2_scan_propose_sign_prove_member_and_scan_1)
|
||||
// {
|
||||
// // 1. create fake blockchain
|
||||
// // 2. create Alice, Bob wallet2 instance
|
||||
// // 3. send a mix of fake-input legacy and carrot txs to Alice
|
||||
// // 4. step blockchain forward 10 blocks
|
||||
// // 5. scan blockchain with Alice wallet
|
||||
// // 6. create carrot transaction proposal
|
||||
// // 7. construct proofs for transaction
|
||||
// // 8. serialize tx
|
||||
// // 9. deserialize tx
|
||||
// // 10. check ver_non_input_consensus()
|
||||
// // 11. check verRctNonSemanticsSimple()
|
||||
// // 12. add Alice's transaction to blockchain
|
||||
// // 13. scan blockchain with Bob's wallet and assert money received
|
||||
// // 14. scan blockchain with Alice's wallet and assert money left
|
||||
|
||||
// 1.
|
||||
LOG_PRINT_L2("Initiating my imaginary, friendly chain of blocks");
|
||||
mock::fake_pruned_blockchain bc(0);
|
||||
// // 1.
|
||||
// LOG_PRINT_L2("Initiating my imaginary, friendly chain of blocks");
|
||||
// mock::fake_pruned_blockchain bc(0);
|
||||
|
||||
// 2.
|
||||
LOG_PRINT_L2("Generating wallets for Alice and Bob, the usual suspects");
|
||||
tools::wallet2 alice(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
tools::wallet2 bob(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
alice.set_offline(true);
|
||||
bob.set_offline(true);
|
||||
alice.generate("", "");
|
||||
bob.generate("", "");
|
||||
const cryptonote::account_keys &alice_keys = alice.get_account().get_keys();
|
||||
const cryptonote::account_public_address alice_main_addr = alice.get_account().get_keys().m_account_address;
|
||||
const cryptonote::account_public_address bob_main_addr = bob.get_account().get_keys().m_account_address;
|
||||
bc.init_wallet_for_starting_block(alice);
|
||||
bc.init_wallet_for_starting_block(bob);
|
||||
// // 2.
|
||||
// LOG_PRINT_L2("Generating wallets for Alice and Bob, the usual suspects");
|
||||
// tools::wallet2 alice(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
// tools::wallet2 bob(cryptonote::MAINNET, /*kdf_rounds=*/1, /*unattended=*/true);
|
||||
// alice.set_offline(true);
|
||||
// bob.set_offline(true);
|
||||
// alice.generate("", "");
|
||||
// bob.generate("", "");
|
||||
// const cryptonote::account_keys &alice_keys = alice.get_account().get_keys();
|
||||
// const cryptonote::account_public_address alice_main_addr = alice.get_account().get_keys().m_account_address;
|
||||
// const cryptonote::account_public_address bob_main_addr = bob.get_account().get_keys().m_account_address;
|
||||
// bc.init_wallet_for_starting_block(alice);
|
||||
// bc.init_wallet_for_starting_block(bob);
|
||||
|
||||
// 3.
|
||||
LOG_PRINT_L2("Sending transactions from the aether to Alice (0)");
|
||||
const rct::xmr_amount amount0 = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests0{cryptonote::tx_destination_entry(amount0, alice_main_addr, false)};
|
||||
cryptonote::transaction tx = mock::construct_pre_carrot_tx_with_fake_inputs(dests0, /*fee=*/1234, /*hf_version=*/2);
|
||||
bc.add_block(2, {std::move(tx)}, mock::null_addr);
|
||||
LOG_PRINT_L2("Sending transactions from the aether to Alice (1)");
|
||||
const rct::xmr_amount amount1 = rct::randXmrAmount(COIN);
|
||||
std::vector<cryptonote::tx_destination_entry> dests1{cryptonote::tx_destination_entry(amount1, alice.get_subaddress({0, 13}), true)};
|
||||
cryptonote::account_base aether;
|
||||
aether.generate();
|
||||
tx = mock::construct_carrot_pruned_transaction_fake_inputs({carrot::mock::convert_normal_payment_proposal_v1(dests1.front())}, {}, aether.get_keys());
|
||||
bc.add_block(HF_VERSION_CARROT, {std::move(tx)}, mock::null_addr);
|
||||
// // 3.
|
||||
// LOG_PRINT_L2("Sending transactions from the aether to Alice (0)");
|
||||
// const rct::xmr_amount amount0 = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests0{cryptonote::tx_destination_entry(amount0, alice_main_addr, false)};
|
||||
// cryptonote::transaction tx = mock::construct_pre_carrot_tx_with_fake_inputs(dests0, /*fee=*/1234, /*hf_version=*/2);
|
||||
// bc.add_block(2, {std::move(tx)}, mock::null_addr);
|
||||
// LOG_PRINT_L2("Sending transactions from the aether to Alice (1)");
|
||||
// const rct::xmr_amount amount1 = rct::randXmrAmount(COIN);
|
||||
// std::vector<cryptonote::tx_destination_entry> dests1{cryptonote::tx_destination_entry(amount1, alice.get_subaddress({0, 13}), true)};
|
||||
// cryptonote::account_base aether;
|
||||
// aether.generate();
|
||||
// tx = mock::construct_carrot_pruned_transaction_fake_inputs({carrot::mock::convert_normal_payment_proposal_v1(dests1.front())}, {}, aether.get_keys());
|
||||
// bc.add_block(HF_VERSION_CARROT, {std::move(tx)}, mock::null_addr);
|
||||
|
||||
// 4.
|
||||
//!@TODO: figure out why membership proving fails if there's fewer leaves than the curve1 width
|
||||
const size_t target_num_outputs = fcmp_pp::curve_trees::SELENE_CHUNK_WIDTH * fcmp_pp::curve_trees::HELIOS_CHUNK_WIDTH + 7;
|
||||
while (bc.num_outputs() < target_num_outputs)
|
||||
bc.add_block(HF_VERSION_CARROT, {}, mock::null_addr, target_num_outputs - bc.num_outputs());
|
||||
// // 4.
|
||||
// //!@TODO: figure out why membership proving fails if there's fewer leaves than the curve1 width
|
||||
// const size_t target_num_outputs = fcmp_pp::curve_trees::SELENE_CHUNK_WIDTH * fcmp_pp::curve_trees::HELIOS_CHUNK_WIDTH + 7;
|
||||
// while (bc.num_outputs() < target_num_outputs)
|
||||
// bc.add_block(HF_VERSION_CARROT, {}, mock::null_addr, target_num_outputs - bc.num_outputs());
|
||||
|
||||
LOG_PRINT_L2("Twiddling thumbs");
|
||||
for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i)
|
||||
bc.add_block(HF_VERSION_CARROT, {}, mock::null_addr);
|
||||
// LOG_PRINT_L2("Twiddling thumbs");
|
||||
// for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i)
|
||||
// bc.add_block(HF_VERSION_CARROT, {}, mock::null_addr);
|
||||
|
||||
// 5.
|
||||
LOG_PRINT_L2("Alice's vision is filled with shadowy keys, hashes, points, rings, trees, curves, chains, all flowing in and out of one another");
|
||||
uint64_t blocks_added = bc.refresh_wallet(alice, 0);
|
||||
ASSERT_EQ(bc.height()-1, blocks_added);
|
||||
ASSERT_EQ(2, alice.m_transfers.size());
|
||||
ASSERT_EQ(amount0 + amount1, alice.balance_all(true)); // really, we care about unlocked_balance_all() for sending, but that call uses RPC
|
||||
// // 5.
|
||||
// LOG_PRINT_L2("Alice's vision is filled with shadowy keys, hashes, points, rings, trees, curves, chains, all flowing in and out of one another");
|
||||
// uint64_t blocks_added = bc.refresh_wallet(alice, 0);
|
||||
// ASSERT_EQ(bc.height()-1, blocks_added);
|
||||
// ASSERT_EQ(2, alice.m_transfers.size());
|
||||
// ASSERT_EQ(amount0 + amount1, alice.balance_all(true)); // really, we care about unlocked_balance_all() for sending, but that call uses RPC
|
||||
|
||||
// 6.
|
||||
LOG_PRINT_L2("Alice feels pity on Bob and proposes to send his broke ass some dough");
|
||||
const rct::xmr_amount out_amount = rct::randXmrAmount(amount0 + amount1);
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals =
|
||||
tools::wallet::make_carrot_transaction_proposals_wallet2_transfer( // stupidly long function name ;(
|
||||
alice.m_transfers,
|
||||
alice.m_subaddresses,
|
||||
{cryptonote::tx_destination_entry(out_amount, bob_main_addr, false)},
|
||||
/*fee_per_weight=*/1,
|
||||
/*extra=*/{},
|
||||
/*subaddr_account=*/0,
|
||||
/*subaddr_indices=*/{},
|
||||
/*ignore_above=*/std::numeric_limits<rct::xmr_amount>::max(),
|
||||
/*ignore_below=*/0,
|
||||
{},
|
||||
/*top_block_index=*/bc.height()-1,
|
||||
alice_keys);
|
||||
// // 6.
|
||||
// LOG_PRINT_L2("Alice feels pity on Bob and proposes to send his broke ass some dough");
|
||||
// const rct::xmr_amount out_amount = rct::randXmrAmount(amount0 + amount1);
|
||||
// const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals =
|
||||
// tools::wallet::make_carrot_transaction_proposals_wallet2_transfer( // stupidly long function name ;(
|
||||
// alice.m_transfers,
|
||||
// alice.m_subaddresses,
|
||||
// {cryptonote::tx_destination_entry(out_amount, bob_main_addr, false)},
|
||||
// /*fee_per_weight=*/1,
|
||||
// /*extra=*/{},
|
||||
// /*subaddr_account=*/0,
|
||||
// /*subaddr_indices=*/{},
|
||||
// /*ignore_above=*/std::numeric_limits<rct::xmr_amount>::max(),
|
||||
// /*ignore_below=*/0,
|
||||
// {},
|
||||
// /*top_block_index=*/bc.height()-1,
|
||||
// alice_keys);
|
||||
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 tx_proposal = tx_proposals.at(0);
|
||||
// ASSERT_EQ(1, tx_proposals.size());
|
||||
// const carrot::CarrotTransactionProposalV1 tx_proposal = tx_proposals.at(0);
|
||||
|
||||
// 7.
|
||||
LOG_PRINT_L2("Alice has something to prove");
|
||||
tx = tools::wallet::finalize_all_proofs_from_transfer_details(tx_proposal,
|
||||
alice.m_transfers,
|
||||
alice.m_tree_cache,
|
||||
*alice.m_curve_trees,
|
||||
alice_keys);
|
||||
// // 7.
|
||||
// LOG_PRINT_L2("Alice has something to prove");
|
||||
// tx = tools::wallet::finalize_all_proofs_from_transfer_details(tx_proposal,
|
||||
// alice.m_transfers,
|
||||
// alice.m_tree_cache,
|
||||
// *alice.m_curve_trees,
|
||||
// alice_keys);
|
||||
|
||||
// 8.
|
||||
LOG_PRINT_L2("Hello, Mr. Blobby");
|
||||
const cryptonote::blobdata alicebob_tx_blob = cryptonote::tx_to_blob(tx);
|
||||
// // 8.
|
||||
// LOG_PRINT_L2("Hello, Mr. Blobby");
|
||||
// const cryptonote::blobdata alicebob_tx_blob = cryptonote::tx_to_blob(tx);
|
||||
|
||||
// 9.
|
||||
LOG_PRINT_L2("Goodbye, Mr. Blobby");
|
||||
cryptonote::transaction alicebob_tx;
|
||||
ASSERT_TRUE(cryptonote::parse_and_validate_tx_from_blob(alicebob_tx_blob, alicebob_tx));
|
||||
// // 9.
|
||||
// LOG_PRINT_L2("Goodbye, Mr. Blobby");
|
||||
// cryptonote::transaction alicebob_tx;
|
||||
// ASSERT_TRUE(cryptonote::parse_and_validate_tx_from_blob(alicebob_tx_blob, alicebob_tx));
|
||||
|
||||
// 10.
|
||||
LOG_PRINT_L2("Bob couldn't believe someone to be so generous in his time of need, so he verifies");
|
||||
ASSERT_GE(bc.hf_version(), HF_VERSION_FCMP_PLUS_PLUS);
|
||||
cryptonote::tx_verification_context tvc{};
|
||||
ASSERT_TRUE(cryptonote::ver_non_input_consensus(alicebob_tx, tvc, bc.hf_version()));
|
||||
EXPECT_FALSE(tvc.m_verifivation_failed);
|
||||
// // 10.
|
||||
// LOG_PRINT_L2("Bob couldn't believe someone to be so generous in his time of need, so he verifies");
|
||||
// ASSERT_GE(bc.hf_version(), HF_VERSION_FCMP_PLUS_PLUS);
|
||||
// cryptonote::tx_verification_context tvc{};
|
||||
// ASSERT_TRUE(cryptonote::ver_non_input_consensus(alicebob_tx, tvc, bc.hf_version()));
|
||||
// EXPECT_FALSE(tvc.m_verifivation_failed);
|
||||
|
||||
// 11.
|
||||
LOG_PRINT_L2("'Perhaps this is valid money that belongs to another chain', Bob postulates");
|
||||
const uint8_t *tree_root = bc.get_fcmp_tree_root_at(bc.height() - 1);
|
||||
ASSERT_TRUE(cryptonote::Blockchain::expand_transaction_2(alicebob_tx,
|
||||
cryptonote::get_transaction_prefix_hash(alicebob_tx),
|
||||
/*pubkeys=*/{},
|
||||
tree_root));
|
||||
EXPECT_TRUE(rct::verRctNonSemanticsSimple(alicebob_tx.rct_signatures));
|
||||
// // 11.
|
||||
// LOG_PRINT_L2("'Perhaps this is valid money that belongs to another chain', Bob postulates");
|
||||
// const uint8_t *tree_root = bc.get_fcmp_tree_root_at(bc.height() - 1);
|
||||
// ASSERT_TRUE(cryptonote::Blockchain::expand_transaction_2(alicebob_tx,
|
||||
// cryptonote::get_transaction_prefix_hash(alicebob_tx),
|
||||
// /*pubkeys=*/{},
|
||||
// tree_root));
|
||||
// EXPECT_TRUE(rct::verRctNonSemanticsSimple(alicebob_tx.rct_signatures));
|
||||
|
||||
// 12.
|
||||
LOG_PRINT_L2("'Chain, chain, chain (Chain, chain, chain)' - Aretha Franklin");
|
||||
const rct::xmr_amount alicebob_tx_fee = alicebob_tx.rct_signatures.txnFee;
|
||||
bc.add_block(HF_VERSION_CARROT, {std::move(alicebob_tx)}, mock::null_addr);
|
||||
// // 12.
|
||||
// LOG_PRINT_L2("'Chain, chain, chain (Chain, chain, chain)' - Aretha Franklin");
|
||||
// const rct::xmr_amount alicebob_tx_fee = alicebob_tx.rct_signatures.txnFee;
|
||||
// bc.add_block(HF_VERSION_CARROT, {std::move(alicebob_tx)}, mock::null_addr);
|
||||
|
||||
// 13.
|
||||
LOG_PRINT_L2("A great day for Bob");
|
||||
ASSERT_EQ(0, bob.balance_all(true));
|
||||
blocks_added = bc.refresh_wallet(bob, 0);
|
||||
ASSERT_EQ(bc.height()-1, blocks_added);
|
||||
ASSERT_EQ(1, bob.m_transfers.size());
|
||||
EXPECT_EQ(out_amount, bob.balance_all(true));
|
||||
// // 13.
|
||||
// LOG_PRINT_L2("A great day for Bob");
|
||||
// ASSERT_EQ(0, bob.balance_all(true));
|
||||
// blocks_added = bc.refresh_wallet(bob, 0);
|
||||
// ASSERT_EQ(bc.height()-1, blocks_added);
|
||||
// ASSERT_EQ(1, bob.m_transfers.size());
|
||||
// EXPECT_EQ(out_amount, bob.balance_all(true));
|
||||
|
||||
// 14.
|
||||
LOG_PRINT_L2("Alice obtains the fulfillment that only stems from selfless generosity");
|
||||
const rct::xmr_amount alice_old_balance = alice.balance_all(true);
|
||||
ASSERT_GE(alice_old_balance, out_amount + alicebob_tx_fee);
|
||||
blocks_added = bc.refresh_wallet(alice, 0);
|
||||
ASSERT_EQ(1, blocks_added);
|
||||
const rct::xmr_amount alice_new_balance = alice.balance_all(true);
|
||||
ASSERT_LT(alice_new_balance, alice_old_balance);
|
||||
EXPECT_EQ(alice_new_balance + out_amount + alicebob_tx_fee, alice_old_balance);
|
||||
}
|
||||
// // 14.
|
||||
// LOG_PRINT_L2("Alice obtains the fulfillment that only stems from selfless generosity");
|
||||
// const rct::xmr_amount alice_old_balance = alice.balance_all(true);
|
||||
// ASSERT_GE(alice_old_balance, out_amount + alicebob_tx_fee);
|
||||
// blocks_added = bc.refresh_wallet(alice, 0);
|
||||
// ASSERT_EQ(1, blocks_added);
|
||||
// const rct::xmr_amount alice_new_balance = alice.balance_all(true);
|
||||
// ASSERT_LT(alice_new_balance, alice_old_balance);
|
||||
// EXPECT_EQ(alice_new_balance + out_amount + alicebob_tx_fee, alice_old_balance);
|
||||
// }
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user