forked from such-gitea/wownero-lws
Add support for subaddress lookahead (#195)
This commit is contained in:
committed by
Lee *!* Clagett
parent
e8b889e95f
commit
16111cae2c
39
tests/unit/db/print.test.h
Normal file
39
tests/unit/db/print.test.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2025, 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 "framework.test.h"
|
||||
#include <ostream>
|
||||
|
||||
namespace lws { namespace db
|
||||
{
|
||||
inline std::ostream& operator<<(std::ostream& out, const index_ranges& src)
|
||||
{
|
||||
using lest::to_string;
|
||||
return out << to_string(src.get_container());
|
||||
}
|
||||
}} // lws // db
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include "common/util.h" // monero/src/
|
||||
#include "db/string.h"
|
||||
#include "error.h"
|
||||
#include "framework.test.h"
|
||||
|
||||
namespace lws { namespace db { namespace test
|
||||
{
|
||||
@@ -68,3 +71,201 @@ namespace lws { namespace db { namespace test
|
||||
return lws::account{make_db_account(pubs, key), {}, {}};
|
||||
}
|
||||
}}} // lws // db // test
|
||||
|
||||
LWS_CASE("lws::db::storage")
|
||||
{
|
||||
lws::db::account_address account_address{};
|
||||
crypto::secret_key view{};
|
||||
crypto::generate_keys(account_address.spend_public, view);
|
||||
crypto::generate_keys(account_address.view_public, view);
|
||||
const std::string address = lws::db::address_string(account_address);
|
||||
const std::string viewkey = epee::to_hex::string(epee::as_byte_span(unwrap(unwrap(view))));
|
||||
|
||||
const lws::db::address_index lookahead{
|
||||
lws::db::major_index(2), lws::db::minor_index(2)
|
||||
};
|
||||
|
||||
SETUP("Database with account")
|
||||
{
|
||||
lws::db::test::cleanup_db on_scope_exit{};
|
||||
lws::db::storage db = lws::db::test::get_fresh_db();
|
||||
EXPECT(db.add_account(account_address, view));
|
||||
|
||||
const lws::db::block_info last_block =
|
||||
MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_last_block());
|
||||
|
||||
const auto get_account = [&db, &account_address] () -> lws::db::account
|
||||
{
|
||||
return MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_account(account_address)).second;
|
||||
};
|
||||
|
||||
SECTION("rollback lookahead_fail via rescan")
|
||||
{
|
||||
EXPECT(db.import_request(account_address, last_block.id, lookahead));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 10));
|
||||
|
||||
const auto block_failed = lws::db::block_id(to_uint(last_block.id) + 1);
|
||||
const auto update =
|
||||
db.update_lookahead(account_address, block_failed, {lws::db::major_index(10), lws::db::minor_index(10)}, 10);
|
||||
EXPECT(update == -1);
|
||||
EXPECT(get_account().lookahead_fail == block_failed);
|
||||
|
||||
EXPECT(db.rescan(last_block.id, {std::addressof(account_address), 1}));
|
||||
EXPECT(get_account().lookahead_fail == lws::db::block_id(0));
|
||||
}
|
||||
|
||||
SECTION("rollback lookahead_fail via import")
|
||||
{
|
||||
EXPECT(db.import_request(account_address, last_block.id, lookahead));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 10));
|
||||
|
||||
const auto block_failed = lws::db::block_id(to_uint(last_block.id) + 1);
|
||||
const auto update =
|
||||
db.update_lookahead(account_address, block_failed, {lws::db::major_index(10), lws::db::minor_index(10)}, 10);
|
||||
EXPECT(update == -1);
|
||||
EXPECT(get_account().lookahead_fail == block_failed);
|
||||
|
||||
EXPECT(db.import_request(account_address, last_block.id, lookahead));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 10));
|
||||
EXPECT(get_account().lookahead_fail == lws::db::block_id(0));
|
||||
}
|
||||
|
||||
const auto add_output = [&] ()
|
||||
{
|
||||
auto account = get_account();
|
||||
const lws::db::transaction_link link{
|
||||
lws::db::block_id(to_uint(last_block.id) + 1), crypto::rand<crypto::hash>()
|
||||
};
|
||||
const crypto::public_key tx_public = []() {
|
||||
crypto::secret_key secret;
|
||||
crypto::public_key out;
|
||||
crypto::generate_keys(out, secret);
|
||||
return out;
|
||||
}();
|
||||
const crypto::hash tx_prefix = crypto::rand<crypto::hash>();
|
||||
const crypto::public_key pub = crypto::rand<crypto::public_key>();
|
||||
const rct::key ringct = crypto::rand<rct::key>();
|
||||
const auto extra =
|
||||
lws::db::extra(lws::db::extra::coinbase_output | lws::db::extra::ringct_output);
|
||||
const auto payment_id_ = crypto::rand<lws::db::output::payment_id_>();
|
||||
const crypto::key_image image = crypto::rand<crypto::key_image>();
|
||||
|
||||
lws::account real_account{account, {}, {}};
|
||||
real_account.add_out(
|
||||
lws::db::output{
|
||||
link,
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{500, 30},
|
||||
std::uint64_t(40000),
|
||||
std::uint32_t(16),
|
||||
std::uint32_t(2),
|
||||
tx_public
|
||||
},
|
||||
std::uint64_t(7000),
|
||||
std::uint64_t(4670),
|
||||
tx_prefix,
|
||||
pub,
|
||||
ringct,
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
lws::db::pack(extra, sizeof(crypto::hash)),
|
||||
payment_id_,
|
||||
std::uint64_t(100),
|
||||
lws::db::address_index{lws::db::major_index(2), lws::db::minor_index(10)}
|
||||
}
|
||||
);
|
||||
|
||||
{
|
||||
std::vector<crypto::hash> hashes{
|
||||
last_block.hash,
|
||||
crypto::rand<crypto::hash>(),
|
||||
crypto::rand<crypto::hash>(),
|
||||
crypto::rand<crypto::hash>(),
|
||||
crypto::rand<crypto::hash>(),
|
||||
crypto::rand<crypto::hash>()
|
||||
};
|
||||
|
||||
const auto thing = db.update(last_block.id, epee::to_span(hashes), {std::addressof(real_account), 1}, {});
|
||||
if (!thing)
|
||||
std::cout << thing.error().message() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SECTION("Lookahead with outputs")
|
||||
{
|
||||
add_output();
|
||||
const auto scan_height = get_account().scan_height;
|
||||
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))).empty());
|
||||
EXPECT(db.import_request(account_address, scan_height, lookahead));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 18));
|
||||
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{
|
||||
{lws::db::major_index(0), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}},
|
||||
{lws::db::major_index(1), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}},
|
||||
{lws::db::major_index(2), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(11)}}}},
|
||||
{lws::db::major_index(3), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}},
|
||||
};
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
|
||||
SECTION("shrink lookahead")
|
||||
{
|
||||
const lws::db::address_index test1{
|
||||
lws::db::major_index(3), lws::db::minor_index(2)
|
||||
};
|
||||
const lws::db::address_index test2{
|
||||
lws::db::major_index(2), lws::db::minor_index(3)
|
||||
};
|
||||
const lws::db::address_index shrink{
|
||||
lws::db::major_index(1), lws::db::minor_index(1)
|
||||
};
|
||||
EXPECT(!db.shrink_lookahead(account_address, test1));
|
||||
EXPECT(!db.shrink_lookahead(account_address, test2));
|
||||
EXPECT(db.shrink_lookahead(account_address, lookahead));
|
||||
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
EXPECT(get_account().lookahead == lookahead);
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
|
||||
EXPECT(db.shrink_lookahead(account_address, shrink));
|
||||
EXPECT(get_account().lookahead == shrink);
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Lookahead failure with outputs")
|
||||
{
|
||||
add_output();
|
||||
const auto scan_height = get_account().scan_height;
|
||||
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))).empty());
|
||||
EXPECT(db.import_request(account_address, scan_height, lookahead));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 17));
|
||||
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{
|
||||
{lws::db::major_index(0), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}},
|
||||
{lws::db::major_index(1), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}},
|
||||
{lws::db::major_index(2), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(11)}}}}
|
||||
};
|
||||
|
||||
EXPECT(MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
|
||||
SECTION("shrink lookahead")
|
||||
{
|
||||
const lws::db::address_index test1{
|
||||
lws::db::major_index(3), lws::db::minor_index(2)
|
||||
};
|
||||
const lws::db::address_index test2{
|
||||
lws::db::major_index(2), lws::db::minor_index(3)
|
||||
};
|
||||
const lws::db::address_index shrink{
|
||||
lws::db::major_index(1), lws::db::minor_index(1)
|
||||
};
|
||||
EXPECT(!db.shrink_lookahead(account_address, test1));
|
||||
EXPECT(!db.shrink_lookahead(account_address, test2));
|
||||
EXPECT(!db.shrink_lookahead(account_address, lookahead));
|
||||
EXPECT(!db.shrink_lookahead(account_address, shrink));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +655,9 @@ using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
|
||||
template< typename T, typename R >
|
||||
using ForNonContainerNonPointer = typename std::enable_if< ! (is_container<T>::value || std::is_pointer<T>::value), R>::type;
|
||||
|
||||
template< typename T >
|
||||
auto to_string( T const & item ) -> ForNonContainerNonPointer<T, std::string>;
|
||||
|
||||
template< typename T >
|
||||
auto make_enum_string( T const & item ) -> ForNonEnum<T, std::string>
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <optional>
|
||||
#include "db/data.h"
|
||||
#include "db/print.test.h"
|
||||
#include "db/storage.test.h"
|
||||
#include "db/string.h"
|
||||
#include "error.h"
|
||||
@@ -151,7 +152,7 @@ LWS_CASE("rest_server")
|
||||
std::string message =
|
||||
"{\"address\":\"" + address + "\",\"view_key\":\"" + viewkey + "\",\"create_account\":true,\"generated_locally\":true}";
|
||||
std::string response = invoke(client, "/login", message);
|
||||
EXPECT(response == "{\"new_address\":true,\"generated_locally\":true}");
|
||||
EXPECT(response == "{\"new_address\":true,\"generated_locally\":true,\"lookahead\":{\"maj_i\":0,\"min_i\":0}}");
|
||||
|
||||
auto account = get_account();
|
||||
EXPECT(account.id == lws::db::account_id(1));
|
||||
@@ -219,10 +220,20 @@ LWS_CASE("rest_server")
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Accepted, waiting for approval\","
|
||||
"\"new_request\":true,"
|
||||
"\"request_fulfilled\":false}"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 0));
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Approved\","
|
||||
"\"new_request\":false,"
|
||||
"\"request_fulfilled\":true,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}));
|
||||
response = invoke(client, "/get_address_info", message);
|
||||
EXPECT(response ==
|
||||
"{\"locked_funds\":\"0\","
|
||||
@@ -236,6 +247,167 @@ LWS_CASE("rest_server")
|
||||
);
|
||||
}
|
||||
|
||||
SECTION("Import with lookahead")
|
||||
{
|
||||
EXPECT(account.start_height != lws::db::block_id(0));
|
||||
|
||||
const std::string scan_height = std::to_string(std::uint64_t(account.scan_height));
|
||||
const std::string start_height = std::to_string(std::uint64_t(account.start_height));
|
||||
message = "{\"address\":\"" + address + "\",\"view_key\":\"" + viewkey + "\"}";
|
||||
response = invoke(client, "/get_address_info", message);
|
||||
EXPECT(response ==
|
||||
"{\"locked_funds\":\"0\","
|
||||
"\"total_received\":\"0\","
|
||||
"\"total_sent\":\"0\","
|
||||
"\"scanned_height\":" + scan_height + "," +
|
||||
"\"scanned_block_height\":" + scan_height + ","
|
||||
"\"start_height\":" + start_height + ","
|
||||
"\"transaction_height\":" + scan_height + ","
|
||||
"\"blockchain_height\":" + scan_height + "}"
|
||||
);
|
||||
|
||||
message = "{\"address\":\"" + address + "\",\"view_key\":\"" + viewkey + "\", \"lookahead\":{\"maj_i\":2,\"min_i\":3}}";
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Accepted, waiting for approval\","
|
||||
"\"new_request\":true,"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Waiting for Approval\","
|
||||
"\"new_request\":false,"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 6));
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Approved\","
|
||||
"\"new_request\":false,"
|
||||
"\"request_fulfilled\":true,"
|
||||
"\"lookahead\":{\"maj_i\":2,\"min_i\":3}}"
|
||||
);
|
||||
|
||||
response = invoke(client, "/get_address_info", message);
|
||||
EXPECT(response ==
|
||||
"{\"locked_funds\":\"0\","
|
||||
"\"total_received\":\"0\","
|
||||
"\"total_sent\":\"0\","
|
||||
"\"scanned_height\":0,"
|
||||
"\"scanned_block_height\":0,"
|
||||
"\"start_height\":0,"
|
||||
"\"transaction_height\":" + scan_height + ","
|
||||
"\"blockchain_height\":" + scan_height + ","
|
||||
"\"lookahead\":{\"maj_i\":2,\"min_i\":3}}"
|
||||
);
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const auto account = MONERO_UNWRAP(reader.get_account(lws::db::account_status::active, lws::db::account_id(1)));
|
||||
const lws::db::address_index lookahead{lws::db::major_index(2), lws::db::minor_index(3)};
|
||||
EXPECT(account.lookahead == lookahead);
|
||||
EXPECT(account.lookahead_fail == lws::db::block_id(0));
|
||||
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{
|
||||
{lws::db::major_index(0), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(2)}}}},
|
||||
{lws::db::major_index(1), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(2)}}}},
|
||||
};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Import with lookahead failure")
|
||||
{
|
||||
EXPECT(account.start_height != lws::db::block_id(0));
|
||||
|
||||
const std::string scan_height = std::to_string(std::uint64_t(account.scan_height));
|
||||
const std::string start_height = std::to_string(std::uint64_t(account.start_height));
|
||||
message = "{\"address\":\"" + address + "\",\"view_key\":\"" + viewkey + "\"}";
|
||||
response = invoke(client, "/get_address_info", message);
|
||||
EXPECT(response ==
|
||||
"{\"locked_funds\":\"0\","
|
||||
"\"total_received\":\"0\","
|
||||
"\"total_sent\":\"0\","
|
||||
"\"scanned_height\":" + scan_height + "," +
|
||||
"\"scanned_block_height\":" + scan_height + ","
|
||||
"\"start_height\":" + start_height + ","
|
||||
"\"transaction_height\":" + scan_height + ","
|
||||
"\"blockchain_height\":" + scan_height + "}"
|
||||
);
|
||||
|
||||
message = "{\"address\":\"" + address + "\",\"view_key\":\"" + viewkey + "\", \"lookahead\":{\"maj_i\":2,\"min_i\":3}}";
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Accepted, waiting for approval\","
|
||||
"\"new_request\":true,"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Waiting for Approval\","
|
||||
"\"new_request\":false,"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":0,\"min_i\":0}}"
|
||||
);
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account_address), 1}, 5));
|
||||
response = invoke(client, "/import_wallet_request", message);
|
||||
EXPECT(response ==
|
||||
"{\"import_fee\":\"0\","
|
||||
"\"status\":\"Accepted, waiting for approval\","
|
||||
"\"new_request\":true,"
|
||||
"\"request_fulfilled\":false,"
|
||||
"\"lookahead\":{\"maj_i\":2,\"min_i\":3}}"
|
||||
);
|
||||
|
||||
response = invoke(client, "/get_address_info", message);
|
||||
EXPECT(response ==
|
||||
"{\"locked_funds\":\"0\","
|
||||
"\"total_received\":\"0\","
|
||||
"\"total_sent\":\"0\","
|
||||
"\"scanned_height\":0,"
|
||||
"\"scanned_block_height\":0,"
|
||||
"\"start_height\":0,"
|
||||
"\"transaction_height\":" + scan_height + ","
|
||||
"\"blockchain_height\":" + scan_height + ","
|
||||
"\"lookahead_fail\":1,"
|
||||
"\"lookahead\":{\"maj_i\":2,\"min_i\":3}}"
|
||||
);
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const auto account = MONERO_UNWRAP(reader.get_account(lws::db::account_status::active, lws::db::account_id(1)));
|
||||
const lws::db::address_index lookahead{lws::db::major_index(2), lws::db::minor_index(3)};
|
||||
EXPECT(account.lookahead == lookahead);
|
||||
EXPECT(account.lookahead_fail == lws::db::block_id(1));
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))).empty());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SECTION("One Receive, Zero Spends")
|
||||
{
|
||||
const std::string scan_height = std::to_string(std::uint64_t(account.scan_height) + 5);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cryptonote_config.h" // monero/src
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h" // monero/src
|
||||
#include "db/chain.test.h"
|
||||
#include "db/print.test.h"
|
||||
#include "db/storage.test.h"
|
||||
#include "device/device_default.hpp" // monero/src
|
||||
#include "hardforks/hardforks.h" // monero/src
|
||||
@@ -149,7 +150,7 @@ namespace
|
||||
{ pub_keys.push_back(val.key); }
|
||||
};
|
||||
|
||||
transaction make_tx(lest::env& lest_env, const cryptonote::account_keys& keys, std::vector<cryptonote::tx_destination_entry>& destinations, const std::uint32_t ring_base, const bool use_view_tag)
|
||||
transaction make_tx(lest::env& lest_env, const cryptonote::account_keys& keys, std::vector<cryptonote::tx_destination_entry> destinations, const std::uint32_t ring_base, const bool use_view_tag)
|
||||
{
|
||||
static constexpr std::uint64_t input_amount = 20000;
|
||||
static constexpr std::uint64_t output_amount = 8000;
|
||||
@@ -174,6 +175,9 @@ namespace
|
||||
subaddresses[destination.addr.m_spend_public_key] = {0, index};
|
||||
}
|
||||
|
||||
if (2 < destinations.size())
|
||||
destinations.erase(destinations.begin() + 1, destinations.end() - 1);
|
||||
|
||||
std::vector<cryptonote::tx_source_entry> sources;
|
||||
sources.emplace_back();
|
||||
sources.back().amount = input_amount;
|
||||
@@ -307,7 +311,7 @@ LWS_CASE("lws::scanner::sync and lws::scanner::run")
|
||||
keys_subaddr2.m_account_address = hw.get_subaddress(keys, cryptonote::subaddress_index{0, 2});
|
||||
|
||||
const auto sub1_secret = hw.get_subaddress_secret_key(keys.m_view_secret_key, cryptonote::subaddress_index{0, 1});
|
||||
const auto sub2_secret = hw.get_subaddress_secret_key(keys.m_view_secret_key, cryptonote::subaddress_index{0, 1});
|
||||
const auto sub2_secret = hw.get_subaddress_secret_key(keys.m_view_secret_key, cryptonote::subaddress_index{0, 2});
|
||||
|
||||
sc_add(to_bytes(keys_subaddr1.m_spend_secret_key), to_bytes(sub1_secret), to_bytes(keys.m_spend_secret_key));
|
||||
sc_add(to_bytes(keys_subaddr1.m_view_secret_key), to_bytes(keys_subaddr1.m_spend_secret_key), to_bytes(keys.m_view_secret_key));
|
||||
@@ -416,7 +420,7 @@ LWS_CASE("lws::scanner::sync and lws::scanner::run")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("lws::scanner::run")
|
||||
SECTION("lws::scanner::run (with upsert)")
|
||||
{
|
||||
{
|
||||
const std::vector<lws::db::subaddress_dict> indexes{
|
||||
@@ -436,7 +440,7 @@ LWS_CASE("lws::scanner::sync and lws::scanner::run")
|
||||
EXPECT(result->at(0).second.get_container().at(0).size() == 2);
|
||||
EXPECT(result->at(0).second.get_container().at(0).at(0) == lws::db::minor_index(1));
|
||||
EXPECT(result->at(0).second.get_container().at(0).at(1) == lws::db::minor_index(2));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<cryptonote::tx_destination_entry> destinations;
|
||||
destinations.emplace_back();
|
||||
@@ -534,7 +538,7 @@ LWS_CASE("lws::scanner::sync and lws::scanner::run")
|
||||
bmessage.output_indices.resize(1);
|
||||
messages.push_back(daemon_response(bmessage));
|
||||
{
|
||||
static constexpr const lws::scanner_options opts{true, false};
|
||||
static constexpr const lws::scanner_options opts{1, false};
|
||||
lws::scanner scanner{db.clone(), epee::net_utils::ssl_verification_t::none};
|
||||
boost::thread server_thread(&scanner_thread, std::ref(scanner), rpc.zmq_context(), std::cref(messages));
|
||||
const join on_scope_exit{server_thread};
|
||||
@@ -735,7 +739,412 @@ LWS_CASE("lws::scanner::sync and lws::scanner::run")
|
||||
EXPECT(MONERO_UNWRAP(reader.get_outputs(lws::db::account_id(2))).count() == 0);
|
||||
EXPECT(MONERO_UNWRAP(reader.get_spends(lws::db::account_id(2))).count() == 0);
|
||||
}
|
||||
} //SECTION (lws::scanner::run)
|
||||
} //SECTION (lws::scanner::run (with upsert))
|
||||
|
||||
SECTION("lws::scanner::run (with lookahead)")
|
||||
{
|
||||
std::vector<cryptonote::tx_destination_entry> destinations;
|
||||
destinations.emplace_back();
|
||||
destinations.back().amount = 8000;
|
||||
destinations.back().addr = keys.m_account_address;
|
||||
|
||||
std::vector<epee::byte_slice> messages{};
|
||||
transaction tx = make_miner_tx(lest_env, last_block.id, account, false);
|
||||
EXPECT(tx.pub_keys.size() == 1);
|
||||
EXPECT(tx.spend_publics.size() == 1);
|
||||
|
||||
transaction tx2 = make_tx(lest_env, keys, destinations, 20, true);
|
||||
EXPECT(tx2.pub_keys.size() == 1);
|
||||
EXPECT(tx2.spend_publics.size() == 1);
|
||||
|
||||
transaction tx3 = make_tx(lest_env, keys, destinations, 86, false);
|
||||
EXPECT(tx3.pub_keys.size() == 1);
|
||||
EXPECT(tx3.spend_publics.size() == 1);
|
||||
|
||||
destinations.emplace_back();
|
||||
destinations.back().amount = 2000;
|
||||
destinations.back().addr = keys_subaddr1.m_account_address;
|
||||
destinations.back().is_subaddress = true;
|
||||
|
||||
transaction tx4 = make_tx(lest_env, keys, destinations, 50, false);
|
||||
EXPECT(tx4.pub_keys.size() == 1);
|
||||
EXPECT(tx4.spend_publics.size() == 2);
|
||||
|
||||
destinations.emplace_back();
|
||||
destinations.back().amount = 1000;
|
||||
destinations.back().addr = keys_subaddr2.m_account_address;
|
||||
destinations.back().is_subaddress = true;
|
||||
|
||||
transaction tx5 = make_tx(lest_env, keys, destinations, 146, true);
|
||||
EXPECT(tx5.pub_keys.size() == 1);
|
||||
EXPECT(tx5.spend_publics.size() == 2);
|
||||
|
||||
cryptonote::rpc::GetBlocksFast::Response bmessage{};
|
||||
bmessage.start_height = std::uint64_t(last_block.id) + 1;
|
||||
bmessage.current_height = bmessage.start_height + 1;
|
||||
bmessage.blocks.emplace_back();
|
||||
bmessage.blocks.back().block.miner_tx = tx.tx;
|
||||
bmessage.blocks.back().block.tx_hashes.push_back(cryptonote::get_transaction_hash(tx2.tx));
|
||||
bmessage.blocks.back().block.tx_hashes.push_back(cryptonote::get_transaction_hash(tx3.tx));
|
||||
bmessage.blocks.back().block.tx_hashes.push_back(cryptonote::get_transaction_hash(tx4.tx));
|
||||
bmessage.blocks.back().block.tx_hashes.push_back(cryptonote::get_transaction_hash(tx5.tx));
|
||||
bmessage.blocks.back().transactions.push_back(tx2.tx);
|
||||
bmessage.blocks.back().transactions.push_back(tx3.tx);
|
||||
bmessage.blocks.back().transactions.push_back(tx4.tx);
|
||||
bmessage.blocks.back().transactions.push_back(tx5.tx);
|
||||
bmessage.output_indices.emplace_back();
|
||||
bmessage.output_indices.back().emplace_back();
|
||||
bmessage.output_indices.back().back().push_back(100);
|
||||
bmessage.output_indices.back().emplace_back();
|
||||
bmessage.output_indices.back().back().push_back(101);
|
||||
bmessage.output_indices.back().emplace_back();
|
||||
bmessage.output_indices.back().back().push_back(102);
|
||||
bmessage.output_indices.back().emplace_back();
|
||||
bmessage.output_indices.back().back().push_back(200);
|
||||
bmessage.output_indices.back().back().push_back(201);
|
||||
bmessage.output_indices.back().emplace_back();
|
||||
bmessage.output_indices.back().back().push_back(300);
|
||||
bmessage.output_indices.back().back().push_back(301);
|
||||
bmessage.blocks.push_back(bmessage.blocks.back());
|
||||
bmessage.output_indices.push_back(bmessage.output_indices.back());
|
||||
|
||||
std::vector<crypto::hash> hashes{
|
||||
last_block.hash,
|
||||
cryptonote::get_block_hash(bmessage.blocks.back().block),
|
||||
};
|
||||
{
|
||||
cryptonote::rpc::GetHashesFast::Response hmessage{};
|
||||
|
||||
hmessage.start_height = std::uint64_t(last_block.id);
|
||||
hmessage.hashes = hashes;
|
||||
hmessage.current_height = hmessage.start_height + hashes.size() - 1;
|
||||
messages.push_back(daemon_response(hmessage));
|
||||
|
||||
hmessage.start_height = hmessage.current_height;
|
||||
hmessage.hashes.front() = hmessage.hashes.back();
|
||||
hmessage.hashes.resize(1);
|
||||
messages.push_back(daemon_response(hmessage));
|
||||
|
||||
{
|
||||
lws::scanner scanner{db.clone(), epee::net_utils::ssl_verification_t::none};
|
||||
boost::thread server_thread(&scanner_thread, std::ref(scanner), rpc.zmq_context(), std::cref(messages));
|
||||
const join on_scope_exit{server_thread};
|
||||
EXPECT(scanner.sync(MONERO_UNWRAP(rpc.connect())));
|
||||
lws_test::test_chain(lest_env, MONERO_UNWRAP(db.start_read()), last_block.id, epee::to_span(hashes));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT(db.add_account(account, keys.m_view_secret_key));
|
||||
EXPECT(db.add_account(account2, keys2.m_view_secret_key));
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
|
||||
const lws::db::block_id user_height =
|
||||
MONERO_UNWRAP(MONERO_UNWRAP(db.start_read()).get_account(lws::db::account_status::active, lws::db::account_id(1))).scan_height;
|
||||
|
||||
EXPECT(db.import_request(account, user_height, {lws::db::major_index(1), lws::db::minor_index(2)}));
|
||||
EXPECT(db.accept_requests(lws::db::request::import_scan, {std::addressof(account), 1}, 2));
|
||||
|
||||
{
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{
|
||||
{lws::db::major_index(0), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(1)}}}}
|
||||
};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
|
||||
messages.clear();
|
||||
messages.push_back(daemon_response(bmessage));
|
||||
bmessage.start_height = bmessage.current_height;
|
||||
bmessage.blocks.resize(1);
|
||||
bmessage.output_indices.resize(1);
|
||||
messages.push_back(daemon_response(bmessage));
|
||||
{
|
||||
static constexpr const lws::scanner_options opts{10, false};
|
||||
lws::scanner scanner{db.clone(), epee::net_utils::ssl_verification_t::none};
|
||||
boost::thread server_thread(&scanner_thread, std::ref(scanner), rpc.zmq_context(), std::cref(messages));
|
||||
const join on_scope_exit{server_thread};
|
||||
scanner.run(std::move(rpc), 1, {}, {}, opts);
|
||||
}
|
||||
|
||||
hashes.push_back(cryptonote::get_block_hash(bmessage.blocks.back().block));
|
||||
lws_test::test_chain(lest_env, MONERO_UNWRAP(db.start_read()), last_block.id, epee::to_span(hashes));
|
||||
|
||||
const lws::db::block_id new_last_block_id = lws::db::block_id(std::uint64_t(last_block.id) + 2);
|
||||
EXPECT(get_account().scan_height == new_last_block_id);
|
||||
{
|
||||
const std::map<std::pair<lws::db::output_id, std::uint32_t>, lws::db::output> expected{
|
||||
{
|
||||
{lws::db::output_id{0, 100}, 35184372088830}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 100}, 35184372088830, 0, 0, tx.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx.tx),
|
||||
tx.spend_publics.at(0),
|
||||
rct::commit(35184372088830, rct::identity()),
|
||||
{},
|
||||
lws::db::pack(lws::db::extra(lws::db::extra::coinbase_output | lws::db::extra::ringct_output), 0),
|
||||
{},
|
||||
0, // fee
|
||||
lws::db::address_index{}
|
||||
},
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 101}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx2.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 101}, 8000, 15, 0, tx2.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx2.tx),
|
||||
tx2.spend_publics.at(0),
|
||||
tx2.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
12000, // fee
|
||||
lws::db::address_index{}
|
||||
},
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 102}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx3.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 102}, 8000, 15, 0, tx3.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx3.tx),
|
||||
tx3.spend_publics.at(0),
|
||||
tx3.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
12000, // fee
|
||||
lws::db::address_index{}
|
||||
},
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 200}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx4.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 200}, 8000, 15, 0, tx4.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx4.tx),
|
||||
tx4.spend_publics.at(0),
|
||||
tx4.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
10000, // fee
|
||||
lws::db::address_index{}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 201}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx4.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 201}, 8000, 15, 1, tx4.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx4.tx),
|
||||
tx4.spend_publics.at(1),
|
||||
tx4.tx.rct_signatures.outPk.at(1).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
10000, // fee
|
||||
lws::db::address_index{}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 200}, 2000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx4.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 200}, 2000, 15, 0, tx4.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx4.tx),
|
||||
tx4.spend_publics.at(0),
|
||||
tx4.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
10000, // fee
|
||||
lws::db::address_index{lws::db::major_index::primary, lws::db::minor_index(1)}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 201}, 2000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx4.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 201}, 2000, 15, 1, tx4.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx4.tx),
|
||||
tx4.spend_publics.at(1),
|
||||
tx4.tx.rct_signatures.outPk.at(1).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
10000, // fee
|
||||
lws::db::address_index{lws::db::major_index::primary, lws::db::minor_index(1)}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 300}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx5.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 300}, 8000, 15, 0, tx5.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx5.tx),
|
||||
tx5.spend_publics.at(0),
|
||||
tx5.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
11000, // fee
|
||||
lws::db::address_index{}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 301}, 8000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx5.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 301}, 8000, 15, 1, tx5.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx5.tx),
|
||||
tx5.spend_publics.at(1),
|
||||
tx5.tx.rct_signatures.outPk.at(1).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
11000, // fee
|
||||
lws::db::address_index{}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 300}, 1000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx5.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 300}, 1000, 15, 0, tx5.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx5.tx),
|
||||
tx5.spend_publics.at(0),
|
||||
tx5.tx.rct_signatures.outPk.at(0).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
11000, // fee
|
||||
lws::db::address_index{lws::db::major_index::primary, lws::db::minor_index(2)}
|
||||
}
|
||||
},
|
||||
{
|
||||
{lws::db::output_id{0, 301}, 1000}, lws::db::output{
|
||||
lws::db::transaction_link{new_last_block_id, cryptonote::get_transaction_hash(tx5.tx)},
|
||||
lws::db::output::spend_meta_{
|
||||
lws::db::output_id{0, 301}, 1000, 15, 1, tx5.pub_keys.at(0)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
cryptonote::get_transaction_prefix_hash(tx5.tx),
|
||||
tx5.spend_publics.at(1),
|
||||
tx5.tx.rct_signatures.outPk.at(1).mask,
|
||||
{},
|
||||
lws::db::pack(lws::db::extra::ringct_output, 8),
|
||||
{},
|
||||
11000, // fee
|
||||
lws::db::address_index{lws::db::major_index::primary, lws::db::minor_index(2)}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto reader = MONERO_UNWRAP(db.start_read());
|
||||
auto outputs = MONERO_UNWRAP(reader.get_outputs(lws::db::account_id(1)));
|
||||
EXPECT(outputs.count() == 6);
|
||||
auto output_it = outputs.make_iterator();
|
||||
for (auto output_it = outputs.make_iterator(); !output_it.is_end(); ++output_it)
|
||||
{
|
||||
auto real_output = *output_it;
|
||||
const auto expected_output =
|
||||
expected.find(std::make_pair(real_output.spend_meta.id, real_output.spend_meta.amount));
|
||||
EXPECT(expected_output != expected.end());
|
||||
|
||||
EXPECT(real_output.link.height == expected_output->second.link.height);
|
||||
EXPECT(real_output.link.tx_hash == expected_output->second.link.tx_hash);
|
||||
EXPECT(real_output.spend_meta.id == expected_output->second.spend_meta.id);
|
||||
EXPECT(real_output.spend_meta.amount == expected_output->second.spend_meta.amount);
|
||||
EXPECT(real_output.spend_meta.mixin_count == expected_output->second.spend_meta.mixin_count);
|
||||
EXPECT(real_output.spend_meta.index == expected_output->second.spend_meta.index);
|
||||
EXPECT(real_output.tx_prefix_hash == expected_output->second.tx_prefix_hash);
|
||||
EXPECT(real_output.spend_meta.tx_public == expected_output->second.spend_meta.tx_public);
|
||||
EXPECT(real_output.pub == expected_output->second.pub);
|
||||
EXPECT(rct::commit(real_output.spend_meta.amount, real_output.ringct_mask) == expected_output->second.ringct_mask);
|
||||
EXPECT(real_output.extra == expected_output->second.extra);
|
||||
if (unpack(expected_output->second.extra).second == 8)
|
||||
EXPECT(real_output.payment_id.short_ == expected_output->second.payment_id.short_);
|
||||
EXPECT(real_output.fee == expected_output->second.fee);
|
||||
EXPECT(real_output.recipient == expected_output->second.recipient);
|
||||
}
|
||||
|
||||
auto spends = MONERO_UNWRAP(reader.get_spends(lws::db::account_id(1)));
|
||||
EXPECT(spends.count() == 2);
|
||||
auto spend_it = spends.make_iterator();
|
||||
EXPECT(!spend_it.is_end());
|
||||
|
||||
auto real_spend = *spend_it;
|
||||
EXPECT(real_spend.link.height == new_last_block_id);
|
||||
EXPECT(real_spend.link.tx_hash == cryptonote::get_transaction_hash(tx3.tx));
|
||||
lws::db::output_id expected_out{0, 100};
|
||||
EXPECT(real_spend.source == expected_out);
|
||||
EXPECT(real_spend.mixin_count == 15);
|
||||
EXPECT(real_spend.length == 0);
|
||||
EXPECT(real_spend.payment_id == crypto::hash{});
|
||||
EXPECT(real_spend.sender == lws::db::address_index{});
|
||||
|
||||
++spend_it;
|
||||
EXPECT(!spend_it.is_end());
|
||||
|
||||
real_spend = *spend_it;
|
||||
EXPECT(real_spend.link.height == new_last_block_id);
|
||||
EXPECT(real_spend.link.tx_hash == cryptonote::get_transaction_hash(tx3.tx));
|
||||
expected_out = lws::db::output_id{0, 101};
|
||||
EXPECT(real_spend.source == expected_out);
|
||||
EXPECT(real_spend.mixin_count == 15);
|
||||
EXPECT(real_spend.length == 0);
|
||||
EXPECT(real_spend.payment_id == crypto::hash{});
|
||||
EXPECT(real_spend.sender == lws::db::address_index{});
|
||||
|
||||
EXPECT(MONERO_UNWRAP(reader.get_outputs(lws::db::account_id(2))).count() == 0);
|
||||
EXPECT(MONERO_UNWRAP(reader.get_spends(lws::db::account_id(2))).count() == 0);
|
||||
|
||||
{
|
||||
const std::vector<lws::db::subaddress_dict> expected_range{
|
||||
{lws::db::major_index(0), {{lws::db::index_range{lws::db::minor_index(0), lws::db::minor_index(2)}}}}
|
||||
};
|
||||
EXPECT(MONERO_UNWRAP(reader.get_subaddresses(lws::db::account_id(1))) == expected_range);
|
||||
}
|
||||
}
|
||||
} //SECTION (lws::scanner::run (lookahead))
|
||||
} // SETUP
|
||||
} // LWS_CASE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user