aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet/simplewallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet/simplewallet.cpp')
-rw-r--r--src/simplewallet/simplewallet.cpp87
1 files changed, 82 insertions, 5 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 1640fa990..e8b203d9d 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -92,6 +92,8 @@ typedef cryptonote::simple_wallet sw;
#define MIN_RING_SIZE 11 // Used to inform user about min ring size -- does not track actual protocol
+#define OLD_AGE_WARN_THRESHOLD (30 * 86400 / DIFFICULTY_TARGET_V2) // 30 days
+
#define LOCK_IDLE_SCOPE() \
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
@@ -4934,7 +4936,7 @@ void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block
m_refresh_progress_reporter.update(height, false);
}
//----------------------------------------------------------------------------------------------------
-void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
+void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time)
{
message_writer(console_color_green, false) << "\r" <<
tr("Height ") << height << ", " <<
@@ -4956,6 +4958,8 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
(m_long_payment_id_support ? tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead.") : tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete. Support will be withdrawn in the future. Use subaddresses instead."));
}
}
+ if (unlock_time)
+ message_writer() << tr("NOTE: This transaction is locked, see details with: show_transfer ") + epee::string_tools::pod_to_hex(txid);
if (m_auto_refresh_refreshing)
m_cmd_binder.print_prompt();
else
@@ -5606,6 +5610,43 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx> &ptx_vector)
+{
+ // count the number of old outputs
+ std::string err;
+ uint64_t bc_height = get_daemon_blockchain_height(err);
+ if (!err.empty())
+ return true;
+
+ int max_n_old = 0;
+ for (const auto &ptx: ptx_vector)
+ {
+ int n_old = 0;
+ for (const auto i: ptx.selected_transfers)
+ {
+ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i);
+ uint64_t age = bc_height - td.m_block_height;
+ if (age > OLD_AGE_WARN_THRESHOLD)
+ ++n_old;
+ }
+ max_n_old = std::max(max_n_old, n_old);
+ }
+ if (max_n_old > 1)
+ {
+ std::stringstream prompt;
+ prompt << tr("Transaction spends more than one very old output. Privacy would be better if they were sent separately.");
+ prompt << ENDL << tr("Spend them now anyway?");
+ std::string accepted = input_line(prompt.str(), true);
+ if (std::cin.eof())
+ return false;
+ if (!command_line::is_yes(accepted))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::string> &args_, bool called_by_mms)
{
// "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"
@@ -5907,6 +5948,12 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
}
+ if (!prompt_if_old(ptx_vector))
+ {
+ fail_msg_writer() << tr("transaction cancelled.");
+ return false;
+ }
+
// if more than one tx necessary, prompt user to confirm
if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1)
{
@@ -6090,7 +6137,8 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
{
- return sweep_main(0, true, args_);
+ sweep_main(0, true, args_);
+ return true;
}
//----------------------------------------------------------------------------------------------------
@@ -6410,6 +6458,12 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
return true;
}
+ if (!prompt_if_old(ptx_vector))
+ {
+ fail_msg_writer() << tr("transaction cancelled.");
+ return false;
+ }
+
// give user total and fee, and prompt to confirm
uint64_t total_fee = 0, total_sent = 0;
for (size_t n = 0; n < ptx_vector.size(); ++n)
@@ -6756,7 +6810,8 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
{
- return sweep_main(0, false, args_);
+ sweep_main(0, false, args_);
+ return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
@@ -6772,7 +6827,8 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
fail_msg_writer() << tr("invalid amount threshold");
return true;
}
- return sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
+ return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
@@ -7683,6 +7739,8 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
local_args.erase(local_args.begin());
}
+ const uint64_t last_block_height = m_wallet->get_blockchain_current_height();
+
if (in || coinbase) {
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
m_wallet->get_payments(payments, min_height, max_height, m_current_subaddress_account, subaddr_indices);
@@ -7697,6 +7755,25 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
std::string destination = m_wallet->get_subaddress_as_str({m_current_subaddress_account, pd.m_subaddr_index.minor});
const std::string type = pd.m_coinbase ? tr("block") : tr("in");
const bool unlocked = m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
+ std::string locked_msg = "unlocked";
+ if (!unlocked)
+ {
+ locked_msg = "locked";
+ const uint64_t unlock_time = pd.m_unlock_time;
+ if (pd.m_unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
+ {
+ uint64_t bh = std::max(pd.m_unlock_time, pd.m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
+ if (bh >= last_block_height)
+ locked_msg = std::to_string(bh - last_block_height) + " blks";
+ }
+ else
+ {
+ uint64_t current_time = static_cast<uint64_t>(time(NULL));
+ uint64_t threshold = current_time + (m_wallet->use_fork_rules(2, 0) ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1);
+ if (threshold < pd.m_unlock_time)
+ locked_msg = get_human_readable_timespan(std::chrono::seconds(pd.m_unlock_time - threshold));
+ }
+ }
transfers.push_back({
type,
pd.m_block_height,
@@ -7710,7 +7787,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
{{destination, pd.m_amount}},
{pd.m_subaddr_index.minor},
note,
- (unlocked) ? "unlocked" : "locked"
+ locked_msg
});
}
}