Skip to content

Commit

Permalink
Merge branch 'dev' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
jagerman committed Jun 13, 2022
2 parents 78ed40d + 946b182 commit a33c089
Show file tree
Hide file tree
Showing 16 changed files with 165 additions and 52 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)")

project(oxen
VERSION 10.1.0
VERSION 10.1.1
LANGUAGES CXX C)
set(OXEN_RELEASE_CODENAME "Wistful Wagyu")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,13 @@ namespace epee
{
static_assert(Size > 0, "cannot deserialize empty std::array");
size_t next_i = 0;
for (auto [it, end] = stg.template converting_array_range<T>(pname, parent_section); it != end; ++it) {
CHECK_AND_ASSERT_MES(next_i < array.size(), false, "too many values to deserialize into fixed size std::array");
array[next_i++] = *it;
}
CHECK_AND_ASSERT_MES(next_i == array.size(), false, "not enough values to deserialize into fixed size std::array");
try {
for (auto [it, end] = stg.template converting_array_range<T>(pname, parent_section); it != end; ++it) {
CHECK_AND_ASSERT_MES(next_i < array.size(), false, "too many values to deserialize into fixed size std::array");
array[next_i++] = *it;
}
CHECK_AND_ASSERT_MES(next_i == array.size(), false, "not enough values to deserialize into fixed size std::array");
} catch (const std::out_of_range&) { return false; }
return true;
}
//--------------------------------------------------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions src/blockchain_db/lmdb/db_lmdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,9 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, std::string &b
if (result != 0)
throw1(DB_ERROR(lmdb_error("Error finding txpool tx blob: ", result).c_str()));

if (v.mv_size == 0)
throw1(DB_ERROR("Error finding txpool tx blob: tx is present, but data is empty"));

bd.assign(reinterpret_cast<const char*>(v.mv_data), v.mv_size);
return true;
}
Expand Down
6 changes: 6 additions & 0 deletions src/cryptonote_core/cryptonote_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,12 @@ namespace cryptonote
tx_info.tvc.m_too_big = true;
return;
}
else if (tx_info.blob->empty())
{
LOG_PRINT_L1("WRONG TRANSACTION BLOB, blob is empty, rejected");
tx_info.tvc.m_verifivation_failed = true;
return;
}

