simplewallet: report timestamp based expected unlock time on balance

This commit is contained in:
moneromooo-monero 2020-04-19 15:57:11 +00:00
parent 57854a3e21
commit 8b655de8ed
No known key found for this signature in database
GPG Key ID: 686F07454D6CEFC3
5 changed files with 52 additions and 24 deletions

View File

@ -143,6 +143,7 @@ enum TransferType {
}; };
static std::string get_human_readable_timespan(std::chrono::seconds seconds); static std::string get_human_readable_timespan(std::chrono::seconds seconds);
static std::string get_human_readable_timespan(uint64_t seconds);
namespace namespace
{ {
@ -5748,15 +5749,19 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
uint64_t blocks_to_unlock; uint64_t blocks_to_unlock, time_to_unlock;
uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock); uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock, &time_to_unlock);
std::string unlock_time_message; std::string unlock_time_message;
if (blocks_to_unlock > 0) if (blocks_to_unlock > 0 && time_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) and %s to unlock)") % blocks_to_unlock % get_human_readable_timespan(time_to_unlock)).str();
else if (blocks_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str(); unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
else if (time_to_unlock > 0)
unlock_time_message = (boost::format(" (%s to unlock)") % get_human_readable_timespan(time_to_unlock)).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", " success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra; << tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false); std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false); std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
if (!detailed || balance_per_subaddress.empty()) if (!detailed || balance_per_subaddress.empty())
return true; return true;
success_msg_writer() << tr("Balance per address:"); success_msg_writer() << tr("Balance per address:");
@ -8233,6 +8238,11 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
return sw::tr("a long time"); return sw::tr("a long time");
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
static std::string get_human_readable_timespan(uint64_t seconds)
{
return get_human_readable_timespan(std::chrono::seconds(seconds));
}
//----------------------------------------------------------------------------------------------------
// mutates local_args as it parses and consumes arguments // mutates local_args as it parses and consumes arguments
bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vector<transfer_view>& transfers) bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vector<transfer_view>& transfers)
{ {

View File

@ -5839,18 +5839,22 @@ uint64_t wallet2::balance(uint32_t index_major, bool strict) const
return amount; return amount;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock) const uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{ {
uint64_t amount = 0; uint64_t amount = 0;
if (blocks_to_unlock) if (blocks_to_unlock)
*blocks_to_unlock = 0; *blocks_to_unlock = 0;
if (time_to_unlock)
*time_to_unlock = 0;
if(m_light_wallet) if(m_light_wallet)
return m_light_wallet_balance; return m_light_wallet_balance;
for (const auto& i : unlocked_balance_per_subaddress(index_major, strict)) for (const auto& i : unlocked_balance_per_subaddress(index_major, strict))
{ {
amount += i.second.first; amount += i.second.first;
if (blocks_to_unlock && i.second.second > *blocks_to_unlock) if (blocks_to_unlock && i.second.second.first > *blocks_to_unlock)
*blocks_to_unlock = i.second.second; *blocks_to_unlock = i.second.second.first;
if (time_to_unlock && i.second.second.second > *time_to_unlock)
*time_to_unlock = i.second.second.second;
} }
return amount; return amount;
} }
@ -5887,35 +5891,40 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
return amount_per_subaddr; return amount_per_subaddr;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
{ {
std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr; std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> amount_per_subaddr;
const uint64_t blockchain_height = get_blockchain_current_height(); const uint64_t blockchain_height = get_blockchain_current_height();
const uint64_t now = time(NULL);
for(const transfer_details& td: m_transfers) for(const transfer_details& td: m_transfers)
{ {
if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen) if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{ {
uint64_t amount = 0, blocks_to_unlock = 0; uint64_t amount = 0, blocks_to_unlock = 0, time_to_unlock = 0;
if (is_transfer_unlocked(td)) if (is_transfer_unlocked(td))
{ {
amount = td.amount(); amount = td.amount();
blocks_to_unlock = 0; blocks_to_unlock = 0;
time_to_unlock = 0;
} }
else else
{ {
uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS); uint64_t unlock_height = td.m_block_height + std::max<uint64_t>(CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS);
if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height) if (td.m_tx.unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER && td.m_tx.unlock_time > unlock_height)
unlock_height = td.m_tx.unlock_time; unlock_height = td.m_tx.unlock_time;
uint64_t unlock_time = td.m_tx.unlock_time >= CRYPTONOTE_MAX_BLOCK_NUMBER ? td.m_tx.unlock_time : 0;
blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0; blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 0;
time_to_unlock = unlock_time > now ? unlock_time - now : 0;
amount = 0; amount = 0;
} }
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor); auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end()) if (found == amount_per_subaddr.end())
amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock); amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, std::make_pair(blocks_to_unlock, time_to_unlock));
else else
{ {
found->second.first += amount; found->second.first += amount;
found->second.second = std::max(found->second.second, blocks_to_unlock); found->second.second.first = std::max(found->second.second.first, blocks_to_unlock);
found->second.second.second = std::max(found->second.second.second, time_to_unlock);
} }
} }
} }
@ -5930,17 +5939,21 @@ uint64_t wallet2::balance_all(bool strict) const
return r; return r;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock) const uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock, uint64_t *time_to_unlock) const
{ {
uint64_t r = 0; uint64_t r = 0;
if (blocks_to_unlock) if (blocks_to_unlock)
*blocks_to_unlock = 0; *blocks_to_unlock = 0;
if (time_to_unlock)
*time_to_unlock = 0;
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major) for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
{ {
uint64_t local_blocks_to_unlock; uint64_t local_blocks_to_unlock, local_time_to_unlock;
r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL); r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL, time_to_unlock ? &local_time_to_unlock : NULL);
if (blocks_to_unlock) if (blocks_to_unlock)
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock); *blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
if (time_to_unlock)
*time_to_unlock = std::max(*time_to_unlock, local_time_to_unlock);
} }
return r; return r;
} }
@ -9579,7 +9592,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money // throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination); THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false); std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false); std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false);
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance

