mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-12-25 22:57:46 +00:00
wallet: add number of blocks required for the balance to fully unlock
This commit is contained in:
parent
3f1e9e84c0
commit
c12b43cb5a
5 changed files with 64 additions and 23 deletions
|
@ -4948,10 +4948,15 @@ 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 unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, &blocks_to_unlock);
|
||||||
|
std::string unlock_time_message;
|
||||||
|
if (blocks_to_unlock > 0)
|
||||||
|
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
|
||||||
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
|
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
|
||||||
<< tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance(m_current_subaddress_account)) << 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);
|
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account);
|
||||||
std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
|
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
|
||||||
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:");
|
||||||
|
@ -4963,7 +4968,7 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
|
||||||
cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first};
|
cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first};
|
||||||
std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6);
|
std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6);
|
||||||
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; });
|
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; });
|
||||||
success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first]) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
|
success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5430,13 +5430,19 @@ uint64_t wallet2::balance(uint32_t index_major) const
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
uint64_t wallet2::unlocked_balance(uint32_t index_major) const
|
uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unlock) const
|
||||||
{
|
{
|
||||||
uint64_t amount = 0;
|
uint64_t amount = 0;
|
||||||
|
if (blocks_to_unlock)
|
||||||
|
*blocks_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))
|
for (const auto& i : unlocked_balance_per_subaddress(index_major))
|
||||||
amount += i.second;
|
{
|
||||||
|
amount += i.second.first;
|
||||||
|
if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
|
||||||
|
*blocks_to_unlock = i.second.second;
|
||||||
|
}
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
@ -5469,18 +5475,36 @@ 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, uint64_t> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
|
std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
|
||||||
{
|
{
|
||||||
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
|
||||||
|
const uint64_t blockchain_height = get_blockchain_current_height();
|
||||||
for(const transfer_details& td: m_transfers)
|
for(const transfer_details& td: m_transfers)
|
||||||
{
|
{
|
||||||
if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen && is_transfer_unlocked(td))
|
if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
|
||||||
{
|
{
|
||||||
|
uint64_t amount = 0, blocks_to_unlock = 0;
|
||||||
|
if (is_transfer_unlocked(td))
|
||||||
|
{
|
||||||
|
amount = td.amount();
|
||||||
|
blocks_to_unlock = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
unlock_height = td.m_tx.unlock_time;
|
||||||
|
blocks_to_unlock = unlock_height > blockchain_height ? unlock_height - blockchain_height : 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] = td.amount();
|
amount_per_subaddr[td.m_subaddr_index.minor] = std::make_pair(amount, blocks_to_unlock);
|
||||||
else
|
else
|
||||||
found->second += td.amount();
|
{
|
||||||
|
found->second.first += amount;
|
||||||
|
found->second.second = std::max(found->second.second, blocks_to_unlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return amount_per_subaddr;
|
return amount_per_subaddr;
|
||||||
|
@ -5494,11 +5518,18 @@ uint64_t wallet2::balance_all() const
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
uint64_t wallet2::unlocked_balance_all() const
|
uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
|
||||||
{
|
{
|
||||||
uint64_t r = 0;
|
uint64_t r = 0;
|
||||||
|
if (blocks_to_unlock)
|
||||||
|
*blocks_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)
|
||||||
r += unlocked_balance(index_major);
|
{
|
||||||
|
uint64_t local_blocks_to_unlock;
|
||||||
|
r += unlocked_balance(index_major, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
|
||||||
|
if (blocks_to_unlock)
|
||||||
|
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
@ -9044,7 +9075,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, uint64_t> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
|
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
|
||||||
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
|
std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
|
||||||
|
|
||||||
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
|
||||||
|
@ -9062,7 +9093,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
for (uint32_t index_minor : subaddr_indices)
|
for (uint32_t index_minor : subaddr_indices)
|
||||||
{
|
{
|
||||||
balance_subtotal += balance_per_subaddr[index_minor];
|
balance_subtotal += balance_per_subaddr[index_minor];
|
||||||
unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor];
|
unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor].first;
|
||||||
}
|
}
|
||||||
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > balance_subtotal, error::not_enough_money,
|
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > balance_subtotal, error::not_enough_money,
|
||||||
balance_subtotal, needed_money, 0);
|
balance_subtotal, needed_money, 0);
|
||||||
|
@ -9128,7 +9159,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||||
{
|
{
|
||||||
auto sort_predicate = [&unlocked_balance_per_subaddr] (const std::pair<uint32_t, std::vector<size_t>>& x, const std::pair<uint32_t, std::vector<size_t>>& y)
|
auto sort_predicate = [&unlocked_balance_per_subaddr] (const std::pair<uint32_t, std::vector<size_t>>& x, const std::pair<uint32_t, std::vector<size_t>>& y)
|
||||||
{
|
{
|
||||||
return unlocked_balance_per_subaddr[x.first] > unlocked_balance_per_subaddr[y.first];
|
return unlocked_balance_per_subaddr[x.first].first > unlocked_balance_per_subaddr[y.first].first;
|
||||||
};
|
};
|
||||||
std::sort(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), sort_predicate);
|
std::sort(unused_transfers_indices_per_subaddr.begin(), unused_transfers_indices_per_subaddr.end(), sort_predicate);
|
||||||
std::sort(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), sort_predicate);
|
std::sort(unused_dust_indices_per_subaddr.begin(), unused_dust_indices_per_subaddr.end(), sort_predicate);
|
||||||
|
|
|
@ -765,13 +765,13 @@ namespace tools
|
||||||
|
|
||||||
// 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) const;
|
uint64_t balance(uint32_t subaddr_index_major) const;
|
||||||
uint64_t unlocked_balance(uint32_t subaddr_index_major) const;
|
uint64_t unlocked_balance(uint32_t subaddr_index_major, uint64_t *blocks_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) const;
|
std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major) const;
|
||||||
std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
|
std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
|
||||||
// all locked & unlocked balances of all subaddress accounts
|
// all locked & unlocked balances of all subaddress accounts
|
||||||
uint64_t balance_all() const;
|
uint64_t balance_all() const;
|
||||||
uint64_t unlocked_balance_all() const;
|
uint64_t unlocked_balance_all(uint64_t *blocks_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,
|
||||||
|
|
|
@ -385,10 +385,10 @@ namespace tools
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
res.balance = req.all_accounts ? m_wallet->balance_all() : m_wallet->balance(req.account_index);
|
res.balance = req.all_accounts ? m_wallet->balance_all() : m_wallet->balance(req.account_index);
|
||||||
res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all() : m_wallet->unlocked_balance(req.account_index);
|
res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(&res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, &res.blocks_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, uint64_t>> unlocked_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;
|
||||||
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)
|
||||||
|
@ -408,7 +408,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, uint64_t> unlocked_balance_per_subaddress = unlocked_balance_per_subaddress_per_account[account_index];
|
std::map<uint32_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())
|
||||||
{
|
{
|
||||||
|
@ -427,7 +427,8 @@ namespace tools
|
||||||
cryptonote::subaddress_index index = {info.account_index, info.address_index};
|
cryptonote::subaddress_index index = {info.account_index, info.address_index};
|
||||||
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];
|
info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
|
||||||
|
info.blocks_to_unlock = unlocked_balance_per_subaddress[i].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));
|
||||||
|
|
|
@ -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 8
|
#define WALLET_RPC_VERSION_MINOR 9
|
||||||
#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
|
||||||
|
@ -81,6 +81,7 @@ namespace wallet_rpc
|
||||||
uint64_t unlocked_balance;
|
uint64_t unlocked_balance;
|
||||||
std::string label;
|
std::string label;
|
||||||
uint64_t num_unspent_outputs;
|
uint64_t num_unspent_outputs;
|
||||||
|
uint64_t blocks_to_unlock;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(account_index)
|
KV_SERIALIZE(account_index)
|
||||||
|
@ -90,6 +91,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(unlocked_balance)
|
KV_SERIALIZE(unlocked_balance)
|
||||||
KV_SERIALIZE(label)
|
KV_SERIALIZE(label)
|
||||||
KV_SERIALIZE(num_unspent_outputs)
|
KV_SERIALIZE(num_unspent_outputs)
|
||||||
|
KV_SERIALIZE(blocks_to_unlock)
|
||||||
END_KV_SERIALIZE_MAP()
|
END_KV_SERIALIZE_MAP()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,12 +101,14 @@ namespace wallet_rpc
|
||||||
uint64_t unlocked_balance;
|
uint64_t unlocked_balance;
|
||||||
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;
|
||||||
|
|
||||||
BEGIN_KV_SERIALIZE_MAP()
|
BEGIN_KV_SERIALIZE_MAP()
|
||||||
KV_SERIALIZE(balance)
|
KV_SERIALIZE(balance)
|
||||||
KV_SERIALIZE(unlocked_balance)
|
KV_SERIALIZE(unlocked_balance)
|
||||||
KV_SERIALIZE(multisig_import_needed)
|
KV_SERIALIZE(multisig_import_needed)
|
||||||
KV_SERIALIZE(per_subaddress)
|
KV_SERIALIZE(per_subaddress)
|
||||||
|
KV_SERIALIZE(blocks_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;
|
||||||
|
|
Loading…
Reference in a new issue