2023-01-02 15:12:39 +00:00
// Copyright (c) 2014-2023, The Monero Project
2018-11-20 13:40:51 +00:00
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
# include "include_base_utils.h"
# include "cryptonote_basic/cryptonote_basic_impl.h"
# include "cryptonote_basic/account.h"
# include "cryptonote_core/cryptonote_tx_utils.h"
# include "misc_language.h"
# include "string_tools.h"
using namespace cryptonote ;
2023-09-29 17:13:37 +00:00
# include <cmath>
2018-11-20 13:40:51 +00:00
# include <boost/regex.hpp>
2020-04-07 16:25:25 +00:00
# include <common/apply_permutation.h>
2018-11-20 13:40:51 +00:00
# include "common/util.h"
# include "common/command_line.h"
# include "trezor_tests.h"
2019-02-27 15:55:31 +00:00
# include "tools.h"
2018-11-20 13:40:51 +00:00
# include "device/device_cold.hpp"
# include "device_trezor/device_trezor.hpp"
namespace po = boost : : program_options ;
namespace
{
2023-09-29 17:13:37 +00:00
const command_line : : arg_descriptor < std : : string > arg_filter = { " filter " , " Regular expression filter for which tests to run " } ;
const command_line : : arg_descriptor < std : : string > arg_trezor_path = { " trezor-path " , " Path to the trezor device to use, has to support debug link " , " " } ;
const command_line : : arg_descriptor < bool > arg_heavy_tests = { " heavy-tests " , " Runs expensive tests (volume tests) " , false } ;
const command_line : : arg_descriptor < std : : string > arg_chain_path = { " chain-path " , " Path to the serialized blockchain, speeds up testing " , " " } ;
const command_line : : arg_descriptor < bool > arg_fix_chain = { " fix-chain " , " If chain-patch is given and file cannot be used, it is ignored and overwriten " , false } ;
2018-11-20 13:40:51 +00:00
}
2019-02-27 15:55:31 +00:00
# define HW_TREZOR_NAME "Trezor"
2023-09-29 17:13:37 +00:00
# define TEST_DECOY_MINING_COUNTS 3
# define TREZOR_ACCOUNT_ORDERING &m_miner_account, &m_alice_account, &m_alice2_account, &m_bob_account, &m_eve_account
# define TREZOR_ALL_WALLET_VCT vct_wallets(m_wl_alice.get(), m_wl_alice2.get(), m_wl_bob.get(), m_wl_eve.get())
# define TREZOR_COMMON_TEST_CASE(genclass, CORE, BASE) do { \
if ( filter . empty ( ) | | boost : : regex_match ( std : : string ( # genclass ) , match , boost : : regex ( filter ) ) ) { \
rollback_chain ( CORE , BASE . head_block ( ) ) ; \
2018-11-20 13:40:51 +00:00
genclass ctest ; \
BASE . fork ( ctest ) ; \
GENERATE_AND_PLAY_INSTANCE ( genclass , ctest , * ( CORE ) ) ; \
2019-04-03 19:29:35 +00:00
} \
} while ( 0 )
2018-11-20 13:40:51 +00:00
# define TREZOR_SETUP_CHAIN(NAME) do { \
+ + tests_count ; \
try { \
2020-04-07 16:25:25 +00:00
setup_chain ( core , trezor_base , chain_path , fix_chain , vm_core ) ; \
2018-11-20 13:40:51 +00:00
} catch ( const std : : exception & ex ) { \
2020-04-07 16:25:25 +00:00
MERROR ( " Chain setup failed for " < < NAME ) ; \
throw ; \
2018-11-20 13:40:51 +00:00
} \
} while ( 0 )
2023-09-29 17:13:37 +00:00
typedef struct {
bool heavy_tests ;
} chain_file_opts_t ;
2019-02-27 15:55:31 +00:00
2023-09-29 17:13:37 +00:00
static const std : : string CUR_CHAIN_MAGIC = " MoneroTrezorTestsEventFile " ;
static const unsigned long CUR_CHAIN_VERSION = 2 ;
2019-02-27 15:55:31 +00:00
static device_trezor_test * trezor_device = nullptr ;
static device_trezor_test * ensure_trezor_test_device ( ) ;
2018-11-20 13:40:51 +00:00
static void rollback_chain ( cryptonote : : core * core , const cryptonote : : block & head ) ;
2019-02-27 15:55:31 +00:00
static void setup_chain ( cryptonote : : core * core , gen_trezor_base & trezor_base , std : : string chain_path , bool fix_chain , const po : : variables_map & vm_core ) ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
static long get_env_long ( const char * env_name , boost : : optional < long > def = boost : : none ) {
const char * env_data = getenv ( env_name ) ;
2019-04-03 19:29:35 +00:00
return env_data ? atol ( env_data ) : ( def ? def . get ( ) : 0 ) ;
}
2023-09-29 17:13:37 +00:00
static std : : string get_env_string ( const char * env_name , boost : : optional < std : : string > def = boost : : none ) {
const char * env_data = getenv ( env_name ) ;
return env_data ? std : : string ( env_data ) : ( def ? def . get ( ) : std : : string ( ) ) ;
}
2018-11-20 13:40:51 +00:00
int main ( int argc , char * argv [ ] )
{
TRY_ENTRY ( ) ;
tools : : on_startup ( ) ;
epee : : string_tools : : set_module_name_and_folder ( argv [ 0 ] ) ;
//set up logging options
mlog_configure ( mlog_get_default_log_path ( " trezor_tests.log " ) , true ) ;
mlog_set_log_level ( 2 ) ;
po : : options_description desc_options ( " Allowed options " ) ;
command_line : : add_arg ( desc_options , command_line : : arg_help ) ;
command_line : : add_arg ( desc_options , arg_filter ) ;
command_line : : add_arg ( desc_options , arg_trezor_path ) ;
command_line : : add_arg ( desc_options , arg_heavy_tests ) ;
command_line : : add_arg ( desc_options , arg_chain_path ) ;
command_line : : add_arg ( desc_options , arg_fix_chain ) ;
po : : variables_map vm ;
bool r = command_line : : handle_error_helper ( desc_options , [ & ] ( )
{
po : : store ( po : : parse_command_line ( argc , argv , desc_options ) , vm ) ;
po : : notify ( vm ) ;
return true ;
} ) ;
if ( ! r )
return 1 ;
if ( command_line : : get_arg ( vm , command_line : : arg_help ) )
{
std : : cout < < desc_options < < std : : endl ;
return 0 ;
}
const std : : string filter = tools : : glob_to_regex ( command_line : : get_arg ( vm , arg_filter ) ) ;
boost : : smatch match ;
size_t tests_count = 0 ;
std : : vector < std : : string > failed_tests ;
std : : string trezor_path = command_line : : get_arg ( vm , arg_trezor_path ) ;
std : : string chain_path = command_line : : get_arg ( vm , arg_chain_path ) ;
const bool heavy_tests = command_line : : get_arg ( vm , arg_heavy_tests ) ;
const bool fix_chain = command_line : : get_arg ( vm , arg_fix_chain ) ;
2019-04-03 19:29:35 +00:00
hw : : register_device ( HW_TREZOR_NAME , ensure_trezor_test_device ( ) ) ; // shim device for call tracking
2018-11-20 13:40:51 +00:00
// Bootstrapping common chain & accounts
2023-09-29 17:13:37 +00:00
const std : : string trezor_path_env = get_env_string ( " TREZOR_PATH " ) ;
const uint8_t initial_hf = ( uint8_t ) get_env_long ( " TEST_MIN_HF " , TREZOR_TEST_MIN_HF_DEFAULT ) ;
const uint8_t max_hf = ( uint8_t ) get_env_long ( " TEST_MAX_HF " , TREZOR_TEST_MAX_HF_DEFAULT ) ;
const bool mining_enabled = get_env_long ( " TEST_MINING_ENABLED " , TREZOR_TEST_MINING_ENABLED_DEFAULT | | heavy_tests ) > 0 ;
const long mining_timeout = get_env_long ( " TEST_MINING_TIMEOUT " , TREZOR_TEST_MINING_TIMEOUT_DEFAULT ) ;
const auto sync_test = get_env_long ( " TEST_KI_SYNC " , TREZOR_TEST_KI_SYNC_DEFAULT ) ;
const bool env_gen_heavy = get_env_long ( " TEST_GEN_HEAVY " , 0 ) > 0 | | heavy_tests ;
2019-04-03 21:58:34 +00:00
MINFO ( " Test versions " < < MONERO_RELEASE_NAME < < " ' (v " < < MONERO_VERSION_FULL < < " ) " ) ;
2020-04-07 16:25:25 +00:00
MINFO ( " Testing hardforks [ " < < ( int ) initial_hf < < " , " < < ( int ) max_hf < < " ], sync-test: " < < sync_test ) ;
2019-02-27 15:55:31 +00:00
cryptonote : : core core_obj ( nullptr ) ;
cryptonote : : core * const core = & core_obj ;
std : : shared_ptr < mock_daemon > daemon = nullptr ;
2018-11-20 13:40:51 +00:00
gen_trezor_base trezor_base ;
2023-09-29 17:13:37 +00:00
trezor_base . setup_args ( ! trezor_path . empty ( ) ? trezor_path : trezor_path_env , heavy_tests , mining_enabled , mining_timeout ) ;
trezor_base . heavy_test_set ( env_gen_heavy | | heavy_tests ) ;
2019-02-27 15:55:31 +00:00
trezor_base . set_hard_fork ( initial_hf ) ;
2018-11-20 13:40:51 +00:00
2019-02-27 15:55:31 +00:00
// Arguments for core & daemon
po : : variables_map vm_core ;
po : : options_description desc_params_core ( " Core " ) ;
mock_daemon : : init_options ( desc_params_core ) ;
tools : : options : : build_options ( vm_core , desc_params_core ) ;
mock_daemon : : default_options ( vm_core ) ;
2018-11-20 13:40:51 +00:00
// Transaction tests
2019-04-03 19:29:35 +00:00
for ( uint8_t hf = initial_hf ; hf < = max_hf + 1 ; + + hf )
2019-02-27 15:55:31 +00:00
{
2022-04-12 00:06:19 +00:00
if ( hf = = 14 ) { // HF 14 is skipped.
continue ;
}
2019-04-03 19:29:35 +00:00
if ( hf > initial_hf | | hf > max_hf )
2019-02-27 15:55:31 +00:00
{
daemon - > stop_and_deinit ( ) ;
daemon = nullptr ;
trezor_base . daemon ( nullptr ) ;
2019-04-03 19:29:35 +00:00
if ( hf > max_hf )
{
break ;
}
2019-02-27 15:55:31 +00:00
}
2019-04-03 19:29:35 +00:00
MDEBUG ( " Transaction tests for HF " < < ( int ) hf ) ;
2019-02-27 15:55:31 +00:00
trezor_base . set_hard_fork ( hf ) ;
TREZOR_SETUP_CHAIN ( std : : string ( " HF " ) + std : : to_string ( ( int ) hf ) ) ;
daemon = std : : make_shared < mock_daemon > ( core , vm_core ) ;
CHECK_AND_ASSERT_THROW_MES ( daemon - > nettype ( ) = = trezor_base . nettype ( ) , " Serialized chain network type does not match " ) ;
daemon - > try_init_and_run ( ) ;
trezor_base . daemon ( daemon ) ;
// Hard-fork independent tests
2020-04-07 16:25:25 +00:00
if ( hf = = initial_hf & & sync_test > 0 )
2019-02-27 15:55:31 +00:00
{
TREZOR_COMMON_TEST_CASE ( gen_trezor_ki_sync_without_refresh , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_live_refresh , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_ki_sync_with_refresh , core , trezor_base ) ;
}
2023-09-29 17:13:37 +00:00
TREZOR_COMMON_TEST_CASE ( gen_trezor_no_passphrase , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_wallet_passphrase , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_passphrase , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_pin , core , trezor_base ) ;
2019-02-27 15:55:31 +00:00
TREZOR_COMMON_TEST_CASE ( gen_trezor_1utxo , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_1utxo_paymentid_short , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_1utxo_paymentid_short_integrated , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_acc1 , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_to_sub , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_to_2sub , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_to_1norm_2sub , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_2utxo_sub_acc_to_1norm_2sub , core , trezor_base ) ;
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_to_7outs , core , trezor_base ) ;
2022-04-12 00:06:19 +00:00
TREZOR_COMMON_TEST_CASE ( gen_trezor_4utxo_to_15outs , core , trezor_base ) ;
2023-09-29 17:13:37 +00:00
TREZOR_COMMON_TEST_CASE ( gen_trezor_16utxo_to_sub , core , trezor_base ) ;
2019-02-27 15:55:31 +00:00
TREZOR_COMMON_TEST_CASE ( wallet_api_tests , core , trezor_base ) ;
}
2018-11-20 13:40:51 +00:00
if ( trezor_base . heavy_tests ( ) )
{
TREZOR_COMMON_TEST_CASE ( gen_trezor_many_utxo , core , trezor_base ) ;
2022-04-12 00:06:19 +00:00
TREZOR_COMMON_TEST_CASE ( gen_trezor_many_utxo_many_txo , core , trezor_base ) ;
2018-11-20 13:40:51 +00:00
}
core - > deinit ( ) ;
el : : Level level = ( failed_tests . empty ( ) ? el : : Level : : Info : el : : Level : : Error ) ;
MLOG ( level , " \n REPORT: " ) ;
MLOG ( level , " Test run: " < < tests_count ) ;
MLOG ( level , " Failures: " < < failed_tests . size ( ) ) ;
if ( ! failed_tests . empty ( ) )
{
MLOG ( level , " FAILED TESTS: " ) ;
BOOST_FOREACH ( auto test_name , failed_tests )
{
MLOG ( level , " " < < test_name ) ;
}
}
return failed_tests . empty ( ) ? 0 : 1 ;
CATCH_ENTRY_L0 ( " main " , 1 ) ;
}
static void rollback_chain ( cryptonote : : core * core , const cryptonote : : block & head )
{
CHECK_AND_ASSERT_THROW_MES ( core , " Core is null " ) ;
block popped_block ;
std : : vector < transaction > popped_txs ;
crypto : : hash head_hash = get_block_hash ( head ) , cur_hash { } ;
uint64_t height = get_block_height ( head ) , cur_height = 0 ;
2023-09-29 17:13:37 +00:00
MDEBUG ( " Rolling back to " < < height < < " to hash " < < head_hash ) ;
2018-11-20 13:40:51 +00:00
do {
core - > get_blockchain_top ( cur_height , cur_hash ) ;
if ( cur_height < = height & & head_hash = = cur_hash )
return ;
CHECK_AND_ASSERT_THROW_MES ( cur_height > height , " Height differs " ) ;
core - > get_blockchain_storage ( ) . get_db ( ) . pop_block ( popped_block , popped_txs ) ;
} while ( true ) ;
}
2023-09-29 17:13:37 +00:00
static bool deserialize_chain_from_file ( std : : vector < test_event_entry > & events , gen_trezor_base & test_base , unsigned long & version , const std : : string & file_path , chain_file_opts_t & opts )
2018-11-20 13:40:51 +00:00
{
TRY_ENTRY ( ) ;
std : : ifstream data_file ;
data_file . open ( file_path , std : : ios_base : : binary | std : : ios_base : : in ) ;
2023-09-29 17:13:37 +00:00
std : : string magic ;
2018-11-20 13:40:51 +00:00
if ( data_file . fail ( ) )
return false ;
try
{
boost : : archive : : portable_binary_iarchive a ( data_file ) ;
test_base . clear ( ) ;
2023-09-29 17:13:37 +00:00
a > > magic ;
CHECK_AND_ASSERT_THROW_MES ( magic = = CUR_CHAIN_MAGIC , " Chain file load error - magic differs " ) ;
a > > version ;
a > > opts . heavy_tests ;
a > > magic ;
CHECK_AND_ASSERT_THROW_MES ( magic = = CUR_CHAIN_MAGIC , " Chain file load error - magic differs " ) ;
2018-11-20 13:40:51 +00:00
a > > events ;
a > > test_base ;
2023-09-29 17:13:37 +00:00
a > > magic ;
CHECK_AND_ASSERT_THROW_MES ( magic = = CUR_CHAIN_MAGIC , " Chain file load error - magic differs " ) ;
CHECK_AND_ASSERT_THROW_MES ( ! data_file . fail ( ) , " Chain file load error - file.fail() " ) ;
CHECK_AND_ASSERT_THROW_MES ( ! data_file . bad ( ) , " Chain file load error - bad read " ) ;
2018-11-20 13:40:51 +00:00
return true ;
}
catch ( . . . )
{
MWARNING ( " Chain deserialization failed " ) ;
return false ;
}
2023-09-29 17:13:37 +00:00
CATCH_ENTRY_L0 ( " deserialize_chain_from_file " , false ) ;
2018-11-20 13:40:51 +00:00
}
2023-09-29 17:13:37 +00:00
static bool serialize_chain_to_file ( std : : vector < test_event_entry > & events , gen_trezor_base & test_base , const std : : string & file_path , const chain_file_opts_t & opts )
2018-11-20 13:40:51 +00:00
{
TRY_ENTRY ( ) ;
std : : ofstream data_file ;
data_file . open ( file_path , std : : ios_base : : binary | std : : ios_base : : out | std : : ios : : trunc ) ;
if ( data_file . fail ( ) )
return false ;
try
{
boost : : archive : : portable_binary_oarchive a ( data_file ) ;
2023-09-29 17:13:37 +00:00
a < < CUR_CHAIN_MAGIC ;
a < < CUR_CHAIN_VERSION ;
a < < opts . heavy_tests ;
a < < CUR_CHAIN_MAGIC ;
2018-11-20 13:40:51 +00:00
a < < events ;
a < < test_base ;
2023-09-29 17:13:37 +00:00
a < < CUR_CHAIN_MAGIC ;
2018-11-20 13:40:51 +00:00
return ! data_file . fail ( ) ;
}
catch ( . . . )
{
2023-09-29 17:13:37 +00:00
MWARNING ( " Chain serialization failed " ) ;
2018-11-20 13:40:51 +00:00
return false ;
}
return false ;
CATCH_ENTRY_L0 ( " serialize_chain_to_file " , false ) ;
}
2019-02-27 15:55:31 +00:00
template < class t_test_class >
static bool init_core_replay_events ( std : : vector < test_event_entry > & events , cryptonote : : core * core , const po : : variables_map & vm_core )
{
// this test needs for it to be so.
get_test_options < t_test_class > gto ;
// Hardforks can be specified in events.
v_hardforks_t hardforks ;
2019-04-07 16:15:20 +00:00
cryptonote : : test_options test_options_tmp { nullptr , 0 } ;
2019-02-27 15:55:31 +00:00
const cryptonote : : test_options * test_options_ = & gto . test_options ;
if ( extract_hard_forks ( events , hardforks ) ) {
hardforks . push_back ( std : : make_pair ( ( uint8_t ) 0 , ( uint64_t ) 0 ) ) ; // terminator
test_options_tmp . hard_forks = hardforks . data ( ) ;
test_options_ = & test_options_tmp ;
}
core - > deinit ( ) ;
CHECK_AND_ASSERT_THROW_MES ( core - > init ( vm_core , test_options_ ) , " Core init failed " ) ;
core - > get_blockchain_storage ( ) . get_db ( ) . set_batch_transactions ( true ) ;
// start with a clean pool
std : : vector < crypto : : hash > pool_txs ;
CHECK_AND_ASSERT_THROW_MES ( core - > get_pool_transaction_hashes ( pool_txs ) , " Failed to flush txpool " ) ;
core - > get_blockchain_storage ( ) . flush_txes_from_pool ( pool_txs ) ;
t_test_class validator ;
return replay_events_through_core < t_test_class > ( * core , events , validator ) ;
}
static void setup_chain ( cryptonote : : core * core , gen_trezor_base & trezor_base , std : : string chain_path , bool fix_chain , const po : : variables_map & vm_core )
2018-11-20 13:40:51 +00:00
{
std : : vector < test_event_entry > events ;
const bool do_serialize = ! chain_path . empty ( ) ;
const bool chain_file_exists = do_serialize & & boost : : filesystem : : exists ( chain_path ) ;
bool loaded = false ;
bool generated = false ;
2023-09-29 17:13:37 +00:00
unsigned long chain_version = 0 ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
chain_file_opts_t opts = { . heavy_tests = trezor_base . heavy_tests ( ) } ;
2018-11-20 13:40:51 +00:00
if ( chain_file_exists )
{
2023-09-29 17:13:37 +00:00
chain_file_opts_t loaded_opts ;
const auto fix_suggestion = fix_chain ? " Chain file will be regenerated. " : " Use --fix_chain to regenerate chain file " ;
bool deserialize_ok = deserialize_chain_from_file ( events , trezor_base , chain_version , chain_path , loaded_opts ) ;
if ( ! deserialize_ok )
2018-11-20 13:40:51 +00:00
{
2023-09-29 17:13:37 +00:00
MERROR ( " Failed to deserialize data from file: " < < chain_path < < " . " < < fix_suggestion ) ;
CHECK_AND_ASSERT_THROW_MES ( fix_chain , " Chain load error. " < < fix_suggestion ) ;
}
else if ( chain_version ! = CUR_CHAIN_VERSION ) {
MERROR ( " Loaded chain version " < < chain_version < < " differs from current target " < < CUR_CHAIN_VERSION < < " in the chain file: " < < chain_path < < " . " < < fix_suggestion ) ;
CHECK_AND_ASSERT_THROW_MES ( fix_chain , " Chain load error - versions differ. " < < fix_suggestion ) ;
deserialize_ok = false ;
}
else if ( opts . heavy_tests & & ! loaded_opts . heavy_tests ) {
MERROR ( " Loaded chain does not include transactions for heavy test, the chain file: " < < chain_path < < " . " < < fix_suggestion ) ;
CHECK_AND_ASSERT_THROW_MES ( fix_chain , " Chain does not heavy tx set - versions differ. " < < fix_suggestion ) ;
deserialize_ok = false ;
}
if ( deserialize_ok ) {
2018-11-20 13:40:51 +00:00
trezor_base . load ( events ) ;
generated = true ;
loaded = true ;
}
2023-09-29 17:13:37 +00:00
else {
events . clear ( ) ;
trezor_base . clear ( ) ;
}
2018-11-20 13:40:51 +00:00
}
if ( ! generated )
{
try
{
2019-02-27 15:55:31 +00:00
trezor_base . clear ( ) ;
2018-11-20 13:40:51 +00:00
generated = trezor_base . generate ( events ) ;
2023-09-29 17:13:37 +00:00
trezor_base . fix_hf ( events ) ;
2018-11-20 13:40:51 +00:00
if ( generated & & ! loaded & & do_serialize )
{
trezor_base . update_trackers ( events ) ;
2023-09-29 17:13:37 +00:00
if ( ! serialize_chain_to_file ( events , trezor_base , chain_path , opts ) )
2018-11-20 13:40:51 +00:00
{
MERROR ( " Failed to serialize data to file: " < < chain_path ) ;
}
}
}
CATCH_REPLAY ( gen_trezor_base ) ;
}
trezor_base . fix_hf ( events ) ;
2019-02-27 15:55:31 +00:00
if ( generated & & init_core_replay_events < gen_trezor_base > ( events , core , vm_core ) )
2018-11-20 13:40:51 +00:00
{
MGINFO_GREEN ( " #TEST-chain-init# Succeeded " ) ;
}
else
{
MERROR ( " #TEST-chain-init# Failed " ) ;
throw std : : runtime_error ( " Chain init error " ) ;
}
}
2023-09-29 17:13:37 +00:00
static fnc_accept_output_t fnc_trezor_default_acceptor_tx_in = [ ] ( const fnc_accept_output_crate_t & info ) - > bool {
return info . oi . is_coin_base | | info . oi . blk_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE < = info . cur_height + 1 ;
} ;
2019-02-27 15:55:31 +00:00
static device_trezor_test * ensure_trezor_test_device ( ) {
if ( ! trezor_device ) {
trezor_device = new device_trezor_test ( ) ;
trezor_device - > set_name ( HW_TREZOR_NAME ) ;
}
return trezor_device ;
}
2023-09-29 17:13:37 +00:00
static size_t min_mixin_for_hf ( uint8_t hf )
{
if ( hf > = HF_VERSION_MIN_MIXIN_15 )
return 15 ;
if ( hf > = HF_VERSION_MIN_MIXIN_10 )
return 10 ;
return 0 ;
}
static int bp_version_from_hf ( uint8_t hf )
{
return hf > = HF_VERSION_BULLETPROOF_PLUS ? 4 : hf > = HF_VERSION_CLSAG ? 3 : hf > = HF_VERSION_SMALLER_BP ? 2 : 1 ;
}
2018-11-20 13:40:51 +00:00
static void add_hforks ( std : : vector < test_event_entry > & events , const v_hardforks_t & hard_forks )
{
event_replay_settings repl_set ;
repl_set . hard_forks = boost : : make_optional ( hard_forks ) ;
events . push_back ( repl_set ) ;
}
static void add_top_hfork ( std : : vector < test_event_entry > & events , const v_hardforks_t & hard_forks )
{
event_replay_settings repl_set ;
v_hardforks_t top_fork ;
top_fork . push_back ( hard_forks . back ( ) ) ;
repl_set . hard_forks = boost : : make_optional ( top_fork ) ;
events . push_back ( repl_set ) ;
}
static crypto : : public_key get_tx_pub_key_from_received_outs ( const tools : : wallet2 : : transfer_details & td )
{
std : : vector < tx_extra_field > tx_extra_fields ;
parse_tx_extra ( td . m_tx . extra , tx_extra_fields ) ;
tx_extra_pub_key pub_key_field ;
THROW_WALLET_EXCEPTION_IF ( ! find_tx_extra_field_by_type ( tx_extra_fields , pub_key_field , 0 ) , tools : : error : : wallet_internal_error ,
" Public key wasn't found in the transaction extra " ) ;
const crypto : : public_key tx_pub_key = pub_key_field . pub_key ;
bool two_found = find_tx_extra_field_by_type ( tx_extra_fields , pub_key_field , 1 ) ;
if ( ! two_found ) {
return tx_pub_key ;
} else {
throw std : : runtime_error ( " Unsupported tx pub resolution " ) ;
}
}
2023-09-29 17:13:37 +00:00
static void generate_tx_block ( std : : vector < test_event_entry > & events , std : : list < cryptonote : : transaction > & txs_lst , cryptonote : : block & head ,
const cryptonote : : account_base & from , const cryptonote : : account_base & to , uint64_t amount , size_t repeat ,
size_t mixin , bool rct , rct : : RangeProofType range_proof_type , int bp_version )
{
const size_t per_tx_limit = 14 ;
const size_t iters = repeat ? std : : ceil ( repeat / ( double ) per_tx_limit ) : 1 ;
for ( size_t j = 0 ; j < iters ; + + j )
{
const auto dests = build_dsts ( to , false , amount , j < iters - 1 ? per_tx_limit : repeat - j * per_tx_limit ) ;
cryptonote : : transaction t ;
construct_tx_to_key ( events , t , head , from , dests , TESTS_DEFAULT_FEE , mixin , rct , range_proof_type , bp_version , true , fnc_trezor_default_acceptor_tx_in ) ;
txs_lst . push_back ( t ) ;
events . push_back ( t ) ;
}
}
static void generate_tx_block ( std : : vector < test_event_entry > & events , std : : list < cryptonote : : transaction > & txs_lst , cryptonote : : block & head ,
const cryptonote : : account_base & from , const std : : vector < cryptonote : : tx_destination_entry > & destinations , size_t repeat ,
size_t mixin , bool rct , rct : : RangeProofType range_proof_type , int bp_version )
{
CHECK_AND_ASSERT_THROW_MES ( destinations . size ( ) < 16 , " Keep destinations below 16, BP+ limit " ) ;
for ( size_t j = 0 ; j < repeat ; + + j )
{
cryptonote : : transaction t ;
construct_tx_to_key ( events , t , head , from , destinations , TESTS_DEFAULT_FEE , mixin , rct , range_proof_type , bp_version , true , fnc_trezor_default_acceptor_tx_in ) ;
txs_lst . push_back ( t ) ;
events . push_back ( t ) ;
}
}
static void generate_tx_block ( std : : vector < test_event_entry > & events , std : : list < cryptonote : : transaction > & txs_lst , cryptonote : : block & head ,
const cryptonote : : account_base & from , const cryptonote : : account_base & to , uint64_t amount , size_t repeat = 1 ,
uint8_t hf = 1 )
{
generate_tx_block ( events , txs_lst , head , from , to , amount , repeat , min_mixin_for_hf ( hf ) , hf > = 8 , rct : : RangeProofPaddedBulletproof , bp_version_from_hf ( hf ) ) ;
}
static void generate_tx_block ( std : : vector < test_event_entry > & events , std : : list < cryptonote : : transaction > & txs_lst , cryptonote : : block & head ,
const cryptonote : : account_base & from , const std : : vector < cryptonote : : tx_destination_entry > & destinations , size_t repeat = 1 ,
uint8_t hf = 1 )
{
generate_tx_block ( events , txs_lst , head , from , destinations , repeat , min_mixin_for_hf ( hf ) , hf > = 8 , rct : : RangeProofPaddedBulletproof , bp_version_from_hf ( hf ) ) ;
}
2018-11-20 13:40:51 +00:00
static void setup_shim ( hw : : wallet_shim * shim )
{
shim - > get_tx_pub_key_from_received_outs = & get_tx_pub_key_from_received_outs ;
}
bool get_short_payment_id ( crypto : : hash8 & payment_id8 , const tools : : wallet2 : : pending_tx & ptx , hw : : device & hwdev )
{
std : : vector < tx_extra_field > tx_extra_fields ;
parse_tx_extra ( ptx . tx . extra , tx_extra_fields ) ; // ok if partially parsed
cryptonote : : tx_extra_nonce extra_nonce ;
if ( find_tx_extra_field_by_type ( tx_extra_fields , extra_nonce ) )
{
if ( get_encrypted_payment_id_from_tx_extra_nonce ( extra_nonce . nonce , payment_id8 ) )
{
if ( ptx . dests . empty ( ) )
{
MWARNING ( " Encrypted payment id found, but no destinations public key, cannot decrypt " ) ;
return false ;
}
return hwdev . decrypt_payment_id ( payment_id8 , ptx . dests [ 0 ] . addr . m_view_public_key , ptx . tx_key ) ;
}
}
return false ;
}
static tools : : wallet2 : : tx_construction_data get_construction_data_with_decrypted_short_payment_id ( const tools : : wallet2 : : pending_tx & ptx , hw : : device & hwdev )
{
tools : : wallet2 : : tx_construction_data construction_data = ptx . construction_data ;
crypto : : hash8 payment_id = crypto : : null_hash8 ;
if ( get_short_payment_id ( payment_id , ptx , hwdev ) )
{
// Remove encrypted
remove_field_from_tx_extra ( construction_data . extra , typeid ( cryptonote : : tx_extra_nonce ) ) ;
// Add decrypted
std : : string extra_nonce ;
set_encrypted_payment_id_to_tx_extra_nonce ( extra_nonce , payment_id ) ;
THROW_WALLET_EXCEPTION_IF ( ! add_extra_nonce_to_tx_extra ( construction_data . extra , extra_nonce ) ,
tools : : error : : wallet_internal_error , " Failed to add decrypted payment id to tx extra " ) ;
MDEBUG ( " Decrypted payment ID: " < < payment_id ) ;
}
return construction_data ;
}
static std : : string get_payment_id ( const std : : vector < uint8_t > & tx_extra )
{
std : : vector < cryptonote : : tx_extra_field > tx_extra_fields ;
cryptonote : : parse_tx_extra ( tx_extra , tx_extra_fields ) ; // ok if partially parsed
cryptonote : : tx_extra_nonce extra_nonce ;
: : crypto : : hash payment_id { } ;
if ( find_tx_extra_field_by_type ( tx_extra_fields , extra_nonce ) )
{
: : crypto : : hash8 payment_id8 { } ;
if ( cryptonote : : get_encrypted_payment_id_from_tx_extra_nonce ( extra_nonce . nonce , payment_id8 ) )
{
return std : : string ( payment_id8 . data , 8 ) ;
}
else if ( cryptonote : : get_payment_id_from_tx_extra_nonce ( extra_nonce . nonce , payment_id ) )
{
return std : : string ( payment_id . data , 32 ) ;
}
}
return std : : string ( ) ;
}
static crypto : : hash8 to_short_payment_id ( const std : : string & payment_id )
{
crypto : : hash8 payment_id_short ;
CHECK_AND_ASSERT_THROW_MES ( payment_id . size ( ) = = 8 , " Invalid argument " ) ;
memcpy ( payment_id_short . data , payment_id . data ( ) , 8 ) ;
return payment_id_short ;
}
static crypto : : hash to_long_payment_id ( const std : : string & payment_id )
{
crypto : : hash payment_id_long ;
CHECK_AND_ASSERT_THROW_MES ( payment_id . size ( ) = = 32 , " Invalid argument " ) ;
memcpy ( payment_id_long . data , payment_id . data ( ) , 32 ) ;
return payment_id_long ;
}
static std : : vector < uint8_t > build_payment_id_extra ( const std : : string & payment_id )
{
std : : vector < uint8_t > res ;
if ( payment_id . size ( ) = = 8 ) {
std : : string extra_nonce ;
set_encrypted_payment_id_to_tx_extra_nonce ( extra_nonce , to_short_payment_id ( payment_id ) ) ;
THROW_WALLET_EXCEPTION_IF ( ! add_extra_nonce_to_tx_extra ( res , extra_nonce ) ,
tools : : error : : wallet_internal_error , " Failed to add decrypted payment id to tx extra " ) ;
} else if ( payment_id . size ( ) = = 32 ) {
std : : string extra_nonce ;
set_payment_id_to_tx_extra_nonce ( extra_nonce , to_long_payment_id ( payment_id ) ) ;
THROW_WALLET_EXCEPTION_IF ( ! add_extra_nonce_to_tx_extra ( res , extra_nonce ) ,
tools : : error : : wallet_internal_error , " Failed to add decrypted payment id to tx extra " ) ;
}
return res ;
}
static cryptonote : : address_parse_info init_addr_parse_info ( cryptonote : : account_public_address & addr , bool is_sub = false , boost : : optional < crypto : : hash8 > payment_id = boost : : none )
{
cryptonote : : address_parse_info res ;
res . address = addr ;
res . is_subaddress = is_sub ;
if ( payment_id ) {
res . has_payment_id = true ;
res . payment_id = payment_id . get ( ) ;
} else {
res . has_payment_id = false ;
}
return res ;
}
static void expand_tsx ( cryptonote : : transaction & tx )
{
auto & rv = tx . rct_signatures ;
if ( rv . type = = rct : : RCTTypeFull )
{
rv . p . MGs . resize ( 1 ) ;
rv . p . MGs [ 0 ] . II . resize ( tx . vin . size ( ) ) ;
for ( size_t n = 0 ; n < tx . vin . size ( ) ; + + n )
rv . p . MGs [ 0 ] . II [ n ] = rct : : ki2rct ( boost : : get < txin_to_key > ( tx . vin [ n ] ) . k_image ) ;
}
2020-09-03 14:07:08 +00:00
else if ( rv . type = = rct : : RCTTypeSimple | | rv . type = = rct : : RCTTypeBulletproof | | rv . type = = rct : : RCTTypeBulletproof2 )
2018-11-20 13:40:51 +00:00
{
CHECK_AND_ASSERT_THROW_MES ( rv . p . MGs . size ( ) = = tx . vin . size ( ) , " Bad MGs size " ) ;
for ( size_t n = 0 ; n < tx . vin . size ( ) ; + + n )
{
rv . p . MGs [ n ] . II . resize ( 1 ) ;
rv . p . MGs [ n ] . II [ 0 ] = rct : : ki2rct ( boost : : get < txin_to_key > ( tx . vin [ n ] ) . k_image ) ;
}
}
2022-04-12 00:06:19 +00:00
else if ( rv . type = = rct : : RCTTypeCLSAG | | rv . type = = rct : : RCTTypeBulletproofPlus )
2020-09-03 14:07:08 +00:00
{
if ( ! tx . pruned )
{
CHECK_AND_ASSERT_THROW_MES ( rv . p . CLSAGs . size ( ) = = tx . vin . size ( ) , " Bad CLSAGs size " ) ;
for ( size_t n = 0 ; n < tx . vin . size ( ) ; + + n )
{
rv . p . CLSAGs [ n ] . I = rct : : ki2rct ( boost : : get < txin_to_key > ( tx . vin [ n ] ) . k_image ) ;
}
}
}
else
{
CHECK_AND_ASSERT_THROW_MES ( false , " Unsupported rct tx type: " + boost : : lexical_cast < std : : string > ( rv . type ) ) ;
}
2018-11-20 13:40:51 +00:00
}
static std : : vector < tools : : wallet2 * > vct_wallets ( tools : : wallet2 * w1 = nullptr , tools : : wallet2 * w2 = nullptr , tools : : wallet2 * w3 = nullptr , tools : : wallet2 * w4 = nullptr , tools : : wallet2 * w5 = nullptr )
{
std : : vector < tools : : wallet2 * > res ;
if ( w1 )
res . push_back ( w1 ) ;
if ( w2 )
res . push_back ( w2 ) ;
if ( w3 )
res . push_back ( w3 ) ;
if ( w4 )
res . push_back ( w4 ) ;
if ( w5 )
res . push_back ( w5 ) ;
return res ;
}
2023-09-29 17:13:37 +00:00
# define TREZOR_ALL_ACCOUNTS 0xffffff
static uint64_t get_available_funds ( tools : : wallet2 * wallet , uint32_t account = 0 , uint64_t * nutxos = nullptr , uint64_t * nutxos_rct = nullptr )
2019-02-27 15:55:31 +00:00
{
tools : : wallet2 : : transfer_container transfers ;
wallet - > get_transfers ( transfers ) ;
uint64_t sum = 0 ;
for ( const auto & cur : transfers )
{
2023-09-29 17:13:37 +00:00
const bool utxo = ! cur . m_spent & & ( account = = TREZOR_ALL_ACCOUNTS | | cur . m_subaddr_index . major = = account ) ;
sum + = utxo ? cur . amount ( ) : 0 ;
if ( nutxos ) {
* nutxos + = utxo ;
}
if ( nutxos_rct & & cur . is_rct ( ) ) {
* nutxos_rct + = utxo ;
}
2019-02-27 15:55:31 +00:00
}
return sum ;
}
2023-09-29 17:13:37 +00:00
static std : : string wallet_desc_str ( tools : : wallet2 * wallet , uint32_t account = 0 )
{
std : : stringstream ss ;
uint64_t nutxos = 0 , nutxos_rct = 0 , nutxos_all = 0 , nutxos_rct_all = 0 ;
uint64_t funds = get_available_funds ( wallet , account , & nutxos , & nutxos_rct ) ;
uint64_t funds_all = get_available_funds ( wallet , TREZOR_ALL_ACCOUNTS , & nutxos_all , & nutxos_rct_all ) ;
ss < < " funds: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) funds / COIN )
< < " , utxos: " < < std : : setfill ( ' ' ) < < std : : setw ( 3 ) < < nutxos
< < " , rct: " < < std : : setfill ( ' ' ) < < std : : setw ( 3 ) < < nutxos_rct
< < " ; all accounts: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) funds_all / COIN )
< < " , utxos: " < < std : : setfill ( ' ' ) < < std : : setw ( 3 ) < < nutxos_all
< < " , rct: " < < std : : setfill ( ' ' ) < < std : : setw ( 3 ) < < nutxos_rct_all ;
return ss . str ( ) ;
}
2018-11-20 13:40:51 +00:00
// gen_trezor_base
2019-02-27 15:55:31 +00:00
const uint64_t gen_trezor_base : : m_ts_start = 1397862000 ; // As default wallet timestamp is 1397516400
2018-11-20 13:40:51 +00:00
const uint64_t gen_trezor_base : : m_wallet_ts = m_ts_start - 60 * 60 * 24 * 4 ;
const std : : string gen_trezor_base : : m_device_name = " Trezor:udp " ;
2023-09-29 17:13:37 +00:00
const std : : string gen_trezor_base : : m_miner_master_seed_str = " 8b133a3868993176b613738816247a7f4d357cae555996519cf5b543e9b3554b " ; // sha256(miner)
2018-11-20 13:40:51 +00:00
const std : : string gen_trezor_base : : m_master_seed_str = " 14821d0bc5659b24cafbc889dc4fc60785ee08b65d71c525f81eeaba4f3a570f " ;
const std : : string gen_trezor_base : : m_device_seed = " permit universe parent weapon amused modify essay borrow tobacco budget walnut lunch consider gallery ride amazing frog forget treat market chapter velvet useless topple " ;
const std : : string gen_trezor_base : : m_alice_spend_private = m_master_seed_str ;
const std : : string gen_trezor_base : : m_alice_view_private = " a6ccd4ac344a295d1387f8d18c81bdd394f1845de84188e204514ef9370fd403 " ;
2023-09-29 17:13:37 +00:00
const std : : string gen_trezor_base : : m_alice2_passphrase = " a " ;
const std : : string gen_trezor_base : : m_alice2_master_seed = " 0b86cf0e71204ca3cdc389daf0bb1cf654ac7d54edfed68a9faf921ba140a708 " ;
const std : : string gen_trezor_base : : m_bob_master_seed = " 81b637d8fcd2c6da6359e6963113a1170de795e4b725b84d1e0b4cfd9ec58ce9 " ; // sha256(bob)
const std : : string gen_trezor_base : : m_eve_master_seed = " 85262adf74518bbb70c7cb94cd6159d91669e5a81edf1efebd543eadbda9fa2b " ; // sha256(eve)
2018-11-20 13:40:51 +00:00
gen_trezor_base : : gen_trezor_base ( ) {
2023-09-29 17:13:37 +00:00
m_rct_config = { rct : : RangeProofPaddedBulletproof , 4 } ;
2019-02-27 15:55:31 +00:00
m_test_get_tx_key = true ;
m_network_type = cryptonote : : TESTNET ;
2018-11-20 13:40:51 +00:00
}
gen_trezor_base : : gen_trezor_base ( const gen_trezor_base & other ) :
m_generator ( other . m_generator ) , m_bt ( other . m_bt ) , m_miner_account ( other . m_miner_account ) ,
m_bob_account ( other . m_bob_account ) , m_alice_account ( other . m_alice_account ) , m_eve_account ( other . m_eve_account ) ,
2023-09-29 17:13:37 +00:00
m_hard_forks ( other . m_hard_forks ) , m_head ( other . m_head ) , m_events ( other . m_events ) ,
m_trezor ( other . m_trezor ) , m_rct_config ( other . m_rct_config ) , m_top_hard_fork ( other . m_top_hard_fork ) ,
2019-02-27 15:55:31 +00:00
m_heavy_tests ( other . m_heavy_tests ) , m_test_get_tx_key ( other . m_test_get_tx_key ) , m_live_refresh_enabled ( other . m_live_refresh_enabled ) ,
2023-09-29 17:13:37 +00:00
m_network_type ( other . m_network_type ) , m_daemon ( other . m_daemon ) , m_alice2_account ( other . m_alice2_account ) ,
m_trezor_path ( other . m_trezor_path ) , m_trezor_pin ( other . m_trezor_pin ) , m_trezor_passphrase ( other . m_trezor_passphrase ) ,
m_trezor_use_passphrase ( other . m_trezor_use_passphrase ) , m_trezor_use_alice2 ( other . m_trezor_use_alice2 ) ,
m_gen_heavy_test_set ( other . m_gen_heavy_test_set ) ,
m_mining_enabled ( other . m_mining_enabled ) ,
m_mining_timeout ( other . m_mining_timeout ) ,
m_no_change_in_tested_tx ( other . m_no_change_in_tested_tx )
2018-11-20 13:40:51 +00:00
{
}
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : setup_args ( const std : : string & trezor_path , bool heavy_tests , bool mining_enabled , long mining_timeout )
2018-11-20 13:40:51 +00:00
{
m_trezor_path = trezor_path . empty ( ) ? m_device_name : std : : string ( " Trezor: " ) + trezor_path ;
m_heavy_tests = heavy_tests ;
2023-09-29 17:13:37 +00:00
m_gen_heavy_test_set | = heavy_tests ;
m_mining_enabled = mining_enabled ;
m_mining_timeout = mining_timeout ;
2018-11-20 13:40:51 +00:00
}
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : setup_trezor ( bool use_passphrase , const std : : string & pin )
2018-11-20 13:40:51 +00:00
{
hw : : device & hwdev = hw : : get_device ( m_trezor_path ) ;
2019-02-27 15:55:31 +00:00
auto trezor = dynamic_cast < device_trezor_test * > ( & hwdev ) ;
CHECK_AND_ASSERT_THROW_MES ( trezor , " Dynamic cast failed " ) ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
trezor - > set_callback ( this ) ;
trezor - > setup_for_tests ( m_trezor_path , m_device_seed , m_network_type , use_passphrase , pin ) ;
2019-02-27 15:55:31 +00:00
m_trezor = trezor ;
2018-11-20 13:40:51 +00:00
}
void gen_trezor_base : : fork ( gen_trezor_base & other )
{
other . m_generator = m_generator ;
other . m_bt = m_bt ;
2019-02-27 15:55:31 +00:00
other . m_network_type = m_network_type ;
other . m_daemon = m_daemon ;
2018-11-20 13:40:51 +00:00
other . m_events = m_events ;
other . m_head = m_head ;
other . m_hard_forks = m_hard_forks ;
2019-04-03 19:29:35 +00:00
other . m_top_hard_fork = m_top_hard_fork ;
2018-11-20 13:40:51 +00:00
other . m_trezor_path = m_trezor_path ;
other . m_heavy_tests = m_heavy_tests ;
2023-09-29 17:13:37 +00:00
other . m_gen_heavy_test_set = m_gen_heavy_test_set ;
2018-11-20 13:40:51 +00:00
other . m_rct_config = m_rct_config ;
2019-02-27 15:55:31 +00:00
other . m_test_get_tx_key = m_test_get_tx_key ;
other . m_live_refresh_enabled = m_live_refresh_enabled ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
other . m_trezor_pin = m_trezor_pin ;
other . m_trezor_passphrase = m_trezor_passphrase ;
other . m_trezor_use_passphrase = m_trezor_use_passphrase ;
other . m_trezor_use_alice2 = m_trezor_use_alice2 ;
other . m_mining_enabled = m_mining_enabled ;
other . m_mining_timeout = m_mining_timeout ;
2018-11-20 13:40:51 +00:00
other . m_miner_account = m_miner_account ;
other . m_bob_account = m_bob_account ;
other . m_alice_account = m_alice_account ;
2023-09-29 17:13:37 +00:00
other . m_alice2_account = m_alice2_account ;
2018-11-20 13:40:51 +00:00
other . m_eve_account = m_eve_account ;
other . m_trezor = m_trezor ;
2023-09-29 17:13:37 +00:00
other . m_no_change_in_tested_tx = m_no_change_in_tested_tx ;
2020-04-07 16:25:25 +00:00
other . m_generator . set_events ( & other . m_events ) ;
other . m_generator . set_network_type ( m_network_type ) ;
2018-11-20 13:40:51 +00:00
}
void gen_trezor_base : : clear ( )
{
m_generator = test_generator ( ) ;
m_bt = block_tracker ( ) ;
m_events . clear ( ) ;
m_hard_forks . clear ( ) ;
m_trezor = nullptr ;
}
void gen_trezor_base : : add_shared_events ( std : : vector < test_event_entry > & events )
{
events . reserve ( m_events . size ( ) ) ;
for ( const test_event_entry & c : m_events ) {
events . push_back ( c ) ;
}
}
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : init_accounts ( )
2018-11-20 13:40:51 +00:00
{
crypto : : secret_key master_seed { } ;
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( epee : : string_tools : : hex_to_pod ( m_miner_master_seed_str , master_seed ) , " Hexdecode fails: m_miner_master_seed_str " ) ;
m_miner_account . generate ( master_seed , true ) ;
DEFAULT_HARDFORKS ( m_hard_forks ) ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( epee : : string_tools : : hex_to_pod ( m_master_seed_str , master_seed ) , " Hexdecode fails: m_master_seed_str " ) ;
2018-11-20 13:40:51 +00:00
m_alice_account . generate ( master_seed , true ) ;
m_alice_account . set_createtime ( m_wallet_ts ) ;
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( epee : : string_tools : : hex_to_pod ( m_alice2_master_seed , master_seed ) , " Hexdecode fails: m_alice2_master_seed " ) ;
m_alice2_account . generate ( master_seed , true ) ;
m_alice2_account . set_createtime ( m_wallet_ts ) ;
CHECK_AND_ASSERT_THROW_MES ( epee : : string_tools : : hex_to_pod ( m_bob_master_seed , master_seed ) , " Hexdecode fails: m_bob_master_seed " ) ;
m_bob_account . generate ( master_seed , true ) ;
m_bob_account . set_createtime ( m_wallet_ts ) ;
CHECK_AND_ASSERT_THROW_MES ( epee : : string_tools : : hex_to_pod ( m_eve_master_seed , master_seed ) , " Hexdecode fails: m_eve_master_seed " ) ;
m_eve_account . generate ( master_seed , true ) ;
m_eve_account . set_createtime ( m_wallet_ts ) ;
}
void gen_trezor_base : : init_wallets ( )
{
m_wl_alice . reset ( new tools : : wallet2 ( m_network_type , 1 , true ) ) ;
m_wl_alice2 . reset ( new tools : : wallet2 ( m_network_type , 1 , true ) ) ;
m_wl_bob . reset ( new tools : : wallet2 ( m_network_type , 1 , true ) ) ;
m_wl_eve . reset ( new tools : : wallet2 ( m_network_type , 1 , true ) ) ;
wallet_accessor_test : : set_account ( m_wl_alice . get ( ) , m_alice_account ) ;
wallet_accessor_test : : set_account ( m_wl_alice2 . get ( ) , m_alice2_account ) ;
wallet_accessor_test : : set_account ( m_wl_bob . get ( ) , m_bob_account ) ;
wallet_accessor_test : : set_account ( m_wl_eve . get ( ) , m_eve_account ) ;
m_wl_alice - > expand_subaddresses ( { 5 , 20 } ) ;
m_wl_alice2 - > expand_subaddresses ( { 5 , 20 } ) ;
m_wl_bob - > expand_subaddresses ( { 5 , 20 } ) ;
m_wl_eve - > expand_subaddresses ( { 5 , 20 } ) ;
}
void gen_trezor_base : : log_wallets_desc ( )
{
MDEBUG ( " Wallet for Alice: " < < wallet_desc_str ( m_wl_alice . get ( ) ) ) ;
MDEBUG ( " Wallet for Alice2: " < < wallet_desc_str ( m_wl_alice2 . get ( ) ) ) ;
MDEBUG ( " Wallet for Bob: " < < wallet_desc_str ( m_wl_bob . get ( ) ) ) ;
MDEBUG ( " Wallet for Eve: " < < wallet_desc_str ( m_wl_eve . get ( ) ) ) ;
2018-11-20 13:40:51 +00:00
}
2019-02-27 15:55:31 +00:00
void gen_trezor_base : : update_client_settings ( )
{
auto dev_trezor = dynamic_cast < : : hw : : trezor : : device_trezor * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_trezor , " Could not cast to device_trezor " ) ;
dev_trezor - > set_live_refresh_enabled ( m_live_refresh_enabled ) ;
}
2018-11-20 13:40:51 +00:00
bool gen_trezor_base : : generate ( std : : vector < test_event_entry > & events )
{
2023-09-29 17:13:37 +00:00
init_accounts ( ) ;
setup_trezor ( m_trezor_use_passphrase , m_trezor_pin ) ;
2018-11-20 13:40:51 +00:00
// Events, custom genesis so it matches wallet genesis
auto & generator = m_generator ; // macro shortcut
2020-04-07 16:25:25 +00:00
generator . set_events ( & events ) ;
generator . set_network_type ( m_network_type ) ;
2018-11-20 13:40:51 +00:00
cryptonote : : block blk_gen ;
std : : vector < size_t > block_weights ;
2019-02-27 15:55:31 +00:00
generate_genesis_block ( blk_gen , get_config ( m_network_type ) . GENESIS_TX , get_config ( m_network_type ) . GENESIS_NONCE ) ;
2018-11-20 13:40:51 +00:00
events . push_back ( blk_gen ) ;
2020-09-03 14:07:08 +00:00
uint64_t rew = 0 ;
cryptonote : : get_block_reward ( 0 , get_transaction_weight ( blk_gen . miner_tx ) , 0 , rew , 1 ) ;
generator . add_block ( blk_gen , 0 , block_weights , 0 , rew ) ;
2018-11-20 13:40:51 +00:00
// First event has to be the genesis block
cryptonote : : account_base * accounts [ ] = { TREZOR_ACCOUNT_ORDERING } ;
for ( cryptonote : : account_base * ac : accounts ) {
events . push_back ( * ac ) ;
}
// Another block with predefined timestamp.
// Carefully set reward and already generated coins so it passes miner_tx check.
cryptonote : : block blk_0 ;
2023-09-29 17:13:37 +00:00
cryptonote : : block & last_block = blk_0 ;
2018-11-20 13:40:51 +00:00
{
std : : list < cryptonote : : transaction > tx_list ;
const crypto : : hash prev_id = get_block_hash ( blk_gen ) ;
const uint64_t already_generated_coins = generator . get_already_generated_coins ( prev_id ) ;
block_weights . clear ( ) ;
generator . get_last_n_block_weights ( block_weights , prev_id , CRYPTONOTE_REWARD_BLOCKS_WINDOW ) ;
generator . construct_block ( blk_0 , 1 , prev_id , m_miner_account , m_ts_start , already_generated_coins , block_weights , tx_list ) ;
}
2023-09-29 17:13:37 +00:00
events . push_back ( last_block ) ;
MDEBUG ( " Gen+1 block has time: " < < last_block . timestamp < < " blid: " < < get_block_hash ( last_block ) ) ;
2018-11-20 13:40:51 +00:00
// Generate some spendable funds on the Miner account
2023-09-29 17:13:37 +00:00
REWIND_BLOCKS_N ( events , blk_3 , last_block , m_miner_account , 20 ) ;
last_block = blk_3 ;
// Rewind so the miners funds are unlocked for initial transactions, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW blocks
REWIND_BLOCKS_N ( events , blk_3r1 , last_block , m_miner_account , CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - 10 ) ;
last_block = blk_3r1 ;
last_block = rewind_blocks_with_decoys ( events , last_block , 10 , 1 , TEST_DECOY_MINING_COUNTS ) ;
MDEBUG ( " Mining chain generated, height: " < < get_block_height ( last_block ) < < " , #events: " < < events . size ( ) < < " , last block: " < < get_block_hash ( last_block ) ) ;
// Non-rct transactions Miner -> Alice
// Note that change transaction is spendable after CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE so we batch it to a tx
std : : list < cryptonote : : transaction > txs_blk_4 ;
generate_tx_block ( events , txs_blk_4 , last_block , m_miner_account , m_alice_account , MK_TCOINS ( 0.1 ) , 20 , 1 ) ;
MAKE_NEXT_BLOCK_TX_LIST ( events , blk_4 , last_block , m_miner_account , txs_blk_4 ) ;
last_block = blk_4 ;
MDEBUG ( " Non-rct transactions generated, height: " < < get_block_height ( last_block ) < < " , #events: " < < events . size ( ) < < " , last block: " < < get_block_hash ( last_block ) ) ;
2018-11-20 13:40:51 +00:00
// Hard fork to bulletproofs version, v9.
const uint8_t CUR_HF = 9 ;
auto hardfork_height = num_blocks ( events ) ; // next block is v9
ADD_HARDFORK ( m_hard_forks , CUR_HF , hardfork_height ) ;
add_hforks ( events , m_hard_forks ) ;
2023-09-29 17:13:37 +00:00
MDEBUG ( " Hardfork " < < ( int ) CUR_HF < < " height: " < < hardfork_height < < " , #events: " < < events . size ( ) < < " at block: " < < get_block_hash ( last_block ) ) ;
2018-11-20 13:40:51 +00:00
// RCT transactions, wallets have to be used, wallet init
2023-09-29 17:13:37 +00:00
init_wallets ( ) ;
2018-11-20 13:40:51 +00:00
auto addr_alice_sub_0_1 = m_wl_alice - > get_subaddress ( { 0 , 1 } ) ;
auto addr_alice_sub_0_2 = m_wl_alice - > get_subaddress ( { 0 , 2 } ) ;
auto addr_alice_sub_0_3 = m_wl_alice - > get_subaddress ( { 0 , 3 } ) ;
auto addr_alice_sub_0_4 = m_wl_alice - > get_subaddress ( { 0 , 4 } ) ;
auto addr_alice_sub_0_5 = m_wl_alice - > get_subaddress ( { 0 , 5 } ) ;
auto addr_alice_sub_1_0 = m_wl_alice - > get_subaddress ( { 1 , 0 } ) ;
auto addr_alice_sub_1_1 = m_wl_alice - > get_subaddress ( { 1 , 1 } ) ;
auto addr_alice_sub_1_2 = m_wl_alice - > get_subaddress ( { 1 , 2 } ) ;
2023-09-29 17:13:37 +00:00
// Miner -> Alice, RCT funds
std : : list < cryptonote : : transaction > txs_blk_5 ;
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , m_alice_account , MK_TCOINS ( 1 ) , 1 , CUR_HF ) ;
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , m_alice_account , MK_TCOINS ( 0.1 ) , heavy_tests ( ) | | heavy_test_set ( ) ? 95 : 0 , CUR_HF ) ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
// Simple RCT transactions
MDEBUG ( " blk_5 construction - RCT set " ) ;
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , m_alice_account , MK_TCOINS ( 1 ) , 1 , CUR_HF ) ;
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , build_dsts ( {
{ m_alice_account , false , MK_TCOINS ( 1 ) } ,
{ m_alice_account , false , MK_TCOINS ( 1 ) } ,
{ m_alice_account , false , MK_TCOINS ( 1 ) } ,
{ m_alice2_account , false , MK_TCOINS ( 1 ) }
} ) , 1 , CUR_HF ) ;
2018-11-20 13:40:51 +00:00
// Sub-address destinations + multi out to force use of additional keys
2023-09-29 17:13:37 +00:00
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , build_dsts ( {
{ addr_alice_sub_0_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_3 , true , MK_TCOINS ( 0.1 ) } ,
{ m_miner_account , false , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_3 , true , MK_TCOINS ( 0.1 ) } ,
{ m_miner_account , false , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_4 , true , MK_TCOINS ( 0.1 ) } } ) , 1 , CUR_HF ) ;
2018-11-20 13:40:51 +00:00
// Transfer to other accounts
2023-09-29 17:13:37 +00:00
generate_tx_block ( events , txs_blk_5 , last_block , m_miner_account , build_dsts ( {
{ addr_alice_sub_1_0 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_0 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_3 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_2 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_1_1 , true , MK_TCOINS ( 0.1 ) } ,
{ addr_alice_sub_0_5 , true , MK_TCOINS ( 0.1 ) } } ) , 1 , CUR_HF ) ;
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk_5 , last_block , m_miner_account , txs_blk_5 , CUR_HF ) ;
last_block = blk_5 ;
2018-11-20 13:40:51 +00:00
// Simple transaction check
bool resx = rct : : verRctSemanticsSimple ( txs_blk_5 . begin ( ) - > rct_signatures ) ;
bool resy = rct : : verRctNonSemanticsSimple ( txs_blk_5 . begin ( ) - > rct_signatures ) ;
CHECK_AND_ASSERT_THROW_MES ( resx , " Tsx5[0] semantics failed " ) ;
CHECK_AND_ASSERT_THROW_MES ( resy , " Tsx5[0] non-semantics failed " ) ;
2023-09-29 17:13:37 +00:00
// Rewind blocks so there are more spendable coins
last_block = rewind_blocks_with_decoys ( events , last_block , CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE + 2 , CUR_HF , TEST_DECOY_MINING_COUNTS ) ;
2018-11-20 13:40:51 +00:00
// RCT transactions, wallets have to be used
2023-09-29 17:13:37 +00:00
MDEBUG ( " Post blk_5 construction " ) ;
wallet_tools : : process_transactions ( vct_wallets ( m_wl_alice . get ( ) , m_wl_alice2 . get ( ) , m_wl_bob . get ( ) ) , events , last_block , m_bt ) ;
log_wallets_desc ( ) ;
2018-11-20 13:40:51 +00:00
// Send Alice -> Bob, manually constructed. Simple TX test, precondition.
cryptonote : : transaction tx_1 ;
2023-09-29 17:13:37 +00:00
uint64_t tx_1_amount = MK_TCOINS ( 0.1 ) ;
2018-11-20 13:40:51 +00:00
std : : vector < size_t > selected_transfers ;
std : : vector < tx_source_entry > sources ;
2023-09-29 17:13:37 +00:00
bool res = wallet_tools : : fill_tx_sources ( m_wl_alice . get ( ) , sources , TREZOR_TEST_MIXIN , boost : : none , tx_1_amount + TREZOR_TEST_FEE , m_bt , selected_transfers , get_block_height ( last_block ) , 0 , 1 ) ;
CHECK_AND_ASSERT_THROW_MES ( res , " Tx01: tx fill sources failed " ) ;
res = construct_tx_to_key ( tx_1 , m_wl_alice . get ( ) , m_bob_account , tx_1_amount , sources , TREZOR_TEST_FEE , true , rct : : RangeProofPaddedBulletproof , 1 ) ;
CHECK_AND_ASSERT_THROW_MES ( res , " Tx01: tx construction failed " ) ;
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
std : : list < cryptonote : : transaction > txs_blk_6 ;
txs_blk_6 . push_back ( tx_1 ) ;
2018-11-20 13:40:51 +00:00
events . push_back ( tx_1 ) ;
2023-09-29 17:13:37 +00:00
generate_tx_block ( events , txs_blk_6 , last_block , m_miner_account , m_alice_account , MK_TCOINS ( 1 ) , 1 , CUR_HF ) ;
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk_6 , last_block , m_miner_account , txs_blk_6 , CUR_HF ) ;
last_block = blk_6 ;
MDEBUG ( " Post 1st tsx: " < < ( num_blocks ( events ) - 1 ) < < " at block: " < < get_block_hash ( last_block ) < < " , event: " < < events . size ( ) ) ;
2018-11-20 13:40:51 +00:00
// Simple transaction check
resx = rct : : verRctSemanticsSimple ( tx_1 . rct_signatures ) ;
resy = rct : : verRctNonSemanticsSimple ( tx_1 . rct_signatures ) ;
CHECK_AND_ASSERT_THROW_MES ( resx , " tx_1 semantics failed " ) ;
CHECK_AND_ASSERT_THROW_MES ( resy , " tx_1 non-semantics failed " ) ;
2023-09-29 17:13:37 +00:00
last_block = rewind_blocks_with_decoys ( events , last_block , CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE , CUR_HF , TEST_DECOY_MINING_COUNTS ) ;
MDEBUG ( " Blockchain generation up to " < < ( int ) CUR_HF < < " finished at height " < < num_blocks ( events ) < < " , #events: " < < events . size ( ) ) ;
wallet_tools : : process_transactions ( TREZOR_ALL_WALLET_VCT , events , last_block , m_bt ) ;
log_wallets_desc ( ) ;
2019-04-03 19:29:35 +00:00
2023-09-29 17:13:37 +00:00
m_head = last_block ;
2018-11-20 13:40:51 +00:00
m_events = events ;
return true ;
}
void gen_trezor_base : : load ( std : : vector < test_event_entry > & events )
{
2023-09-29 17:13:37 +00:00
init_accounts ( ) ;
2018-11-20 13:40:51 +00:00
m_events = events ;
2020-04-07 16:25:25 +00:00
m_generator . set_events ( & m_events ) ;
m_generator . set_network_type ( m_network_type ) ;
2018-11-20 13:40:51 +00:00
unsigned acc_idx = 0 ;
cryptonote : : account_base * accounts [ ] = { TREZOR_ACCOUNT_ORDERING } ;
unsigned accounts_num = ( sizeof ( accounts ) / sizeof ( accounts [ 0 ] ) ) ;
for ( auto & ev : events )
{
if ( typeid ( cryptonote : : block ) = = ev . type ( ) )
{
m_head = boost : : get < cryptonote : : block > ( ev ) ;
}
else if ( typeid ( cryptonote : : account_base ) = = ev . type ( ) ) // accounts
{
const auto & acc = boost : : get < cryptonote : : account_base > ( ev ) ;
if ( acc_idx < accounts_num )
{
* accounts [ acc_idx + + ] = acc ;
}
}
else if ( typeid ( event_replay_settings ) = = ev . type ( ) ) // hard forks
{
const auto & rep_settings = boost : : get < event_replay_settings > ( ev ) ;
if ( rep_settings . hard_forks )
{
const auto & hf = rep_settings . hard_forks . get ( ) ;
std : : copy ( hf . begin ( ) , hf . end ( ) , std : : back_inserter ( m_hard_forks ) ) ;
}
}
}
// Setup wallets, synchronize blocks
2023-09-29 17:13:37 +00:00
init_wallets ( ) ;
wallet_tools : : process_transactions ( TREZOR_ALL_WALLET_VCT , events , m_head , m_bt ) ;
log_wallets_desc ( ) ;
2018-11-20 13:40:51 +00:00
}
2019-04-03 19:29:35 +00:00
void gen_trezor_base : : rewind_blocks ( std : : vector < test_event_entry > & events , size_t rewind_n , uint8_t hf )
{
2023-09-29 17:13:37 +00:00
m_head = rewind_blocks_with_decoys ( events , m_head , rewind_n , hf , TEST_DECOY_MINING_COUNTS ) ;
2019-04-03 19:29:35 +00:00
m_events = events ;
2023-09-29 17:13:37 +00:00
}
cryptonote : : block gen_trezor_base : : rewind_blocks_with_decoys ( std : : vector < test_event_entry > & events , cryptonote : : block & head , size_t rewind_n , uint8_t hf , size_t num_decoys_per_block )
{
auto & generator = m_generator ; // shortcut required by MAKE_NEXT_BLOCK_TX_LIST_HF
cryptonote : : block blk_last = head ;
for ( size_t i = 0 ; i < rewind_n ; + + i )
{
std : : list < cryptonote : : transaction > txs_lst ;
generate_tx_block ( events , txs_lst , blk_last , m_miner_account , m_bob_account , MK_TCOINS ( 0.0001 ) , num_decoys_per_block , hf ) ;
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk , blk_last , m_miner_account , txs_lst , hf ) ;
blk_last = blk ;
}
2019-04-03 19:29:35 +00:00
2023-09-29 17:13:37 +00:00
MDEBUG ( " Blocks rewound: " < < rewind_n < < " , #blocks: " < < num_blocks ( events ) < < " , #events: " < < events . size ( ) ) ;
return blk_last ;
2019-04-03 19:29:35 +00:00
}
2018-11-20 13:40:51 +00:00
void gen_trezor_base : : fix_hf ( std : : vector < test_event_entry > & events )
{
// If current test requires higher hard-fork, move it up
2020-04-07 16:25:25 +00:00
auto current_hf = m_hard_forks . back ( ) . first ;
CHECK_AND_ASSERT_THROW_MES ( current_hf < = m_top_hard_fork , " Generated chain hardfork is higher than desired maximum " ) ;
2020-09-03 14:07:08 +00:00
CHECK_AND_ASSERT_THROW_MES ( m_rct_config . bp_version < 2 | | m_top_hard_fork > = 10 , " Desired maximum is too low for BPv2 " ) ;
2019-04-03 19:29:35 +00:00
2020-04-07 16:25:25 +00:00
for ( ; current_hf < m_top_hard_fork ; current_hf + = 1 )
2019-04-03 19:29:35 +00:00
{
2020-04-07 16:25:25 +00:00
auto const hf_to_add = current_hf + 1 ;
2018-11-20 13:40:51 +00:00
auto hardfork_height = num_blocks ( events ) ;
2019-04-03 19:29:35 +00:00
2020-04-07 16:25:25 +00:00
ADD_HARDFORK ( m_hard_forks , hf_to_add , hardfork_height ) ;
add_top_hfork ( events , m_hard_forks ) ;
MDEBUG ( " Hardfork added at height: " < < hardfork_height < < " , from " < < ( int ) current_hf < < " to " < < ( int ) hf_to_add ) ;
2023-09-29 17:13:37 +00:00
// Wallet2 requires 10 blocks extra to activate HF
rewind_blocks ( events , hf_to_add = = m_top_hard_fork ? 10 : 1 , hf_to_add ) ;
if ( hf_to_add = = m_top_hard_fork ) {
MDEBUG ( " Blockchain generation up to " < < ( int ) hf_to_add < < " finished at height " < < num_blocks ( events ) < < " , #events: " < < events . size ( ) ) ;
}
2018-11-20 13:40:51 +00:00
}
2023-09-29 17:13:37 +00:00
wallet_tools : : process_transactions ( TREZOR_ALL_WALLET_VCT , events , m_head , m_bt ) ;
2018-11-20 13:40:51 +00:00
}
void gen_trezor_base : : update_trackers ( std : : vector < test_event_entry > & events )
{
wallet_tools : : process_transactions ( nullptr , events , m_head , m_bt ) ;
}
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : init_trezor_account ( ) {
setup_trezor ( m_trezor_use_passphrase , m_trezor_pin ) ;
2019-02-27 15:55:31 +00:00
update_client_settings ( ) ;
2023-09-29 17:13:37 +00:00
if ( m_trezor_use_alice2 ) {
m_alice2_account . create_from_device ( * m_trezor ) ;
m_alice2_account . set_createtime ( m_wallet_ts ) ;
} else {
m_alice_account . create_from_device ( * m_trezor ) ;
m_alice_account . set_createtime ( m_wallet_ts ) ;
}
}
2018-11-20 13:40:51 +00:00
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : test_setup ( std : : vector < test_event_entry > & events )
{
add_shared_events ( events ) ;
init_trezor_account ( ) ;
init_wallets ( ) ;
wallet_tools : : process_transactions ( TREZOR_ALL_WALLET_VCT , events , m_head , m_bt ) ;
2018-11-20 13:40:51 +00:00
}
2019-02-27 15:55:31 +00:00
void gen_trezor_base : : add_transactions_to_events (
std : : vector < test_event_entry > & events ,
test_generator & generator ,
const std : : vector < cryptonote : : transaction > & txs )
2018-11-20 13:40:51 +00:00
{
// If current test requires higher hard-fork, move it up
const auto current_hf = m_hard_forks . back ( ) . first ;
2019-04-03 19:29:35 +00:00
const uint8_t tx_hf = m_top_hard_fork ;
CHECK_AND_ASSERT_THROW_MES ( tx_hf < = current_hf , " Too late for HF change: " < < ( int ) tx_hf < < " current: " < < ( int ) current_hf ) ;
CHECK_AND_ASSERT_THROW_MES ( m_rct_config . bp_version < 2 | | tx_hf > = 10 , " HF too low for BPv2: " < < ( int ) tx_hf ) ;
2018-11-20 13:40:51 +00:00
std : : list < cryptonote : : transaction > tx_list ;
2019-02-27 15:55:31 +00:00
for ( const auto & tx : txs )
{
events . push_back ( tx ) ;
tx_list . push_back ( tx ) ;
}
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk_new , m_head , m_miner_account , tx_list , tx_hf ) ;
MDEBUG ( " New tsx: " < < ( num_blocks ( events ) - 1 ) < < " at block: " < < get_block_hash ( blk_new ) ) ;
m_head = blk_new ;
}
2023-09-29 17:13:37 +00:00
void gen_trezor_base : : test_trezor_tx ( std : : vector < test_event_entry > & events , std : : vector < tools : : wallet2 : : pending_tx > & ptxs , std : : vector < cryptonote : : address_parse_info > & dsts_info , test_generator & generator , std : : vector < tools : : wallet2 * > wallets , bool is_sweep , size_t sender_idx )
2019-02-27 15:55:31 +00:00
{
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( sender_idx < wallets . size ( ) , " Sender index out of bounds " ) ;
2019-02-27 15:55:31 +00:00
// Construct pending transaction for signature in the Trezor.
const uint64_t height_pre = num_blocks ( events ) - 1 ;
cryptonote : : block head_block = get_head_block ( events ) ;
const crypto : : hash head_hash = get_block_hash ( head_block ) ;
tools : : wallet2 : : unsigned_tx_set txs ;
std : : vector < cryptonote : : transaction > tx_list ;
2018-11-20 13:40:51 +00:00
for ( auto & ptx : ptxs ) {
txs . txes . push_back ( get_construction_data_with_decrypted_short_payment_id ( ptx , * m_trezor ) ) ;
}
2022-10-20 15:23:28 +00:00
const auto transfers = wallet_accessor_test : : get_transfers ( m_wl_alice . get ( ) ) ;
txs . transfers = std : : make_tuple ( 0 , transfers . size ( ) , transfers ) ;
2018-11-20 13:40:51 +00:00
auto dev_cold = dynamic_cast < : : hw : : device_cold * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_cold , " Device does not implement cold signing interface " ) ;
tools : : wallet2 : : signed_tx_set exported_txs ;
hw : : tx_aux_data aux_data ;
hw : : wallet_shim wallet_shim ;
setup_shim ( & wallet_shim ) ;
aux_data . tx_recipients = dsts_info ;
2019-02-27 15:55:31 +00:00
aux_data . bp_version = m_rct_config . bp_version ;
2020-09-03 14:07:08 +00:00
aux_data . hard_fork = m_top_hard_fork ;
2018-11-20 13:40:51 +00:00
dev_cold - > tx_sign ( & wallet_shim , txs , exported_txs , aux_data ) ;
2020-09-03 14:07:08 +00:00
MDEBUG ( " Signed tx data from hw: " < < exported_txs . ptx . size ( ) < < " transactions, hf: " < < ( int ) m_top_hard_fork < < " , bpv: " < < m_rct_config . bp_version ) ;
2018-11-20 13:40:51 +00:00
CHECK_AND_ASSERT_THROW_MES ( exported_txs . ptx . size ( ) = = ptxs . size ( ) , " Invalid transaction sizes " ) ;
for ( size_t i = 0 ; i < exported_txs . ptx . size ( ) ; + + i ) {
auto & c_ptx = exported_txs . ptx [ i ] ;
c_ptx . tx . rct_signatures . mixRing = ptxs [ i ] . tx . rct_signatures . mixRing ;
expand_tsx ( c_ptx . tx ) ;
// Simple TX tests, more complex are performed in the core.
MTRACE ( cryptonote : : obj_to_json_str ( c_ptx . tx ) ) ;
bool resx = rct : : verRctSemanticsSimple ( c_ptx . tx . rct_signatures ) ;
bool resy = rct : : verRctNonSemanticsSimple ( c_ptx . tx . rct_signatures ) ;
CHECK_AND_ASSERT_THROW_MES ( resx , " Trezor tx_1 semantics failed " ) ;
CHECK_AND_ASSERT_THROW_MES ( resy , " Trezor tx_1 Nonsemantics failed " ) ;
tx_list . push_back ( c_ptx . tx ) ;
2022-10-20 15:23:28 +00:00
const crypto : : hash txhash = cryptonote : : get_transaction_hash ( c_ptx . tx ) ;
2018-11-20 13:40:51 +00:00
MDEBUG ( " Transaction: " < < dump_data ( c_ptx . tx ) ) ;
2022-10-20 15:23:28 +00:00
MDEBUG ( " Transaction hash: " < < epee : : string_tools : : pod_to_hex ( txhash ) ) ;
MDEBUG ( " Serialized transaction: " < < epee : : string_tools : : buff_to_hex_nodelimer ( tx_to_blob ( c_ptx . tx ) ) ) ;
2018-11-20 13:40:51 +00:00
}
2019-02-27 15:55:31 +00:00
add_transactions_to_events ( events , generator , tx_list ) ;
2018-11-20 13:40:51 +00:00
// TX receive test
uint64_t sum_in = 0 ;
uint64_t sum_out = 0 ;
2023-09-29 17:13:37 +00:00
const cryptonote : : account_base * sender_account = & wallets [ sender_idx ] - > get_account ( ) ;
2018-11-20 13:40:51 +00:00
for ( size_t txid = 0 ; txid < exported_txs . ptx . size ( ) ; + + txid ) {
auto & c_ptx = exported_txs . ptx [ txid ] ;
auto & c_tx = c_ptx . tx ;
const crypto : : hash txhash = cryptonote : : get_transaction_hash ( c_tx ) ;
const size_t num_outs = c_tx . vout . size ( ) ;
size_t num_received = 0 ;
uint64_t cur_sum_in = 0 ;
uint64_t cur_sum_out = 0 ;
uint64_t cur_sum_out_recv = 0 ;
std : : unordered_set < size_t > recv_out_idx ;
std : : string exp_payment_id = get_payment_id ( c_ptx . construction_data . extra ) ;
std : : string enc_payment_id = get_payment_id ( c_tx . extra ) ;
size_t num_payment_id_checks_done = 0 ;
CHECK_AND_ASSERT_THROW_MES ( exp_payment_id . empty ( ) | | exp_payment_id . size ( ) = = 8 | | exp_payment_id . size ( ) = = 32 , " Required payment ID invalid " ) ;
CHECK_AND_ASSERT_THROW_MES ( ( exp_payment_id . size ( ) = = 32 ) = = ( enc_payment_id . size ( ) = = 32 ) , " Required and built payment ID size mismatch " ) ;
CHECK_AND_ASSERT_THROW_MES ( exp_payment_id . size ( ) < = enc_payment_id . size ( ) , " Required and built payment ID size mismatch " ) ;
for ( auto & src : c_ptx . construction_data . sources ) {
cur_sum_in + = src . amount ;
}
for ( auto & dst : c_ptx . construction_data . splitted_dsts ) {
cur_sum_out + = dst . amount ;
}
CHECK_AND_ASSERT_THROW_MES ( c_tx . rct_signatures . txnFee + cur_sum_out = = cur_sum_in , " Tx Input Output amount mismatch " ) ;
for ( size_t widx = 0 ; widx < wallets . size ( ) ; + + widx ) {
2023-09-29 17:13:37 +00:00
const bool sender = widx = = sender_idx ;
2018-11-20 13:40:51 +00:00
tools : : wallet2 * wl = wallets [ widx ] ;
2019-02-27 15:55:31 +00:00
wallet_tools : : process_transactions ( wl , events , m_head , m_bt , boost : : make_optional ( head_hash ) ) ;
2018-11-20 13:40:51 +00:00
tools : : wallet2 : : transfer_container m_trans ;
tools : : wallet2 : : transfer_container m_trans_txid ;
wl - > get_transfers ( m_trans ) ;
std : : copy_if ( m_trans . begin ( ) , m_trans . end ( ) , std : : back_inserter ( m_trans_txid ) , [ & txhash ] ( const tools : : wallet2 : : transfer_details & item ) {
return item . m_txid = = txhash ;
} ) ;
// Testing if the transaction output has been received
num_received + = m_trans_txid . size ( ) ;
for ( auto & ctran : m_trans_txid ) {
cur_sum_out_recv + = ctran . amount ( ) ;
recv_out_idx . insert ( ctran . m_internal_output_index ) ;
CHECK_AND_ASSERT_THROW_MES ( ! ctran . m_spent , " Txout is spent " ) ;
CHECK_AND_ASSERT_THROW_MES ( ! sender | | ctran . m_key_image_known , " Key Image unknown for recipient " ) ; // sender is Trezor, does not need to have KI
}
// Sender output payment (contains change and stuff)
if ( sender ) {
std : : list < std : : pair < crypto : : hash , tools : : wallet2 : : confirmed_transfer_details > > confirmed_transfers ; // txid -> tdetail
std : : list < std : : pair < crypto : : hash , tools : : wallet2 : : confirmed_transfer_details > > confirmed_transfers_txid ; // txid -> tdetail
wl - > get_payments_out ( confirmed_transfers , height_pre ) ;
std : : copy_if ( confirmed_transfers . begin ( ) , confirmed_transfers . end ( ) , std : : back_inserter ( confirmed_transfers_txid ) , [ & txhash ] ( const std : : pair < crypto : : hash , tools : : wallet2 : : confirmed_transfer_details > & item ) {
return item . first = = txhash ;
} ) ;
CHECK_AND_ASSERT_THROW_MES ( confirmed_transfers_txid . size ( ) = = 1 , " Sender does not have outgoing transfer for the transaction " ) ;
}
// Received payment from the block
std : : list < std : : pair < crypto : : hash , tools : : wallet2 : : payment_details > > payments ; // payment id -> [payment details] multimap
std : : list < std : : pair < crypto : : hash , tools : : wallet2 : : payment_details > > payments_txid ; // payment id -> [payment details] multimap
wl - > get_payments ( payments , height_pre ) ;
std : : copy_if ( payments . begin ( ) , payments . end ( ) , std : : back_inserter ( payments_txid ) , [ & txhash ] ( const std : : pair < crypto : : hash , tools : : wallet2 : : payment_details > & item ) {
return item . second . m_tx_hash = = txhash ;
} ) ;
for ( auto & paydet : payments_txid ) {
CHECK_AND_ASSERT_THROW_MES ( exp_payment_id . empty ( ) | | ( memcmp ( exp_payment_id . data ( ) , paydet . first . data , exp_payment_id . size ( ) ) = = 0 ) , " Payment ID mismatch " ) ;
num_payment_id_checks_done + = 1 ;
}
}
CHECK_AND_ASSERT_THROW_MES ( c_tx . rct_signatures . txnFee + cur_sum_out_recv = = cur_sum_in , " Tx Input Output amount mismatch " ) ;
CHECK_AND_ASSERT_THROW_MES ( exp_payment_id . empty ( ) | | num_payment_id_checks_done > 0 , " No Payment ID checks " ) ;
if ( ! is_sweep ) {
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( ( num_received + m_no_change_in_tested_tx ) = = num_outs , " Number of received outputs do not match number of outgoing " ) ;
CHECK_AND_ASSERT_THROW_MES ( ( recv_out_idx . size ( ) + m_no_change_in_tested_tx ) = = num_outs , " Num of outs received do not match " ) ;
2018-11-20 13:40:51 +00:00
} else {
CHECK_AND_ASSERT_THROW_MES ( num_received + 1 > = num_outs , " Number of received outputs do not match number of outgoing " ) ;
CHECK_AND_ASSERT_THROW_MES ( recv_out_idx . size ( ) + 1 > = num_outs , " Num of outs received do not match " ) ; // can have dummy out
}
sum_in + = cur_sum_in ;
sum_out + = cur_sum_out + c_tx . rct_signatures . txnFee ;
}
CHECK_AND_ASSERT_THROW_MES ( sum_in = = sum_out , " Tx amount mismatch " ) ;
2019-02-27 15:55:31 +00:00
// Test get_tx_key feature for stored private tx keys
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( sender_account ! = nullptr , " Sender account is null " ) ;
test_get_tx ( events , wallets , sender_account , exported_txs . ptx , aux_data . tx_device_aux ) ;
2019-02-27 15:55:31 +00:00
}
bool gen_trezor_base : : verify_tx_key ( const : : crypto : : secret_key & tx_priv , const : : crypto : : public_key & tx_pub , const subaddresses_t & subs )
{
: : crypto : : public_key tx_pub_c ;
: : crypto : : secret_key_to_public_key ( tx_priv , tx_pub_c ) ;
if ( tx_pub = = tx_pub_c )
return true ;
for ( const auto & elem : subs )
{
tx_pub_c = rct : : rct2pk ( rct : : scalarmultKey ( rct : : pk2rct ( elem . first ) , rct : : sk2rct ( tx_priv ) ) ) ;
if ( tx_pub = = tx_pub_c )
return true ;
}
return false ;
}
void gen_trezor_base : : test_get_tx (
std : : vector < test_event_entry > & events ,
std : : vector < tools : : wallet2 * > wallets ,
2023-09-29 17:13:37 +00:00
const cryptonote : : account_base * account ,
2019-02-27 15:55:31 +00:00
const std : : vector < tools : : wallet2 : : pending_tx > & ptxs ,
const std : : vector < std : : string > & aux_tx_info )
{
if ( ! m_test_get_tx_key )
{
return ;
}
auto dev_cold = dynamic_cast < : : hw : : device_cold * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_cold , " Device does not implement cold signing interface " ) ;
if ( ! dev_cold - > is_get_tx_key_supported ( ) )
{
MERROR ( " Get TX key is not supported by the connected Trezor " ) ;
return ;
}
subaddresses_t all_subs ;
for ( tools : : wallet2 * wlt : wallets )
{
wlt - > expand_subaddresses ( { 10 , 20 } ) ;
const subaddresses_t & cur_sub = wallet_accessor_test : : get_subaddresses ( wlt ) ;
all_subs . insert ( cur_sub . begin ( ) , cur_sub . end ( ) ) ;
}
for ( size_t txid = 0 ; txid < ptxs . size ( ) ; + + txid )
{
const auto & c_ptx = ptxs [ txid ] ;
const auto & c_tx = c_ptx . tx ;
const : : crypto : : hash tx_prefix_hash = cryptonote : : get_transaction_prefix_hash ( c_tx ) ;
auto tx_pub = cryptonote : : get_tx_pub_key_from_extra ( c_tx . extra ) ;
auto additional_pub_keys = cryptonote : : get_additional_tx_pub_keys_from_extra ( c_tx . extra ) ;
hw : : device_cold : : tx_key_data_t tx_key_data ;
std : : vector < : : crypto : : secret_key > tx_keys ;
dev_cold - > load_tx_key_data ( tx_key_data , aux_tx_info [ txid ] ) ;
CHECK_AND_ASSERT_THROW_MES ( std : : string ( tx_prefix_hash . data , 32 ) = = tx_key_data . tx_prefix_hash , " TX prefix mismatch " ) ;
2023-09-29 17:13:37 +00:00
dev_cold - > get_tx_key ( tx_keys , tx_key_data , account - > get_keys ( ) . m_view_secret_key ) ; // alice
2019-02-27 15:55:31 +00:00
CHECK_AND_ASSERT_THROW_MES ( ! tx_keys . empty ( ) , " Empty TX keys " ) ;
CHECK_AND_ASSERT_THROW_MES ( verify_tx_key ( tx_keys [ 0 ] , tx_pub , all_subs ) , " Tx pub mismatch " ) ;
CHECK_AND_ASSERT_THROW_MES ( additional_pub_keys . size ( ) = = tx_keys . size ( ) - 1 , " Invalid additional keys count " ) ;
for ( size_t i = 0 ; i < additional_pub_keys . size ( ) ; + + i )
{
CHECK_AND_ASSERT_THROW_MES ( verify_tx_key ( tx_keys [ i + 1 ] , additional_pub_keys [ i ] , all_subs ) , " Tx pub mismatch " ) ;
}
}
}
void gen_trezor_base : : mine_and_test ( std : : vector < test_event_entry > & events )
{
2023-09-29 17:13:37 +00:00
if ( ! m_mining_enabled ) {
MDEBUG ( " Mining test disabled " ) ;
return ;
}
2019-02-27 15:55:31 +00:00
cryptonote : : core * core = daemon ( ) - > core ( ) ;
const uint64_t height_before_mining = daemon ( ) - > get_height ( ) ;
const auto miner_address = cryptonote : : get_account_address_as_str ( FAKECHAIN , false , get_address ( m_miner_account ) ) ;
2023-09-29 17:13:37 +00:00
daemon ( ) - > mine_blocks ( 1 , miner_address , std : : chrono : : seconds ( m_mining_timeout ) ) ;
2019-02-27 15:55:31 +00:00
const uint64_t cur_height = daemon ( ) - > get_height ( ) ;
CHECK_AND_ASSERT_THROW_MES ( height_before_mining < cur_height , " Mining fail " ) ;
const crypto : : hash top_hash = core - > get_blockchain_storage ( ) . get_block_id_by_height ( height_before_mining ) ;
cryptonote : : block top_block { } ;
CHECK_AND_ASSERT_THROW_MES ( core - > get_blockchain_storage ( ) . get_block_by_hash ( top_hash , top_block ) , " Block fetch fail " ) ;
CHECK_AND_ASSERT_THROW_MES ( ! top_block . tx_hashes . empty ( ) , " Mined block is empty " ) ;
std : : vector < cryptonote : : transaction > txs_found ;
std : : vector < crypto : : hash > txs_missed ;
bool r = core - > get_blockchain_storage ( ) . get_transactions ( top_block . tx_hashes , txs_found , txs_missed ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " Transaction lookup fail " ) ;
CHECK_AND_ASSERT_THROW_MES ( ! txs_found . empty ( ) , " Transaction lookup fail " ) ;
// Transaction is not expanded, but mining verified it.
events . push_back ( txs_found [ 0 ] ) ;
events . push_back ( top_block ) ;
}
void gen_trezor_base : : set_hard_fork ( uint8_t hf )
{
m_top_hard_fork = hf ;
if ( hf < 9 ) {
throw std : : runtime_error ( " Minimal supported Hardfork is 9 " ) ;
2020-09-03 14:07:08 +00:00
} else if ( hf < = 11 ) {
2019-02-27 15:55:31 +00:00
rct_config ( { rct : : RangeProofPaddedBulletproof , 1 } ) ;
2020-09-03 14:07:08 +00:00
} else if ( hf = = 12 ) {
2019-02-27 15:55:31 +00:00
rct_config ( { rct : : RangeProofPaddedBulletproof , 2 } ) ;
2020-09-03 14:07:08 +00:00
} else if ( hf = = HF_VERSION_CLSAG ) {
rct_config ( { rct : : RangeProofPaddedBulletproof , 3 } ) ;
2022-04-12 00:06:19 +00:00
} else if ( hf = = HF_VERSION_BULLETPROOF_PLUS ) {
rct_config ( { rct : : RangeProofPaddedBulletproof , 4 } ) ;
2020-09-03 14:07:08 +00:00
} else {
throw std : : runtime_error ( " Unsupported HF " ) ;
2019-02-27 15:55:31 +00:00
}
2018-11-20 13:40:51 +00:00
}
2023-09-29 17:13:37 +00:00
boost : : optional < epee : : wipeable_string > gen_trezor_base : : on_pin_request ( ) {
return boost : : make_optional ( epee : : wipeable_string ( ( m_trezor_pin ) . data ( ) , ( m_trezor_pin ) . size ( ) ) ) ;
}
boost : : optional < epee : : wipeable_string > gen_trezor_base : : on_passphrase_request ( bool & on_device ) {
on_device = false ;
return boost : : make_optional ( epee : : wipeable_string ( ( m_trezor_passphrase ) . data ( ) , ( m_trezor_passphrase ) . size ( ) ) ) ;
}
2018-11-20 13:40:51 +00:00
# define TREZOR_TEST_PREFIX() \
test_generator generator ( m_generator ) ; \
test_setup ( events ) ; \
tsx_builder t_builder_o ( this ) ; \
tsx_builder * t_builder = & t_builder_o
# define TREZOR_TEST_SUFFIX() \
auto _dsts = t_builder - > build ( ) ; \
auto _dsts_info = t_builder - > dest_info ( ) ; \
2023-09-29 17:13:37 +00:00
test_trezor_tx ( events , _dsts , _dsts_info , generator , TREZOR_ALL_WALLET_VCT ) ; \
2018-11-20 13:40:51 +00:00
return true
# define TREZOR_SKIP_IF_VERSION_LEQ(x) if (m_trezor->get_version() <= x) { MDEBUG("Test skipped"); return true; }
# define TREZOR_TEST_PAYMENT_ID "\xde\xad\xc0\xde\xde\xad\xc0\xde"
tsx_builder * tsx_builder : : sources ( std : : vector < cryptonote : : tx_source_entry > & sources , std : : vector < size_t > & selected_transfers )
{
m_sources = sources ;
m_selected_transfers = selected_transfers ;
return this ;
}
2023-09-29 17:13:37 +00:00
tsx_builder * tsx_builder : : compute_sources ( boost : : optional < size_t > num_utxo , uint64_t extra_amount , ssize_t offset , int step , boost : : optional < fnc_accept_tx_source_t > fnc_accept )
2018-11-20 13:40:51 +00:00
{
CHECK_AND_ASSERT_THROW_MES ( m_tester , " m_tester wallet empty " ) ;
CHECK_AND_ASSERT_THROW_MES ( m_from , " m_from wallet empty " ) ;
// typedef std::function<bool(const tx_source_info_crate_t &info, bool &abort)> fnc_accept_tx_source_t;
boost : : optional < fnc_accept_tx_source_t > fnc_accept_to_use = boost : : none ;
auto c_account = m_account ;
fnc_accept_tx_source_t fnc_acc = [ c_account , & fnc_accept ] ( const tx_source_info_crate_t & info , bool & abort ) - > bool {
if ( info . td - > m_subaddr_index . major ! = c_account ) {
return false ;
}
if ( fnc_accept ) {
return ( fnc_accept . get ( ) ) ( info , abort ) ;
}
return true ;
} ;
2023-09-29 17:13:37 +00:00
const uint64_t needed_amount = m_fee + std : : accumulate ( m_destinations_orig . begin ( ) , m_destinations_orig . end ( ) , 0 , [ ] ( int a , const cryptonote : : tx_destination_entry & b ) { return a + b . amount ; } ) ;
const uint64_t real_amount = needed_amount + extra_amount ;
MDEBUG ( " Computing sources for tx, |utxos| = " < < ( num_utxo ? std : : to_string ( num_utxo . get ( ) ) : " * " )
< < " , sum: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) real_amount / COIN )
< < " , need: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) needed_amount / COIN )
< < " , extra: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) extra_amount / COIN )
< < " , fee: " < < std : : setfill ( ' ' ) < < std : : setw ( 12 ) < < ( ( double ) m_fee / COIN ) ) ;
bool res = wallet_tools : : fill_tx_sources ( m_from , m_sources , m_mixin , num_utxo , real_amount , m_tester - > m_bt , m_selected_transfers , m_cur_height , offset , step , fnc_acc , fnc_trezor_default_acceptor_tx_in ) ;
CHECK_AND_ASSERT_THROW_MES ( ! num_utxo | | num_utxo = = m_sources . size ( ) , " !!Test error, Number of computed inputs " < < m_sources . size ( ) < < " does not match desired number " < < num_utxo . get ( ) ) ;
2018-11-20 13:40:51 +00:00
CHECK_AND_ASSERT_THROW_MES ( res , " Tx source fill error " ) ;
return this ;
}
2023-09-29 17:13:37 +00:00
tsx_builder * tsx_builder : : compute_sources_to_sub ( boost : : optional < size_t > num_utxo , uint64_t extra_amount , ssize_t offset , int step , boost : : optional < fnc_accept_tx_source_t > fnc_accept )
2018-11-20 13:40:51 +00:00
{
fnc_accept_tx_source_t fnc = [ & fnc_accept ] ( const tx_source_info_crate_t & info , bool & abort ) - > bool {
if ( info . td - > m_subaddr_index . minor = = 0 ) {
return false ;
}
if ( fnc_accept ) {
return ( fnc_accept . get ( ) ) ( info , abort ) ;
}
return true ;
} ;
2023-09-29 17:13:37 +00:00
return compute_sources ( num_utxo , extra_amount , offset , step , fnc ) ;
2018-11-20 13:40:51 +00:00
}
2023-09-29 17:13:37 +00:00
tsx_builder * tsx_builder : : compute_sources_to_sub_acc ( boost : : optional < size_t > num_utxo , uint64_t extra_amount , ssize_t offset , int step , boost : : optional < fnc_accept_tx_source_t > fnc_accept )
2018-11-20 13:40:51 +00:00
{
fnc_accept_tx_source_t fnc = [ & fnc_accept ] ( const tx_source_info_crate_t & info , bool & abort ) - > bool {
if ( info . td - > m_subaddr_index . minor = = 0 | | info . src - > real_out_additional_tx_keys . size ( ) = = 0 ) {
return false ;
}
if ( fnc_accept ) {
return ( fnc_accept . get ( ) ) ( info , abort ) ;
}
return true ;
} ;
2023-09-29 17:13:37 +00:00
return compute_sources ( num_utxo , extra_amount , offset , step , fnc ) ;
2018-11-20 13:40:51 +00:00
}
tsx_builder * tsx_builder : : destinations ( std : : vector < cryptonote : : tx_destination_entry > & dsts )
{
m_destinations_orig = dsts ;
return this ;
}
tsx_builder * tsx_builder : : add_destination ( const cryptonote : : tx_destination_entry & dst )
{
m_destinations_orig . push_back ( dst ) ;
return this ;
}
tsx_builder * tsx_builder : : add_destination ( const var_addr_t addr , bool is_subaddr , uint64_t amount )
{
m_destinations_orig . push_back ( build_dst ( addr , is_subaddr , amount ) ) ;
return this ;
}
tsx_builder * tsx_builder : : add_destination ( const tools : : wallet2 * wallet , bool is_subaddr , uint64_t amount )
{
m_destinations_orig . push_back ( build_dst ( get_address ( wallet ) , is_subaddr , amount ) ) ;
return this ;
}
tsx_builder * tsx_builder : : set_integrated ( size_t idx )
{
2022-10-20 15:23:28 +00:00
CHECK_AND_ASSERT_THROW_MES ( m_destinations_orig . size ( ) > idx , " Destination size not big enough to set integrated flag " ) ;
2018-11-20 13:40:51 +00:00
m_integrated . insert ( idx ) ;
2022-10-20 15:23:28 +00:00
m_destinations_orig [ idx ] . is_integrated = true ;
2018-11-20 13:40:51 +00:00
return this ;
}
tsx_builder * tsx_builder : : clear_current ( )
{
m_account = 0 ;
m_selected_transfers . clear ( ) ;
m_sources . clear ( ) ;
m_destinations . clear ( ) ;
m_destinations_orig . clear ( ) ;
m_dsts_info . clear ( ) ;
m_integrated . clear ( ) ;
m_payment_id . clear ( ) ;
return this ;
}
tsx_builder * tsx_builder : : build_tx ( )
{
CHECK_AND_ASSERT_THROW_MES ( m_tester , " m_tester wallet empty " ) ;
CHECK_AND_ASSERT_THROW_MES ( m_from , " m_from wallet empty " ) ;
// Amount sanity check input >= fee + outputs
const uint64_t out_amount = sum_amount ( m_destinations_orig ) ;
const uint64_t in_amount = sum_amount ( m_sources ) ;
CHECK_AND_ASSERT_THROW_MES ( in_amount > = out_amount + m_fee , " Not enough input credits for outputs and fees " ) ;
// Create new pending transaction, init with sources and destinations
m_ptxs . emplace_back ( ) ;
auto & ptx = m_ptxs . back ( ) ;
std : : vector < uint8_t > extra = build_payment_id_extra ( m_payment_id ) ;
fill_tx_destinations ( m_from - > get_subaddress ( { m_account , 0 } ) , m_destinations_orig , m_fee , m_sources , m_destinations , true ) ;
construct_pending_tx ( ptx , extra ) ;
ptx . construction_data . subaddr_account = m_account ;
// Build destinations parse info
for ( size_t i = 0 ; i < m_destinations_orig . size ( ) ; + + i ) {
auto & cdest = m_destinations_orig [ i ] ;
cryptonote : : address_parse_info info = init_addr_parse_info ( cdest . addr , cdest . is_subaddress ) ;
if ( m_integrated . find ( i ) ! = m_integrated . end ( ) ) {
CHECK_AND_ASSERT_THROW_MES ( m_payment_id . size ( ) = = 8 , " Integrated set but payment_id.size() != 8 " ) ;
info . has_payment_id = true ;
info . payment_id = to_short_payment_id ( m_payment_id ) ;
}
m_dsts_info . push_back ( info ) ;
}
return this ;
}
tsx_builder * tsx_builder : : construct_pending_tx ( tools : : wallet2 : : pending_tx & ptx , boost : : optional < std : : vector < uint8_t > > extra )
{
CHECK_AND_ASSERT_THROW_MES ( m_from , " Wallet not provided " ) ;
cryptonote : : transaction tx ;
subaddresses_t & subaddresses = wallet_accessor_test : : get_subaddresses ( m_from ) ;
crypto : : secret_key tx_key ;
std : : vector < crypto : : secret_key > additional_tx_keys ;
std : : vector < tx_destination_entry > destinations_copy = m_destinations ;
2020-04-07 16:25:25 +00:00
auto sources_copy = m_sources ;
2018-11-20 13:40:51 +00:00
auto change_addr = m_from - > get_account ( ) . get_keys ( ) . m_account_address ;
bool r = construct_tx_and_get_tx_key ( m_from - > get_account ( ) . get_keys ( ) , subaddresses , m_sources , destinations_copy ,
change_addr , extra ? extra . get ( ) : std : : vector < uint8_t > ( ) , tx , 0 , tx_key ,
2022-10-20 15:23:28 +00:00
additional_tx_keys , true , m_rct_config , this - > m_tester - > cur_hf ( ) > = HF_VERSION_VIEW_TAGS ) ;
2018-11-20 13:40:51 +00:00
CHECK_AND_ASSERT_THROW_MES ( r , " Transaction construction failed " ) ;
2020-04-07 16:25:25 +00:00
// Selected transfers permutation
std : : vector < size_t > ins_order ;
for ( size_t n = 0 ; n < m_sources . size ( ) ; + + n )
{
for ( size_t idx = 0 ; idx < sources_copy . size ( ) ; + + idx )
{
CHECK_AND_ASSERT_THROW_MES ( ( size_t ) sources_copy [ idx ] . real_output < sources_copy [ idx ] . outputs . size ( ) , " Invalid real_output " ) ;
if ( sources_copy [ idx ] . outputs [ sources_copy [ idx ] . real_output ] . second . dest = = m_sources [ n ] . outputs [ m_sources [ n ] . real_output ] . second . dest )
ins_order . push_back ( idx ) ;
}
}
CHECK_AND_ASSERT_THROW_MES ( ins_order . size ( ) = = m_sources . size ( ) , " Failed to work out sources permutation " ) ;
2018-11-20 13:40:51 +00:00
ptx . key_images = " " ;
ptx . fee = TESTS_DEFAULT_FEE ;
ptx . dust = 0 ;
ptx . dust_added_to_fee = false ;
ptx . tx = tx ;
ptx . change_dts = m_destinations . back ( ) ;
ptx . selected_transfers = m_selected_transfers ;
2020-04-07 16:25:25 +00:00
tools : : apply_permutation ( ins_order , ptx . selected_transfers ) ;
2018-11-20 13:40:51 +00:00
ptx . tx_key = tx_key ;
ptx . additional_tx_keys = additional_tx_keys ;
ptx . dests = m_destinations ;
ptx . multisig_sigs . clear ( ) ;
ptx . construction_data . sources = m_sources ;
ptx . construction_data . change_dts = m_destinations . back ( ) ;
ptx . construction_data . splitted_dsts = m_destinations ;
ptx . construction_data . selected_transfers = ptx . selected_transfers ;
ptx . construction_data . extra = tx . extra ;
ptx . construction_data . unlock_time = 0 ;
ptx . construction_data . use_rct = true ;
2019-04-03 19:29:35 +00:00
ptx . construction_data . rct_config = m_rct_config ;
2018-11-20 13:40:51 +00:00
ptx . construction_data . dests = m_destinations_orig ;
ptx . construction_data . subaddr_account = 0 ;
ptx . construction_data . subaddr_indices . clear ( ) ;
for ( uint32_t i = 0 ; i < 20 ; + + i )
ptx . construction_data . subaddr_indices . insert ( i ) ;
return this ;
}
std : : vector < tools : : wallet2 : : pending_tx > tsx_builder : : build ( )
{
return m_ptxs ;
}
2019-02-27 15:55:31 +00:00
device_trezor_test : : device_trezor_test ( ) : m_tx_sign_ctr ( 0 ) , m_compute_key_image_ctr ( 0 ) { }
void device_trezor_test : : clear_test_counters ( ) {
m_tx_sign_ctr = 0 ;
m_compute_key_image_ctr = 0 ;
2023-09-29 17:13:37 +00:00
m_live_synced_ki . clear ( ) ;
2019-02-27 15:55:31 +00:00
}
2023-09-29 17:13:37 +00:00
void device_trezor_test : : setup_for_tests ( const std : : string & trezor_path , const std : : string & seed , cryptonote : : network_type network_type , bool use_passphrase , const std : : string & pin ) {
2019-02-27 15:55:31 +00:00
this - > clear_test_counters ( ) ;
this - > set_debug ( true ) ; // debugging commands on Trezor (auto-confirm transactions)
CHECK_AND_ASSERT_THROW_MES ( this - > set_name ( trezor_path ) , " Could not set device name " < < trezor_path ) ;
this - > set_network_type ( network_type ) ;
this - > set_derivation_path ( " " ) ; // empty derivation path
CHECK_AND_ASSERT_THROW_MES ( this - > init ( ) , " Could not initialize the device " < < trezor_path ) ;
CHECK_AND_ASSERT_THROW_MES ( this - > connect ( ) , " Could not connect to the device " < < trezor_path ) ;
this - > wipe_device ( ) ;
2023-09-29 17:13:37 +00:00
this - > load_device ( seed , pin , use_passphrase ) ;
2019-02-27 15:55:31 +00:00
this - > release ( ) ;
this - > disconnect ( ) ;
}
bool device_trezor_test : : compute_key_image ( const : : cryptonote : : account_keys & ack , const : : crypto : : public_key & out_key ,
const : : crypto : : key_derivation & recv_derivation , size_t real_output_index ,
const : : cryptonote : : subaddress_index & received_index ,
: : cryptonote : : keypair & in_ephemeral , : : crypto : : key_image & ki ) {
bool res = device_trezor : : compute_key_image ( ack , out_key , recv_derivation , real_output_index , received_index ,
in_ephemeral , ki ) ;
m_compute_key_image_ctr + = res ;
2023-09-29 17:13:37 +00:00
m_live_synced_ki . insert ( ki ) ;
2019-02-27 15:55:31 +00:00
return res ;
}
void
device_trezor_test : : tx_sign ( hw : : wallet_shim * wallet , const : : tools : : wallet2 : : unsigned_tx_set & unsigned_tx , size_t idx ,
hw : : tx_aux_data & aux_data , std : : shared_ptr < hw : : trezor : : protocol : : tx : : Signer > & signer ) {
m_tx_sign_ctr + = 1 ;
device_trezor : : tx_sign ( wallet , unsigned_tx , idx , aux_data , signer ) ;
}
2018-11-20 13:40:51 +00:00
bool gen_trezor_ki_sync : : generate ( std : : vector < test_event_entry > & events )
{
test_generator generator ( m_generator ) ;
test_setup ( events ) ;
auto dev_cold = dynamic_cast < : : hw : : device_cold * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_cold , " Device does not implement cold signing interface " ) ;
std : : vector < std : : pair < crypto : : key_image , crypto : : signature > > ski ;
tools : : wallet2 : : transfer_container transfers ;
hw : : wallet_shim wallet_shim ;
setup_shim ( & wallet_shim ) ;
m_wl_alice - > get_transfers ( transfers ) ;
dev_cold - > ki_sync ( & wallet_shim , transfers , ski ) ;
CHECK_AND_ASSERT_THROW_MES ( ski . size ( ) = = transfers . size ( ) , " Size mismatch " ) ;
for ( size_t i = 0 ; i < transfers . size ( ) ; + + i )
{
auto & td = transfers [ i ] ;
auto & kip = ski [ i ] ;
CHECK_AND_ASSERT_THROW_MES ( ! td . m_key_image_known | | td . m_key_image = = kip . first , " Key Image invalid: " < < i ) ;
}
uint64_t spent = 0 , unspent = 0 ;
m_wl_alice - > import_key_images ( ski , 0 , spent , unspent , false ) ;
2019-02-27 15:55:31 +00:00
auto dev_trezor_test = dynamic_cast < device_trezor_test * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_cold , " Device does not implement test interface " ) ;
if ( ! m_live_refresh_enabled )
CHECK_AND_ASSERT_THROW_MES ( dev_trezor_test - > m_compute_key_image_ctr = = 0 , " Live refresh should not happen: " < < dev_trezor_test - > m_compute_key_image_ctr ) ;
2023-09-29 17:13:37 +00:00
else {
CHECK_AND_ASSERT_THROW_MES ( dev_trezor_test - > m_compute_key_image_ctr > = ski . size ( ) , " Live refresh counts invalid " ) ;
for ( size_t i = 0 ; i < transfers . size ( ) ; + + i )
{
CHECK_AND_ASSERT_THROW_MES ( dev_trezor_test - > m_live_synced_ki . count ( ski [ i ] . first ) > 0 , " Key image not foind in live sync: " < < ski [ i ] . first ) ;
}
}
2019-02-27 15:55:31 +00:00
return true ;
}
bool gen_trezor_ki_sync_with_refresh : : generate ( std : : vector < test_event_entry > & events )
{
m_live_refresh_enabled = true ;
return gen_trezor_ki_sync : : generate ( events ) ;
}
bool gen_trezor_ki_sync_without_refresh : : generate ( std : : vector < test_event_entry > & events )
{
m_live_refresh_enabled = false ;
return gen_trezor_ki_sync : : generate ( events ) ;
}
bool gen_trezor_live_refresh : : generate ( std : : vector < test_event_entry > & events )
{
test_generator generator ( m_generator ) ;
test_setup ( events ) ;
auto dev_cold = dynamic_cast < : : hw : : device_cold * > ( m_trezor ) ;
CHECK_AND_ASSERT_THROW_MES ( dev_cold , " Device does not implement cold signing interface " ) ;
if ( ! dev_cold - > is_live_refresh_supported ( ) ) {
MDEBUG ( " Trezor does not support live refresh " ) ;
return true ;
}
hw : : device & sw_device = hw : : get_device ( " default " ) ;
dev_cold - > live_refresh_start ( ) ;
for ( unsigned i = 0 ; i < 50 ; + + i )
{
cryptonote : : subaddress_index subaddr = { 0 , i } ;
: : crypto : : secret_key r ;
: : crypto : : public_key R ;
: : crypto : : key_derivation D ;
: : crypto : : public_key pub_ver ;
: : crypto : : key_image ki ;
: : crypto : : random32_unbiased ( ( unsigned char * ) r . data ) ;
: : crypto : : secret_key_to_public_key ( r , R ) ;
memcpy ( D . data , rct : : scalarmultKey ( rct : : pk2rct ( R ) , rct : : sk2rct ( m_alice_account . get_keys ( ) . m_view_secret_key ) ) . bytes , 32 ) ;
: : crypto : : secret_key scalar_step1 ;
: : crypto : : secret_key scalar_step2 ;
: : crypto : : derive_secret_key ( D , i , m_alice_account . get_keys ( ) . m_spend_secret_key , scalar_step1 ) ;
if ( i = = 0 )
{
scalar_step2 = scalar_step1 ;
}
else
{
: : crypto : : secret_key subaddr_sk = sw_device . get_subaddress_secret_key ( m_alice_account . get_keys ( ) . m_view_secret_key , subaddr ) ;
sw_device . sc_secret_add ( scalar_step2 , scalar_step1 , subaddr_sk ) ;
}
: : crypto : : secret_key_to_public_key ( scalar_step2 , pub_ver ) ;
: : crypto : : generate_key_image ( pub_ver , scalar_step2 , ki ) ;
cryptonote : : keypair in_ephemeral ;
: : crypto : : key_image ki2 ;
dev_cold - > live_refresh (
m_alice_account . get_keys ( ) . m_view_secret_key ,
pub_ver ,
D ,
i ,
subaddr ,
in_ephemeral ,
ki2
) ;
CHECK_AND_ASSERT_THROW_MES ( ki = = ki2 , " Key image inconsistent " ) ;
}
dev_cold - > live_refresh_finish ( ) ;
2018-11-20 13:40:51 +00:00
return true ;
}
bool gen_trezor_1utxo : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
2023-09-29 17:13:37 +00:00
m_no_change_in_tested_tx = true ;
const uint64_t amount = MK_TCOINS ( 1 ) ;
const fnc_accept_tx_source_t acceptor = [ ] ( const tx_source_info_crate_t & info , bool & abort ) - > bool { return info . td - > amount ( ) = = amount & & info . td - > m_subaddr_index . minor = = 0 ; } ;
2018-11-20 13:40:51 +00:00
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
2023-09-29 17:13:37 +00:00
- > add_destination ( m_eve_account , false , MK_TCOINS ( 1 ) - TREZOR_TEST_FEE ) // no change
2018-11-20 13:40:51 +00:00
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( boost : : none , 0 , - 1 , - 1 , acceptor )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_1utxo_paymentid_short : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > payment_id ( TREZOR_TEST_PAYMENT_ID )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 1 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_1utxo_paymentid_short_integrated : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > payment_id ( TREZOR_TEST_PAYMENT_ID )
- > set_integrated ( 0 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 1 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo_acc1 : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 1 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo_to_sub : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo_to_2sub : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 3 } ) , true , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo_to_1norm_2sub : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve . get ( ) , false , 1000 )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > rct_config ( m_rct_config )
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_2utxo_sub_acc_to_1norm_2sub : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve . get ( ) , false , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources_to_sub_acc ( 2 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_4utxo_to_7outs : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 2 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 3 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve . get ( ) , false , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
2022-04-12 00:06:19 +00:00
bool gen_trezor_4utxo_to_15outs : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 2 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 3 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 2 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 3 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve . get ( ) , false , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 4 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
bool gen_trezor_16utxo_to_sub : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > rct_config ( m_rct_config )
- > compute_sources ( 16 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2022-04-12 00:06:19 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
2018-11-20 13:40:51 +00:00
bool gen_trezor_many_utxo : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
2022-04-12 00:06:19 +00:00
- > mixin ( num_mixin ( ) )
2018-11-20 13:40:51 +00:00
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 110 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2018-11-20 13:40:51 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
2022-04-12 00:06:19 +00:00
bool gen_trezor_many_utxo_many_txo : : generate ( std : : vector < test_event_entry > & events )
{
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 2 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 3 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 1 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 2 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 0 , 3 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 1 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 2 , 4 } ) , true , 1000 )
- > add_destination ( m_wl_eve - > get_subaddress ( { 3 , 4 } ) , true , 1000 )
- > rct_config ( m_rct_config )
2023-09-29 17:13:37 +00:00
- > compute_sources ( 40 , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
2022-04-12 00:06:19 +00:00
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
}
2023-09-29 17:13:37 +00:00
bool gen_trezor_no_passphrase : : generate ( std : : vector < test_event_entry > & events )
{
m_trezor_use_passphrase = false ;
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > rct_config ( m_rct_config )
- > compute_sources ( boost : : none , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
return true ;
}
bool gen_trezor_wallet_passphrase : : generate ( std : : vector < test_event_entry > & events )
2019-02-27 15:55:31 +00:00
{
m_wallet_dir = boost : : filesystem : : unique_path ( ) ;
boost : : filesystem : : create_directories ( m_wallet_dir ) ;
2023-09-29 17:13:37 +00:00
m_trezor_use_alice2 = true ;
m_trezor_use_passphrase = true ;
m_trezor_passphrase = m_alice2_passphrase ;
test_setup ( events ) ;
const auto wallet_path = ( m_wallet_dir / " alice2 " ) . string ( ) ;
const epee : : wipeable_string & password = epee : : wipeable_string ( " test-pass " ) ;
m_wl_alice2 - > store_to ( wallet_path , password ) ;
// Positive load
MDEBUG ( " Loading wallet with correct passphrase " ) ;
m_wl_alice2 - > callback ( this ) ;
m_wl_alice2 - > load ( wallet_path , password ) ;
// Negative load
m_trezor_passphrase = " bad-passphrase-0112312312312 " ;
setup_trezor ( m_trezor_use_passphrase , m_trezor_pin ) ;
update_client_settings ( ) ;
m_wl_alice2 - > callback ( this ) ;
MDEBUG ( " Loading wallet with different passphrase - should fail " ) ;
try {
m_wl_alice2 - > load ( wallet_path , password ) ;
CHECK_AND_ASSERT_THROW_MES ( false , " Wallet load should not pass with different passphrase " ) ;
} catch ( const tools : : error : : wallet_internal_error & ex ) {
CHECK_AND_ASSERT_THROW_MES ( ex . to_string ( ) . find ( " does not match wallet " ) ! = std : : string : : npos , " Unexpected wallet exception " ) ;
}
return true ;
2019-02-27 15:55:31 +00:00
}
2023-09-29 17:13:37 +00:00
gen_trezor_wallet_passphrase : : ~ gen_trezor_wallet_passphrase ( )
2019-02-27 15:55:31 +00:00
{
try
{
if ( ! m_wallet_dir . empty ( ) & & boost : : filesystem : : exists ( m_wallet_dir ) )
{
boost : : filesystem : : remove_all ( m_wallet_dir ) ;
}
}
2023-09-29 17:13:37 +00:00
catch ( . . . ) { }
}
boost : : optional < epee : : wipeable_string > gen_trezor_wallet_passphrase : : on_device_pin_request ( ) {
return on_pin_request ( ) ;
}
boost : : optional < epee : : wipeable_string > gen_trezor_wallet_passphrase : : on_device_passphrase_request ( bool & on_device ) {
return on_passphrase_request ( on_device ) ;
}
bool gen_trezor_passphrase : : generate ( std : : vector < test_event_entry > & events )
{
m_trezor_use_passphrase = true ;
m_trezor_use_alice2 = true ;
m_trezor_passphrase = m_alice2_passphrase ;
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice2 . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > rct_config ( m_rct_config )
- > compute_sources ( boost : : none , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
- > build_tx ( ) ;
auto _dsts = t_builder - > build ( ) ;
auto _dsts_info = t_builder - > dest_info ( ) ;
test_trezor_tx ( events , _dsts , _dsts_info , generator , TREZOR_ALL_WALLET_VCT , false , 1 ) ;
return true ;
}
bool gen_trezor_pin : : generate ( std : : vector < test_event_entry > & events )
{
m_trezor_pin = " 0000 " ;
TREZOR_TEST_PREFIX ( ) ;
t_builder - > cur_height ( num_blocks ( events ) - 1 )
- > mixin ( num_mixin ( ) )
- > fee ( TREZOR_TEST_FEE )
- > from ( m_wl_alice . get ( ) , 0 )
- > add_destination ( m_eve_account , false , 1000 )
- > rct_config ( m_rct_config )
- > compute_sources ( boost : : none , MK_TCOINS ( 0.0001 ) , - 1 , - 1 )
- > build_tx ( ) ;
TREZOR_TEST_SUFFIX ( ) ;
return true ;
}
void wallet_api_tests : : init ( )
{
m_wallet_dir = boost : : filesystem : : unique_path ( ) ;
boost : : filesystem : : create_directories ( m_wallet_dir ) ;
}
wallet_api_tests : : ~ wallet_api_tests ( )
{
try
2019-02-27 15:55:31 +00:00
{
2023-09-29 17:13:37 +00:00
if ( ! m_wallet_dir . empty ( ) & & boost : : filesystem : : exists ( m_wallet_dir ) )
{
boost : : filesystem : : remove_all ( m_wallet_dir ) ;
}
2019-02-27 15:55:31 +00:00
}
2023-09-29 17:13:37 +00:00
catch ( . . . ) { }
2019-02-27 15:55:31 +00:00
}
bool wallet_api_tests : : generate ( std : : vector < test_event_entry > & events )
{
init ( ) ;
test_setup ( events ) ;
const std : : string wallet_path = ( m_wallet_dir / " wallet " ) . string ( ) ;
const auto api_net_type = m_network_type = = TESTNET ? Monero : : TESTNET : Monero : : MAINNET ;
Monero : : WalletManager * wmgr = Monero : : WalletManagerFactory : : getWalletManager ( ) ;
2023-09-29 17:13:37 +00:00
std : : unique_ptr < Monero : : Wallet > w { wmgr - > createWalletFromDevice ( wallet_path , " " , api_net_type , m_trezor_path , 1 , " " , 1 , this ) } ;
2019-02-27 15:55:31 +00:00
CHECK_AND_ASSERT_THROW_MES ( w - > init ( daemon ( ) - > rpc_addr ( ) , 0 ) , " Wallet init fail " ) ;
2022-10-20 15:23:28 +00:00
auto walletImpl = dynamic_cast < Monero : : WalletImpl * > ( w . get ( ) ) ;
CHECK_AND_ASSERT_THROW_MES ( walletImpl , " Dynamic wallet cast failed " ) ;
WalletApiAccessorTest : : allow_mismatched_daemon_version ( walletImpl , true ) ;
2023-09-29 17:13:37 +00:00
walletImpl - > setTrustedDaemon ( true ) ;
2022-10-20 15:23:28 +00:00
2019-02-27 15:55:31 +00:00
CHECK_AND_ASSERT_THROW_MES ( w - > refresh ( ) , " Refresh fail " ) ;
2023-09-29 17:13:37 +00:00
uint64_t spent , unspent ;
walletImpl - > coldKeyImageSync ( spent , unspent ) ;
CHECK_AND_ASSERT_THROW_MES ( walletImpl - > rescanSpent ( ) , " Rescan spent fail " ) ;
2019-02-27 15:55:31 +00:00
uint64_t balance = w - > balance ( 0 ) ;
2019-04-03 19:29:35 +00:00
MDEBUG ( " Balance: " < < balance ) ;
2020-09-03 14:07:08 +00:00
CHECK_AND_ASSERT_THROW_MES ( w - > status ( ) = = Monero : : PendingTransaction : : Status_Ok , " Status nok, " < < w - > errorString ( ) ) ;
2019-02-27 15:55:31 +00:00
2023-09-29 17:13:37 +00:00
const uint64_t tx_amount = MK_TCOINS ( 0.5 ) ;
2019-02-27 15:55:31 +00:00
auto addr = get_address ( m_eve_account ) ;
auto recepient_address = cryptonote : : get_account_address_as_str ( m_network_type , false , addr ) ;
Monero : : PendingTransaction * transaction = w - > createTransaction ( recepient_address ,
" " ,
2023-09-29 17:13:37 +00:00
tx_amount ,
2022-04-12 00:06:19 +00:00
num_mixin ( ) ,
2019-02-27 15:55:31 +00:00
Monero : : PendingTransaction : : Priority_Medium ,
0 ,
std : : set < uint32_t > { } ) ;
2020-09-03 14:07:08 +00:00
CHECK_AND_ASSERT_THROW_MES ( transaction - > status ( ) = = Monero : : PendingTransaction : : Status_Ok , " Status nok: " < < transaction - > status ( ) < < " , msg: " < < transaction - > errorString ( ) ) ;
2019-02-27 15:55:31 +00:00
w - > refresh ( ) ;
2023-09-29 17:13:37 +00:00
CHECK_AND_ASSERT_THROW_MES ( w - > balance ( 0 ) = = balance , " Err balance " ) ;
CHECK_AND_ASSERT_THROW_MES ( transaction - > amount ( ) = = tx_amount , " Err amount " ) ;
CHECK_AND_ASSERT_THROW_MES ( transaction - > commit ( ) , " Err commit " ) ;
CHECK_AND_ASSERT_THROW_MES ( w - > balance ( 0 ) ! = balance , " Err balance2 " ) ;
CHECK_AND_ASSERT_THROW_MES ( wmgr - > closeWallet ( w . get ( ) ) , " Err close " ) ;
2019-02-27 15:55:31 +00:00
( void ) w . release ( ) ;
mine_and_test ( events ) ;
return true ;
}
2023-09-29 17:13:37 +00:00
Monero : : optional < std : : string > wallet_api_tests : : onDevicePinRequest ( ) {
return Monero : : optional < std : : string > ( m_trezor_pin ) ;
}
Monero : : optional < std : : string > wallet_api_tests : : onDevicePassphraseRequest ( bool & on_device ) {
on_device = false ;
return Monero : : optional < std : : string > ( m_trezor_passphrase ) ;
}