View File

@ -822,13 +822,13 @@ private:
// locked & unlocked balance of given or current subaddress account // locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major, bool strict) const; uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL) const; uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
// locked & unlocked balance per subaddress of given or current subaddress account // locked & unlocked balance per subaddress of given or current subaddress account
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const; std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
// all locked & unlocked balances of all subaddress accounts // all locked & unlocked balances of all subaddress accounts
uint64_t balance_all(bool strict) const; uint64_t balance_all(bool strict) const;
uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL) const; uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL, uint64_t *time_to_unlock = NULL) const;
template<typename T> template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,

View File

@ -428,10 +428,10 @@ namespace tools
try try
{ {
res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict); res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict);
res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock); res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock, &res.time_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock, &res.time_to_unlock);
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images(); res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account; std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account; std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account;
if (req.all_accounts) if (req.all_accounts)
{ {
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index) for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
@ -451,7 +451,7 @@ namespace tools
{ {
uint32_t account_index = p.first; uint32_t account_index = p.first;
std::map<uint32_t, uint64_t> balance_per_subaddress = p.second; std::map<uint32_t, uint64_t> balance_per_subaddress = p.second;
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index]; std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
std::set<uint32_t> address_indices; std::set<uint32_t> address_indices;
if (!req.all_accounts && !req.address_indices.empty()) if (!req.all_accounts && !req.address_indices.empty())
{ {
@ -471,7 +471,8 @@ namespace tools
info.address = m_wallet->get_subaddress_as_str(index); info.address = m_wallet->get_subaddress_as_str(index);
info.balance = balance_per_subaddress[i]; info.balance = balance_per_subaddress[i];
info.unlocked_balance = unlocked_balance_per_subaddress[i].first; info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second; info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second.first;
info.time_to_unlock = unlocked_balance_per_subaddress[i].second.second;
info.label = m_wallet->get_subaddress_label(index); info.label = m_wallet->get_subaddress_label(index);
info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; }); info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; });
res.per_subaddress.emplace_back(std::move(info)); res.per_subaddress.emplace_back(std::move(info));

View File

@ -47,7 +47,7 @@
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1 #define WALLET_RPC_VERSION_MAJOR 1
#define WALLET_RPC_VERSION_MINOR 17 #define WALLET_RPC_VERSION_MINOR 18
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR) #define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools namespace tools
@ -84,6 +84,7 @@ namespace wallet_rpc
std::string label; std::string label;
uint64_t num_unspent_outputs; uint64_t num_unspent_outputs;
uint64_t blocks_to_unlock; uint64_t blocks_to_unlock;
uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index) KV_SERIALIZE(account_index)
@ -94,6 +95,7 @@ namespace wallet_rpc
KV_SERIALIZE(label) KV_SERIALIZE(label)
KV_SERIALIZE(num_unspent_outputs) KV_SERIALIZE(num_unspent_outputs)
KV_SERIALIZE(blocks_to_unlock) KV_SERIALIZE(blocks_to_unlock)
KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
@ -104,6 +106,7 @@ namespace wallet_rpc
bool multisig_import_needed; bool multisig_import_needed;
std::vector<per_subaddress_info> per_subaddress; std::vector<per_subaddress_info> per_subaddress;
uint64_t blocks_to_unlock; uint64_t blocks_to_unlock;
uint64_t time_to_unlock;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance) KV_SERIALIZE(balance)
@ -111,6 +114,7 @@ namespace wallet_rpc
KV_SERIALIZE(multisig_import_needed) KV_SERIALIZE(multisig_import_needed)
KV_SERIALIZE(per_subaddress) KV_SERIALIZE(per_subaddress)
KV_SERIALIZE(blocks_to_unlock) KV_SERIALIZE(blocks_to_unlock)
KV_SERIALIZE(time_to_unlock)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<response_t> response; typedef epee::misc_utils::struct_init<response_t> response;