mirror of https://github.com/oxen-io/oxen-core.git
Merge commit 'f2f725d8db3535055d1c7e102c0bba75b22a3409' into LokiMergeUpstream
This commit is contained in:
commit
2fe5ddb2ca
|
@ -233,13 +233,24 @@ public:
|
|||
char *str;
|
||||
};
|
||||
|
||||
static void add_anchors(ub_ctx *ctx)
|
||||
{
|
||||
const char * const *ds = ::get_builtin_ds();
|
||||
while (*ds)
|
||||
{
|
||||
MINFO("adding trust anchor: " << *ds);
|
||||
ub_ctx_add_ta(ctx, string_copy(*ds++));
|
||||
}
|
||||
}
|
||||
|
||||
DNSResolver::DNSResolver() : m_data(new DNSResolverData())
|
||||
{
|
||||
int use_dns_public = 0;
|
||||
std::vector<std::string> dns_public_addr;
|
||||
if (auto res = getenv("DNS_PUBLIC"))
|
||||
const char *DNS_PUBLIC = getenv("DNS_PUBLIC");
|
||||
if (DNS_PUBLIC)
|
||||
{
|
||||
dns_public_addr = tools::dns_utils::parse_dns_public(res);
|
||||
dns_public_addr = tools::dns_utils::parse_dns_public(DNS_PUBLIC);
|
||||
if (!dns_public_addr.empty())
|
||||
{
|
||||
MGINFO("Using public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)");
|
||||
|
@ -267,11 +278,28 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData())
|
|||
ub_ctx_hosts(m_data->m_ub_context, NULL);
|
||||
}
|
||||
|
||||
const char * const *ds = ::get_builtin_ds();
|
||||
while (*ds)
|
||||
add_anchors(m_data->m_ub_context);
|
||||
|
||||
if (!DNS_PUBLIC)
|
||||
{
|
||||
MINFO("adding trust anchor: " << *ds);
|
||||
ub_ctx_add_ta(m_data->m_ub_context, string_copy(*ds++));
|
||||
// if no DNS_PUBLIC specified, we try a lookup to what we know
|
||||
// should be a valid DNSSEC record, and switch to known good
|
||||
// DNSSEC resolvers if verification fails
|
||||
bool available, valid;
|
||||
static const char *probe_hostname = "updates.moneropulse.org";
|
||||
auto records = get_txt_record(probe_hostname, available, valid);
|
||||
if (!valid)
|
||||
{
|
||||
MINFO("Failed to verify DNSSEC record from " << probe_hostname << ", falling back to TCP with well known DNSSEC resolvers");
|
||||
ub_ctx_delete(m_data->m_ub_context);
|
||||
m_data->m_ub_context = ub_ctx_create();
|
||||
add_anchors(m_data->m_ub_context);
|
||||
dns_public_addr = tools::dns_utils::parse_dns_public(DNS_PUBLIC);
|
||||
for (const auto &ip: dns_public_addr)
|
||||
ub_ctx_set_fwd(m_data->m_ub_context, string_copy(ip.c_str()));
|
||||
ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no"));
|
||||
ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,6 +139,7 @@ static_assert(STAKING_PORTIONS % 3 == 0, "Use a multiple of three, so that it di
|
|||
#define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 5000 //5 seconds
|
||||
#define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70
|
||||
#define P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT 2
|
||||
#define P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT 2
|
||||
#define P2P_DEFAULT_LIMIT_RATE_UP 2048 // kB/s
|
||||
#define P2P_DEFAULT_LIMIT_RATE_DOWN 8192 // kB/s
|
||||
|
||||
|
|
|
@ -114,6 +114,7 @@ namespace cryptonote
|
|||
void stop();
|
||||
void on_connection_close(cryptonote_connection_context &context);
|
||||
void set_max_out_peers(unsigned int max) { m_max_out_peers = max; }
|
||||
void set_no_sync(bool value) { m_no_sync = value; }
|
||||
std::string get_peers_overview() const;
|
||||
std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const;
|
||||
bool needs_new_sync_connections() const;
|
||||
|
@ -146,6 +147,7 @@ namespace cryptonote
|
|||
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
|
||||
bool kick_idle_peers();
|
||||
bool check_standby_peers();
|
||||
bool update_sync_search();
|
||||
int try_add_next_blocks(cryptonote_connection_context &context);
|
||||
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
||||
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||
|
@ -157,10 +159,12 @@ namespace cryptonote
|
|||
std::atomic<uint32_t> m_syncronized_connections_count;
|
||||
std::atomic<bool> m_synchronized;
|
||||
std::atomic<bool> m_stopping;
|
||||
std::atomic<bool> m_no_sync;
|
||||
boost::mutex m_sync_lock;
|
||||
block_queue m_block_queue;
|
||||
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
|
||||
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
|
||||
epee::math_helper::once_a_time_seconds<101> m_sync_search_checker;
|
||||
std::atomic<unsigned int> m_max_out_peers;
|
||||
tools::PerformanceTimer m_sync_timer, m_add_timer;
|
||||
uint64_t m_last_add_end_time;
|
||||
|
|
|
@ -73,7 +73,8 @@ namespace cryptonote
|
|||
m_p2p(p_net_layout),
|
||||
m_syncronized_connections_count(0),
|
||||
m_synchronized(offline),
|
||||
m_stopping(false)
|
||||
m_stopping(false),
|
||||
m_no_sync(false)
|
||||
|
||||
{
|
||||
if(!m_p2p)
|
||||
|
@ -375,6 +376,13 @@ namespace cryptonote
|
|||
m_core.set_target_blockchain_height((hshd.current_height));
|
||||
}
|
||||
MINFO(context << "Remote blockchain height: " << hshd.current_height << ", id: " << hshd.top_id);
|
||||
|
||||
if (m_no_sync)
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
return true;
|
||||
}
|
||||
|
||||
context.m_state = cryptonote_connection_context::state_synchronizing;
|
||||
//let the socket to send response to handshake, but request callback, to let send request data after response
|
||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||
|
@ -1452,6 +1460,7 @@ skip:
|
|||
{
|
||||
m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this));
|
||||
m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::check_standby_peers, this));
|
||||
m_sync_search_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::update_sync_search, this));
|
||||
return m_core.on_idle();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
|
@ -1481,6 +1490,47 @@ skip:
|
|||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::update_sync_search()
|
||||
{
|
||||
const uint64_t target = m_core.get_target_blockchain_height();
|
||||
const uint64_t height = m_core.get_current_blockchain_height();
|
||||
if (target > height) // if we're not synced yet, don't do it
|
||||
return true;
|
||||
|
||||
MTRACE("Checking for outgoing syncing peers...");
|
||||
unsigned n_syncing = 0, n_synced = 0;
|
||||
boost::uuids::uuid last_synced_peer_id(boost::uuids::nil_uuid());
|
||||
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||
{
|
||||
if (!peer_id || context.m_is_income) // only consider connected outgoing peers
|
||||
return true;
|
||||
if (context.m_state == cryptonote_connection_context::state_synchronizing)
|
||||
++n_syncing;
|
||||
if (context.m_state == cryptonote_connection_context::state_normal)
|
||||
{
|
||||
++n_synced;
|
||||
if (!context.m_anchor)
|
||||
last_synced_peer_id = context.m_connection_id;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
MTRACE(n_syncing << " syncing, " << n_synced << " synced");
|
||||
|
||||
// if we're at max out peers, and not enough are syncing
|
||||
if (n_synced + n_syncing >= m_max_out_peers && n_syncing < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id != boost::uuids::nil_uuid())
|
||||
{
|
||||
if (!m_p2p->for_connection(last_synced_peer_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
MINFO(ctx << "dropping synced peer, " << n_syncing << " syncing, " << n_synced << " synced");
|
||||
drop_connection(ctx, false, false);
|
||||
return true;
|
||||
}))
|
||||
MDEBUG("Failed to find peer we wanted to drop");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::check_standby_peers()
|
||||
{
|
||||
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||
|
|
|
@ -81,11 +81,9 @@ int main(int argc, char* argv[])
|
|||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_output_file = {"output-file", "Specify output file", "", true};
|
||||
const command_line::arg_descriptor<uint32_t> arg_log_level = {"log-level", "", log_level};
|
||||
const command_line::arg_descriptor<std::string> arg_input = {"input", "Specify input has a hexadecimal string", ""};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, arg_output_file);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_input);
|
||||
|
||||
|
@ -121,52 +119,10 @@ int main(int argc, char* argv[])
|
|||
|
||||
mlog_configure("", true);
|
||||
|
||||
std::string m_config_folder;
|
||||
|
||||
std::ostream *output;
|
||||
std::ofstream *raw_data_file = NULL;
|
||||
if (command_line::has_arg(vm, arg_output_file))
|
||||
{
|
||||
output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file));
|
||||
|
||||
const boost::filesystem::path dir_path = output_file_path.parent_path();
|
||||
if (!dir_path.empty())
|
||||
{
|
||||
if (boost::filesystem::exists(dir_path))
|
||||
{
|
||||
if (!boost::filesystem::is_directory(dir_path))
|
||||
{
|
||||
std::cerr << "output directory path is a file: " << dir_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!boost::filesystem::create_directory(dir_path))
|
||||
{
|
||||
std::cerr << "Failed to create directory " << dir_path << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw_data_file = new std::ofstream();
|
||||
raw_data_file->open(output_file_path.string(), std::ios_base::out | std::ios::trunc);
|
||||
if (raw_data_file->fail())
|
||||
return 1;
|
||||
output = raw_data_file;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_file_path = "";
|
||||
output = &std::cout;
|
||||
}
|
||||
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(input, blob))
|
||||
{
|
||||
std::cerr << "Invalid hex input" << std::endl;
|
||||
std::cerr << "Invalid hex input: " << input << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -213,11 +169,5 @@ int main(int argc, char* argv[])
|
|||
|
||||
|
||||
|
||||
if (output->fail())
|
||||
return 1;
|
||||
output->flush();
|
||||
if (raw_data_file)
|
||||
delete raw_data_file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -133,6 +133,7 @@ namespace nodetool
|
|||
const command_line::arg_descriptor<std::vector<std::string> > arg_proxy = {"proxy", "<network-type>,<socks-ip:port>[,max_connections] i.e. \"tor,127.0.0.1:9050,100\""};
|
||||
const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound = {"anonymous-inbound", "<hidden-service-address>,<[bind-ip:]port>[,max_connections] i.e. \"x.onion,127.0.0.1:18083,100\""};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
|
||||
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
|
||||
|
||||
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
|
||||
const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1};
|
||||
|
|
|
@ -487,6 +487,7 @@ namespace nodetool
|
|||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_proxy;
|
||||
extern const command_line::arg_descriptor<std::vector<std::string> > arg_anonymous_inbound;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port;
|
||||
extern const command_line::arg_descriptor<bool> arg_no_sync;
|
||||
|
||||
extern const command_line::arg_descriptor<bool> arg_no_igd;
|
||||
extern const command_line::arg_descriptor<bool> arg_offline;
|
||||
|
|
|
@ -104,6 +104,7 @@ namespace nodetool
|
|||
command_line::add_arg(desc, arg_proxy);
|
||||
command_line::add_arg(desc, arg_anonymous_inbound);
|
||||
command_line::add_arg(desc, arg_p2p_hide_my_port);
|
||||
command_line::add_arg(desc, arg_no_sync);
|
||||
command_line::add_arg(desc, arg_no_igd);
|
||||
command_line::add_arg(desc, arg_out_peers);
|
||||
command_line::add_arg(desc, arg_in_peers);
|
||||
|
@ -311,6 +312,9 @@ namespace nodetool
|
|||
if(command_line::has_arg(vm, arg_p2p_hide_my_port))
|
||||
m_hide_my_port = true;
|
||||
|
||||
if (command_line::has_arg(vm, arg_no_sync))
|
||||
m_payload_handler.set_no_sync(true);
|
||||
|
||||
if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) )
|
||||
return false;
|
||||
else
|
||||
|
|
|
@ -6522,17 +6522,17 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const
|
|||
return epee::file_io_utils::save_string_to_file(filename, ciphertext);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func)
|
||||
bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
|
||||
{
|
||||
const size_t magiclen = strlen(MULTISIG_UNSIGNED_TX_PREFIX);
|
||||
if (strncmp(s.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen))
|
||||
if (strncmp(multisig_tx_st.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen))
|
||||
{
|
||||
LOG_PRINT_L0("Bad magic from multisig tx data");
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
s = decrypt_with_view_secret_key(std::string(s, magiclen));
|
||||
multisig_tx_st = decrypt_with_view_secret_key(std::string(multisig_tx_st, magiclen));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
|
@ -6541,7 +6541,7 @@ bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported
|
|||
}
|
||||
try
|
||||
{
|
||||
std::istringstream iss(s);
|
||||
std::istringstream iss(multisig_tx_st);
|
||||
boost::archive::portable_binary_iarchive ar(iss);
|
||||
ar >> exported_txs;
|
||||
}
|
||||
|
@ -6563,6 +6563,17 @@ bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported
|
|||
CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func)
|
||||
{
|
||||
if(!parse_multisig_tx_from_str(s, exported_txs))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to parse multisig transaction from string");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_PRINT_L1("Loaded multisig tx unsigned data from binary: " << exported_txs.m_ptx.size() << " transactions");
|
||||
for (auto &ptx: exported_txs.m_ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx));
|
||||
|
||||
|
|
|
@ -855,6 +855,7 @@ namespace tools
|
|||
void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux);
|
||||
void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux);
|
||||
uint64_t cold_key_image_sync(uint64_t &spent, uint64_t &unspent);
|
||||
bool parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const;
|
||||
bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
|
||||
bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
|
||||
bool sign_multisig_tx_from_file(const std::string &filename, std::vector<crypto::hash> &txids, std::function<bool(const multisig_tx_set&)> accept_func);
|
||||
|
|
|
@ -1074,40 +1074,70 @@ namespace tools
|
|||
er.message = "command not supported by watch-only wallet";
|
||||
return false;
|
||||
}
|
||||
|
||||
tools::wallet2::unsigned_tx_set exported_txs;
|
||||
try
|
||||
if(req.unsigned_txset.empty() && req.multisig_txset.empty())
|
||||
{
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
|
||||
er.message = "Failed to parse hex.";
|
||||
return false;
|
||||
}
|
||||
if(!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
|
||||
er.message = "cannot load unsigned_txset";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
|
||||
er.message = "failed to parse unsigned transfers: " + std::string(e.what());
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "no txset provided";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector <wallet2::tx_construction_data> tx_constructions;
|
||||
if (!req.unsigned_txset.empty()) {
|
||||
try {
|
||||
tools::wallet2::unsigned_tx_set exported_txs;
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob)) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
|
||||
er.message = "Failed to parse hex.";
|
||||
return false;
|
||||
}
|
||||
if (!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs)) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
|
||||
er.message = "cannot load unsigned_txset";
|
||||
return false;
|
||||
}
|
||||
tx_constructions = exported_txs.txes;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
|
||||
er.message = "failed to parse unsigned transfers: " + std::string(e.what());
|
||||
return false;
|
||||
}
|
||||
} else if (!req.multisig_txset.empty()) {
|
||||
try {
|
||||
tools::wallet2::multisig_tx_set exported_txs;
|
||||
cryptonote::blobdata blob;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(req.multisig_txset, blob)) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
|
||||
er.message = "Failed to parse hex.";
|
||||
return false;
|
||||
}
|
||||
if (!m_wallet->parse_multisig_tx_from_str(blob, exported_txs)) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA;
|
||||
er.message = "cannot load multisig_txset";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) {
|
||||
tx_constructions.push_back(exported_txs.m_ptx[n].construction_data);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA;
|
||||
er.message = "failed to parse multisig transfers: " + std::string(e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<tools::wallet2::pending_tx> ptx;
|
||||
try
|
||||
{
|
||||
// gather info to ask the user
|
||||
std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
|
||||
int first_known_non_zero_change_index = -1;
|
||||
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
|
||||
for (size_t n = 0; n < tx_constructions.size(); ++n)
|
||||
{
|
||||
const tools::wallet2::tx_construction_data &cd = exported_txs.txes[n];
|
||||
const tools::wallet2::tx_construction_data &cd = tx_constructions[n];
|
||||
res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {}, "", 0, "", 0, 0, ""});
|
||||
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc = res.desc.back();
|
||||
|
||||
|
@ -1171,7 +1201,7 @@ namespace tools
|
|||
{
|
||||
if (first_known_non_zero_change_index == -1)
|
||||
first_known_non_zero_change_index = n;
|
||||
const tools::wallet2::tx_construction_data &cdn = exported_txs.txes[first_known_non_zero_change_index];
|
||||
const tools::wallet2::tx_construction_data &cdn = tx_constructions[first_known_non_zero_change_index];
|
||||
if (memcmp(&cd.change_dts.addr, &cdn.change_dts.addr, sizeof(cd.change_dts.addr)))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
|
||||
|
@ -1199,7 +1229,7 @@ namespace tools
|
|||
|
||||
if (desc.change_amount > 0)
|
||||
{
|
||||
const tools::wallet2::tx_construction_data &cd0 = exported_txs.txes[0];
|
||||
const tools::wallet2::tx_construction_data &cd0 = tx_constructions[0];
|
||||
desc.change_address = get_account_address_as_str(m_wallet->nettype(), cd0.subaddr_account > 0, cd0.change_dts.addr);
|
||||
}
|
||||
|
||||
|
|
|
@ -653,9 +653,11 @@ namespace wallet_rpc
|
|||
struct request_t
|
||||
{
|
||||
std::string unsigned_txset; // Set of unsigned tx returned by "transfer" or "transfer_split" methods.
|
||||
std::string multisig_txset; // Set of unsigned multisig txes returned by "transfer" or "transfer_split" methods
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(unsigned_txset)
|
||||
KV_SERIALIZE(multisig_txset)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
|
Loading…
Reference in New Issue