aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp2
-rw-r--r--src/wallet/wallet2.cpp44
-rw-r--r--src/wallet/wallet2.h2
-rw-r--r--src/wallet/wallet_rpc_server.cpp81
4 files changed, 63 insertions, 66 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 032b873d6..1711db482 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -157,7 +157,7 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
}
}
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time)
{
std::string tx_hash = epee::string_tools::pod_to_hex(txid);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index c222c3115..d14cec4cc 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -39,6 +39,7 @@
#include <boost/algorithm/string/join.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/range/adaptor/transformed.hpp>
+#include <boost/preprocessor/stringize.hpp>
#include "include_base_utils.h"
using namespace epee;
@@ -131,6 +132,9 @@ using namespace cryptonote;
#define GAMMA_SHAPE 19.28
#define GAMMA_SCALE (1/1.61)
+#define DEFAULT_MIN_OUTPUT_COUNT 5
+#define DEFAULT_MIN_OUTPUT_VALUE (2*COIN)
+
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
static const std::string MULTISIG_EXTRA_INFO_MAGIC = "MultisigxV1";
@@ -340,6 +344,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
{
std::vector<std::vector<uint8_t>> ssl_allowed_fingerprints{ daemon_ssl_allowed_fingerprints.size() };
std::transform(daemon_ssl_allowed_fingerprints.begin(), daemon_ssl_allowed_fingerprints.end(), ssl_allowed_fingerprints.begin(), epee::from_hex::vector);
+ for (const auto &fpr: ssl_allowed_fingerprints)
+ {
+ THROW_WALLET_EXCEPTION_IF(fpr.size() != SSL_FINGERPRINT_SIZE, tools::error::wallet_internal_error,
+ "SHA-256 fingerprint should be " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes long.");
+ }
ssl_options = epee::net_utils::ssl_options_t{
std::move(ssl_allowed_fingerprints), std::move(daemon_ssl_ca_file)
@@ -390,8 +399,11 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
{
const boost::string_ref real_daemon = boost::string_ref{daemon_address}.substr(0, daemon_address.rfind(':'));
+ /* If SSL or proxy is enabled, then a specific cert, CA or fingerprint must
+ be specified. This is specific to the wallet. */
const bool verification_required =
- ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy;
+ ssl_options.verification != epee::net_utils::ssl_verification_t::none &&
+ (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || use_proxy);
THROW_WALLET_EXCEPTION_IF(
verification_required && !ssl_options.has_strong_verification(real_daemon),
@@ -994,7 +1006,7 @@ uint64_t gamma_picker::pick()
const uint64_t n_rct = rct_offsets[index] - first_rct;
if (n_rct == 0)
return std::numeric_limits<uint64_t>::max(); // bad pick
- MDEBUG("Picking 1/" << n_rct << " in block " << index);
+ MTRACE("Picking 1/" << n_rct << " in block " << index);
return first_rct + crypto::rand_idx(n_rct);
};
@@ -2007,7 +2019,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
+ m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, td.m_tx.unlock_time);
}
total_received_1 += amount;
notify = true;
@@ -2077,7 +2089,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
- m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index);
+ m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, td.m_tx.unlock_time);
}
total_received_1 += extra_amount;
notify = true;
@@ -7750,7 +7762,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
}
- if (num_outs <= requested_outputs_count && !existing_ring_found)
+ if (num_outs <= requested_outputs_count)
{
for (uint64_t i = 0; i < num_outs; i++)
req.outputs.push_back({amount, i});
@@ -7776,6 +7788,8 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// while we still need more mixins
uint64_t num_usable_outs = num_outs;
bool allow_blackballed = false;
+ MDEBUG("Starting gamma picking with " << num_outs << ", num_usable_outs " << num_usable_outs
+ << ", requested_outputs_count " << requested_outputs_count);
while (num_found < requested_outputs_count)
{
// if we've gone through every possible output, we've gotten all we can
@@ -7875,6 +7889,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
picks[type].insert(i);
req.outputs.push_back({amount, i});
++num_found;
+ MDEBUG("picked " << i << ", " << num_found << " now picked");
}
for (const auto &pick: picks)
@@ -9372,9 +9387,16 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
idx = pop_best_value(indices, tx.selected_transfers, true);
// we might not want to add it if it's a large output and we don't have many left
- if (m_transfers[idx].amount() >= m_min_output_value) {
- if (get_count_above(m_transfers, *unused_transfers_indices, m_min_output_value) < m_min_output_count) {
- LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_money(m_min_output_value) << ", not adding");
+ uint64_t min_output_value = m_min_output_value;
+ uint32_t min_output_count = m_min_output_count;
+ if (min_output_value == 0 && min_output_count == 0)
+ {
+ min_output_value = DEFAULT_MIN_OUTPUT_VALUE;
+ min_output_count = DEFAULT_MIN_OUTPUT_COUNT;
+ }
+ if (m_transfers[idx].amount() >= min_output_value) {
+ if (get_count_above(m_transfers, *unused_transfers_indices, min_output_value) < min_output_count) {
+ LOG_PRINT_L2("Second output was not strictly needed, and we're running out of outputs above " << print_money(min_output_value) << ", not adding");
break;
}
}
@@ -12607,8 +12629,7 @@ std::string wallet2::make_uri(const std::string &address, const std::string &pay
if (!payment_id.empty())
{
crypto::hash pid32;
- crypto::hash8 pid8;
- if (!wallet2::parse_long_payment_id(payment_id, pid32) && !wallet2::parse_short_payment_id(payment_id, pid8))
+ if (!wallet2::parse_long_payment_id(payment_id, pid32))
{
error = "Invalid payment id";
return std::string();
@@ -12702,8 +12723,7 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin
return false;
}
crypto::hash hash;
- crypto::hash8 hash8;
- if (!wallet2::parse_long_payment_id(kv[1], hash) && !wallet2::parse_short_payment_id(kv[1], hash8))
+ if (!wallet2::parse_long_payment_id(kv[1], hash))
{
error = "Invalid payment id: " + kv[1];
return false;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index d101e87f5..921c150cb 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -118,7 +118,7 @@ private:
public:
// Full wallet callbacks
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
- virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
+ virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index, uint64_t unlock_time) {}
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {}
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) {}
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 4076ae957..47235dc44 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -31,6 +31,7 @@
#include <boost/asio/ip/address.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/preprocessor/stringize.hpp>
#include <cstdint>
#include "include_base_utils.h"
using namespace epee;
@@ -65,11 +66,6 @@ namespace
const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false};
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl = {"rpc-ssl", tools::wallet2::tr("Enable SSL on wallet RPC connections: enabled|disabled|autodetect"), "autodetect"};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_private_key = {"rpc-ssl-private-key", tools::wallet2::tr("Path to a PEM format private key"), ""};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_certificate = {"rpc-ssl-certificate", tools::wallet2::tr("Path to a PEM format certificate"), ""};
- const command_line::arg_descriptor<std::string> arg_rpc_ssl_ca_certificates = {"rpc-ssl-ca-certificates", tools::wallet2::tr("Path to file containing concatenated PEM format certificate(s) to replace system CA(s).")};
- const command_line::arg_descriptor<std::vector<std::string>> arg_rpc_ssl_allowed_fingerprints = {"rpc-ssl-allowed-fingerprints", tools::wallet2::tr("List of certificate fingerprints to allow")};
constexpr const char default_rpc_username[] = "monero";
@@ -243,37 +239,6 @@ namespace tools
assert(bool(http_login));
} // end auth enabled
- auto rpc_ssl_private_key = command_line::get_arg(vm, arg_rpc_ssl_private_key);
- auto rpc_ssl_certificate = command_line::get_arg(vm, arg_rpc_ssl_certificate);
- auto rpc_ssl_ca_file = command_line::get_arg(vm, arg_rpc_ssl_ca_certificates);
- auto rpc_ssl_allowed_fingerprints = command_line::get_arg(vm, arg_rpc_ssl_allowed_fingerprints);
- auto rpc_ssl = command_line::get_arg(vm, arg_rpc_ssl);
- epee::net_utils::ssl_options_t rpc_ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
-
- if (!rpc_ssl_ca_file.empty() || !rpc_ssl_allowed_fingerprints.empty())
- {
- std::vector<std::vector<uint8_t>> allowed_fingerprints{ rpc_ssl_allowed_fingerprints.size() };
- std::transform(rpc_ssl_allowed_fingerprints.begin(), rpc_ssl_allowed_fingerprints.end(), allowed_fingerprints.begin(), epee::from_hex::vector);
-
- rpc_ssl_options = epee::net_utils::ssl_options_t{
- std::move(allowed_fingerprints), std::move(rpc_ssl_ca_file)
- };
- }
-
- // user specified CA file or fingeprints implies enabled SSL by default
- if (rpc_ssl_options.verification != epee::net_utils::ssl_verification_t::user_certificates || !command_line::is_arg_defaulted(vm, arg_rpc_ssl))
- {
- if (!epee::net_utils::ssl_support_from_string(rpc_ssl_options.support, rpc_ssl))
- {
- MERROR("Invalid argument for " << std::string(arg_rpc_ssl.name));
- return false;
- }
- }
-
- rpc_ssl_options.auth = epee::net_utils::ssl_authentication_t{
- std::move(rpc_ssl_private_key), std::move(rpc_ssl_certificate)
- };
-
m_auto_refresh_period = DEFAULT_AUTO_REFRESH_PERIOD;
m_last_auto_refresh_time = boost::posix_time::min_date_time;
@@ -283,7 +248,7 @@ namespace tools
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),
- std::move(rpc_ssl_options)
+ std::move(rpc_config->ssl_options)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -385,7 +350,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 = get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr);
+ td.address = d.original.empty() ? get_account_address_as_str(m_wallet->nettype(), d.is_subaddress, d.addr) : d.original;
}
entry.type = "out";
@@ -410,6 +375,14 @@ namespace tools
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
entry.unlock_time = pd.m_tx.unlock_time;
entry.note = m_wallet->get_tx_note(txid);
+
+ for (const auto &d: pd.m_dests) {
+ 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;
+ }
+
entry.type = is_failed ? "failed" : "pending";
entry.subaddr_index = { pd.m_subaddr_account, 0 };
for (uint32_t i: pd.m_subaddr_indices)
@@ -1772,6 +1745,11 @@ namespace tools
else if (payment_id_str.size() == 2 * sizeof(payment_id8))
{
r = epee::string_tools::hex_to_pod(payment_id_str, payment_id8);
+ if (r)
+ {
+ memcpy(payment_id.data, payment_id8.data, 8);
+ memset(payment_id.data + 8, 0, 24);
+ }
}
else
{
@@ -1833,14 +1811,12 @@ namespace tools
wallet2::transfer_container transfers;
m_wallet->get_transfers(transfers);
- bool transfers_found = false;
for (const auto& td : transfers)
{
if (!filter || available != td.m_spent)
{
if (req.account_index != td.m_subaddr_index.major || (!req.subaddr_indices.empty() && req.subaddr_indices.count(td.m_subaddr_index.minor) == 0))
continue;
- transfers_found = true;
wallet_rpc::transfer_details rpc_transfers;
rpc_transfers.amount = td.amount();
rpc_transfers.spent = td.m_spent;
@@ -2805,20 +2781,20 @@ namespace tools
}
crypto::hash long_payment_id;
- crypto::hash8 short_payment_id;
if (!wallet2::parse_long_payment_id(req.payment_id, payment_id))
{
if (!wallet2::parse_short_payment_id(req.payment_id, info.payment_id))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
- er.message = "Payment id has invalid format: \"" + req.payment_id + "\", expected 16 or 64 character string";
+ er.message = "Payment id has invalid format: \"" + req.payment_id + "\", expected 64 character string";
return false;
}
else
{
- memcpy(payment_id.data, info.payment_id.data, 8);
- memset(payment_id.data + 8, 0, 24);
+ er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
+ er.message = "Payment id has invalid format: standalone short payment IDs are forbidden, they must be part of an integrated address";
+ return false;
}
}
}
@@ -4069,9 +4045,10 @@ namespace tools
{ cryptonote::TESTNET, "testnet" },
{ cryptonote::STAGENET, "stagenet" },
};
+ if (!req.any_net_type && !m_wallet) return not_open(er);
for (const auto &net_type: net_types)
{
- if (!req.any_net_type && net_type.type != m_wallet->nettype())
+ if (!req.any_net_type && (!m_wallet || net_type.type != m_wallet->nettype()))
continue;
if (req.allow_openalias)
{
@@ -4149,10 +4126,15 @@ namespace tools
std::move(req.ssl_private_key_path), std::move(req.ssl_certificate_path)
};
- if (ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled && !ssl_options.has_strong_verification(boost::string_ref{}))
+ const bool verification_required =
+ ssl_options.verification != epee::net_utils::ssl_verification_t::none &&
+ ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled;
+
+ if (verification_required && !ssl_options.has_strong_verification(boost::string_ref{}))
{
er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
er.message = "SSL is enabled but no user certificate or fingerprints were provided";
+ return false;
}
if (!m_wallet->set_daemon(req.address, boost::none, req.trusted, std::move(ssl_options)))
@@ -4177,7 +4159,7 @@ namespace tools
{
er.code = WALLET_RPC_ERROR_CODE_INVALID_LOG_LEVEL;
er.message = "Error: log level not valid";
- return true;
+ return false;
}
mlog_set_log_level(req.level);
return true;
@@ -4393,11 +4375,6 @@ int main(int argc, char** argv) {
command_line::add_arg(desc_params, arg_from_json);
command_line::add_arg(desc_params, arg_wallet_dir);
command_line::add_arg(desc_params, arg_prompt_for_password);
- command_line::add_arg(desc_params, arg_rpc_ssl);
- command_line::add_arg(desc_params, arg_rpc_ssl_private_key);
- command_line::add_arg(desc_params, arg_rpc_ssl_certificate);
- command_line::add_arg(desc_params, arg_rpc_ssl_ca_certificates);
- command_line::add_arg(desc_params, arg_rpc_ssl_allowed_fingerprints);
daemonizer::init_options(hidden_options, desc_params);
desc_params.add(hidden_options);