Skip to content

Commit 4ba4d7e

Browse files
committed
simplewallet: hide ring-signature UX after FCMP++
Conditionally hide print-ring-members and default-ring-size from the set command's help text, getter output, and setter path when FCMP++ fork rules are active. Make apropos use FCMP++-aware command documentation, and warn when an explicit ring_size is provided but ignored under FCMP++.
1 parent 7dbeb59 commit 4ba4d7e

2 files changed

Lines changed: 146 additions & 82 deletions

File tree

src/simplewallet/simplewallet.cpp

Lines changed: 145 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -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
//----------------------------------------------------------------------------------------------------
63326391
bool 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

Comments
 (0)