aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/transaction_history.cpp2
-rw-r--r--src/wallet/api/wallet.cpp127
-rw-r--r--src/wallet/api/wallet.h5
-rw-r--r--src/wallet/api/wallet2_api.h20
-rw-r--r--src/wallet/message_store.cpp14
-rw-r--r--src/wallet/message_transporter.cpp61
-rw-r--r--src/wallet/message_transporter.h1
-rw-r--r--src/wallet/wallet2.cpp174
-rw-r--r--src/wallet/wallet2.h17
-rw-r--r--src/wallet/wallet_args.cpp5
-rw-r--r--src/wallet/wallet_rpc_server.cpp15
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h4
12 files changed, 316 insertions, 129 deletions
diff --git a/src/wallet/api/transaction_history.cpp b/src/wallet/api/transaction_history.cpp
index f4ad8b1f6..ad7029a3c 100644
--- a/src/wallet/api/transaction_history.cpp
+++ b/src/wallet/api/transaction_history.cpp
@@ -181,7 +181,7 @@ void TransactionHistoryImpl::refresh()
// single output transaction might contain multiple transfers
for (const auto &d: pd.m_dests) {
- ti->m_transfers.push_back({d.amount, get_account_address_as_str(m_wallet->m_wallet->nettype(), d.is_subaddress, d.addr)});
+ ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
}
m_history.push_back(ti);
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 140261f0b..e632b8d23 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1407,8 +1407,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
-PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
- PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
+PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
clearStatus();
@@ -1429,75 +1428,75 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
do {
- if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr)) {
- // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
- setStatusError(tr("Invalid destination address"));
+ std::vector<uint8_t> extra;
+ std::string extra_nonce;
+ vector<cryptonote::tx_destination_entry> dsts;
+ if (!amount && dst_addr.size() > 1) {
+ setStatusError(tr("Sending all requires one destination address"));
break;
}
-
-
- std::vector<uint8_t> extra;
- // if dst_addr is not an integrated address, parse payment_id
- if (!info.has_payment_id && !payment_id.empty()) {
- // copy-pasted from simplewallet.cpp:2212
+ if (amount && (dst_addr.size() != (*amount).size())) {
+ setStatusError(tr("Destinations and amounts are unequal"));
+ break;
+ }
+ if (!payment_id.empty()) {
crypto::hash payment_id_long;
- bool r = tools::wallet2::parse_long_payment_id(payment_id, payment_id_long);
- if (r) {
- std::string extra_nonce;
+ if (tools::wallet2::parse_long_payment_id(payment_id, payment_id_long)) {
cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
} else {
- r = tools::wallet2::parse_short_payment_id(payment_id, info.payment_id);
- if (r) {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- }
- }
-
- if (!r) {
- setStatusError(tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id);
+ setStatusError(tr("payment id has invalid format, expected 64 character hex string: ") + payment_id);
break;
}
}
- else if (info.has_payment_id) {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
- bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- if (!r) {
- setStatusError(tr("Failed to add short payment id: ") + epee::string_tools::pod_to_hex(info.payment_id));
+ bool error = false;
+ for (size_t i = 0; i < dst_addr.size() && !error; i++) {
+ if(!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), dst_addr[i])) {
+ // TODO: copy-paste 'if treating as an address fails, try as url' from simplewallet.cpp:1982
+ setStatusError(tr("Invalid destination address"));
+ error = true;
break;
}
- }
-
-
- //std::vector<tools::wallet2::pending_tx> ptx_vector;
+ if (info.has_payment_id) {
+ if (!extra_nonce.empty()) {
+ setStatusError(tr("a single transaction cannot use more than one payment id"));
+ error = true;
+ break;
+ }
+ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
+ }
- try {
if (amount) {
- vector<cryptonote::tx_destination_entry> dsts;
cryptonote::tx_destination_entry de;
- de.original = dst_addr;
+ de.original = dst_addr[i];
de.addr = info.address;
- de.amount = *amount;
+ de.amount = (*amount)[i];
de.is_subaddress = info.is_subaddress;
de.is_integrated = info.has_payment_id;
dsts.push_back(de);
- transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
- adjusted_priority,
- extra, subaddr_account, subaddr_indices);
} else {
- // for the GUI, sweep_all (i.e. amount set as "(all)") will always sweep all the funds in all the addresses
- if (subaddr_indices.empty())
- {
+ if (subaddr_indices.empty()) {
for (uint32_t index = 0; index < m_wallet->get_num_subaddresses(subaddr_account); ++index)
subaddr_indices.insert(index);
}
+ }
+ }
+ if (error) {
+ break;
+ }
+ if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) {
+ setStatusError(tr("failed to set up payment id, though it was decoded correctly"));
+ break;
+ }
+ try {
+ if (amount) {
+ transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
+ adjusted_priority,
+ extra, subaddr_account, subaddr_indices);
+ } else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
- adjusted_priority,
- extra, subaddr_account, subaddr_indices);
+ adjusted_priority,
+ extra, subaddr_account, subaddr_indices);
}
-
pendingTxPostProcess(transaction);
if (multisig().isMultisig) {
@@ -1574,6 +1573,13 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
return transaction;
}
+PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
+ PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
+
+{
+ return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
+}
+
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
{
@@ -1742,18 +1748,27 @@ std::string WalletImpl::getTxKey(const std::string &txid_str) const
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
- if (m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
+ try
{
clearStatus();
- std::ostringstream oss;
- oss << epee::string_tools::pod_to_hex(tx_key);
- for (size_t i = 0; i < additional_tx_keys.size(); ++i)
- oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
- return oss.str();
+ if (m_wallet->get_tx_key(txid, tx_key, additional_tx_keys))
+ {
+ clearStatus();
+ std::ostringstream oss;
+ oss << epee::string_tools::pod_to_hex(tx_key);
+ for (size_t i = 0; i < additional_tx_keys.size(); ++i)
+ oss << epee::string_tools::pod_to_hex(additional_tx_keys[i]);
+ return oss.str();
+ }
+ else
+ {
+ setStatusError(tr("no tx keys found for this txid"));
+ return "";
+ }
}
- else
+ catch (const std::exception &e)
{
- setStatusError(tr("no tx keys found for this txid"));
+ setStatusError(e.what());
return "";
}
}
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index a367a1917..331bf4b38 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -149,6 +149,11 @@ public:
bool hasMultisigPartialKeyImages() const override;
PendingTransaction* restoreMultisigTransaction(const std::string& signData) override;
+ PendingTransaction * createTransactionMultDest(const std::vector<std::string> &dst_addr, const std::string &payment_id,
+ optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
+ PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
+ uint32_t subaddr_account = 0,
+ std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 9e556cb2f..e543a115b 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -812,6 +812,26 @@ struct Wallet
* @return PendingTransaction
*/
virtual PendingTransaction* restoreMultisigTransaction(const std::string& signData) = 0;
+
+ /*!
+ * \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored
+ * \param dst_addr vector of destination address as string
+ * \param payment_id optional payment_id, can be empty string
+ * \param amount vector of amounts
+ * \param mixin_count mixin count. if 0 passed, wallet will use default value
+ * \param subaddr_account subaddress account from which the input funds are taken
+ * \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
+ * \param priority
+ * \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
+ * after object returned
+ */
+
+ virtual PendingTransaction * createTransactionMultDest(const std::vector<std::string> &dst_addr, const std::string &payment_id,
+ optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
+ PendingTransaction::Priority = PendingTransaction::Priority_Low,
+ uint32_t subaddr_account = 0,
+ std::set<uint32_t> subaddr_indices = {}) = 0;
+
/*!
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
* \param dst_addr destination address as string
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index 7381005c1..96d4ef3ce 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -397,10 +397,9 @@ void message_store::stop_auto_config()
for (uint32_t i = 0; i < m_num_authorized_signers; ++i)
{
authorized_signer &m = m_signers[i];
- if (!m.me && !m.auto_config_transport_address.empty())
+ if (!m.auto_config_transport_address.empty())
{
- // Try to delete those "unused API" addresses in PyBitmessage, especially since
- // it seems it's not possible to delete them interactively, only to "disable" them
+ // Try to delete the chan that was used for auto-config
m_transporter.delete_transport_address(m.auto_config_transport_address);
}
m.auto_config_token.clear();
@@ -429,14 +428,7 @@ void message_store::setup_signer_for_auto_config(uint32_t index, const std::stri
m.auto_config_token = token;
crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key);
crypto::secret_key_to_public_key(m.auto_config_secret_key, m.auto_config_public_key);
- if (receiving)
- {
- m.auto_config_transport_address = m_transporter.derive_and_receive_transport_address(m.auto_config_token);
- }
- else
- {
- m.auto_config_transport_address = m_transporter.derive_transport_address(m.auto_config_token);
- }
+ m.auto_config_transport_address = m_transporter.derive_transport_address(m.auto_config_token);
}
bool message_store::get_signer_index_by_monero_address(const cryptonote::account_public_address &monero_address, uint32_t &index) const
diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp
index 2f8188a3c..cf9b45b37 100644
--- a/src/wallet/message_transporter.cpp
+++ b/src/wallet/message_transporter.cpp
@@ -192,47 +192,47 @@ bool message_transporter::delete_message(const std::string &transport_id)
return true;
}
-// Deterministically derive a transport / Bitmessage address from 'seed' (the 10-hex-digits
-// auto-config token will be used), but do not set it up for receiving in PyBitmessage as
-// well, because it's possible the address will only ever be used to SEND auto-config data
+// Deterministically derive a new transport address from 'seed' (the 10-hex-digits auto-config
+// token will be used) and set it up for sending and receiving
+// In a first attempt a normal Bitmessage address was used here, but it turned out the
+// key exchange necessary to put it into service could take a long time or even did not
+// work out at all sometimes. Also there were problems when deleting those temporary
+// addresses again after auto-config. Now a chan is used which avoids all these drawbacks
+// quite nicely.
std::string message_transporter::derive_transport_address(const std::string &seed)
{
+ // Don't use the seed directly as chan name; that would be too dangerous, e.g. in the
+ // case of a PyBitmessage instance used by multiple unrelated people
+ // If an auto-config token gets hashed in another context use different salt instead of "chan"
+ std::string salted_seed = seed + "chan";
+ std::string chan_name = epee::string_tools::pod_to_hex(crypto::cn_fast_hash(salted_seed.data(), salted_seed.size()));
+
+ // Calculate the Bitmessage address that the chan will get for being able to
+ // use 'joinChain', as 'createChan' will fail and not tell the address if the chan
+ // already exists (which it can if all auto-config participants share a PyBitmessage
+ // instance). 'joinChan' will also fail in that case, but that won't matter.
std::string request;
start_xml_rpc_cmd(request, "getDeterministicAddress");
- add_xml_rpc_base64_param(request, seed);
+ add_xml_rpc_base64_param(request, chan_name);
add_xml_rpc_integer_param(request, 4); // addressVersionNumber
add_xml_rpc_integer_param(request, 1); // streamNumber
end_xml_rpc_cmd(request);
std::string answer;
post_request(request, answer);
std::string address = get_str_between_tags(answer, "<string>", "</string>");
- return address;
-}
-
-// Derive a transport address and configure it for receiving in PyBitmessage, typically
-// for receiving auto-config messages by the wallet of the auto-config organizer
-std::string message_transporter::derive_and_receive_transport_address(const std::string &seed)
-{
- // We need to call both "get_deterministic_address" AND "createDeterministicAddresses"
- // because we won't get back the address from the latter call if it exists already
- std::string address = derive_transport_address(seed);
- std::string request;
- start_xml_rpc_cmd(request, "createDeterministicAddresses");
- add_xml_rpc_base64_param(request, seed);
- add_xml_rpc_integer_param(request, 1); // numberOfAddresses
- add_xml_rpc_integer_param(request, 4); // addressVersionNumber
+ start_xml_rpc_cmd(request, "joinChan");
+ add_xml_rpc_base64_param(request, chan_name);
+ add_xml_rpc_string_param(request, address);
end_xml_rpc_cmd(request);
- std::string answer;
post_request(request, answer);
-
return address;
}
bool message_transporter::delete_transport_address(const std::string &transport_address)
{
std::string request;
- start_xml_rpc_cmd(request, "deleteAddress");
+ start_xml_rpc_cmd(request, "leaveChan");
add_xml_rpc_string_param(request, transport_address);
end_xml_rpc_cmd(request);
std::string answer;
@@ -270,7 +270,22 @@ bool message_transporter::post_request(const std::string &request, std::string &
std::string string_value = get_str_between_tags(answer, "<string>", "</string>");
if ((string_value.find("API Error") == 0) || (string_value.find("RPC ") == 0))
{
- THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value);
+ if ((string_value.find("API Error 0021") == 0) && (request.find("joinChan") != std::string::npos))
+ {
+ // Error that occurs if one tries to join an already joined chan, which can happen
+ // if several auto-config participants share one PyBitmessage instance: As a little
+ // hack simply ignore the error. (A clean solution would be to check for the chan
+ // with 'listAddresses2', but parsing the returned array is much more complicated.)
+ }
+ else if ((string_value.find("API Error 0013") == 0) && (request.find("leaveChan") != std::string::npos))
+ {
+ // Error that occurs if one tries to leave an already left / deleted chan, which can happen
+ // if several auto-config participants share one PyBitmessage instance: Also ignore.
+ }
+ else
+ {
+ THROW_WALLET_EXCEPTION(tools::error::bitmessage_api_error, string_value);
+ }
}
return r;
diff --git a/src/wallet/message_transporter.h b/src/wallet/message_transporter.h
index 736fc9b63..28c099d87 100644
--- a/src/wallet/message_transporter.h
+++ b/src/wallet/message_transporter.h
@@ -91,7 +91,6 @@ public:
bool delete_message(const std::string &transport_id);
void stop() { m_run.store(false, std::memory_order_relaxed); }
std::string derive_transport_address(const std::string &seed);
- std::string derive_and_receive_transport_address(const std::string &seed);
bool delete_transport_address(const std::string &transport_address);
private:
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index f25e9ad97..b89f10eeb 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -40,6 +40,7 @@
#include <boost/asio/ip/address.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/preprocessor/stringize.hpp>
+#include <openssl/evp.h>
#include "include_base_utils.h"
using namespace epee;
@@ -135,9 +136,13 @@ using namespace cryptonote;
#define DEFAULT_MIN_OUTPUT_COUNT 5
#define DEFAULT_MIN_OUTPUT_VALUE (2*COIN)
+#define DEFAULT_INACTIVITY_LOCK_TIMEOUT 90 // a minute and a half
+
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1";
+static const std::string ASCII_OUTPUT_MAGIC = "MoneroAsciiDataV1";
+
namespace
{
std::string get_default_ringdb_path()
@@ -217,6 +222,8 @@ namespace
add_reason(reason, "invalid input");
if (res.invalid_output)
add_reason(reason, "invalid output");
+ if (res.too_few_outputs)
+ add_reason(reason, "too few outputs");
if (res.too_big)
add_reason(reason, "too big");
if (res.overspend)
@@ -273,6 +280,7 @@ struct options {
const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" };
const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false};
const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false};
+ const command_line::arg_descriptor<std::string> extra_entropy = {"extra-entropy", tools::wallet2::tr("File containing extra entropy to initialize the PRNG (any data, aim for 256 bits of entropy to be useful, wihch typically means more than 256 bits of data)")};
};
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
@@ -474,6 +482,15 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (command_line::get_arg(vm, opts.offline))
wallet->set_offline();
+ const std::string extra_entropy = command_line::get_arg(vm, opts.extra_entropy);
+ if (!extra_entropy.empty())
+ {
+ std::string data;
+ THROW_WALLET_EXCEPTION_IF(!epee::file_io_utils::load_file_to_string(extra_entropy, data),
+ tools::error::wallet_internal_error, "Failed to load extra entropy from " + extra_entropy);
+ add_extra_entropy_thread_safe(data.data(), data.size());
+ }
+
try
{
if (!command_line::is_arg_defaulted(vm, opts.tx_notify))
@@ -1112,6 +1129,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_segregation_height(0),
m_ignore_fractional_outputs(true),
m_track_uses(false),
+ m_inactivity_lock_timeout(DEFAULT_INACTIVITY_LOCK_TIMEOUT),
m_setup_background_mining(BackgroundMiningMaybe),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
@@ -1141,7 +1159,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_device_last_key_image_sync(0),
m_use_dns(true),
m_offline(false),
- m_rpc_version(0)
+ m_rpc_version(0),
+ m_export_format(ExportFormat::Binary)
{
}
@@ -1198,6 +1217,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.tx_notify);
command_line::add_arg(desc_params, opts.no_dns);
command_line::add_arg(desc_params, opts.offline);
+ command_line::add_arg(desc_params, opts.extra_entropy);
}
std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -3633,6 +3653,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_track_uses ? 1 : 0);
json.AddMember("track_uses", value2, json.GetAllocator());
+ value2.SetInt(m_inactivity_lock_timeout);
+ json.AddMember("inactivity_lock_timeout", value2, json.GetAllocator());
+
value2.SetInt(m_setup_background_mining);
json.AddMember("setup_background_mining", value2, json.GetAllocator());
@@ -3645,6 +3668,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_original_keys_available ? 1 : 0);
json.AddMember("original_keys_available", value2, json.GetAllocator());
+ value2.SetInt(m_export_format);
+ json.AddMember("export_format", value2, json.GetAllocator());
+
value2.SetUint(1);
json.AddMember("encrypted_secret_keys", value2, json.GetAllocator());
@@ -3682,7 +3708,7 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
std::string tmp_file_name = keys_file_name + ".new";
std::string buf;
r = ::serialization::dump_binary(keys_file_data, buf);
- r = r && epee::file_io_utils::save_string_to_file(tmp_file_name, buf);
+ r = r && save_to_file(tmp_file_name, buf);
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
unlock_keys_file();
@@ -3739,7 +3765,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
wallet2::keys_file_data keys_file_data;
std::string buf;
bool encrypted_secret_keys = false;
- bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
+ bool r = load_from_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
@@ -3752,7 +3778,6 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject())
crypto::chacha8(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]);
-
// The contents should be JSON if the wallet follows the new format.
if (json.Parse(account_data.c_str()).HasParseError())
{
@@ -3787,10 +3812,12 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
m_track_uses = false;
+ m_inactivity_lock_timeout = DEFAULT_INACTIVITY_LOCK_TIMEOUT;
m_setup_background_mining = BackgroundMiningMaybe;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
+ m_export_format = ExportFormat::Binary;
m_device_name = "";
m_device_derivation_path = "";
m_key_device_type = hw::device::device_type::SOFTWARE;
@@ -3942,6 +3969,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
m_track_uses = field_track_uses;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, inactivity_lock_timeout, uint32_t, Uint, false, DEFAULT_INACTIVITY_LOCK_TIMEOUT);
+ m_inactivity_lock_timeout = field_inactivity_lock_timeout;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, setup_background_mining, BackgroundMiningSetupType, Int, false, BackgroundMiningMaybe);
m_setup_background_mining = field_setup_background_mining;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
@@ -3952,6 +3981,9 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, encrypted_secret_keys, uint32_t, Uint, false, false);
encrypted_secret_keys = field_encrypted_secret_keys;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, export_format, ExportFormat, Int, false, Binary);
+ m_export_format = field_export_format;
+
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string());
if (m_device_name.empty())
{
@@ -4099,7 +4131,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
wallet2::keys_file_data keys_file_data;
std::string buf;
bool encrypted_secret_keys = false;
- bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
+ bool r = load_from_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
@@ -4184,7 +4216,7 @@ void wallet2::create_keys_file(const std::string &wallet_, bool watch_only, cons
if (create_address_file)
{
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
+ r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true);
if(!r) MERROR("String with address text not saved");
}
}
@@ -4206,7 +4238,7 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri
rapidjson::Document json;
wallet2::keys_file_data keys_file_data;
std::string buf;
- bool r = epee::file_io_utils::load_file_to_string(keys_file_name, buf);
+ bool r = load_from_file(keys_file_name, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
@@ -4755,7 +4787,7 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
{
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
+ r = save_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype), true);
if(!r) MERROR("String with address text not saved");
}
}
@@ -5264,7 +5296,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
wallet2::cache_file_data cache_file_data;
std::string buf;
- bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf, std::numeric_limits<size_t>::max());
+ bool r = load_from_file(m_wallet_file, buf, std::numeric_limits<size_t>::max());
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
// try to read it as an encrypted cache
@@ -5499,7 +5531,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
{
// save address to the new file
const std::string address_file = m_wallet_file + ".address.txt";
- r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_nettype));
+ r = save_to_file(address_file, m_account.get_public_address_str(m_nettype), true);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
}
// remove old wallet file
@@ -5534,7 +5566,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
binary_archive<true> oar(oss);
bool success = ::serialization::serialize(oar, cache_file_data);
if (success) {
- success = epee::file_io_utils::save_string_to_file(new_file, oss.str());
+ success = save_to_file(new_file, oss.str());
}
THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file);
#else
@@ -6123,7 +6155,7 @@ void wallet2::commit_tx(pending_tx& ptx)
amount_in += m_transfers[idx].amount();
}
add_unconfirmed_tx(ptx.tx, amount_in, dests, payment_id, ptx.change_dts.amount, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices);
- if (store_tx_info())
+ if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
m_tx_keys.insert(std::make_pair(txid, ptx.tx_key));
m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys));
@@ -6162,7 +6194,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
std::string ciphertext = dump_tx_to_str(ptx_vector);
if (ciphertext.empty())
return false;
- return epee::file_io_utils::save_string_to_file(filename, ciphertext);
+ return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) const
@@ -6204,7 +6236,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx
LOG_PRINT_L0("File " << unsigned_filename << " does not exist: " << errcode);
return false;
}
- if (!epee::file_io_utils::load_file_to_string(unsigned_filename.c_str(), s))
+ if (!load_from_file(unsigned_filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << unsigned_filename);
return false;
@@ -6312,7 +6344,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
// normally, the tx keys are saved in commit_tx, when the tx is actually sent to the daemon.
// we can't do that here since the tx will be sent from the compromised wallet, which we don't want
// to see that info, so we save it here
- if (store_tx_info())
+ if (store_tx_info() && ptx.tx_key != crypto::null_skey)
{
const crypto::hash txid = get_transaction_hash(ptx.tx);
m_tx_keys.insert(std::make_pair(txid, tx_key));
@@ -6425,7 +6457,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
return false;
}
- if (!epee::file_io_utils::save_string_to_file(signed_filename, ciphertext))
+ if (!save_to_file(signed_filename, ciphertext))
{
LOG_PRINT_L0("Failed to save file to " << signed_filename);
return false;
@@ -6437,7 +6469,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f
{
std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx));
std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i)));
- if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex))
+ if (!save_to_file(raw_filename, tx_as_hex))
{
LOG_PRINT_L0("Failed to save file to " << raw_filename);
return false;
@@ -6485,7 +6517,7 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return false;
}
- if (!epee::file_io_utils::load_file_to_string(signed_filename.c_str(), s))
+ if (!load_from_file(signed_filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << signed_filename);
return false;
@@ -6616,7 +6648,7 @@ bool wallet2::save_multisig_tx(const multisig_tx_set &txs, const std::string &fi
std::string ciphertext = save_multisig_tx(txs);
if (ciphertext.empty())
return false;
- return epee::file_io_utils::save_string_to_file(filename, ciphertext);
+ return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
wallet2::multisig_tx_set wallet2::make_multisig_tx_set(const std::vector<pending_tx>& ptx_vector) const
@@ -6644,7 +6676,7 @@ bool wallet2::save_multisig_tx(const std::vector<pending_tx>& ptx_vector, const
std::string ciphertext = save_multisig_tx(ptx_vector);
if (ciphertext.empty())
return false;
- return epee::file_io_utils::save_string_to_file(filename, ciphertext);
+ return save_to_file(filename, ciphertext);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const
@@ -6735,7 +6767,7 @@ bool wallet2::load_multisig_tx_from_file(const std::string &filename, multisig_t
LOG_PRINT_L0("File " << filename << " does not exist: " << errcode);
return false;
}
- if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s))
+ if (!load_from_file(filename.c_str(), s))
{
LOG_PRINT_L0("Failed to load from " << filename);
return false;
@@ -7448,7 +7480,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
order.resize(light_wallet_requested_outputs_count);
for (size_t n = 0; n < order.size(); ++n)
order[n] = n;
- std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>()));
+ std::shuffle(order.begin(), order.end(), crypto::random_device{});
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs with amounts " << print_money(td.is_rct() ? 0 : td.amount()));
@@ -8023,7 +8055,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
order.resize(requested_outputs_count);
for (size_t n = 0; n < order.size(); ++n)
order[n] = n;
- std::shuffle(order.begin(), order.end(), std::default_random_engine(crypto::rand<unsigned>()));
+ std::shuffle(order.begin(), order.end(), crypto::random_device{});
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs of size " << print_money(td.is_rct() ? 0 : td.amount()));
for (size_t o = 0; o < requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
@@ -8165,6 +8197,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
if (needed_money < found_money)
{
change_dts.addr = get_subaddress({subaddr_account, 0});
+ change_dts.is_subaddress = subaddr_account != 0;
change_dts.amount = found_money - needed_money;
}
@@ -10308,6 +10341,8 @@ bool wallet2::get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx
if (i == m_tx_keys.end())
return false;
tx_key = i->second;
+ if (tx_key == crypto::null_skey)
+ return false;
const auto j = m_additional_tx_keys.find(txid);
if (j != m_additional_tx_keys.end())
additional_tx_keys = j->second;
@@ -10319,6 +10354,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
bool r = get_tx_key_cached(txid, tx_key, additional_tx_keys);
if (r)
{
+ MDEBUG("tx key cached for txid: " << txid);
return true;
}
@@ -10380,13 +10416,18 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
dev_cold->get_tx_key(tx_keys, tx_key_data, m_account.get_keys().m_view_secret_key);
if (tx_keys.empty())
{
+ MDEBUG("Empty tx keys for txid: " << txid);
+ return false;
+ }
+
+ if (tx_keys[0] == crypto::null_skey)
+ {
return false;
}
tx_key = tx_keys[0];
tx_keys.erase(tx_keys.begin());
additional_tx_keys = tx_keys;
-
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -11596,10 +11637,10 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
return tx_pub_key;
}
-bool wallet2::export_key_images(const std::string &filename) const
+bool wallet2::export_key_images(const std::string &filename, bool all) const
{
PERF_TIMER(export_key_images);
- std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images();
+ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all);
std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
const uint32_t offset = ski.first;
@@ -11622,7 +11663,7 @@ bool wallet2::export_key_images(const std::string &filename) const
// encrypt data, keep magic plaintext
PERF_TIMER(export_key_images_encrypt);
std::string ciphertext = encrypt_with_view_secret_key(data);
- return epee::file_io_utils::save_string_to_file(filename, magic + ciphertext);
+ return save_to_file(filename, magic + ciphertext);
}
//----------------------------------------------------------------------------------------------------
@@ -11687,7 +11728,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
{
PERF_TIMER(import_key_images_fsu);
std::string data;
- bool r = epee::file_io_utils::load_file_to_string(filename, data);
+ bool r = load_from_file(filename, data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, std::string(tr("failed to read file ")) + filename);
@@ -13091,6 +13132,83 @@ void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &st
THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error");
}
//----------------------------------------------------------------------------------------------------
+
+bool wallet2::save_to_file(const std::string& path_to_file, const std::string& raw, bool is_printable) const
+{
+ if (is_printable || m_export_format == ExportFormat::Binary)
+ {
+ return epee::file_io_utils::save_string_to_file(path_to_file, raw);
+ }
+
+ FILE *fp = fopen(path_to_file.c_str(), "w+");
+ // Save the result b/c we need to close the fp before returning success/failure.
+ int write_result = PEM_write(fp, ASCII_OUTPUT_MAGIC.c_str(), "", (const unsigned char *) raw.c_str(), raw.length());
+ fclose(fp);
+
+ if (write_result == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+//----------------------------------------------------------------------------------------------------
+
+bool wallet2::load_from_file(const std::string& path_to_file, std::string& target_str,
+ size_t max_size)
+{
+ std::string data;
+ bool r = epee::file_io_utils::load_file_to_string(path_to_file, data, max_size);
+ if (!r)
+ {
+ return false;
+ }
+
+ if (!boost::algorithm::contains(boost::make_iterator_range(data.begin(), data.end()), ASCII_OUTPUT_MAGIC))
+ {
+ // It's NOT our ascii dump.
+ target_str = std::move(data);
+ return true;
+ }
+
+ // Creating a BIO and calling PEM_read_bio instead of simpler PEM_read
+ // to avoid reading the file from disk twice.
+ BIO* b = BIO_new_mem_buf((const void*) data.data(), data.length());
+
+ char *name = NULL;
+ char *header = NULL;
+ unsigned char *openssl_data = NULL;
+ long len = 0;
+
+ // Save the result b/c we need to free the data before returning success/failure.
+ int success = PEM_read_bio(b, &name, &header, &openssl_data, &len);
+
+ try
+ {
+ target_str = std::string((const char*) openssl_data, len);
+ }
+ catch (...)
+ {
+ success = 0;
+ }
+
+ OPENSSL_free((void *) name);
+ OPENSSL_free((void *) header);
+ OPENSSL_free((void *) openssl_data);
+ BIO_free(b);
+
+ if (success == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::hash_m_transfer(const transfer_details & transfer, crypto::hash &hash) const
{
KECCAK_CTX state;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index a6d042297..5607602e7 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -227,6 +227,11 @@ private:
BackgroundMiningNo = 2,
};
+ enum ExportFormat {
+ Binary = 0,
+ Ascii,
+ };
+
static const char* tr(const char* str);
static bool has_testnet_option(const boost::program_options::variables_map& vm);
@@ -1046,10 +1051,14 @@ private:
void track_uses(bool value) { m_track_uses = value; }
BackgroundMiningSetupType setup_background_mining() const { return m_setup_background_mining; }
void setup_background_mining(BackgroundMiningSetupType value) { m_setup_background_mining = value; }
+ uint32_t inactivity_lock_timeout() const { return m_inactivity_lock_timeout; }
+ void inactivity_lock_timeout(uint32_t seconds) { m_inactivity_lock_timeout = seconds; }
const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
void device_derivation_path(const std::string &device_derivation_path) { m_device_derivation_path = device_derivation_path; }
+ const ExportFormat & export_format() const { return m_export_format; }
+ inline void set_export_format(const ExportFormat& export_format) { m_export_format = export_format; }
bool get_tx_key_cached(const crypto::hash &txid, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys) const;
void set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys);
@@ -1175,7 +1184,7 @@ private:
void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
- bool export_key_images(const std::string &filename) const;
+ bool export_key_images(const std::string &filename, bool all = false) const;
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
@@ -1300,6 +1309,9 @@ private:
bool frozen(const crypto::key_image &ki) const;
bool frozen(const transfer_details &td) const;
+ bool save_to_file(const std::string& path_to_file, const std::string& binary, bool is_printable = false) const;
+ static bool load_from_file(const std::string& path_to_file, std::string& target_str, size_t max_size = 1000000000);
+
uint64_t get_bytes_sent() const;
uint64_t get_bytes_received() const;
@@ -1496,6 +1508,7 @@ private:
uint64_t m_segregation_height;
bool m_ignore_fractional_outputs;
bool m_track_uses;
+ uint32_t m_inactivity_lock_timeout;
BackgroundMiningSetupType m_setup_background_mining;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
@@ -1546,6 +1559,8 @@ private:
std::shared_ptr<tools::Notify> m_tx_notify;
std::unique_ptr<wallet_device_callback> m_device_callback;
+
+ ExportFormat m_export_format;
};
}
BOOST_CLASS_VERSION(tools::wallet2, 28)
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index a4bb342ca..9da9d109c 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -206,7 +206,10 @@ namespace wallet_args
if (!command_line::is_arg_defaulted(vm, arg_log_level))
MINFO("Setting log level = " << command_line::get_arg(vm, arg_log_level));
else
- MINFO("Setting log levels = " << getenv("MONERO_LOGS"));
+ {
+ const char *logs = getenv("MONERO_LOGS");
+ MINFO("Setting log levels = " << (logs ? logs : "<default>"));
+ }
MINFO(wallet_args::tr("Logging to: ") << log_path);
Print(print) << boost::format(wallet_args::tr("Logging to %s")) % log_path;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 9d3605d11..7c87e7114 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -36,6 +36,7 @@
#include "include_base_utils.h"
using namespace epee;
+#include "version.h"
#include "wallet_rpc_server.h"
#include "wallet/wallet_args.h"
#include "common/command_line.h"
@@ -247,7 +248,9 @@ namespace tools
m_net_server.set_threads_prefix("RPC");
auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
- rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login),
+ rng, std::move(bind_port), std::move(rpc_config->bind_ip),
+ std::move(rpc_config->bind_ipv6_address), std::move(rpc_config->use_ipv6), std::move(rpc_config->require_ipv4),
+ std::move(rpc_config->access_control_origins), std::move(http_login),
std::move(rpc_config->ssl_options)
);
}
@@ -350,7 +353,7 @@ namespace tools
entry.destinations.push_back(wallet_rpc::transfer_destination());
wallet_rpc::transfer_destination &td = entry.destinations.back();
td.amount = d.amount;
- td.address = d.original.empty() ? get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) : d.original;
+ td.address = d.address(m_wallet->nettype(), pd.m_payment_id);
}
entry.type = "out";
@@ -380,7 +383,7 @@ namespace tools
entry.destinations.push_back(wallet_rpc::transfer_destination());
wallet_rpc::transfer_destination &td = entry.destinations.back();
td.amount = d.amount;
- td.address = d.original.empty() ? get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) : d.original;
+ td.address = d.address(m_wallet->nettype(), pd.m_payment_id);
}
entry.type = is_failed ? "failed" : "pending";
@@ -4089,9 +4092,8 @@ namespace tools
}
}
- er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
- er.message = std::string("Invalid address");
- return false;
+ res.valid = false;
+ return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_set_daemon(const wallet_rpc::COMMAND_RPC_SET_DAEMON::request& req, wallet_rpc::COMMAND_RPC_SET_DAEMON::response& res, epee::json_rpc::error& er, const connection_context *ctx)
@@ -4187,6 +4189,7 @@ namespace tools
bool wallet_rpc_server::on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
res.version = WALLET_RPC_VERSION;
+ res.release = MONERO_VERSION_IS_RELEASE;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 4504ac752..2dfe6db85 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 13
+#define WALLET_RPC_VERSION_MINOR 14
#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)
namespace tools
@@ -2418,9 +2418,11 @@ namespace wallet_rpc
struct response_t
{
uint32_t version;
+ bool release;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(version)
+ KV_SERIALIZE(release)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;