aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp6
-rw-r--r--src/blockchain_utilities/CMakeLists.txt2
-rw-r--r--src/cryptonote_config.h2
-rw-r--r--src/cryptonote_core/blockchain.cpp35
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp10
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h4
-rw-r--r--src/daemon/command_parser_executor.cpp19
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp42
-rw-r--r--src/daemon/rpc_command_executor.h2
-rwxr-xr-x[-rw-r--r--]src/rpc/core_rpc_server.cpp2
-rw-r--r--src/rpc/message.cpp53
-rwxr-xr-x[-rw-r--r--]src/rpc/rpc_args.cpp18
-rwxr-xr-x[-rw-r--r--]src/rpc/rpc_args.h2
-rw-r--r--src/simplewallet/simplewallet.cpp74
-rw-r--r--src/wallet/api/wallet.cpp25
-rw-r--r--src/wallet/api/wallet.h12
-rw-r--r--src/wallet/wallet2.cpp37
-rw-r--r--src/wallet/wallet2.h23
-rw-r--r--src/wallet/wallet2_api.h12
-rw-r--r--src/wallet/wallet_errors.h35
-rwxr-xr-x[-rw-r--r--]src/wallet/wallet_rpc_server.cpp189
-rw-r--r--src/wallet/wallet_rpc_server.h1
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h8
24 files changed, 401 insertions, 214 deletions
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 3979a5edf..5bd02bcf7 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1123,6 +1123,12 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
m_folder = filename;
+#ifdef __OpenBSD__
+ if ((mdb_flags & MDB_WRITEMAP) == 0) {
+ MCLOG_RED(el::Level::Info, "global", "Running on OpenBSD: forcing WRITEMAP");
+ mdb_flags |= MDB_WRITEMAP;
+ }
+#endif
// set up lmdb environment
if ((result = mdb_env_create(&m_env)))
throw0(DB_ERROR(lmdb_error("Failed to create lmdb environment: ", result).c_str()));
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index 0eaf71084..bd32e0c55 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -93,6 +93,7 @@ endif()
set_property(TARGET blockchain_import
PROPERTY
OUTPUT_NAME "monero-blockchain-import")
+install(TARGETS blockchain_import DESTINATION bin)
monero_add_executable(blockchain_export
${blockchain_export_sources}
@@ -114,4 +115,5 @@ target_link_libraries(blockchain_export
set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
+install(TARGETS blockchain_export DESTINATION bin)
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 5a61fc78c..e38e15cb2 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -150,7 +150,7 @@ namespace config
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
- uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 26;
+ uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 42;
uint16_t const P2P_DEFAULT_PORT = 18080;
uint16_t const RPC_DEFAULT_PORT = 18081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 18082;
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 933914363..9d89c6280 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -139,14 +139,20 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
bool Blockchain::have_tx(const crypto::hash &id) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
return m_db->tx_exists(id);
}
//------------------------------------------------------------------
bool Blockchain::have_tx_keyimg_as_spent(const crypto::key_image &key_im) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
return m_db->has_key_image(key_im);
}
//------------------------------------------------------------------
@@ -287,7 +293,10 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const txin_to_ke
uint64_t Blockchain::get_current_blockchain_height() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
return m_db->height();
}
//------------------------------------------------------------------
@@ -571,7 +580,10 @@ crypto::hash Blockchain::get_tail_id(uint64_t& height) const
crypto::hash Blockchain::get_tail_id() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
return m_db->top_block_hash();
}
//------------------------------------------------------------------
@@ -633,7 +645,10 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
try
{
return m_db->get_block_hash_from_height(height);
@@ -1928,7 +1943,10 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
uint64_t Blockchain::block_difficulty(uint64_t i) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
try
{
return m_db->get_block_difficulty(i);
@@ -2209,7 +2227,10 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_
size_t Blockchain::get_total_transactions() const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
+ // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
+ // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
+ // lock if it is otherwise needed.
return m_db->get_tx_count();
}
//------------------------------------------------------------------
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 586df9079..96f6ee872 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -158,7 +158,7 @@ namespace cryptonote
return destinations[0].addr.m_view_public_key;
}
//---------------------------------------------------------------
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const cryptonote::account_public_address& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct)
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct)
{
if (destinations.empty())
{
@@ -301,7 +301,7 @@ namespace cryptonote
account_public_address single_dest_subaddress;
for(const tx_destination_entry& dst_entr: destinations)
{
- if (dst_entr.addr == change_addr)
+ if (change_addr && dst_entr.addr == *change_addr)
continue;
if (unique_dst_addresses.count(dst_entr.addr) == 0)
{
@@ -354,7 +354,7 @@ namespace cryptonote
}
bool r;
- if (dst_entr.addr == change_addr)
+ if (change_addr && dst_entr.addr == *change_addr)
{
// sending change to yourself; derivation = a*R
r = crypto::generate_key_derivation(txkey.pub, sender_account_keys.m_view_secret_key, derivation);
@@ -565,13 +565,13 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
+ bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
{
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
- return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations, destinations.back().addr, extra, tx, unlock_time, tx_key, additional_tx_keys);
+ return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys);
}
//---------------------------------------------------------------
bool generate_genesis_block(
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index b5de44b88..9a3b2484d 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -73,8 +73,8 @@ namespace cryptonote
//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
- bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const cryptonote::account_public_address& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false);
+ bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false);
bool generate_genesis_block(
block& bl
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index c85e5edb5..5307b2472 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -187,9 +187,24 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
bool t_command_parser_executor::print_transaction(const std::vector<std::string>& args)
{
+ bool include_hex = false;
+ bool include_json = false;
+
+ // Assumes that optional flags come after mandatory argument <transaction_hash>
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "+hex")
+ include_hex = true;
+ else if (args[i] == "+json")
+ include_json = true;
+ else
+ {
+ std::cout << "unexpected argument: " << args[i] << std::endl;
+ return true;
+ }
+ }
if (args.empty())
{
- std::cout << "expected: print_tx <transaction hash>" << std::endl;
+ std::cout << "expected: print_tx <transaction_hash> [+hex] [+json]" << std::endl;
return true;
}
@@ -197,7 +212,7 @@ bool t_command_parser_executor::print_transaction(const std::vector<std::string>
crypto::hash tx_hash;
if (parse_hash256(str_hash, tx_hash))
{
- m_executor.print_transaction(tx_hash);
+ m_executor.print_transaction(tx_hash, include_hex, include_json);
}
return true;
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 3f1543857..b134aee61 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -91,7 +91,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"print_tx"
, std::bind(&t_command_parser_executor::print_transaction, &m_parser, p::_1)
- , "Print transaction, print_tx <transaction_hash>"
+ , "Print transaction, print_tx <transaction_hash> [+hex] [+json]"
);
m_command_lookup.set_handler(
"is_key_image_spent"
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 867c523c9..2c11dcb31 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -693,7 +693,9 @@ bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
return true;
}
-bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
+bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
+ bool include_hex,
+ bool include_json) {
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
@@ -728,30 +730,34 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height;
}
- // first as hex
const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front();
- tools::success_msg_writer() << as_hex;
+ // Print raw hex if requested
+ if (include_hex)
+ tools::success_msg_writer() << as_hex << std::endl;
- // then as json
- crypto::hash tx_hash, tx_prefix_hash;
- cryptonote::transaction tx;
- cryptonote::blobdata blob;
- if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob))
- {
- tools::fail_msg_writer() << "Failed to parse tx";
- }
- else if (!cryptonote::parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash))
+ // Print json if requested
+ if (include_json)
{
- tools::fail_msg_writer() << "Failed to parse tx blob";
- }
- else
- {
- tools::success_msg_writer() << cryptonote::obj_to_json_str(tx) << std::endl;
+ crypto::hash tx_hash, tx_prefix_hash;
+ cryptonote::transaction tx;
+ cryptonote::blobdata blob;
+ if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob))
+ {
+ tools::fail_msg_writer() << "Failed to parse tx to get json format";
+ }
+ else if (!cryptonote::parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash))
+ {
+ tools::fail_msg_writer() << "Failed to parse tx blob to get json format";
+ }
+ else
+ {
+ tools::success_msg_writer() << cryptonote::obj_to_json_str(tx) << std::endl;
+ }
}
}
else
{
- tools::fail_msg_writer() << "transaction wasn't found: " << transaction_hash << std::endl;
+ tools::fail_msg_writer() << "Transaction wasn't found: " << transaction_hash << std::endl;
}
return true;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index c9d0ac671..efe1ae56a 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -95,7 +95,7 @@ public:
bool print_block_by_height(uint64_t height);
- bool print_transaction(crypto::hash transaction_hash);
+ bool print_transaction(crypto::hash transaction_hash, bool include_hex, bool include_json);
bool is_key_image_spent(const crypto::key_image &ki);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 9095aacae..b3ce30d0c 100644..100755
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -101,7 +101,7 @@ namespace cryptonote
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
- std::move(port), std::move(rpc_config->bind_ip), std::move(http_login)
+ std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
);
}
//------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 086820180..d6da124d1 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -45,6 +45,15 @@ const char* Message::STATUS_FAILED = "Failed";
const char* Message::STATUS_BAD_REQUEST = "Invalid request type";
const char* Message::STATUS_BAD_JSON = "Malformed json";
+namespace
+{
+constexpr const char error_field[] = "error";
+constexpr const char id_field[] = "id";
+constexpr const char method_field[] = "method";
+constexpr const char params_field[] = "params";
+constexpr const char result_field[] = "result";
+}
+
rapidjson::Value Message::toJson(rapidjson::Document& doc) const
{
rapidjson::Value val(rapidjson::kObjectType);
@@ -70,8 +79,8 @@ FullMessage::FullMessage(const std::string& request, Message* message)
{
doc.SetObject();
- doc.AddMember("method", rapidjson::StringRef(request.c_str()), doc.GetAllocator());
- doc.AddMember("params", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(method_field, rapidjson::StringRef(request.c_str()), doc.GetAllocator());
+ doc.AddMember(params_field, message->toJson(doc), doc.GetAllocator());
// required by JSON-RPC 2.0 spec
doc.AddMember("jsonrpc", rapidjson::Value("2.0"), doc.GetAllocator());
@@ -86,7 +95,7 @@ FullMessage::FullMessage(Message* message)
if (message->status == Message::STATUS_OK)
{
- doc.AddMember("response", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(result_field, message->toJson(doc), doc.GetAllocator());
}
else
{
@@ -111,14 +120,14 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
if (request)
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- OBJECT_HAS_MEMBER_OR_THROW(doc, "params")
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
}
else
{
- if (!doc.HasMember("response") && !doc.HasMember("error"))
+ if (!doc.HasMember(result_field) && !doc.HasMember(error_field))
{
- throw cryptonote::json::MISSING_KEY("error/response");
+ throw cryptonote::json::MISSING_KEY("error/result");
}
}
}
@@ -126,9 +135,9 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
std::string FullMessage::getJson()
{
- if (!doc.HasMember("id"))
+ if (!doc.HasMember(id_field))
{
- doc.AddMember("id", rapidjson::Value("unused"), doc.GetAllocator());
+ doc.AddMember(id_field, rapidjson::Value("unused"), doc.GetAllocator());
}
rapidjson::StringBuffer buf;
@@ -142,24 +151,24 @@ std::string FullMessage::getJson()
std::string FullMessage::getRequestType() const
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- return doc["method"].GetString();
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ return doc[method_field].GetString();
}
rapidjson::Value& FullMessage::getMessage()
{
- if (doc.HasMember("params"))
+ if (doc.HasMember(params_field))
{
- return doc["params"];
+ return doc[params_field];
}
- else if (doc.HasMember("response"))
+ else if (doc.HasMember(result_field))
{
- return doc["response"];
+ return doc[result_field];
}
//else
- OBJECT_HAS_MEMBER_OR_THROW(doc, "error")
- return doc["error"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, error_field)
+ return doc[error_field];
}
@@ -172,20 +181,20 @@ rapidjson::Value FullMessage::getMessageCopy()
rapidjson::Value& FullMessage::getID()
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "id")
- return doc["id"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, id_field)
+ return doc[id_field];
}
void FullMessage::setID(rapidjson::Value& id)
{
- auto itr = doc.FindMember("id");
+ auto itr = doc.FindMember(id_field);
if (itr != doc.MemberEnd())
{
itr->value = id;
}
else
{
- doc.AddMember("id", id, doc.GetAllocator());
+ doc.AddMember(id_field, id, doc.GetAllocator());
}
}
@@ -193,7 +202,7 @@ cryptonote::rpc::error FullMessage::getError()
{
cryptonote::rpc::error err;
err.use = false;
- if (doc.HasMember("error"))
+ if (doc.HasMember(error_field))
{
GET_FROM_JSON_OBJECT(doc, err, error);
err.use = true;
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index 4435f74d1..93309bf3c 100644..100755
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -28,6 +28,7 @@
//
#include "rpc_args.h"
+#include <boost/algorithm/string.hpp>
#include <boost/asio/ip/address.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
@@ -38,6 +39,7 @@ namespace cryptonote
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify ip to bind rpc server"), "127.0.0.1"})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
+ , rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
{}
const char* rpc_args::tr(const char* str) { return i18n_translate(str, "cryptonote::rpc_args"); }
@@ -48,6 +50,7 @@ namespace cryptonote
command_line::add_arg(desc, arg.rpc_bind_ip);
command_line::add_arg(desc, arg.rpc_login);
command_line::add_arg(desc, arg.confirm_external_bind);
+ command_line::add_arg(desc, arg.rpc_access_control_origins);
}
boost::optional<rpc_args> rpc_args::process(const boost::program_options::variables_map& vm)
@@ -91,6 +94,21 @@ namespace cryptonote
}
}
+ auto access_control_origins_input = command_line::get_arg(vm, arg.rpc_access_control_origins);
+ if (!access_control_origins_input.empty())
+ {
+ if (!config.login)
+ {
+ LOG_ERROR(arg.rpc_access_control_origins.name << tr(" requires RFC server password --") << arg.rpc_login.name << tr(" cannot be empty"));
+ return boost::none;
+ }
+
+ std::vector<std::string> access_control_origins;
+ boost::split(access_control_origins, access_control_origins_input, boost::is_any_of(","));
+ std::for_each(access_control_origins.begin(), access_control_origins.end(), boost::bind(&boost::trim<std::string>, _1, std::locale::classic()));
+ config.access_control_origins = std::move(access_control_origins);
+ }
+
return {std::move(config)};
}
}
diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h
index d6e7bab07..72b5aa706 100644..100755
--- a/src/rpc/rpc_args.h
+++ b/src/rpc/rpc_args.h
@@ -53,6 +53,7 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> rpc_bind_ip;
const command_line::arg_descriptor<std::string> rpc_login;
const command_line::arg_descriptor<bool> confirm_external_bind;
+ const command_line::arg_descriptor<std::string> rpc_access_control_origins;
};
static const char* tr(const char* str);
@@ -62,6 +63,7 @@ namespace cryptonote
static boost::optional<rpc_args> process(const boost::program_options::variables_map& vm);
std::string bind_ip;
+ std::vector<std::string> access_control_origins;
boost::optional<tools::login> login; // currently `boost::none` if unspecified by user
};
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a0d9a32c6..c936f481e 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -107,7 +107,7 @@ enum TransferType {
namespace
{
- const auto allowed_priority_strings = {"default", "unimportant", "normal", "elevated", "priority"};
+ const std::array<const char* const, 5> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}};
const auto arg_wallet_file = wallet_args::arg_wallet_file();
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
@@ -278,6 +278,18 @@ namespace
}
}
+bool parse_priority(const std::string& arg, uint32_t& priority)
+{
+ auto priority_pos = std::find(
+ allowed_priority_strings.begin(),
+ allowed_priority_strings.end(),
+ arg);
+ if(priority_pos != allowed_priority_strings.end()) {
+ priority = std::distance(allowed_priority_strings.begin(), priority_pos);
+ return true;
+ }
+ return false;
+}
std::string simple_wallet::get_commands_str()
{
@@ -820,8 +832,8 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1), tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>] - Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer", boost::bind(&simple_wallet::locked_transfer, this, _1), tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>] - Same as transfer, but with number of blocks to lock the transaction for, max 1000000"));
m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with ring_size 1"));
- m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1), tr("sweep_all [index=<N1>[,<N2>,...]] [<ring_size>] <address> [<payment_id>] - Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used."));
- m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this, _1), tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<ring_size>] <address> [<payment_id>] - Send all unlocked outputs below the threshold to an address"));
+ m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1), tr("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>] - Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used."));
+ m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this, _1), tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>] - Send all unlocked outputs below the threshold to an address"));
m_cmd_binder.set_handler("donate", boost::bind(&simple_wallet::donate, this, _1), tr("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>] - Donate <amount> to the development team (donate.getmonero.org)"));
m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), tr("Sign a transaction from a file"));
m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), tr("Submit a signed transaction from a file"));
@@ -2485,17 +2497,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
local_args.erase(local_args.begin());
}
- int priority = 0;
- if(local_args.size() > 0) {
- auto priority_pos = std::find(
- allowed_priority_strings.begin(),
- allowed_priority_strings.end(),
- local_args[0]);
- if(priority_pos != allowed_priority_strings.end()) {
- local_args.erase(local_args.begin());
- priority = std::distance(allowed_priority_strings.begin(), priority_pos);
- }
- }
+ uint32_t priority = 0;
+ if (local_args.size() > 0 && parse_priority(local_args[0], priority))
+ local_args.erase(local_args.begin());
size_t fake_outs_count = 0;
if(local_args.size() > 0) {
@@ -2823,13 +2827,20 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -2995,13 +3006,20 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -3084,6 +3102,10 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
local_args.erase(local_args.begin());
}
+ uint32_t priority = 0;
+ if (local_args.size() > 0 && parse_priority(local_args[0], priority))
+ local_args.erase(local_args.begin());
+
size_t fake_outs_count = 0;
if(local_args.size() > 0) {
size_t ring_size;
@@ -3188,7 +3210,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon);
if (ptx_vector.empty())
{
@@ -3275,13 +3297,20 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
@@ -3625,13 +3654,20 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
- catch (const tools::error::not_enough_money& e)
+ catch (const tools::error::not_enough_unlocked_money& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") %
print_money(e.available()) %
print_money(e.tx_amount()));
fail_msg_writer() << tr("Not enough money in unlocked balance");
}
+ catch (const tools::error::not_enough_money& e)
+ {
+ LOG_PRINT_L0(boost::format("not enough money to transfer, overall balance only %s, sent amount %s") %
+ print_money(e.available()) %
+ print_money(e.tx_amount()));
+ fail_msg_writer() << tr("Not enough money in overall balance");
+ }
catch (const tools::error::tx_not_possible& e)
{
LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") %
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index db7e60cd7..8e747d16b 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1044,8 +1044,7 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
// - confirmed_transfer_details)
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
- uint32_t subaddr_account, std::set<uint32_t> subaddr_indices,
- PendingTransaction::Priority priority)
+ PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
clearStatus();
@@ -1147,7 +1146,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
m_errorString = (boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str();
m_status = Status_Error;
- } catch (const tools::error::not_enough_money& e) {
+ } catch (const tools::error::not_enough_unlocked_money& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1156,6 +1155,15 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
print_money(e.tx_amount());
m_errorString = writer.str();
+ } catch (const tools::error::not_enough_money& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
+ writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount());
+ m_errorString = writer.str();
+
} catch (const tools::error::tx_not_possible& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1241,7 +1249,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
m_errorString = tr("failed to get random outputs to mix");
m_status = Status_Error;
- } catch (const tools::error::not_enough_money& e) {
+ } catch (const tools::error::not_enough_unlocked_money& e) {
m_status = Status_Error;
std::ostringstream writer;
@@ -1250,6 +1258,15 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
print_money(e.tx_amount());
m_errorString = writer.str();
+ } catch (const tools::error::not_enough_money& e) {
+ m_status = Status_Error;
+ std::ostringstream writer;
+
+ writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
+ print_money(e.available()) %
+ print_money(e.tx_amount());
+ m_errorString = writer.str();
+
} catch (const tools::error::tx_not_possible& e) {
m_status = Status_Error;
std::ostringstream writer;
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index ecb218ea0..051eda3ba 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -73,7 +73,7 @@ public:
int status() const;
std::string errorString() const;
bool setPassword(const std::string &password);
- std::string address(uint32_t accountIndex, uint32_t addressIndex) const;
+ std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const;
std::string integratedAddress(const std::string &payment_id) const;
std::string secretViewKey() const;
std::string publicViewKey() const;
@@ -88,8 +88,8 @@ public:
ConnectionStatus connected() const;
void setTrustedDaemon(bool arg);
bool trustedDaemon() const;
- uint64_t balance(uint32_t accountIndex) const;
- uint64_t unlockedBalance(uint32_t accountIndex) const;
+ uint64_t balance(uint32_t accountIndex = 0) const;
+ uint64_t unlockedBalance(uint32_t accountIndex = 0) const;
uint64_t blockChainHeight() const;
uint64_t approximateBlockChainHeight() const;
uint64_t daemonBlockChainHeight() const;
@@ -117,9 +117,9 @@ public:
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
- uint32_t subaddr_account,
- std::set<uint32_t> subaddr_indices,
- PendingTransaction::Priority priority = PendingTransaction::Priority_Low);
+ PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
+ uint32_t subaddr_account = 0,
+ std::set<uint32_t> subaddr_indices = {});
virtual PendingTransaction * createSweepUnmixableTransaction();
bool submitTransaction(const std::string &fileName);
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 2e05b1484..f0eaf2331 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -692,20 +692,20 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_subaddress_label(const cryptonote::subaddress_index& index) const
{
- if (index.major >= m_subaddress_labels.size())
- throw std::runtime_error("index.major is out of bound");
- if (index.minor >= m_subaddress_labels[index.major].size())
- throw std::runtime_error("index.minor is out of bound");
+ if (index.major >= m_subaddress_labels.size() || index.minor >= m_subaddress_labels[index.major].size())
+ {
+ MERROR("Subaddress label doesn't exist");
+ return "";
+ }
return m_subaddress_labels[index.major][index.minor];
}
//----------------------------------------------------------------------------------------------------
void wallet2::set_subaddress_label(const cryptonote::subaddress_index& index, const std::string &label)
{
- if (index.major >= m_subaddress_labels.size())
- throw std::runtime_error("index.major is out of bound");
- if (index.minor >= m_subaddress_labels[index.major].size())
- throw std::runtime_error("index.minor is out of bound");
- m_subaddress_labels[index.major][index.minor] = label;
+ if (index.major >= m_subaddress_labels.size() || index.minor >= m_subaddress_labels[index.major].size())
+ MERROR("Subaddress index is out of bounds. Failed to set subaddress label.");
+ else
+ m_subaddress_labels[index.major][index.minor] = label;
}
//----------------------------------------------------------------------------------------------------
/*!
@@ -788,7 +788,7 @@ void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote
{
tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask);
}
- tx_money_got_in_outs[tx_scan_info.received->index] = tx_scan_info.money_transfered;
+ tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered;
tx_scan_info.amount = tx_scan_info.money_transfered;
++num_vouts_received;
}
@@ -1520,7 +1520,7 @@ void wallet2::pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_hei
void wallet2::remove_obsolete_pool_txs(const std::vector<crypto::hash> &tx_hashes)
{
// remove pool txes to us that aren't in the pool anymore
- std::unordered_map<crypto::hash, wallet2::payment_details>::iterator uit = m_unconfirmed_payments.begin();
+ std::unordered_multimap<crypto::hash, wallet2::payment_details>::iterator uit = m_unconfirmed_payments.begin();
while (uit != m_unconfirmed_payments.end())
{
const crypto::hash &txid = uit->second.m_tx_hash;
@@ -4441,7 +4441,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
}
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
@@ -4598,7 +4598,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
}
LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee));
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
@@ -4751,7 +4751,7 @@ static size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs)
size += (2*64*32+32+64*32) * n_outputs;
// MGs
- size += n_inputs * (32 * (mixin+1) + 32);
+ size += n_inputs * (64 * (mixin+1) + 32);
// mixRing - not serialized, can be reconstructed
/* size += 2 * 32 * (mixin+1) * n_inputs; */
@@ -5475,6 +5475,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
}
+ // early out if we know we can't make it anyway
+ // we could also check for being within FEE_PER_KB, but if the fee calculation
+ // ever changes, this might be missed, so let this go through
+ // first check overall balance is enough, then unlocked one, so we throw distinct exceptions
+ THROW_WALLET_EXCEPTION_IF(needed_money > balance(), error::not_enough_money,
+ unlocked_balance(), needed_money, 0);
+ THROW_WALLET_EXCEPTION_IF(needed_money > unlocked_balance(), error::not_enough_unlocked_money,
+ unlocked_balance(), needed_money, 0);
+
// shuffle & sort output indices
{
std::random_device rd;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 2ef1e56d2..f1e12a700 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -467,8 +467,8 @@ namespace tools
size_t get_num_subaddresses(uint32_t index_major) const { return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; }
void add_subaddress(uint32_t index_major, const std::string& label); // throws when index is out of bound
void expand_subaddresses(const cryptonote::subaddress_index& index);
- std::string get_subaddress_label(const cryptonote::subaddress_index& index) const; // throws when index is out of bound
- void set_subaddress_label(const cryptonote::subaddress_index &index, const std::string &label); // throws when index is out of bound
+ std::string get_subaddress_label(const cryptonote::subaddress_index& index) const;
+ void set_subaddress_label(const cryptonote::subaddress_index &index, const std::string &label);
/*!
* \brief Tells if the wallet file is deprecated.
*/
@@ -1068,7 +1068,10 @@ namespace boost
x.m_amount_out += x.m_change;
}
if (ver < 7)
+ {
+ x.m_subaddr_account = 0;
return;
+ }
a & x.m_subaddr_account;
a & x.m_subaddr_indices;
}
@@ -1109,7 +1112,10 @@ namespace boost
}
a & x.m_unlock_time;
if (ver < 5)
+ {
+ x.m_subaddr_account = 0;
return;
+ }
a & x.m_subaddr_account;
a & x.m_subaddr_indices;
}
@@ -1125,7 +1131,10 @@ namespace boost
return;
a & x.m_timestamp;
if (ver < 2)
+ {
+ x.m_subaddr_index = {};
return;
+ }
a & x.m_subaddr_index;
}
@@ -1136,7 +1145,10 @@ namespace boost
a & x.m_payment_id;
a & x.m_description;
if (ver < 17)
+ {
+ x.m_is_subaddress = false;
return;
+ }
a & x.m_is_subaddress;
}
@@ -1166,7 +1178,10 @@ namespace boost
a & x.use_rct;
a & x.dests;
if (ver < 1)
+ {
+ x.subaddr_account = 0;
return;
+ }
a & x.subaddr_account;
a & x.subaddr_indices;
}
@@ -1275,10 +1290,10 @@ namespace tools
}
// randomly select inputs for transaction
- // throw if requested send amount is greater than amount available to send
+ // throw if requested send amount is greater than (unlocked) amount available to send
std::list<size_t> selected_transfers;
uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon);
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
+ THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 4d734ab94..a8c150ca7 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -360,7 +360,7 @@ struct Wallet
//! in case error status, returns error string
virtual std::string errorString() const = 0;
virtual bool setPassword(const std::string &password) = 0;
- virtual std::string address(uint32_t accountIndex, uint32_t addressIndex) const = 0;
+ virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0;
std::string mainAddress() const { return address(0, 0); }
virtual std::string path() const = 0;
virtual bool testnet() const = 0;
@@ -476,14 +476,14 @@ struct Wallet
virtual ConnectionStatus connected() const = 0;
virtual void setTrustedDaemon(bool arg) = 0;
virtual bool trustedDaemon() const = 0;
- virtual uint64_t balance(uint32_t accountIndex) const = 0;
+ virtual uint64_t balance(uint32_t accountIndex = 0) const = 0;
uint64_t balanceAll() const {
uint64_t result = 0;
for (uint32_t i = 0; i < numSubaddressAccounts(); ++i)
result += balance(i);
return result;
}
- virtual uint64_t unlockedBalance(uint32_t accountIndex) const = 0;
+ virtual uint64_t unlockedBalance(uint32_t accountIndex = 0) const = 0;
uint64_t unlockedBalanceAll() const {
uint64_t result = 0;
for (uint32_t i = 0; i < numSubaddressAccounts(); ++i)
@@ -623,9 +623,9 @@ struct Wallet
virtual PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
- uint32_t subaddr_account,
- std::set<uint32_t> subaddr_indices,
- PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
+ PendingTransaction::Priority = PendingTransaction::Priority_Low,
+ uint32_t subaddr_account = 0,
+ std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index d1f4a796d..9d66f125e 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -68,6 +68,7 @@ namespace tools
// get_tx_pool_error
// transfer_error *
// get_random_outs_general_error
+ // not_enough_unlocked_money
// not_enough_money
// tx_not_possible
// not_enough_outs_to_mix
@@ -356,11 +357,37 @@ namespace tools
//----------------------------------------------------------------------------------------------------
typedef failed_rpc_request<transfer_error, get_random_outs_error_message_index> get_random_outs_error;
//----------------------------------------------------------------------------------------------------
+ struct not_enough_unlocked_money : public transfer_error
+ {
+ explicit not_enough_unlocked_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
+ : transfer_error(std::move(loc), "not enough unlocked money")
+ , m_available(available)
+ , m_tx_amount(tx_amount)
+ {
+ }
+
+ uint64_t available() const { return m_available; }
+ uint64_t tx_amount() const { return m_tx_amount; }
+
+ std::string to_string() const
+ {
+ std::ostringstream ss;
+ ss << transfer_error::to_string() <<
+ ", available = " << cryptonote::print_money(m_available) <<
+ ", tx_amount = " << cryptonote::print_money(m_tx_amount);
+ return ss.str();
+ }
+
+ private:
+ uint64_t m_available;
+ uint64_t m_tx_amount;
+ };
+ //----------------------------------------------------------------------------------------------------
struct not_enough_money : public transfer_error
{
- explicit not_enough_money(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
+ explicit not_enough_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
: transfer_error(std::move(loc), "not enough money")
- , m_available(availbable)
+ , m_available(available)
, m_tx_amount(tx_amount)
{
}
@@ -384,9 +411,9 @@ namespace tools
//----------------------------------------------------------------------------------------------------
struct tx_not_possible : public transfer_error
{
- explicit tx_not_possible(std::string&& loc, uint64_t availbable, uint64_t tx_amount, uint64_t fee)
+ explicit tx_not_possible(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee)
: transfer_error(std::move(loc), "tx not possible")
- , m_available(availbable)
+ , m_available(available)
, m_tx_amount(tx_amount)
, m_fee(fee)
{
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index b360a3efd..9e6a97bdc 100644..100755
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -216,7 +216,7 @@ namespace tools
m_net_server.set_threads_prefix("RPC");
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
- std::move(bind_port), std::move(rpc_config->bind_ip), std::move(http_login)
+ std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -341,8 +341,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -369,8 +368,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -406,8 +404,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -436,8 +433,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -454,8 +450,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -476,8 +471,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -492,8 +486,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -618,7 +611,7 @@ namespace tools
// reject proposed transactions if there are more than one. see on_transfer_split below.
if (ptx_vector.size() != 1)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
+ er.code = WALLET_RPC_ERROR_CODE_TX_TOO_LARGE;
er.message = "Transaction would be too large. try /transfer_split.";
return false;
}
@@ -642,22 +635,9 @@ namespace tools
}
return true;
}
- catch (const tools::error::daemon_busy& e)
- {
- er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
- er.message = e.what();
- return false;
- }
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
- er.message = e.what();
- return false;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
@@ -725,22 +705,9 @@ namespace tools
return true;
}
- catch (const tools::error::daemon_busy& e)
- {
- er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
- er.message = e.what();
- return false;
- }
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
- er.message = e.what();
- return false;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
@@ -782,22 +749,9 @@ namespace tools
return true;
}
- catch (const tools::error::daemon_busy& e)
- {
- er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
- er.message = e.what();
- return false;
- }
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
- er.message = e.what();
- return false;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
@@ -852,22 +806,9 @@ namespace tools
return true;
}
- catch (const tools::error::daemon_busy& e)
- {
- er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
- er.message = e.what();
- return false;
- }
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
- er.message = e.what();
- return false;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
return true;
@@ -897,10 +838,9 @@ namespace tools
res.payment_id = epee::string_tools::pod_to_hex(payment_id);
return true;
}
- catch (const std::exception &e)
+ catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -929,10 +869,9 @@ namespace tools
res.payment_id = epee::string_tools::pod_to_hex(info.payment_id);
return true;
}
- catch (const std::exception &e)
+ catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -954,8 +893,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -1185,8 +1123,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -1258,8 +1195,7 @@ namespace tools
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -1523,10 +1459,9 @@ namespace tools
}
}
- catch (...)
+ catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
@@ -1579,10 +1514,9 @@ namespace tools
res.height = height;
}
- catch (...)
+ catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed";
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
@@ -1759,10 +1693,9 @@ namespace tools
m_wallet->rescan_spent();
return true;
}
- catch (const std::exception &e)
+ catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
@@ -1827,7 +1760,7 @@ namespace tools
{
if (m_wallet_dir.empty())
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.code = WALLET_RPC_ERROR_CODE_NO_WALLET_DIR;
er.message = "No wallet dir configured";
return false;
}
@@ -1895,6 +1828,11 @@ namespace tools
}
catch (const std::exception& e)
{
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ if (!wal)
+ {
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "Failed to generate wallet";
return false;
@@ -1909,7 +1847,7 @@ namespace tools
{
if (m_wallet_dir.empty())
{
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.code = WALLET_RPC_ERROR_CODE_NO_WALLET_DIR;
er.message = "No wallet dir configured";
return false;
}
@@ -1943,13 +1881,13 @@ namespace tools
command_line::add_arg(desc, arg_password);
po::store(po::parse_command_line(argc, argv, desc), vm2);
}
- std::unique_ptr<tools::wallet2> wal;
+ std::unique_ptr<tools::wallet2> wal = nullptr;
try {
wal = tools::wallet2::make_from_file(vm2, wallet_file).first;
}
catch (const std::exception& e)
{
- wal = nullptr;
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
}
if (!wal)
{
@@ -1963,6 +1901,63 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ void wallet_rpc_server::handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code) {
+ try
+ {
+ std::rethrow_exception(e);
+ }
+ catch (const tools::error::daemon_busy& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
+ er.message = e.what();
+ }
+ catch (const tools::error::zero_destination& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION;
+ er.message = e.what();
+ }
+ catch (const tools::error::not_enough_money& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY;
+ er.message = e.what();
+ }
+ catch (const tools::error::tx_not_possible& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
+ er.message = (boost::format(tr("Transaction not possible. Available only %s, transaction amount %s = %s + %s (fee)")) %
+ cryptonote::print_money(e.available()) %
+ cryptonote::print_money(e.tx_amount() + e.fee()) %
+ cryptonote::print_money(e.tx_amount()) %
+ cryptonote::print_money(e.fee())).str();
+ er.message = e.what();
+ }
+ catch (const tools::error::not_enough_outs_to_mix& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX;
+ er.message = e.what();
+ }
+ catch (const error::file_exists& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_WALLET_ALREADY_EXISTS;
+ er.message = "Cannot create wallet. Already exists.";
+ }
+ catch (const error::invalid_password& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_INVALID_PASSWORD;
+ er.message = "Invalid password.";
+ }
+ catch (const std::exception& e)
+ {
+ er.code = default_error_code;
+ er.message = e.what();
+ }
+ catch (...)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
}
int main(int argc, char** argv) {
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 02c1d4082..b38726cb7 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -166,6 +166,7 @@ namespace tools
void fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::payment_details &pd);
bool not_open(epee::json_rpc::error& er);
uint64_t adjust_mixin(uint64_t mixin);
+ void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code);
wallet2 *m_wallet;
std::string m_wallet_dir;
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index cc9fd3856..e74e9110b 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -46,3 +46,11 @@
#define WALLET_RPC_ERROR_CODE_NOT_OPEN -13
#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUTOFBOUND -14
#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUTOFBOUND -15
+#define WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE -16
+#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -17
+#define WALLET_RPC_ERROR_CODE_TX_TOO_LARGE -18
+#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX -19
+#define WALLET_RPC_ERROR_CODE_ZERO_DESTINATION -20
+#define WALLET_RPC_ERROR_CODE_WALLET_ALREADY_EXISTS -21
+#define WALLET_RPC_ERROR_CODE_INVALID_PASSWORD -22
+#define WALLET_RPC_ERROR_CODE_NO_WALLET_DIR -23