@@ -613,6 +613,99 @@ namespace
613613 return true ;
614614 }
615615
616+ bool uses_legacy_ring_signature_ux (tools::wallet2 *w2)
617+ {
618+ if (!w2)
619+ return true ;
620+ try
621+ {
622+ return !w2->use_fork_rules (HF_VERSION_FCMP_PLUS_PLUS , 0 );
623+ }
624+ catch (const std::exception &)
625+ {
626+ return !w2->use_fork_rules_offline (HF_VERSION_FCMP_PLUS_PLUS , 0 );
627+ }
628+ }
629+
630+ std::string get_set_variable_description (bool legacy_ring_ux)
631+ {
632+ std::string description = tr (" Available options:\n "
633+ " seed language\n "
634+ " Set the wallet's seed language.\n "
635+ " always-confirm-transfers <1|0>\n "
636+ " Whether to confirm unsplit txes.\n " );
637+ if (legacy_ring_ux)
638+ {
639+ description += tr (" print-ring-members <1|0>\n "
640+ " Whether to print detailed information about ring members during confirmation.\n " );
641+ }
642+ description += tr (" store-tx-info <1|0>\n "
643+ " Whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference.\n "
644+ " auto-refresh <1|0>\n "
645+ " Whether to automatically synchronize new blocks from the daemon.\n "
646+ " refresh-type <full|optimize-coinbase|no-coinbase|default>\n "
647+ " Set the wallet's refresh behaviour.\n "
648+ " priority [0|1|2|3|4|5]\n "
649+ " Set the fee to default/unimportant/normal/elevated/priority/max.\n "
650+ " confirm-missing-payment-id <1|0> (obsolete)\n "
651+ " ask-password <0|1|2 (or never|action|decrypt)>\n "
652+ " action: ask the password before many actions such as transfer, etc\n "
653+ " decrypt: same as action, but keeps the spend key encrypted in memory when not needed\n "
654+ " unit <monero|millinero|micronero|nanonero|piconero>\n "
655+ " Set the default monero (sub-)unit.\n "
656+ " max-reorg-depth <unsigned int>\n "
657+ " Set the maximum amount of blocks to accept in a reorg.\n "
658+ " min-outputs-count [n]\n "
659+ " Try to keep at least that many outputs of value at least min-outputs-value.\n "
660+ " min-outputs-value [n]\n "
661+ " Try to keep at least min-outputs-count outputs of at least that value.\n "
662+ " merge-destinations <1|0>\n "
663+ " Whether to merge multiple payments to the same destination address.\n "
664+ " confirm-backlog <1|0>\n "
665+ " Whether to warn if there is transaction backlog.\n "
666+ " confirm-backlog-threshold [n]\n "
667+ " Set a threshold for confirm-backlog to only warn if the transaction backlog is greater than n blocks.\n "
668+ " confirm-export-overwrite <1|0>\n "
669+ " Whether to warn if the file to be exported already exists.\n "
670+ " refresh-from-block-height [n]\n "
671+ " Set the height before which to ignore blocks.\n "
672+ " auto-low-priority <1|0>\n "
673+ " Whether to automatically use the low priority fee level when it's safe to do so.\n "
674+ " segregate-pre-fork-outputs <1|0>\n "
675+ " Set this if you intend to spend outputs on both Monero AND a key reusing fork.\n "
676+ " key-reuse-mitigation2 <1|0>\n "
677+ " Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n "
678+ " subaddress-lookahead <major>:<minor>\n "
679+ " Set the lookahead sizes for the subaddress hash table.\n "
680+ " segregation-height <n>\n "
681+ " Set to the height of a key reusing fork you want to use, 0 to use default.\n "
682+ " ignore-fractional-outputs <1|0>\n "
683+ " Whether to ignore fractional outputs that result in net loss when spending due to fee.\n "
684+ " ignore-outputs-above <amount>\n "
685+ " Ignore outputs of amount above this threshold when spending. Value 0 is translated to the maximum value (18 million) which disables this filter.\n "
686+ " ignore-outputs-below <amount>\n "
687+ " Ignore outputs of amount below this threshold when spending.\n "
688+ " track-uses <1|0>\n "
689+ " Whether to keep track of owned outputs uses.\n "
690+ " background-sync <off|reuse-wallet-password|custom-background-password>\n "
691+ " Set this to enable scanning in the background with just the view key while the wallet is locked.\n "
692+ " setup-background-mining <1|0>\n "
693+ " Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n "
694+ " device-name <device_name[:device_spec]>\n "
695+ " Device name for hardware wallet.\n "
696+ " export-format <\" binary\" |\" ascii\" >\n "
697+ " Save all exported files as binary (cannot be copied and pasted) or ascii (can be).\n "
698+ " load-deprecated-formats <1|0>\n "
699+ " Whether to enable importing data in deprecated formats.\n "
700+ " show-wallet-name-when-locked <1|0>\n "
701+ " Set this if you would like to display the wallet name when locked.\n "
702+ " enable-multisig-experimental <1|0>\n "
703+ " Set this to allow multisig commands. Multisig may currently be exploitable if parties do not trust each other.\n "
704+ " inactivity-lock-timeout <unsigned int>\n "
705+ " How many seconds to wait before locking the wallet (0 to disable)." );
706+ return description;
707+ }
708+
616709 bool get_fake_outs_count (const std::unique_ptr<tools::wallet2> &w2, std::vector<std::string> &local_args, size_t &fake_outs_count)
617710 {
618711 const size_t min_ring_size = w2->get_min_ring_size ();
@@ -630,10 +723,7 @@ namespace
630723 else if (min_ring_size == 0 && w2->get_max_ring_size () == 0 )
631724 {
632725 if (ring_size != 0 )
633- {
634- fail_msg_writer () << tr (" Ring size must be 0" );
635- return false ;
636- }
726+ message_writer () << tr (" Warning: provided ring_size will be ignored for FCMP++ transactions." );
637727 fake_outs_count = 0 ;
638728 local_args.erase (local_args.begin ());
639729 return true ;
@@ -843,9 +933,21 @@ std::string simple_wallet::get_commands_str()
843933 return ss.str ();
844934}
845935
846- std::string simple_wallet::get_command_usage (const std::vector<std::string> &args)
936+ std::pair<std:: string, std::string> simple_wallet::get_command_documentation (const std::vector<std::string> &args)
847937{
848938 std::pair<std::string, std::string> documentation = m_cmd_binder.get_documentation (args);
939+ if (documentation.first .empty ())
940+ return documentation;
941+
942+ if (args.size () == 1 && args.front () == " set" && !uses_legacy_ring_signature_ux (m_wallet.get ()))
943+ documentation.second = get_set_variable_description (false );
944+
945+ return documentation;
946+ }
947+
948+ std::string simple_wallet::get_command_usage (const std::vector<std::string> &args)
949+ {
950+ std::pair<std::string, std::string> documentation = get_command_documentation (args);
849951 std::stringstream ss;
850952 if (documentation.first .empty ())
851953 {
@@ -1813,7 +1915,10 @@ bool simple_wallet::print_ring(const std::vector<std::string> &args)
18131915 rings.push_back ({key_image, ring});
18141916 else if (!m_wallet->get_rings (txid, rings))
18151917 {
1816- fail_msg_writer () << tr (" Key image either not spent, or spent with ring size 1" );
1918+ if (uses_legacy_ring_signature_ux (m_wallet.get ()))
1919+ fail_msg_writer () << tr (" Key image either not spent, or spent with ring size 1" );
1920+ else
1921+ fail_msg_writer () << tr (" Key image either not spent, or is an FCMP++ transaction (no ring data)" );
18171922 return true ;
18181923 }
18191924
@@ -3151,7 +3256,26 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
31513256 PRINT_USAGE (USAGE_APROPOS );
31523257 return true ;
31533258 }
3154- const std::vector<std::string>& command_list = m_cmd_binder.get_command_list (args);
3259+ const std::vector<std::string> all_commands = m_cmd_binder.get_command_list ();
3260+ std::vector<std::string> command_list;
3261+ for (const auto &command: all_commands)
3262+ {
3263+ const std::vector<std::string> cmd{command};
3264+ const std::pair<std::string, std::string> documentation = get_command_documentation (cmd);
3265+ bool take = true ;
3266+ for (const auto &keyword: args)
3267+ {
3268+ const bool in_usage = documentation.first .find (keyword) != std::string::npos;
3269+ const bool in_description = documentation.second .find (keyword) != std::string::npos;
3270+ if (!(in_usage || in_description))
3271+ {
3272+ take = false ;
3273+ break ;
3274+ }
3275+ }
3276+ if (take)
3277+ command_list.push_back (command);
3278+ }
31553279 if (command_list.empty ())
31563280 {
31573281 fail_msg_writer () << tr (" No commands found mentioning keyword(s)" );
@@ -3163,7 +3287,7 @@ bool simple_wallet::apropos(const std::vector<std::string> &args)
31633287 {
31643288 std::vector<std::string> cmd;
31653289 cmd.push_back (command);
3166- std::pair<std::string, std::string> documentation = m_cmd_binder. get_documentation (cmd);
3290+ std::pair<std::string, std::string> documentation = get_command_documentation (cmd);
31673291 success_msg_writer () << " " << documentation.first ;
31683292 }
31693293 success_msg_writer () << " " ;
@@ -3338,77 +3462,7 @@ simple_wallet::simple_wallet()
33383462 m_cmd_binder.set_handler (" set" ,
33393463 boost::bind (&simple_wallet::on_command, this , &simple_wallet::set_variable, _1),
33403464 tr (USAGE_SET_VARIABLE ),
3341- tr (" Available options:\n "
3342- " seed language\n "
3343- " Set the wallet's seed language.\n "
3344- " always-confirm-transfers <1|0>\n "
3345- " Whether to confirm unsplit txes.\n "
3346- " print-ring-members <1|0>\n "
3347- " Whether to print detailed information about ring members during confirmation.\n "
3348- " store-tx-info <1|0>\n "
3349- " Whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference.\n "
3350- " auto-refresh <1|0>\n "
3351- " Whether to automatically synchronize new blocks from the daemon.\n "
3352- " refresh-type <full|optimize-coinbase|no-coinbase|default>\n "
3353- " Set the wallet's refresh behaviour.\n "
3354- " priority [0|1|2|3|4|5]\n "
3355- " Set the fee to default/unimportant/normal/elevated/priority/max.\n "
3356- " confirm-missing-payment-id <1|0> (obsolete)\n "
3357- " ask-password <0|1|2 (or never|action|decrypt)>\n "
3358- " action: ask the password before many actions such as transfer, etc\n "
3359- " decrypt: same as action, but keeps the spend key encrypted in memory when not needed\n "
3360- " unit <monero|millinero|micronero|nanonero|piconero>\n "
3361- " Set the default monero (sub-)unit.\n "
3362- " max-reorg-depth <unsigned int>\n "
3363- " Set the maximum amount of blocks to accept in a reorg.\n "
3364- " min-outputs-count [n]\n "
3365- " Try to keep at least that many outputs of value at least min-outputs-value.\n "
3366- " min-outputs-value [n]\n "
3367- " Try to keep at least min-outputs-count outputs of at least that value.\n "
3368- " merge-destinations <1|0>\n "
3369- " Whether to merge multiple payments to the same destination address.\n "
3370- " confirm-backlog <1|0>\n "
3371- " Whether to warn if there is transaction backlog.\n "
3372- " confirm-backlog-threshold [n]\n "
3373- " Set a threshold for confirm-backlog to only warn if the transaction backlog is greater than n blocks.\n "
3374- " confirm-export-overwrite <1|0>\n "
3375- " Whether to warn if the file to be exported already exists.\n "
3376- " refresh-from-block-height [n]\n "
3377- " Set the height before which to ignore blocks.\n "
3378- " auto-low-priority <1|0>\n "
3379- " Whether to automatically use the low priority fee level when it's safe to do so.\n "
3380- " segregate-pre-fork-outputs <1|0>\n "
3381- " Set this if you intend to spend outputs on both Monero AND a key reusing fork.\n "
3382- " key-reuse-mitigation2 <1|0>\n "
3383- " Set this if you are not sure whether you will spend on a key reusing Monero fork later.\n "
3384- " subaddress-lookahead <major>:<minor>\n "
3385- " Set the lookahead sizes for the subaddress hash table.\n "
3386- " segregation-height <n>\n "
3387- " Set to the height of a key reusing fork you want to use, 0 to use default.\n "
3388- " ignore-fractional-outputs <1|0>\n "
3389- " Whether to ignore fractional outputs that result in net loss when spending due to fee.\n "
3390- " ignore-outputs-above <amount>\n "
3391- " Ignore outputs of amount above this threshold when spending. Value 0 is translated to the maximum value (18 million) which disables this filter.\n "
3392- " ignore-outputs-below <amount>\n "
3393- " Ignore outputs of amount below this threshold when spending.\n "
3394- " track-uses <1|0>\n "
3395- " Whether to keep track of owned outputs uses.\n "
3396- " background-sync <off|reuse-wallet-password|custom-background-password>\n "
3397- " Set this to enable scanning in the background with just the view key while the wallet is locked.\n "
3398- " setup-background-mining <1|0>\n "
3399- " Whether to enable background mining. Set this to support the network and to get a chance to receive new monero.\n "
3400- " device-name <device_name[:device_spec]>\n "
3401- " Device name for hardware wallet.\n "
3402- " export-format <\" binary\" |\" ascii\" >\n "
3403- " Save all exported files as binary (cannot be copied and pasted) or ascii (can be).\n "
3404- " load-deprecated-formats <1|0>\n "
3405- " Whether to enable importing data in deprecated formats.\n "
3406- " show-wallet-name-when-locked <1|0>\n "
3407- " Set this if you would like to display the wallet name when locked.\n "
3408- " enable-multisig-experimental <1|0>\n "
3409- " Set this to allow multisig commands. Multisig may currently be exploitable if parties do not trust each other.\n "
3410- " inactivity-lock-timeout <unsigned int>\n "
3411- " How many seconds to wait before locking the wallet (0 to disable)." ));
3465+ get_set_variable_description (true ));
34123466 m_cmd_binder.set_handler (" encrypted_seed" ,
34133467 boost::bind (&simple_wallet::on_command, this , &simple_wallet::encrypted_seed, _1),
34143468 tr (" Display the encrypted Electrum-style mnemonic seed." ));
@@ -3748,6 +3802,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
37483802{
37493803 if (args.empty ())
37503804 {
3805+ const bool legacy_ring_ux = uses_legacy_ring_signature_ux (m_wallet.get ());
37513806 std::string seed_language = m_wallet->get_seed_language ();
37523807 if (m_use_english_language_names)
37533808 seed_language = crypto::ElectrumWords::get_english_name_for (seed_language);
@@ -3771,9 +3826,11 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
37713826 }
37723827 success_msg_writer () << " seed = " << seed_language;
37733828 success_msg_writer () << " always-confirm-transfers = " << m_wallet->always_confirm_transfers ();
3774- success_msg_writer () << " print-ring-members = " << m_wallet->print_ring_members ();
3829+ if (legacy_ring_ux)
3830+ success_msg_writer () << " print-ring-members = " << m_wallet->print_ring_members ();
37753831 success_msg_writer () << " store-tx-info = " << m_wallet->store_tx_info ();
3776- success_msg_writer () << " default-ring-size = " << (m_wallet->default_mixin () ? m_wallet->default_mixin () + 1 : 0 );
3832+ if (legacy_ring_ux)
3833+ success_msg_writer () << " default-ring-size = " << (m_wallet->default_mixin () ? m_wallet->default_mixin () + 1 : 0 );
37773834 success_msg_writer () << " auto-refresh = " << m_wallet->auto_refresh ();
37783835 success_msg_writer () << " refresh-type = " << get_refresh_type_name (m_wallet->get_refresh_type ());
37793836 success_msg_writer () << " priority = " << priority_index << " (" << priority_string << " )" ;
@@ -3813,6 +3870,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
38133870 else
38143871 {
38153872 CHECK_IF_BACKGROUND_SYNCING (" cannot change wallet settings" );
3873+ const bool legacy_ring_ux = uses_legacy_ring_signature_ux (m_wallet.get ());
38163874
38173875#define CHECK_SIMPLE_VARIABLE (name, f, help ) do \
38183876 if (args[0 ] == name) { \
@@ -3842,7 +3900,8 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
38423900 }
38433901 }
38443902 CHECK_SIMPLE_VARIABLE (" always-confirm-transfers" , set_always_confirm_transfers, tr (" 0 or 1" ));
3845- CHECK_SIMPLE_VARIABLE (" print-ring-members" , set_print_ring_members, tr (" 0 or 1" ));
3903+ if (legacy_ring_ux)
3904+ CHECK_SIMPLE_VARIABLE (" print-ring-members" , set_print_ring_members, tr (" 0 or 1" ));
38463905 CHECK_SIMPLE_VARIABLE (" store-tx-info" , set_store_tx_info, tr (" 0 or 1" ));
38473906 CHECK_SIMPLE_VARIABLE (" auto-refresh" , set_auto_refresh, tr (" 0 or 1" ));
38483907 CHECK_SIMPLE_VARIABLE (" refresh-type" , set_refresh_type, tr (" full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)" ));
@@ -6331,6 +6390,10 @@ bool simple_wallet::process_ring_members(const std::vector<tools::wallet2::pendi
63316390// ----------------------------------------------------------------------------------------------------
63326391bool simple_wallet::prompt_if_old (const std::vector<tools::wallet2::pending_tx> &ptx_vector)
63336392{
6393+ // FCMP++ txs don't use ring signatures, so output age doesn't affect privacy
6394+ if (!ptx_vector.empty () && ptx_vector[0 ].tx .rct_signatures .type >= rct::RCTTypeFcmpPlusPlus)
6395+ return true ;
6396+
63346397 // count the number of old outputs
63356398 std::string err;
63366399 uint64_t bc_height = get_daemon_blockchain_height (err);
0 commit comments