@ -41,6 +41,7 @@ using namespace cryptonote;
# include "common/util.h"
# include "common/command_line.h"
# include "trezor_tests.h"
# include "tools.h"
# include "device/device_cold.hpp"
# include "device_trezor/device_trezor.hpp"
@ -57,7 +58,7 @@ namespace
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 } ;
}
# define HW_TREZOR_NAME "Trezor"
# define TREZOR_ACCOUNT_ORDERING &m_miner_account, &m_alice_account, &m_bob_account, &m_eve_account
# define TREZOR_COMMON_TEST_CASE(genclass, CORE, BASE) \
rollback_chain ( CORE , BASE . head_block ( ) ) ; \
@ -70,14 +71,17 @@ namespace
# define TREZOR_SETUP_CHAIN(NAME) do { \
+ + tests_count ; \
try { \
setup_chain ( & core , trezor_base , chain_path , fix_chain ); \
setup_chain ( core , trezor_base , chain_path , fix_chain , vm_core ); \
} catch ( const std : : exception & ex ) { \
failed_tests . emplace_back ( " gen_trezor_base " # NAME ) ; \
} \
} while ( 0 )
static device_trezor_test * trezor_device = nullptr ;
static device_trezor_test * ensure_trezor_test_device ( ) ;
static void rollback_chain ( cryptonote : : core * core , const cryptonote : : block & head ) ;
static void setup_chain ( cryptonote : : core * * core , gen_trezor_base & trezor_base , std : : string chain_path , bool fix_chain ) ;
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 ) ;
int main ( int argc , char * argv [ ] )
{
@ -123,38 +127,76 @@ int main(int argc, char* argv[])
const bool heavy_tests = command_line : : get_arg ( vm , arg_heavy_tests ) ;
const bool fix_chain = command_line : : get_arg ( vm , arg_fix_chain ) ;
hw : : trezor : : register_all ( ) ;
hw : : register_device ( HW_TREZOR_NAME , ensure_trezor_test_device ( ) ) ;
// hw::trezor::register_all(); // We use our shim instead.
// Bootstrapping common chain & accounts
cryptonote : : core * core = nullptr ;
const uint8_t initial_hf = 9 ;
const uint8_t max_hf = 10 ;
cryptonote : : core core_obj ( nullptr ) ;
cryptonote : : core * const core = & core_obj ;
std : : shared_ptr < mock_daemon > daemon = nullptr ;
gen_trezor_base trezor_base ;
trezor_base . setup_args ( trezor_path , heavy_tests ) ;
trezor_base . rct_config ( { rct : : RangeProofPaddedBulletproof , 1 } ) ; // HF9 tests
trezor_base . set_hard_fork( initial_hf ) ;
TREZOR_SETUP_CHAIN ( " HF9 " ) ;
// Individual test cases using shared pre-generated blockchain.
TREZOR_COMMON_TEST_CASE ( gen_trezor_ki_sync , core , trezor_base ) ;
// 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 ) ;
// Transaction tests
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_1utxo_paymentid_long , 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 ) ;
for ( uint8_t hf = initial_hf ; hf < = max_hf ; + + hf )
{
MDEBUG ( " Transaction tests for HF " < < ( int ) hf ) ;
if ( hf > initial_hf )
{
daemon - > stop_and_deinit ( ) ;
daemon = nullptr ;
trezor_base . daemon ( nullptr ) ;
}
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
if ( hf = = initial_hf )
{
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 ) ;
}
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_1utxo_paymentid_long , 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 ) ;
TREZOR_COMMON_TEST_CASE ( wallet_api_tests , core , trezor_base ) ;
}
if ( trezor_base . heavy_tests ( ) )
{
TREZOR_COMMON_TEST_CASE ( gen_trezor_many_utxo , core , trezor_base ) ;
}
daemon - > stop ( ) ;
core - > deinit ( ) ;
el : : Level level = ( failed_tests . empty ( ) ? el : : Level : : Info : el : : Level : : Error ) ;
MLOG ( level , " \n REPORT: " ) ;
@ -243,7 +285,36 @@ static bool serialize_chain_to_file(std::vector<test_event_entry>& events, gen_t
CATCH_ENTRY_L0 ( " serialize_chain_to_file " , false ) ;
}
static void setup_chain ( cryptonote : : core * * core , gen_trezor_base & trezor_base , std : : string chain_path , bool fix_chain )
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 ;
cryptonote : : test_options test_options_tmp { } ;
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 )
{
std : : vector < test_event_entry > events ;
const bool do_serialize = ! chain_path . empty ( ) ;
@ -272,6 +343,7 @@ static void setup_chain(cryptonote::core ** core, gen_trezor_base & trezor_base,
{
try
{
trezor_base . clear ( ) ;
generated = trezor_base . generate ( events ) ;
if ( generated & & ! loaded & & do_serialize )
@ -287,7 +359,7 @@ static void setup_chain(cryptonote::core ** core, gen_trezor_base & trezor_base,
}
trezor_base . fix_hf ( events ) ;
if ( generated & & do_replay_events_get_core < gen_trezor_base > ( events , core) )
if ( generated & & init_core_replay_events < gen_trezor_base > ( events , core, vm_ core) )
{
MGINFO_GREEN ( " #TEST-chain-init# Succeeded " ) ;
}
@ -298,6 +370,14 @@ static void setup_chain(cryptonote::core ** core, gen_trezor_base & trezor_base,
}
}
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 ;
}
static void add_hforks ( std : : vector < test_event_entry > & events , const v_hardforks_t & hard_forks )
{
event_replay_settings repl_set ;
@ -483,8 +563,20 @@ static std::vector<tools::wallet2*> vct_wallets(tools::wallet2* w1=nullptr, tool
return res ;
}
static uint64_t get_available_funds ( tools : : wallet2 * wallet , uint32_t account = 0 )
{
tools : : wallet2 : : transfer_container transfers ;
wallet - > get_transfers ( transfers ) ;
uint64_t sum = 0 ;
for ( const auto & cur : transfers )
{
sum + = ! cur . m_spent & & cur . m_subaddr_index . major = = account ? cur . amount ( ) : 0 ;
}
return sum ;
}
// gen_trezor_base
const uint64_t gen_trezor_base : : m_ts_start = 1338224400 ;
const uint64_t gen_trezor_base : : m_ts_start = 13 97862000; // As default wallet timestamp is 1397516400
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 " ;
const std : : string gen_trezor_base : : m_master_seed_str = " 14821d0bc5659b24cafbc889dc4fc60785ee08b65d71c525f81eeaba4f3a570f " ;
@ -494,12 +586,16 @@ const std::string gen_trezor_base::m_alice_view_private = "a6ccd4ac344a295d1387f
gen_trezor_base : : gen_trezor_base ( ) {
m_rct_config = { rct : : RangeProofPaddedBulletproof , 1 } ;
m_test_get_tx_key = true ;
m_network_type = cryptonote : : TESTNET ;
}
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 ) ,
m_hard_forks ( other . m_hard_forks ) , m_trezor ( other . m_trezor ) , m_rct_config ( other . m_rct_config )
m_hard_forks ( other . m_hard_forks ) , m_trezor ( other . m_trezor ) , m_rct_config ( other . m_rct_config ) ,
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 ) ,
m_network_type ( other . m_network_type ) , m_daemon ( other . m_daemon )
{
}
@ -513,33 +609,27 @@ void gen_trezor_base::setup_args(const std::string & trezor_path, bool heavy_tes
void gen_trezor_base : : setup_trezor ( )
{
hw : : device & hwdev = hw : : get_device ( m_trezor_path ) ;
m_trezor = dynamic_cast < hw : : trezor : : device_trezor * > ( & hwdev ) ;
CHECK_AND_ASSERT_THROW_MES ( m_trezor , " Dynamic cast failed " ) ;
m_trezor - > set_debug ( true ) ; // debugging commands on Trezor (auto-confirm transactions)
CHECK_AND_ASSERT_THROW_MES ( m_trezor - > set_name ( m_trezor_path ) , " Could not set device name " < < m_trezor_path ) ;
m_trezor - > set_network_type ( MAINNET ) ;
m_trezor - > set_derivation_path ( " " ) ; // empty derivation path
auto trezor = dynamic_cast < device_trezor_test * > ( & hwdev ) ;
CHECK_AND_ASSERT_THROW_MES ( trezor , " Dynamic cast failed " ) ;
CHECK_AND_ASSERT_THROW_MES ( m_trezor - > init ( ) , " Could not initialize the device " < < m_trezor_path ) ;
CHECK_AND_ASSERT_THROW_MES ( m_trezor - > connect ( ) , " Could not connect to the device " < < m_trezor_path ) ;
m_trezor - > wipe_device ( ) ;
m_trezor - > load_device ( m_device_seed ) ;
m_trezor - > release ( ) ;
m_trezor - > disconnect ( ) ;
trezor - > setup_for_tests ( m_trezor_path , m_device_seed , m_network_type ) ;
m_trezor = trezor ;
}
void gen_trezor_base : : fork ( gen_trezor_base & other )
{
other . m_generator = m_generator ;
other . m_bt = m_bt ;
other . m_network_type = m_network_type ;
other . m_daemon = m_daemon ;
other . m_events = m_events ;
other . m_head = m_head ;
other . m_hard_forks = m_hard_forks ;
other . m_trezor_path = m_trezor_path ;
other . m_heavy_tests = m_heavy_tests ;
other . m_rct_config = m_rct_config ;
other . m_test_get_tx_key = m_test_get_tx_key ;
other . m_live_refresh_enabled = m_live_refresh_enabled ;
other . m_miner_account = m_miner_account ;
other . m_bob_account = m_bob_account ;
@ -577,10 +667,22 @@ void gen_trezor_base::init_fields()
m_alice_account . set_createtime ( m_wallet_ts ) ;
}
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 ) ;
}
bool gen_trezor_base : : generate ( std : : vector < test_event_entry > & events )
{
init_fields ( ) ;
setup_trezor ( ) ;
m_live_refresh_enabled = false ;
update_client_settings ( ) ;
m_alice_account . create_from_device ( * m_trezor ) ;
m_alice_account . set_createtime ( m_wallet_ts ) ;
@ -589,7 +691,7 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
cryptonote : : block blk_gen ;
std : : vector < size_t > block_weights ;
generate_genesis_block ( blk_gen , get_config ( MAINNET) . GENESIS_TX , get_config ( MAINNET ) . GENESIS_NONCE ) ;
generate_genesis_block ( blk_gen , get_config ( m_network_type) . GENESIS_TX , get_config ( m_network_type ) . GENESIS_NONCE ) ;
events . push_back ( blk_gen ) ;
generator . add_block ( blk_gen , 0 , block_weights , 0 ) ;
@ -644,8 +746,8 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
MDEBUG ( " Hardfork height: " < < hardfork_height < < " at block: " < < get_block_hash ( blk_4r ) ) ;
// RCT transactions, wallets have to be used, wallet init
m_wl_alice . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_bob . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_alice . reset ( new tools : : wallet2 ( m_network_type , 1 , true ) ) ;
m_wl_bob . 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_bob . get ( ) , m_bob_account ) ;
@ -659,7 +761,7 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
auto addr_alice_sub_1_2 = m_wl_alice - > get_subaddress ( { 1 , 2 } ) ;
// Miner -> Bob, RCT funds
MAKE_TX_LIST_START_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 5 ) , 10 , blk_4 ) ;
MAKE_TX_LIST_START_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 5 0 ) , 10 , blk_4 ) ;
const size_t target_rct = m_heavy_tests ? 105 : 15 ;
for ( size_t i = 0 ; i < target_rct ; + + i )
@ -688,9 +790,9 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
// Simple RCT transactions
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 7 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 1 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 3 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 4 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 1 0 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 3 0 ) , 10 , blk_4 ) ;
MAKE_TX_MIX_LIST_RCT ( events , txs_blk_5 , m_miner_account , m_alice_account , MK_COINS ( 4 0 ) , 10 , blk_4 ) ;
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk_5 , blk_4r , m_miner_account , txs_blk_5 , CUR_HF ) ;
// Simple transaction check
@ -704,6 +806,8 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
// RCT transactions, wallets have to be used
wallet_tools : : process_transactions ( m_wl_alice . get ( ) , events , blk_5r , m_bt ) ;
wallet_tools : : process_transactions ( m_wl_bob . get ( ) , events , blk_5r , m_bt ) ;
MDEBUG ( " Available funds on Alice: " < < get_available_funds ( m_wl_alice . get ( ) ) ) ;
MDEBUG ( " Available funds on Bob: " < < get_available_funds ( m_wl_bob . get ( ) ) ) ;
// Send Alice -> Bob, manually constructed. Simple TX test, precondition.
cryptonote : : transaction tx_1 ;
@ -768,18 +872,21 @@ void gen_trezor_base::load(std::vector<test_event_entry>& events)
m_eve_account . set_createtime ( m_wallet_ts ) ;
setup_trezor ( ) ;
update_client_settings ( ) ;
m_alice_account . create_from_device ( * m_trezor ) ;
m_alice_account . set_createtime ( m_wallet_ts ) ;
m_wl_alice . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_bob . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_eve . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_alice . 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_bob . get ( ) , m_bob_account ) ;
wallet_accessor_test : : set_account ( m_wl_eve . get ( ) , m_eve_account ) ;
wallet_tools : : process_transactions ( m_wl_alice . get ( ) , events , m_head , m_bt ) ;
wallet_tools : : process_transactions ( m_wl_bob . get ( ) , events , m_head , m_bt ) ;
MDEBUG ( " Available funds on Alice: " < < get_available_funds ( m_wl_alice . get ( ) ) ) ;
MDEBUG ( " Available funds on Bob: " < < get_available_funds ( m_wl_bob . get ( ) ) ) ;
}
void gen_trezor_base : : fix_hf ( std : : vector < test_event_entry > & events )
@ -804,12 +911,14 @@ void gen_trezor_base::test_setup(std::vector<test_event_entry>& events)
add_shared_events ( events ) ;
setup_trezor ( ) ;
update_client_settings ( ) ;
m_alice_account . create_from_device ( * m_trezor ) ;
m_alice_account . set_createtime ( m_wallet_ts ) ;
m_wl_alice . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_bob . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_eve . reset ( new tools : : wallet2 ( MAINNET , 1 , true ) ) ;
m_wl_alice . 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_bob . get ( ) , m_bob_account ) ;
wallet_accessor_test : : set_account ( m_wl_eve . get ( ) , m_eve_account ) ;
@ -818,13 +927,11 @@ void gen_trezor_base::test_setup(std::vector<test_event_entry>& events)
wallet_tools : : process_transactions ( m_wl_eve . get ( ) , events , m_head , m_bt ) ;
}
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 )
void gen_trezor_base : : add_transactions_to_events (
std : : vector < test_event_entry > & events ,
test_generator & generator ,
const std : : vector < cryptonote : : transaction > & txs )
{
// 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 ) ;
// If current test requires higher hard-fork, move it up
const auto current_hf = m_hard_forks . back ( ) . first ;
const uint8_t tx_hf = m_rct_config . bp_version = = 2 ? 10 : 9 ;
@ -832,8 +939,28 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
throw std : : runtime_error ( " Too late for HF change " ) ;
}
tools : : wallet2 : : unsigned_tx_set txs ;
std : : list < cryptonote : : transaction > tx_list ;
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 ;
}
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 )
{
// 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 ;
for ( auto & ptx : ptxs ) {
txs . txes . push_back ( get_construction_data_with_decrypted_short_payment_id ( ptx , * m_trezor ) ) ;
@ -848,6 +975,7 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
hw : : wallet_shim wallet_shim ;
setup_shim ( & wallet_shim ) ;
aux_data . tx_recipients = dsts_info ;
aux_data . bp_version = m_rct_config . bp_version ;
dev_cold - > tx_sign ( & wallet_shim , txs , exported_txs , aux_data ) ;
MDEBUG ( " Signed tx data from hw: " < < exported_txs . ptx . size ( ) < < " transactions " ) ;
@ -865,13 +993,11 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
CHECK_AND_ASSERT_THROW_MES ( resx , " Trezor tx_1 semantics failed " ) ;
CHECK_AND_ASSERT_THROW_MES ( resy , " Trezor tx_1 Nonsemantics failed " ) ;
events . push_back ( c_ptx . tx ) ;
tx_list . push_back ( c_ptx . tx ) ;
MDEBUG ( " Transaction: " < < dump_data ( c_ptx . tx ) ) ;
}
MAKE_NEXT_BLOCK_TX_LIST_HF ( events , blk_7 , m_head , m_miner_account , tx_list , tx_hf ) ;
MDEBUG ( " Trezor tsx: " < < ( num_blocks ( events ) - 1 ) < < " at block: " < < get_block_hash ( blk_7 ) ) ;
add_transactions_to_events ( events , generator , tx_list ) ;
// TX receive test
uint64_t sum_in = 0 ;
@ -909,7 +1035,7 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
const bool sender = widx = = 0 ;
tools : : wallet2 * wl = wallets [ widx ] ;
wallet_tools : : process_transactions ( wl , events , blk_7 , m_bt , boost : : make_optional ( head_hash ) ) ;
wallet_tools : : process_transactions ( wl , events , m_head , m_bt , boost : : make_optional ( head_hash ) ) ;
tools : : wallet2 : : transfer_container m_trans ;
tools : : wallet2 : : transfer_container m_trans_txid ;
@ -972,6 +1098,120 @@ void gen_trezor_base::test_trezor_tx(std::vector<test_event_entry>& events, std:
}
CHECK_AND_ASSERT_THROW_MES ( sum_in = = sum_out , " Tx amount mismatch " ) ;
// Test get_tx_key feature for stored private tx keys
test_get_tx ( events , wallets , exported_txs . ptx , aux_data . tx_device_aux ) ;
}
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 ,
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 " ) ;
dev_cold - > get_tx_key ( tx_keys , tx_key_data , m_alice_account . get_keys ( ) . m_view_secret_key ) ;
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 )
{
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 ) ) ;
daemon ( ) - > mine_blocks ( 1 , miner_address ) ;
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 " ) ;
} else if ( hf = = 9 ) {
rct_config ( { rct : : RangeProofPaddedBulletproof , 1 } ) ;
} else {
rct_config ( { rct : : RangeProofPaddedBulletproof , 2 } ) ;
}
}
# define TREZOR_TEST_PREFIX() \
@ -1182,6 +1422,48 @@ std::vector<tools::wallet2::pending_tx> tsx_builder::build()
return m_ptxs ;
}
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 ;
}
void device_trezor_test : : setup_for_tests ( const std : : string & trezor_path , const std : : string & seed , cryptonote : : network_type network_type ) {
this - > clear_test_counters ( ) ;
this - > set_callback ( nullptr ) ;
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 ( ) ;
this - > load_device ( seed ) ;
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 ;
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 ) ;
}
bool gen_trezor_ki_sync : : generate ( std : : vector < test_event_entry > & events )
{
test_generator generator ( m_generator ) ;
@ -1207,6 +1489,92 @@ bool gen_trezor_ki_sync::generate(std::vector<test_event_entry>& events)
uint64_t spent = 0 , unspent = 0 ;
m_wl_alice - > import_key_images ( ski , 0 , spent , unspent , false ) ;
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 ) ;
else
CHECK_AND_ASSERT_THROW_MES ( dev_trezor_test - > m_compute_key_image_ctr = = ski . size ( ) , " Live refresh counts invalid " ) ;
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 ( ) ;
return true ;
}
@ -1407,3 +1775,62 @@ bool gen_trezor_many_utxo::generate(std::vector<test_event_entry>& events)
TREZOR_TEST_SUFFIX ( ) ;
}
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
{
if ( ! m_wallet_dir . empty ( ) & & boost : : filesystem : : exists ( m_wallet_dir ) )
{
boost : : filesystem : : remove_all ( m_wallet_dir ) ;
}
}
catch ( . . . )
{
MERROR ( " Could not remove wallet directory " ) ;
}
}
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 ( ) ;
std : : unique_ptr < Monero : : Wallet > w { wmgr - > createWalletFromDevice ( wallet_path , " " , api_net_type , m_trezor_path , 1 ) } ;
CHECK_AND_ASSERT_THROW_MES ( w - > init ( daemon ( ) - > rpc_addr ( ) , 0 ) , " Wallet init fail " ) ;
CHECK_AND_ASSERT_THROW_MES ( w - > refresh ( ) , " Refresh fail " ) ;
uint64_t balance = w - > balance ( 0 ) ;
MINFO ( " Balance: " < < balance ) ;
CHECK_AND_ASSERT_THROW_MES ( w - > status ( ) = = Monero : : PendingTransaction : : Status_Ok , " Status nok " ) ;
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 ,
" " ,
MK_COINS ( 10 ) ,
TREZOR_TEST_MIXIN ,
Monero : : PendingTransaction : : Priority_Medium ,
0 ,
std : : set < uint32_t > { } ) ;
CHECK_AND_ASSERT_THROW_MES ( transaction - > status ( ) = = Monero : : PendingTransaction : : Status_Ok , " Status nok " ) ;
w - > refresh ( ) ;
CHECK_AND_ASSERT_THROW_MES ( w - > balance ( 0 ) = = balance , " Err " ) ;
CHECK_AND_ASSERT_THROW_MES ( transaction - > amount ( ) = = MK_COINS ( 10 ) , " Err " ) ;
CHECK_AND_ASSERT_THROW_MES ( transaction - > commit ( ) , " Err " ) ;
CHECK_AND_ASSERT_THROW_MES ( w - > balance ( 0 ) ! = balance , " Err " ) ;
CHECK_AND_ASSERT_THROW_MES ( wmgr - > closeWallet ( w . get ( ) ) , " Err " ) ;
( void ) w . release ( ) ;
mine_and_test ( events ) ;
return true ;
}