1
0
Fork 0
forked from lthn/blockchain

Merge branch 'release'

This commit is contained in:
sowle 2025-07-18 21:25:32 +03:00
commit f8e298af86
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
11 changed files with 237 additions and 123 deletions

View file

@ -59,6 +59,7 @@ namespace epee
storage_entry load_storage_entry();
void read(section& sec);
void read(std::string& str);
void read(array_entry &ae);
private:
struct recursuion_limitation_guard
{
@ -114,6 +115,7 @@ namespace epee
void throwable_buffer_reader::read(t_pod_type& pod_val)
{
RECURSION_LIMITATION();
static_assert(std::is_pod<t_pod_type>::value, "POD type expected");
read(&pod_val, sizeof(pod_val));
}
@ -277,5 +279,11 @@ namespace epee
m_ptr+=len;
m_count -= len;
}
inline
void throwable_buffer_reader::read(array_entry &ae)
{
RECURSION_LIMITATION();
CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported");
}
}
}

View file

@ -28,6 +28,8 @@
#include "parserse_base_utils.h"
#include "file_io_utils.h"
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
namespace epee
{
namespace serialization
@ -54,9 +56,10 @@ namespace epee
ASSERT_MES_AND_THROW("json parse error");
}*/
template<class t_storage>
inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg)
inline void run_handler(typename t_storage::hsection current_section, std::string::const_iterator& sec_buf_begin, std::string::const_iterator buf_end, t_storage& stg, unsigned int recursion)
{
CHECK_AND_ASSERT_THROW_MES(recursion < EPEE_JSON_RECURSION_LIMIT_INTERNAL,
"Wrong JSON data: recursion limitation (" << EPEE_JSON_RECURSION_LIMIT_INTERNAL << ") exceeded");
std::string::const_iterator sub_element_start;
std::string name;
typename t_storage::harray h_array = nullptr;
@ -167,7 +170,7 @@ namespace epee
//sub section here
typename t_storage::hsection new_sec = stg.open_section(name, current_section, true);
CHECK_AND_ASSERT_THROW_MES(new_sec, "Failed to insert new section in json: " << std::string(it, buf_end));
run_handler(new_sec, it, buf_end, stg);
run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_wonder_after_value;
}else if(*it == '[')
{//array of something
@ -196,7 +199,7 @@ namespace epee
typename t_storage::hsection new_sec = nullptr;
h_array = stg.insert_first_section(name, new_sec, current_section);
CHECK_AND_ASSERT_THROW_MES(h_array&&new_sec, "failed to create new section");
run_handler(new_sec, it, buf_end, stg);
run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_array_after_value;
array_md = array_mode_sections;
}else if(*it == '"')
@ -270,7 +273,7 @@ namespace epee
typename t_storage::hsection new_sec = NULL;
bool res = stg.insert_next_section(h_array, new_sec);
CHECK_AND_ASSERT_THROW_MES(res&&new_sec, "failed to insert next section");
run_handler(new_sec, it, buf_end, stg);
run_handler(new_sec, it, buf_end, stg, recursion + 1);
state = match_state_array_after_value;
}else CHECK_ISSPACE();
break;
@ -372,7 +375,7 @@ namespace epee
std::string::const_iterator sec_buf_begin = buff_json.begin();
try
{
run_handler(nullptr, sec_buf_begin, buff_json.end(), stg);
run_handler(nullptr, sec_buf_begin, buff_json.end(), stg, 0);
return true;
}
catch(const std::exception& ex)

View file

@ -464,8 +464,7 @@ namespace currency
{
time_pack_txs_ms = epee::misc_utils::get_tick_count();
currency_connection_context exclude_context = boost::value_initialized<currency_connection_context>();
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
arg.hop = 0;
NOTIFY_NEW_BLOCK::request arg{};
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_size();
std::list<crypto::hash> missed_txs;
std::list<transaction> txs;

View file

@ -58,12 +58,10 @@ namespace currency
{
block_complete_entry b;
uint64_t current_blockchain_height;
uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(b)
KV_SERIALIZE(current_blockchain_height)
KV_SERIALIZE(hop)
END_KV_SERIALIZE_MAP()
};
};

