From b3cd5c90cfc30d7e64ac22a387824f05b07a9d45 Mon Sep 17 00:00:00 2001 From: Max Wittal Date: Sun, 20 Oct 2024 01:37:48 +0700 Subject: [PATCH] get_balances() whitelist + limit --- docs/TODO.txt | 1 - include/mmx/Node.h | 11 ++++--- modules/Node.vni | 10 +++--- src/Node_api.cpp | 82 +++++++++++++++++++++++++++++++--------------- src/Wallet.cpp | 14 +++----- src/WebAPI.cpp | 36 +++++++++++--------- 6 files changed, 93 insertions(+), 61 deletions(-) diff --git a/docs/TODO.txt b/docs/TODO.txt index 6bbd9dc5d..b4e040258 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -17,7 +17,6 @@ Mainnet - Swap warning for one-sided pool - VDF trust system (order queue by trust) - Increase min_sync_peers to 5 after launch -- Node + Wallet get_balances() limit - mmx_test framework - 1000 commas for balances - Binary line_info diff --git a/include/mmx/Node.h b/include/mmx/Node.h index bf123aab2..fd6683942 100644 --- a/include/mmx/Node.h +++ b/include/mmx/Node.h @@ -114,13 +114,16 @@ class Node : public NodeBase { uint128 get_total_balance(const std::vector& addresses, const addr_t& currency) const override; - std::map get_balances(const addr_t& address) const override; + std::map get_balances(const addr_t& address, const std::set& whitelist, const int32_t& limit) const override; - std::map get_contract_balances(const addr_t& address) const; + std::map get_contract_balances( + const addr_t& address, const std::set& whitelist, const int32_t& limit) const; - std::map get_total_balances(const std::vector& addresses) const override; + std::map get_total_balances( + const std::vector& addresses, const std::set& whitelist, const int32_t& limit) const override; - std::map, uint128> get_all_balances(const std::vector& addresses) const override; + std::map, uint128> get_all_balances( + const std::vector& addresses, const std::set& whitelist, const int32_t& limit) const override; std::vector get_exec_history(const addr_t& address, const int32_t& limit, const vnx::bool_t& recent) const override; diff --git a/modules/Node.vni b/modules/Node.vni index 7cdc2f2bc..447d8d31a 100644 --- a/modules/Node.vni +++ b/modules/Node.vni @@ -160,22 +160,22 @@ module Node implements vnx.addons.HttpComponent { uint128 get_balance(addr_t address, addr_t currency) const; @Permission(permission_e.PUBLIC) - map get_balances(addr_t address) const; + map get_balances(addr_t address, set whitelist, int limit = 100) const; @Permission(permission_e.PUBLIC) - map get_contract_balances(addr_t address) const; + map get_contract_balances(addr_t address, set whitelist, int limit = 100) const; @Permission(permission_e.PUBLIC) uint128 get_total_balance(vector addresses, addr_t currency) const; @Permission(permission_e.PUBLIC) - map get_total_balances(vector addresses) const; + map get_total_balances(vector addresses, set whitelist, int limit = 100) const; @Permission(permission_e.PUBLIC) - map, uint128> get_all_balances(vector addresses) const; + map, uint128> get_all_balances(vector addresses, set whitelist, int limit = 100) const; @Permission(permission_e.PUBLIC) - vector get_exec_history(addr_t address, int limit = -1, bool recent) const; + vector get_exec_history(addr_t address, int limit = 100, bool recent) const; @Permission(permission_e.PUBLIC) map read_storage(addr_t contract, uint height = -1) const; diff --git a/src/Node_api.cpp b/src/Node_api.cpp index eaa589660..476c90986 100644 --- a/src/Node_api.cpp +++ b/src/Node_api.cpp @@ -613,56 +613,84 @@ uint128 Node::get_total_balance(const std::vector& addresses, const addr return total; } -std::map Node::get_balances(const addr_t& address) const +std::map Node::get_balances(const addr_t& address, const std::set& whitelist, const int32_t& limit) const { - return get_total_balances({address}); + return get_total_balances({address}, whitelist, limit); } -std::map Node::get_contract_balances(const addr_t& address) const +std::map Node::get_contract_balances( + const addr_t& address, const std::set& whitelist, const int32_t& limit) const { - std::map out; - const auto height = get_height() + 1; - const auto contract = get_contract(address); - for(const auto& entry : get_total_balances({address})) { - auto& tmp = out[entry.first]; - if(contract) { - if(contract->is_locked(height)) { - tmp.locked = entry.second; - } else { - tmp.spendable = entry.second; + bool is_locked = false; + if(auto exec = get_contract_as(address)) { + if(auto bin = get_contract_as(exec->binary)) { + const std::string method = "is_locked"; + if(vm::find_method(bin, method)) { + is_locked = call_contract(address, method, {}).to(); } + } + } + std::map out; + for(const auto& entry : get_total_balances({address}, whitelist, limit)) { + const auto& amount = entry.second; + auto& balance = out[entry.first]; + if(is_locked) { + balance.locked = amount; } else { - tmp.spendable = entry.second; + balance.spendable = amount; } - tmp.total = entry.second; + balance.total = amount; + balance.is_validated = !whitelist.empty(); } return out; } -std::map Node::get_total_balances(const std::vector& addresses) const +std::map Node::get_total_balances( + const std::vector& addresses, const std::set& whitelist, const int32_t& limit) const { std::map totals; for(const auto& address : std::set(addresses.begin(), addresses.end())) { - std::vector, uint128>> result; - balance_table.find_range(std::make_pair(address, addr_t()), std::make_pair(address, addr_t::ones()), result); - for(const auto& entry : result) { - if(entry.second) { - totals[entry.first.second] += entry.second; + if(whitelist.empty()) { + std::vector, uint128>> result; + balance_table.find_range(std::make_pair(address, addr_t()), std::make_pair(address, addr_t::ones()), result, limit); + for(const auto& entry : result) { + if(entry.second) { + totals[entry.first.second] += entry.second; + } + } + } else { + for(const auto& currency : whitelist) { + uint128 balance; + balance_table.find(std::make_pair(address, currency), balance); + if(balance) { + totals[currency] += balance; + } } } } return totals; } -std::map, uint128> Node::get_all_balances(const std::vector& addresses) const +std::map, uint128> Node::get_all_balances( + const std::vector& addresses, const std::set& whitelist, const int32_t& limit) const { std::map, uint128> totals; for(const auto& address : std::set(addresses.begin(), addresses.end())) { - std::vector, uint128>> result; - balance_table.find_range(std::make_pair(address, addr_t()), std::make_pair(address, addr_t::ones()), result); - for(const auto& entry : result) { - if(entry.second) { - totals[entry.first] += entry.second; + if(whitelist.empty()) { + std::vector, uint128>> result; + balance_table.find_range(std::make_pair(address, addr_t()), std::make_pair(address, addr_t::ones()), result, limit); + for(const auto& entry : result) { + if(entry.second) { + totals[entry.first] += entry.second; + } + } + } else { + for(const auto& currency : whitelist) { + uint128 balance; + balance_table.find(std::make_pair(address, currency), balance); + if(balance) { + totals[std::make_pair(address, currency)] += balance; + } } } } diff --git a/src/Wallet.cpp b/src/Wallet.cpp index e32e21483..f6d148c52 100644 --- a/src/Wallet.cpp +++ b/src/Wallet.cpp @@ -640,14 +640,14 @@ void Wallet::update_cache(const uint32_t& index) const { const auto height = node->get_height(); const auto addresses = wallet->get_all_addresses(); - const auto balances = node->get_all_balances(addresses); + const auto balances = node->get_all_balances(addresses, token_whitelist); const auto contracts = node->get_contracts_owned_by(addresses); const auto liquidity = node->get_swap_liquidity_by(addresses); const auto history = wallet->pending_tx.empty() ? std::vector() : node->get_tx_ids_since(wallet->height - std::min(params->commit_delay, wallet->height)); wallet->external_balance_map.clear(); - for(const auto& entry : node->get_total_balances(contracts)) { + for(const auto& entry : node->get_total_balances(contracts, token_whitelist)) { wallet->external_balance_map[entry.first] += entry.second; } for(const auto& entry: liquidity) { @@ -770,22 +770,18 @@ std::map Wallet::get_balances( std::map Wallet::get_total_balances(const std::vector& addresses) const { std::map amounts; - for(const auto& entry : node->get_total_balances(addresses)) { + for(const auto& entry : node->get_total_balances(addresses, token_whitelist)) { auto& balance = amounts[entry.first]; balance.total = entry.second; balance.spendable = balance.total; - balance.is_validated = token_whitelist.count(entry.first); + balance.is_validated = true; } return amounts; } std::map Wallet::get_contract_balances(const addr_t& address) const { - auto amounts = node->get_contract_balances(address); - for(auto& entry : amounts) { - entry.second.is_validated = token_whitelist.count(entry.first); - } - return amounts; + return node->get_contract_balances(address, token_whitelist); } std::map> Wallet::get_contracts( diff --git a/src/WebAPI.cpp b/src/WebAPI.cpp index 6064e3a11..e75853768 100644 --- a/src/WebAPI.cpp +++ b/src/WebAPI.cpp @@ -1351,32 +1351,38 @@ void WebAPI::http_request_async(std::shared_ptr } } else if(sub_path == "/address") { - const auto iter = query.find("id"); - if(iter != query.end()) { - const auto address = vnx::from_string_value(iter->second); - node->get_total_balances({address}, - std::bind(&WebAPI::render_address, this, request_id, address, std::placeholders::_1), + const auto address = get_param>(query, "id"); + if(address) { + const auto limit = get_param(query, "limit", 100); + if(is_public && limit > 1000) { + throw std::logic_error("limit > 1000"); + } + node->get_total_balances({*address}, {}, limit, + std::bind(&WebAPI::render_address, this, request_id, *address, std::placeholders::_1), std::bind(&WebAPI::respond_ex, this, request_id, std::placeholders::_1)); } else { - respond_status(request_id, 400, "address?id"); + respond_status(request_id, 400, "address?id|limit"); } } else if(sub_path == "/balance") { - const auto iter_id = query.find("id"); - const auto iter_currency = query.find("currency"); - if(iter_id != query.end()) { - vnx::optional currency; - if(iter_currency != query.end()) { - currency = vnx::from_string(iter_currency->second); + const auto address = get_param>(query, "id"); + if(address) { + const auto limit = get_param(query, "limit", 100); + const auto currency = get_param>(query, "currency"); + if(is_public && limit > 1000) { + throw std::logic_error("limit > 1000"); } - const auto address = vnx::from_string_value(iter_id->second); - node->get_contract_balances(address, + std::set whitelist; + if(currency) { + whitelist.insert(*currency); + } + node->get_contract_balances(*address, whitelist, limit, [this, currency, request_id](const std::map& balances) { render_balances(request_id, currency, balances); }, std::bind(&WebAPI::respond_ex, this, request_id, std::placeholders::_1)); } else { - respond_status(request_id, 400, "balance?id|currency"); + respond_status(request_id, 400, "balance?id|currency|limit"); } } else if(sub_path == "/contract") {