tx_info.parsed = parse_and_validate_tx_from_blob(*tx_info.blob, tx_info.tx, tx_info.tx_hash);
if(!tx_info.parsed)
Expand Down
10 changes: 4 additions & 6 deletions src/cryptonote_protocol/cryptonote_protocol_handler.inl
Original file line number Diff line number Diff line change
Expand Up @@ -2579,17 +2579,15 @@ skip:
template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)
{
for(auto& tx_blob : arg.txs)
m_core.on_transaction_relayed(tx_blob);

// no check for success, so tell core they're relayed unconditionally and snag a copy of the
// hash so that we can look up any associated blink data we should include.
std::vector<crypto::hash> relayed_txes;
relayed_txes.reserve(arg.txs.size());
for (auto &tx_blob : arg.txs)
relayed_txes.push_back(
m_core.on_transaction_relayed(tx_blob)
);
{
if (auto hash = m_core.on_transaction_relayed(tx_blob))
relayed_txes.push_back(hash);
}

// Rebuild arg.blinks from blink data that we have because we don't necessarily have the same
// blink data that got sent to us (we may have additional blink info, or may have rejected some
Expand Down
47 changes: 40 additions & 7 deletions src/simplewallet/simplewallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <fmt/core.h>
#include <oxenc/hex.h>
#include "epee/console_handler.h"
#include "common/i18n.h"
Expand Down Expand Up @@ -5059,18 +5060,49 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
<< 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, 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 (m_current_subaddress_account == 0) { // Only the primary account can stake and earn rewards, currently
if (auto stakes = m_wallet->get_staked_service_nodes(); !stakes.empty()) {
auto my_addr = m_wallet->get_address_as_str();
uint64_t total_staked = 0, stakes_unlocking = 0;
for (auto& stake : stakes)
for (auto& contr : stake.contributors)
if (contr.address == my_addr)
{
total_staked += contr.amount;
if (stake.requested_unlock_height > 0)
stakes_unlocking += contr.amount;
}
success_msg_writer() << fmt::format(tr("Total staked: {}, {} unlocking"), print_money(total_staked), print_money(stakes_unlocking));
}

if (uint64_t batched_amount = m_wallet->get_batched_amount(); batched_amount > 0)
{
uint64_t next_payout_block = m_wallet->get_next_batch_payout();
uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
std::string next_batch_payout = next_payout_block > 0
? fmt::format(tr(" (next payout: block {}, in about {})"),
next_payout_block,
tools::get_human_readable_timespan((next_payout_block - blockchain_height) * TARGET_BLOCK_TIME))
: tr(" (next payout: unknown)");
success_msg_writer() << tr("Pending SN rewards: ")
<< print_money(batched_amount) << ", "
<< next_batch_payout;
}
}
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
success_msg_writer() << boost::format("%15s %21s %21s %7s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Outputs") % tr("Label");
success_msg_writer() << boost::format("%15s %21s %21s %21s %7s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Batched Amount") % tr("Outputs") % tr("Label");
std::vector<wallet::transfer_details> transfers;
m_wallet->get_transfers(transfers);
for (const auto& i : balance_per_subaddress)
{
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);
uint64_t batched_amount = m_wallet->get_batched_amount(address_str);
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const wallet::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].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % print_money(batched_amount) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
}
return true;
}
Expand Down Expand Up @@ -6257,9 +6289,8 @@ bool simple_wallet::query_locked_stakes(bool print_result)
std::string msg_buf;
{
using namespace cryptonote;
auto response = m_wallet->list_current_stakes();

for (rpc::GET_SERVICE_NODES::response::entry const &node_info : response)
for (const auto &node_info : m_wallet->get_staked_service_nodes())
{
bool only_once = true;
for (const auto& contributor : node_info.contributors)
Expand Down Expand Up @@ -9107,18 +9138,20 @@ void simple_wallet::print_accounts(const std::string& tag)
success_msg_writer() << tr("Accounts with tag: ") << tag;
success_msg_writer() << tr("Tag's description: ") << account_tags.first.find(tag)->second;
}
success_msg_writer() << boost::format(" %15s %21s %21s %21s") % tr("Account") % tr("Balance") % tr("Unlocked balance") % tr("Label");
success_msg_writer() << boost::format(" %15s %21s %21s %21s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Batched Amount") % tr("Label");
uint64_t total_balance = 0, total_unlocked_balance = 0;
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
{
std::string address_str = m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6);
if (account_tags.second[account_index] != tag)
continue;
success_msg_writer() << boost::format(tr(" %c%8u %6s %21s %21s %21s"))
success_msg_writer() << boost::format(tr(" %c%8u %6s %21s %21s %21s %21s"))
% (m_current_subaddress_account == account_index ? '*' : ' ')
% account_index
% m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6)
% address_str
% print_money(m_wallet->balance(account_index, false))
% print_money(m_wallet->unlocked_balance(account_index, false))
% print_money(m_wallet->get_batched_amount(address_str))
% m_wallet->get_subaddress_label({account_index, 0});
total_balance += m_wallet->balance(account_index, false);
total_unlocked_balance += m_wallet->unlocked_balance(account_index, false);
Expand Down
14 changes: 13 additions & 1 deletion src/wallet/api/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,12 +1063,24 @@ uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const
return wallet()->unlocked_balance(accountIndex, false);
}

EXPORT
uint64_t WalletImpl::accruedBalance(std::optional<std::string> address) const
{
return wallet()->get_batched_amount(std::move(address));
}

EXPORT
uint64_t WalletImpl::nextAccruedPaymentHeight(std::optional<std::string> address) const
{
return wallet()->get_next_batch_payout(std::move(address));
}

EXPORT
std::vector<Wallet::stake_info>* WalletImpl::listCurrentStakes() const
{
auto* stakes = new std::vector<Wallet::stake_info>;

auto response = wallet()->list_current_stakes();
auto response = wallet()->get_staked_service_nodes();
auto main_addr = mainAddress();

for (const auto& node_info : response)
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/api/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ class WalletImpl : public Wallet
bool trustedDaemon() const override;
uint64_t balance(uint32_t accountIndex = 0) const override;
uint64_t unlockedBalance(uint32_t accountIndex = 0) const override;
uint64_t accruedBalance(std::optional<std::string> address = std::nullopt) const override;
uint64_t nextAccruedPaymentHeight(std::optional<std::string> address = std::nullopt) const override;
std::vector<Wallet::stake_info>* listCurrentStakes() const override;
uint64_t blockChainHeight() const override;
uint64_t approximateBlockChainHeight() const override;
Expand Down
15 changes: 15 additions & 0 deletions src/wallet/api/wallet2_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,21 @@ struct Wallet
return result;
}