View file

@ -290,7 +290,7 @@ namespace currency
}
crypto::hash block_id = get_block_hash(b);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b) << " (hop " << arg.hop << ")", LOG_LEVEL_2);
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK " << block_id << " HEIGHT " << get_block_height(b), LOG_LEVEL_2);
CRITICAL_REGION_BEGIN(m_blocks_id_que_lock);
auto it = m_blocks_id_que.find(block_id);
@ -329,7 +329,6 @@ namespace currency
if (m_core.pre_validate_block(b, bvc, block_id) && bvc.m_added_to_main_chain)
{
//not alternative block, relay it
++arg.hop;
relay_block(arg, context);
prevalidate_relayed = true;
}
@ -377,7 +376,6 @@ namespace currency
if (true/*!prevalidate_relayed*/)
{
// pre-validation failed prevoiusly, but complete check was success, not an alternative block
++arg.hop;
//TODO: Add here announce protocol usage
relay_block(arg, context);
}

View file

@ -293,7 +293,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon");
#endif // #ifdef CPU_MINING_ENABLED
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[raw] Show current wallet balance, with 'raw' param it displays all assets without filtering against whitelists");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[r,raw] Show current wallet balance, with 'raw' param it displays all assets without filtering against whitelists");
m_cmd_binder.set_handler("show_staking_history", boost::bind(&simple_wallet::show_staking_history, this, ph::_1), "show_staking_history [2] - Show staking transfers, if option provided - number of days for history to display");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts");
@ -886,7 +886,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf
message_writer(color, false) <<
"height " << wti.height <<
", tx " << wti.tx_hash <<
" " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.subtransfers[0].amount, decimal_points) << (wti.subtransfers[0].is_income ? " received," : " spent") << " " << token_info;
" " << std::right << std::setw(18) << print_money_trailing_zeros_replaced_with_spaces(wti.subtransfers[0].amount, decimal_points) << (wti.subtransfers[0].is_income ? " received" : " spent") << " " << token_info;
}
else
{
@ -900,7 +900,7 @@ void simple_wallet::on_transfer2(const tools::wallet_public::wallet_transfer_inf
std::string token_info = get_token_info_string(st.asset_id, decimal_points);
message_writer(epee::log_space::console_color_cyan, false) << " "
<< std::right << std::setw(24) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << std::left << (st.is_income ? " received," : " spent") << " " << token_info;
<< std::right << std::setw(24) << print_money_trailing_zeros_replaced_with_spaces(st.amount, decimal_points) << std::left << (st.is_income ? " received" : " spent") << " " << token_info;
}
}
@ -1025,7 +1025,7 @@ bool simple_wallet::refresh(const std::vector<std::string>& args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_balance(const std::vector<std::string>& args /* = std::vector<std::string>()*/)
{
if (args.size() == 1 && args[0] == "raw")
if (args.size() == 1 && (args[0] == "raw" || args[0] == "r"))
{
success_msg_writer() << m_wallet->get_balance_str_raw();
}

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "7"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 416
#define PROJECT_VERSION_BUILD_NO 418
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -3827,6 +3827,9 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
}
if (balances.empty())
balances[currency::native_coin_asset_id] = wallet_public::asset_balance_entry_base{};
return true;
}
//----------------------------------------------------------------------------------------------------
@ -3877,76 +3880,45 @@ bool wallet2::balance(std::list<wallet_public::asset_balance_entry>& balances, u
balances.clear();
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances_map;
this->balance(balances_map, mined);
std::unordered_map<crypto::public_key, currency::asset_descriptor_base> custom_assets_local = m_custom_assets;
for (auto& own_asset : m_own_asset_descriptors)
for (const auto& [asset_id, balance_entry] : balances_map)
{
if (m_whitelisted_assets.find(own_asset.first) == m_whitelisted_assets.end())
{
custom_assets_local[own_asset.first] = own_asset.second;
}
}
asset_descriptor_base asset_info{};
uint32_t asset_flags = 0;
if (!get_asset_info(asset_id, asset_info, asset_flags))
continue;
asset_descriptor_base native_asset_info = AUTO_VAL_INIT(native_asset_info);
native_asset_info.full_name = CURRENCY_NAME_SHORT_BASE;
native_asset_info.ticker = CURRENCY_NAME_ABR;
native_asset_info.decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT;
custom_assets_local[currency::native_coin_asset_id] = native_asset_info;
if (!m_use_assets_whitelisting)
asset_flags &= ~aif_whitelisted;
for (const auto& item : balances_map)
{
asset_descriptor_base asset_info = AUTO_VAL_INIT(asset_info);
//check if asset is whitelisted or customly added
if ((asset_flags & (aif_native_coin | aif_custom | aif_whitelisted)) == 0)
continue;
//check if it custom asset
auto it_cust = custom_assets_local.find(item.first);
if (it_cust == custom_assets_local.end())
{
if (!m_use_assets_whitelisting)
continue;
auto it_local = m_whitelisted_assets.find(item.first);
if (it_local == m_whitelisted_assets.end())
{
WLT_LOG_YELLOW("WARNING: unknown asset " << item.first << " found and skipped; it's NOT included in balance", LOG_LEVEL_1);
continue;
}
else
{
asset_info = it_local->second;
}
}
else
{
asset_info = it_cust->second;
custom_assets_local.erase(it_cust);
}
balances.push_back(wallet_public::asset_balance_entry());
wallet_public::asset_balance_entry& new_item = balances.back();
static_cast<wallet_public::asset_balance_entry_base&>(new_item) = item.second;
new_item.asset_info.asset_id = item.first;
wallet_public::asset_balance_entry& new_item = balances.emplace_back();
static_cast<wallet_public::asset_balance_entry_base&>(new_item) = balance_entry;
new_item.asset_info.asset_id = asset_id;
static_cast<currency::asset_descriptor_base&>(new_item.asset_info) = asset_info;
}
//manually added assets should be always present, at least as zero balanced items
for (auto& asset : custom_assets_local)
for (const auto& [asset_id, custom_asset_entry] : m_custom_assets)
{
balances.push_back(wallet_public::asset_balance_entry());
wallet_public::asset_balance_entry& new_item = balances.back();
new_item.asset_info.asset_id = asset.first;
static_cast<currency::asset_descriptor_base&>(new_item.asset_info) = asset.second;
if (std::find_if(balances.begin(), balances.end(), [asset_id = asset_id](wallet_public::asset_balance_entry& e){ return e.asset_info.asset_id == asset_id; }) != balances.end())
continue;
wallet_public::asset_balance_entry& new_item = balances.emplace_back();
new_item.asset_info.asset_id = asset_id;
static_cast<currency::asset_descriptor_base&>(new_item.asset_info) = custom_asset_entry;
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags) const
bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags, bool ask_daemon_for_unknown /* = false */) const
{
asset_flags = aif_none;
if (asset_id == currency::native_coin_asset_id)
{
asset_info = currency::get_native_coin_asset_descriptor();
asset_flags |= aif_whitelisted;
asset_flags |= (aif_native_coin | aif_whitelisted);
return true;
}
@ -3956,7 +3928,6 @@ bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset
{
asset_info = it_own->second;
asset_flags |= aif_own;
return true;
}
// whitelisted?
@ -3965,7 +3936,6 @@ bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset
{
asset_info = it_white->second;
asset_flags |= aif_whitelisted;
return true;
}
// custom asset?
@ -3973,10 +3943,18 @@ bool wallet2::get_asset_info(const crypto::public_key& asset_id, currency::asset
if (it_cust != m_custom_assets.end())
{
asset_info = it_cust->second;
return true;
asset_flags |= aif_custom;
}
return false;
if (ask_daemon_for_unknown)
{
if (daemon_get_asset_info(asset_id, asset_info))
{
asset_flags |= aif_unknown;
}
}
return asset_flags != aif_none;
}
//----------------------------------------------------------------------------------------------------
size_t wallet2::get_asset_decimal_point(const crypto::public_key& asset_id, size_t result_if_not_found /* = 0 */) const
@ -4132,7 +4110,8 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
bool native_coin = td.is_native_coin();
asset_descriptor_base adb{};
uint32_t asset_info_flags{};
if (get_asset_info(td.get_asset_id(), adb, asset_info_flags) == show_only_unknown)
bool unknown_asset = !get_asset_info(td.get_asset_id(), adb, asset_info_flags, show_only_unknown) || (asset_info_flags & aif_unknown);
if (unknown_asset != show_only_unknown)
{
if (!show_only_unknown)
++unknown_assets_outs_count;
@ -4172,11 +4151,11 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_balance_str() const
{
// balance unlocked / [balance total] ticker asset id
// 0.21 / 98.51 DP2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3
// 190.123456789012 / 199.123456789012 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
// 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
// balance unlocked / [balance total] ticker asset id
// 0.21 / 98.51 DP2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3
// 190.123456789012 / 199.123456789012 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a NATIVE
// 98.0 BGTVUW af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
// 1000.034 DP3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
static const char* header = " balance unlocked / [balance total] ticker asset id";
std::stringstream ss;
@ -4211,13 +4190,12 @@ std::string wallet2::get_balance_str() const
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_balance_str_raw() const
{
// balance unlocked / [balance total] DP asset id
// 0.21 / 98.51 2 a6974d5874e97e5f4ed5ad0a62f0975edbccb1bb55502fc75c7fe808f12f44d3
// 190.123456789012 / 199.123456789012 12 d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 98.0 12 af2b12f3033337f9aea1845a6bc3fc966ed4d13227a3ace7706fca7dbcdaa7e2
// 1000.034 3 d4aba1020f26927571771e04b585b4ffb211f52708d5e4c465bbdfa4a12e6271
// balance unlocked / [balance total] ticker asset id DP flags
// 0.21 / 98.51 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a 12 NATIVE
// 2.0 MYFB 13615ffdfbdc09275a1dfc0fbdaf6a9b07849b835ffdfed0b9e1478ea8924774 1 custom
// 1000.0 BurnCT 14608811180d4bbad96a6b91405e329e4f2a10519e6dcea644f83b9f8ccb5863 12 unknown asset
//WHITELIST:
// 7d3f348fbebfffc4e61a3686189cf870ea393e1c88b8f636acbfdacf9e4b2db2 CT
// a7e8e5b31c24f2d6a07e141701237b136d704c9a89f9a5d1ca4a8290df0b9edc WETH
// ...
static const char* header = " balance unlocked / [balance total] ticker asset id DP flags";
@ -4234,7 +4212,7 @@ std::string wallet2::get_balance_str_raw() const
{
uint32_t asset_flags = 0;
asset_descriptor_base asset_info{};
bool has_info = get_asset_info(entry.first, asset_info, asset_flags);
bool has_info = get_asset_info(entry.first, asset_info, asset_flags, true);
ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, asset_info.decimal_point);
if (entry.second.total == entry.second.unlocked)
ss << std::string(21 + 3, ' ');
@ -4251,7 +4229,7 @@ std::string wallet2::get_balance_str_raw() const
ss << " ";
if (entry.first == native_coin_asset_id)
if (asset_flags & aif_native_coin)
{
ss << "NATIVE";
}
@ -4261,6 +4239,10 @@ std::string wallet2::get_balance_str_raw() const
ss << "own,";
if (asset_flags & aif_whitelisted)
ss << "whitelisted,";
if (asset_flags & aif_custom)
ss << "custom,";
if (asset_flags & aif_unknown)
ss << "unknown asset,";
ss.seekp(-1, ss.cur); // trim comma
}
ss << ENDL;
@ -5813,7 +5795,7 @@ void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_
result_tx = ft.tx;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb)
bool wallet2::daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb) const
{
COMMAND_RPC_GET_ASSET_INFO::request req;
req.asset_id = asset_id;

View file

@ -449,7 +449,7 @@ namespace tools
void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft, const std::vector<currency::tx_service_attachment>& service_entries = std::vector<currency::tx_service_attachment>(), const std::string& address_to_point = std::string(), uint64_t native_amount_to_point = 0);
void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::finalized_tx& ft);
bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb);
bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb) const;
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
void set_defragmentation_tx_settings(bool enabled, uint64_t min_outs, uint64_t max_outs, uint64_t max_allowed_amount = CURRENCY_BLOCK_REWARD, size_t decoys_count = SIZE_MAX);
void set_pos_required_decoys_count(size_t v) { m_required_decoys_count = v; }
@ -466,8 +466,8 @@ namespace tools
uint64_t unlocked_balance() const;
enum asset_info_flags_t : uint32_t { aif_none = 0, aif_whitelisted = 1 << 0, aif_own = 1 << 1 };
bool get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags) const;
enum asset_info_flags_t : uint32_t { aif_none = 0, aif_native_coin = 1 << 0, aif_whitelisted = 1 << 1, aif_own = 1 << 2, aif_custom = 1 << 3, aif_unknown = 1 << 4 };
bool get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_info, uint32_t& asset_flags, bool ask_daemon_for_unknown = false) const;
size_t get_asset_decimal_point(const crypto::public_key& asset_id, size_t result_if_not_found = 0) const;
bool get_asset_decimal_point(const crypto::public_key& asset_id, size_t* p_decimal_point_result) const;