/**
* @brief accruedBalance - returns the accounts balance that has been batched and yet to be paid.
* @param address - the address to look up; if omitted, looks up the current primary wallet address.
* @return
*/
virtual uint64_t accruedBalance(std::optional<std::string> address = std::nullopt) const = 0;

/**
* @brief nextBatchPayout - returns the height at which this wallet is next eligible to receive
* an accrued balance payment.
* @param address - the address to check; if omitted then look up the current primary wallet
* address.
*/
virtual uint64_t nextAccruedPaymentHeight(std::optional<std::string> address = std::nullopt) const = 0;

// Information returned about stakes in listCurrentStakes()
struct stake_info {
std::string sn_pubkey;
Expand Down
13 changes: 12 additions & 1 deletion src/wallet/node_rpc_proxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,19 @@ bool NodeRPCProxy::update_all_service_nodes_cache(uint64_t height) const {
if (m_offline)
return false;

rpc::GET_SERVICE_NODES::request req{};
req.fields = rpc::GET_SERVICE_NODES::requested_fields_t{};
auto& f = *req.fields;
f.active = true;
f.contributors = true;
f.funded = true;
f.registration_height = true;
f.requested_unlock_height = true;
f.service_node_pubkey = true;
f.staking_requirement = true;
f.total_reserved = true;
try {
auto res = invoke_json_rpc<rpc::GET_SERVICE_NODES>({});
auto res = invoke_json_rpc<rpc::GET_SERVICE_NODES>(req);
m_all_service_nodes_cached_height = height;
m_all_service_nodes = std::move(res.service_node_states);
} catch (...) { return false; }
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/node_rpc_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class NodeRPCProxy
bool get_fee_quantization_mask(uint64_t &fee_quantization_mask) const;
std::optional<cryptonote::hf> get_hardfork_version() const;

// Note that this service node responses only fills out fields that are used in wallet code, not
// the full service node records. (see node_rpc_proxy.cpp for the precise list).
std::pair<bool, std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry>> get_service_nodes(std::vector<std::string> pubkeys) const;
std::pair<bool, std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry>> get_all_service_nodes() const;
std::pair<bool, std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry>> get_contributed_service_nodes(const std::string& contributor) const;
Expand Down
71 changes: 41 additions & 30 deletions src/wallet/wallet2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3639,6 +3639,8 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
LOG_PRINT_L1("Failed to check pending transactions");
}

refresh_batching_cache();

m_first_refresh_done = true;

LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance (all accounts): " << print_money(balance_all(false)) << ", unlocked: " << print_money(unlocked_balance_all(false)));
Expand Down Expand Up @@ -12946,37 +12948,10 @@ uint64_t wallet2::get_approximate_blockchain_height() const
return approx_blockchain_height;
}

std::vector<rpc::GET_SERVICE_NODES::response::entry> wallet2::list_current_stakes()
std::vector<rpc::GET_SERVICE_NODES::response::entry> wallet2::get_staked_service_nodes()
{

std::vector<rpc::GET_SERVICE_NODES::response::entry> service_node_states;

auto [success, all_nodes] = this->get_all_service_nodes();
if (!success)
{
return service_node_states;
}

const auto primary_address = this->get_address();
for (auto& node_info : all_nodes)
{
for (const auto& contributor : node_info.contributors)
{
address_parse_info address_info = {};
if (!cryptonote::get_account_address_from_str(address_info, this->nettype(), contributor.address))
{
continue;
}

if (primary_address != address_info.address)
continue;

service_node_states.push_back(std::move(node_info));
break;
}
}

return service_node_states;
auto [success, contributed_nodes] = m_node_rpc_proxy.get_contributed_service_nodes(get_address_as_str());
return std::move(contributed_nodes);
}

void wallet2::set_ons_cache_record(wallet2::ons_detail detail)
Expand All @@ -12994,6 +12969,42 @@ std::unordered_map<std::string, wallet2::ons_detail> wallet2::get_ons_cache()
return ons_records_cache;
}