View file

@ -962,7 +962,7 @@ typedef boost::variant<crypto::public_key, crypto::eth_public_key> public_key_v;
template<typename t_response>
bool sign_signature_with_keys(const t_response& rsp_with_data, tools::wallet_rpc_server& attached_wallet_rpc, const secret_key_v& signer_v, const public_key_v& verifier)
bool ext_sign_and_send_asset_tx(const t_response& rsp_with_data, tools::wallet_rpc_server& attached_wallet_rpc, const secret_key_v& signer_v, const public_key_v& verifier)
{
bool r = false;
tools::wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::request send_signed_req = AUTO_VAL_INIT(send_signed_req);
@ -993,15 +993,15 @@ bool sign_signature_with_keys(const t_response& rsp_with_data, tools::wallet_rpc
return false;
}
send_signed_req.unsigned_tx = rsp_with_data.data_for_external_signing->unsigned_tx;
send_signed_req.expected_tx_id = rsp_with_data.tx_id;
send_signed_req.finalized_tx = rsp_with_data.data_for_external_signing->finalized_tx;
send_signed_req.unsigned_tx = rsp_with_data.data_for_external_signing->unsigned_tx;
send_signed_req.expected_tx_id = rsp_with_data.tx_id;
send_signed_req.finalized_tx = rsp_with_data.data_for_external_signing->finalized_tx;
send_signed_req.unlock_transfers_on_fail = true;
tools::wallet_public::COMMAND_ASSET_SEND_EXT_SIGNED_TX::response send_signed_resp{};
r = invoke_text_json_for_rpc(attached_wallet_rpc, "send_ext_signed_asset_tx", send_signed_req, send_signed_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC send_ext_signed_asset_tx failed: ");
CHECK_AND_ASSERT_MES(send_signed_resp.status == API_RETURN_CODE_OK, false, "RPC send_ext_signed_asset_tx failed: ");
CHECK_AND_ASSERT_MES(r, false, "RPC send_ext_signed_asset_tx failed");
CHECK_AND_ASSERT_MES(send_signed_resp.status == API_RETURN_CODE_OK, false, "RPC send_ext_signed_asset_tx failed: " << send_signed_resp.status);
return true;
}
@ -1025,7 +1025,6 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(bob_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(carol_wlt->get_account().get_public_address(), c, 3);
//r = mine_next_pow_blocks_in_playtime(custody_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
@ -1054,7 +1053,10 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
return false;
}
const crypto::public_key asset_id = resp.new_asset_id;
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
// core RPC server
currency::t_currency_protocol_handler<currency::core> cprotocol(c, NULL);
@ -1104,26 +1106,34 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
return false;
}
r = sign_signature_with_keys(emm_resp, alice_wlt_rpc, miner_wlt->get_account().get_keys().spend_secret_key, miner_wlt->get_account().get_keys().account_address.spend_public_key);
CHECK_AND_ASSERT_MES(r, false, "failed to call sign_signature_with_keys");
r = ext_sign_and_send_asset_tx(emm_resp, alice_wlt_rpc, miner_wlt->get_account().get_keys().spend_secret_key, miner_wlt->get_account().get_keys().account_address.spend_public_key);
CHECK_AND_ASSERT_MES(r, false, "failed to call ext_sign_and_send_asset_tx");
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
//check bob wallet
tools::wallet_public::COMMAND_ASSETS_WHITELIST_ADD::request wtl_req = AUTO_VAL_INIT(wtl_req);
tools::wallet_public::COMMAND_ASSETS_WHITELIST_ADD::response wtl_resp = AUTO_VAL_INIT(wtl_resp);
wtl_req.asset_id = resp.new_asset_id;
tools::wallet_rpc_server bob_wlt_rpc(bob_wlt);
r = invoke_text_json_for_rpc(bob_wlt_rpc, "assets_whitelist_add", wtl_req, wtl_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC send_ext_signed_asset_tx failed: ");
CHECK_AND_ASSERT_MES(wtl_resp.status == API_RETURN_CODE_OK, false, "RPC status failed");
bob_wlt->refresh();
tools::wallet_public::COMMAND_RPC_GET_BALANCE::request balance_req = AUTO_VAL_INIT(balance_req);
tools::wallet_public::COMMAND_RPC_GET_BALANCE::response balance_resp = AUTO_VAL_INIT(balance_resp);
r = invoke_text_json_for_rpc(bob_wlt_rpc, "getbalance", balance_req, balance_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC send_ext_signed_asset_tx failed: ");
CHECK_AND_ASSERT_MES(r, false, "RPC getbalance failed");
r = std::find_if(balance_resp.balances.begin(), balance_resp.balances.end(), [&](tools::wallet_public::asset_balance_entry& e){ return e.asset_info.asset_id == asset_id; }) == balance_resp.balances.end();
CHECK_AND_ASSERT_MES(r, false, "found asset " << resp.new_asset_id << " which is unexpected");
tools::wallet_public::COMMAND_ASSETS_WHITELIST_ADD::request wtl_req = AUTO_VAL_INIT(wtl_req);
tools::wallet_public::COMMAND_ASSETS_WHITELIST_ADD::response wtl_resp = AUTO_VAL_INIT(wtl_resp);
wtl_req.asset_id = resp.new_asset_id;
r = invoke_text_json_for_rpc(bob_wlt_rpc, "assets_whitelist_add", wtl_req, wtl_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC assets_whitelist_add failed");
CHECK_AND_ASSERT_MES(wtl_resp.status == API_RETURN_CODE_OK, false, "RPC status failed");
bob_wlt->refresh();
balance_req = AUTO_VAL_INIT(balance_req);
balance_resp = AUTO_VAL_INIT(balance_resp);
r = invoke_text_json_for_rpc(bob_wlt_rpc, "getbalance", balance_req, balance_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC getbalance failed");
bool found_asset = false;
@ -1132,14 +1142,14 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
if (bal.asset_info.asset_id == resp.new_asset_id)
{
found_asset = true;
CHECK_AND_ASSERT_MES(bal.total == COINS_TO_TRANSFER, false, "Amount is unexpected");
CHECK_EQ(bal.total, COINS_TO_TRANSFER);
}
}
CHECK_AND_ASSERT_MES(found_asset, false, "Asset not found ");
CHECK_AND_ASSERT_MES(found_asset, false, "Asset with id " << resp.new_asset_id << " was not found");
//transfer ownership of the asset to new address
//transfer ownership of the asset to an ETH key
//let's change the owner to ecdsa
crypto::eth_secret_key eth_sk_2{};
crypto::eth_public_key eth_pk_2{};
@ -1160,8 +1170,8 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
return false;
}
r = sign_signature_with_keys(res_own, alice_wlt_rpc, miner_wlt->get_account().get_keys().spend_secret_key, miner_wlt->get_account().get_keys().account_address.spend_public_key);
CHECK_AND_ASSERT_MES(r, false, "failed to call sign_signature_with_keys");
r = ext_sign_and_send_asset_tx(res_own, alice_wlt_rpc, miner_wlt->get_account().get_keys().spend_secret_key, miner_wlt->get_account().get_keys().account_address.spend_public_key);
CHECK_AND_ASSERT_MES(r, false, "failed to call ext_sign_and_send_asset_tx");
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
@ -1169,15 +1179,11 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
//now make another tx and see of ownership got changed
emm_resp = AUTO_VAL_INIT(emm_resp);
r = invoke_text_json_for_rpc(alice_wlt_rpc, "emit_asset", emm_req, emm_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
if (!emm_resp.data_for_external_signing)
{
LOG_ERROR("Missing data_for_external_signing");
return false;
}
CHECK_AND_ASSERT_MES(r, false, "invoke_text_json_for_rpc failed");
CHECK_AND_ASSERT_MES(res_own.data_for_external_signing, false, "data_for_external_signing is missing");
r = sign_signature_with_keys(emm_resp, alice_wlt_rpc, eth_sk_2, eth_pk_2);
CHECK_AND_ASSERT_MES(r, false, "failed to call sign_signature_with_keys");
r = ext_sign_and_send_asset_tx(emm_resp, alice_wlt_rpc, eth_sk_2, eth_pk_2);
CHECK_AND_ASSERT_MES(r, false, "failed to call ext_sign_and_send_asset_tx");
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 3);
@ -1197,6 +1203,66 @@ bool wallet_rpc_thirdparty_custody::c1(currency::core& c, size_t ev_index, const
CHECK_AND_ASSERT_MES(found_asset, false, "Asset not found ");
// Transfer ownership to Carol (standard owner pub key)
tools::wallet_rpc_server carol_wlt_rpc(carol_wlt);
req_own = AUTO_VAL_INIT(req_own);
res_own = AUTO_VAL_INIT(res_own);
req_own.asset_id = asset_id;
req_own.new_owner = carol_acc.get_public_address().spend_public_key;
alice_wlt->refresh();
r = invoke_text_json_for_rpc(alice_wlt_rpc, "transfer_asset_ownership", req_own, res_own);
CHECK_AND_ASSERT_MES(r, false, "invoke_text_json_for_rpc failed");
CHECK_AND_ASSERT_MES(res_own.data_for_external_signing, false, "data_for_external_signing is missing");
// externally sign and send transfer ownership tx
r = ext_sign_and_send_asset_tx(res_own, alice_wlt_rpc, eth_sk_2, eth_pk_2);
CHECK_AND_ASSERT_MES(r, false, "ext_sign_and_send_asset_tx failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "unexpected pool txs count: " << c.get_pool_transactions_count());
// Miner still has some asset coins, transfer them to Carol
miner_wlt->refresh();
tools::wallet_public::COMMAND_RPC_TRANSFER::request miner_tr_req = AUTO_VAL_INIT(miner_tr_req);
tools::wallet_public::COMMAND_RPC_TRANSFER::request miner_tr_res = AUTO_VAL_INIT(miner_tr_res);
miner_tr_req.fee = TESTS_DEFAULT_FEE;
miner_tr_req.destinations.push_back({COINS_TO_TRANSFER * 7ull, carol_acc.get_public_address_str(), asset_id});
r = invoke_text_json_for_rpc(miner_wlt_rpc, "transfer", miner_tr_req, miner_tr_res);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "unexpected pool txs count: " << c.get_pool_transactions_count());
// confirm it
CHECK_AND_ASSERT_MES(mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW), false, "");
// make sure the pool is now empty
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "unexpected pool txs count: " << c.get_pool_transactions_count());
// Carol shouldn't have this asset whitelisted and present in balance
carol_wlt->refresh();
balance_req = AUTO_VAL_INIT(balance_req);
balance_resp = AUTO_VAL_INIT(balance_resp);
r = invoke_text_json_for_rpc(carol_wlt_rpc, "getbalance", balance_req, balance_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC getbalance failed");
CHECK_EQ(balance_resp.balance, 0);
r = std::find_if(balance_resp.balances.begin(), balance_resp.balances.end(), [&](tools::wallet_public::asset_balance_entry& e){ return e.asset_info.asset_id == asset_id; }) == balance_resp.balances.end();
CHECK_AND_ASSERT_MES(r, false, "asset was found, which in unexpected");
// make sure she has asset_id among own assets in spite of that
auto& carol_own_assets = carol_wlt->get_own_assets();
CHECK_EQ(carol_own_assets.size(), 1);
CHECK_EQ(carol_own_assets.count(asset_id), 1);
// whitelist and re-check
wtl_req = AUTO_VAL_INIT(wtl_req);
wtl_resp = AUTO_VAL_INIT(wtl_resp);
wtl_req.asset_id = asset_id;
CHECK_AND_ASSERT_MES(invoke_text_json_for_rpc(carol_wlt_rpc, "assets_whitelist_add", wtl_req, wtl_resp), false, "");
CHECK_AND_ASSERT_MES(wtl_resp.status == API_RETURN_CODE_OK, false, "RPC failed");
// now the asset must show up in the balance
balance_req = AUTO_VAL_INIT(balance_req);
balance_resp = AUTO_VAL_INIT(balance_resp);
r = invoke_text_json_for_rpc(carol_wlt_rpc, "getbalance", balance_req, balance_resp);
CHECK_AND_ASSERT_MES(r, false, "RPC getbalance failed");
CHECK_EQ(balance_resp.balance, 0); // the balance for native coin is still zero
auto it = std::find_if(balance_resp.balances.begin(), balance_resp.balances.end(), [&](tools::wallet_public::asset_balance_entry& e){ return e.asset_info.asset_id == asset_id; });
CHECK_AND_ASSERT_MES(it != balance_resp.balances.end(), false, "asset was not found, which in unexpected");
CHECK_EQ(it->total, COINS_TO_TRANSFER * 7);
return true;
}

View file

@ -12,7 +12,9 @@
#include "net/levin_protocol_handler_async.h"
#include "net/net_utils_base.h"
#include "unit_tests_utils.h"
#include "storages/parserse_base_utils.h"
#include "storages/portable_storage_base.h"
#include "storages/portable_storage.h"
namespace
{
struct test_levin_connection_context : public epee::net_utils::connection_context_base
@ -504,3 +506,61 @@ TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_unexpe
ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
}
using epee::serialization::portable_storage;
using epee::serialization::array_entry;
using epee::serialization::section;
using epee::serialization::throwable_buffer_reader;
/**
* Purpose:
* Verify what the deserialization of array_entry no longer uses memcpy to
* overwrite the boost::variant memory directly. Instead, an unsupported-array-entry
* path should throw an exception indicating array_entry deserialization isn't supported.
*/
TEST(levin_protocol_variant_memcpy, memcpy_variant_verify)
{
std::string buf; // raw buffer simulating an array_entry section
buf.push_back(static_cast<char>(SERIALIZE_FLAG_ARRAY | SERIALIZE_TYPE_ARRAY));
buf.push_back(static_cast<char>(1 << 2));
buf.append(sizeof(array_entry), char(0x41));
throwable_buffer_reader reader(reinterpret_cast<const uint8_t*>(buf.data()), buf.size());
EXPECT_THROW(
reader.load_storage_array_entry(SERIALIZE_TYPE_ARRAY),
std::runtime_error
) << "Expected load_storage_array_entry to throw due to array_entry";
}
/**
* Purpose:
* Construct a JSON string nested deeper than the built-in recursion limit (100 levels).
*/
TEST(json_parse_deep, parser_deep)
{
const int depth = 200;
std::string json;
json.reserve(depth * 10);
// Build a deeply nested JSON
// {"level": {"level": { ... {"level":1} ... }}}
for (int i = 0; i < depth; ++i)
{
json += '{';
json += "\"level\":";
}
json += '1';
for (int i = 0; i < depth; ++i)
{
json += '}';
}
portable_storage storage;
bool ok = epee::serialization::json::load_from_json(json, storage);
EXPECT_FALSE(ok) << "Expected load_from_json to fail when depth " << depth
<< " exceeds the 100-level recursion limit.";
}