void wallet2::refresh_batching_cache()
{
rpc::GET_ACCRUED_BATCHED_EARNINGS::response daemon_resp{};
if (invoke_http<rpc::GET_ACCRUED_BATCHED_EARNINGS>({}, daemon_resp)
&& daemon_resp.status == rpc::STATUS_OK && daemon_resp.addresses.size() == daemon_resp.amounts.size())
{
batching_records_cache.clear();
for (size_t i = 0; i < daemon_resp.addresses.size(); ++i)
batching_records_cache.emplace(std::move(daemon_resp.addresses[i]), std::move(daemon_resp.amounts[i]));
}
}

uint64_t wallet2::get_batched_amount(std::optional<std::string> address) const
{
if (!address)
address = get_address_as_str();
if (auto i = batching_records_cache.find(*address); i != batching_records_cache.end())
return i->second;
return 0;
}

uint64_t wallet2::get_next_batch_payout(std::optional<std::string> address) const
{
auto& conf = cryptonote::get_config(nettype());
cryptonote::account_public_address addr;
if (address) {
cryptonote::address_parse_info info;
if (!get_account_address_from_str(info, nettype(), *address))
return 0;
addr = std::move(info.address);
} else {
addr = get_address();
}
return addr.next_payout_height(get_blockchain_current_height(), conf.BATCHING_INTERVAL);
}

void wallet2::set_tx_note(const crypto::hash &txid, const std::string &note)
{
m_tx_notes[txid] = note;
Expand Down
11 changes: 10 additions & 1 deletion src/wallet/wallet2.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,8 @@ namespace tools
auto get_all_service_nodes() const { return m_node_rpc_proxy.get_all_service_nodes(); }
auto get_service_nodes(std::vector<std::string> const &pubkeys) const { return m_node_rpc_proxy.get_service_nodes(pubkeys); }
auto get_service_node_blacklisted_key_images() const { return m_node_rpc_proxy.get_service_node_blacklisted_key_images(); }
std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry> list_current_stakes();
// List of service nodes this wallet has a stake in:
std::vector<cryptonote::rpc::GET_SERVICE_NODES::response::entry> get_staked_service_nodes();
auto ons_owners_to_names(cryptonote::rpc::ONS_OWNERS_TO_NAMES::request const &request) const { return m_node_rpc_proxy.ons_owners_to_names(request); }
auto ons_names_to_owners(cryptonote::rpc::ONS_NAMES_TO_OWNERS::request const &request) const { return m_node_rpc_proxy.ons_names_to_owners(request); }
auto resolve(cryptonote::rpc::ONS_RESOLVE::request const &request) const { return m_node_rpc_proxy.ons_resolve(request); }
Expand All @@ -849,6 +850,14 @@ namespace tools

std::unordered_map<std::string, ons_detail> get_ons_cache();

std::unordered_map<std::string, uint64_t> batching_records_cache;

void refresh_batching_cache();
// Returns the batched amount for the given address, or main address if empty.
uint64_t get_batched_amount(std::optional<std::string> address = std::nullopt) const;
// Calculates the next batching height for the given address, or main address if nullopt
uint64_t get_next_batch_payout(std::optional<std::string> address = std::nullopt) const;

// Returns the current height up to which the wallet has synchronized the blockchain. Thread
// safe (though the value may be behind if another thread is in the middle of adding blocks).
uint64_t get_blockchain_current_height() const { return m_cached_height; }
Expand Down
5 changes: 5 additions & 0 deletions src/wallet/wallet_rpc_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,11 @@ namespace tools
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, &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();
std::string current_address_str = m_wallet->get_subaddress_as_str({(req.all_accounts ? 0 : req.account_index), 0});
res.accrued_balance = m_wallet->get_batched_amount(current_address_str);
if (res.accrued_balance > 0)
res.accrued_balance_next_payout = m_wallet->get_next_batch_payout(current_address_str);

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, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account;
if (req.all_accounts)
Expand Down
2 changes: 2 additions & 0 deletions src/wallet/wallet_rpc_server_commands_defs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_BALANCE::response)
KV_SERIALIZE(balance)
KV_SERIALIZE(unlocked_balance)
KV_SERIALIZE(accrued_balance)
KV_SERIALIZE(accrued_balance_next_payout)
KV_SERIALIZE(multisig_import_needed)
KV_SERIALIZE(per_subaddress)
KV_SERIALIZE(blocks_to_unlock)
Expand Down
Loading

0 comments on commit a33c089

Please sign in to comment.