diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/api/wallet.cpp | 13 | ||||
-rw-r--r-- | src/wallet/api/wallet.h | 5 | ||||
-rw-r--r-- | src/wallet/api/wallet2_api.h | 7 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.cpp | 4 | ||||
-rw-r--r-- | src/wallet/api/wallet_manager.h | 5 | ||||
-rw-r--r-- | src/wallet/message_store.cpp | 83 | ||||
-rw-r--r-- | src/wallet/message_store.h | 77 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 334 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 210 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 50 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 2 |
11 files changed, 619 insertions, 171 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 66e248427..73ab88a9f 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -938,13 +938,13 @@ string WalletImpl::keysFilename() const return m_wallet->get_keys_file(); } -bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit, const std::string &daemon_username, const std::string &daemon_password, bool use_ssl, bool lightWallet) +bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transaction_size_limit, const std::string &daemon_username, const std::string &daemon_password, bool use_ssl, bool lightWallet, const std::string &proxy_address) { clearStatus(); m_wallet->set_light_wallet(lightWallet); if(daemon_username != "") m_daemon_login.emplace(daemon_username, daemon_password); - return doInit(daemon_address, upper_transaction_size_limit, use_ssl); + return doInit(daemon_address, proxy_address, upper_transaction_size_limit, use_ssl); } bool WalletImpl::lightWalletLogin(bool &isNewWallet) const @@ -2088,6 +2088,11 @@ bool WalletImpl::trustedDaemon() const return m_wallet->is_trusted_daemon(); } +bool WalletImpl::setProxy(const std::string &address) +{ + return m_wallet->set_proxy(address); +} + bool WalletImpl::watchOnly() const { return m_wallet->watch_only(); @@ -2241,9 +2246,9 @@ void WalletImpl::pendingTxPostProcess(PendingTransactionImpl * pending) pending->m_pending_tx = exported_txs.ptx; } -bool WalletImpl::doInit(const string &daemon_address, uint64_t upper_transaction_size_limit, bool ssl) +bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit, bool ssl) { - if (!m_wallet->init(daemon_address, m_daemon_login, boost::asio::ip::tcp::endpoint{}, upper_transaction_size_limit)) + if (!m_wallet->init(daemon_address, m_daemon_login, proxy_address, upper_transaction_size_limit)) return false; // in case new wallet, this will force fast-refresh (pulling hashes instead of blocks) diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 43d85b704..caf1e9ed4 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -102,11 +102,12 @@ public: bool store(const std::string &path) override; std::string filename() const override; std::string keysFilename() const override; - bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false) override; + bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") override; bool connectToDaemon() override; ConnectionStatus connected() const override; void setTrustedDaemon(bool arg) override; bool trustedDaemon() const override; + bool setProxy(const std::string &address) override; uint64_t balance(uint32_t accountIndex = 0) const override; uint64_t unlockedBalance(uint32_t accountIndex = 0) const override; uint64_t blockChainHeight() const override; @@ -225,7 +226,7 @@ private: void stopRefresh(); bool isNewWallet() const; void pendingTxPostProcess(PendingTransactionImpl * pending); - bool doInit(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false); + bool doInit(const std::string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit = 0, bool ssl = false); private: friend class PendingTransactionImpl; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index e2f96a069..50df7e5dd 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -533,9 +533,10 @@ struct Wallet * \param daemon_username * \param daemon_password * \param lightWallet - start wallet in light mode, connect to a openmonero compatible server. + * \param proxy_address - set proxy address, empty string to disable * \return - true on success */ - virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false) = 0; + virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") = 0; /*! * \brief createWatchOnly - Creates a watch only wallet @@ -594,6 +595,7 @@ struct Wallet virtual ConnectionStatus connected() const = 0; virtual void setTrustedDaemon(bool arg) = 0; virtual bool trustedDaemon() const = 0; + virtual bool setProxy(const std::string &address) = 0; virtual uint64_t balance(uint32_t accountIndex = 0) const = 0; uint64_t balanceAll() const { uint64_t result = 0; @@ -1298,6 +1300,9 @@ struct WalletManager std::string subdir, const char *buildtag = nullptr, const char *current_version = nullptr); + + //! sets proxy address, empty string to disable + virtual bool setProxy(const std::string &address) = 0; }; diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 69d17eb02..900fe91e5 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -375,6 +375,10 @@ std::tuple<bool, std::string, std::string, std::string, std::string> WalletManag return std::make_tuple(false, "", "", "", ""); } +bool WalletManagerImpl::setProxy(const std::string &address) +{ + return m_http_client.set_proxy(address); +} ///////////////////// WalletManagerFactory implementation ////////////////////// WalletManager *WalletManagerFactory::getWalletManager() diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index ca8e9ada2..2f603b0a9 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -30,7 +30,7 @@ #include "wallet/api/wallet2_api.h" -#include "net/http_client.h" +#include "net/http.h" #include <string> namespace Monero { @@ -92,11 +92,12 @@ public: bool startMining(const std::string &address, uint32_t threads = 1, bool background_mining = false, bool ignore_battery = true) override; bool stopMining() override; std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const override; + bool setProxy(const std::string &address) override; private: WalletManagerImpl() {} friend struct WalletManagerFactory; - epee::net_utils::http::http_simple_client m_http_client; + net::http::client m_http_client; std::string m_errorString; }; diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp index fb07b42f0..303b576c7 100644 --- a/src/wallet/message_store.cpp +++ b/src/wallet/message_store.cpp @@ -27,7 +27,6 @@ // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "message_store.h" -#include <boost/archive/portable_binary_oarchive.hpp> #include <boost/archive/portable_binary_iarchive.hpp> #include <boost/format.hpp> #include <boost/algorithm/string.hpp> @@ -182,8 +181,8 @@ bool message_store::signer_labels_complete() const void message_store::get_signer_config(std::string &signer_config) { std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << m_signers; + binary_archive<true> ar(oss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, m_signers), tools::error::wallet_internal_error, "Failed to serialize signer config"); signer_config = oss.str(); } @@ -194,8 +193,8 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con { std::stringstream iss; iss << signer_config; - boost::archive::portable_binary_iarchive ar(iss); - ar >> signers; + binary_archive<false> ar(iss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, signers), tools::error::wallet_internal_error, "Failed to serialize signer config"); } catch (...) { @@ -364,8 +363,8 @@ size_t message_store::add_auto_config_data_message(const multisig_wallet_state & data.monero_address = me.monero_address; std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << data; + binary_archive<true> ar(oss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, data), tools::error::wallet_internal_error, "Failed to serialize auto config data"); return add_message(state, 0, message_type::auto_config_data, message_direction::out, oss.str()); } @@ -384,8 +383,8 @@ void message_store::process_auto_config_data_message(uint32_t id) { std::stringstream iss; iss << m.content; - boost::archive::portable_binary_iarchive ar(iss); - ar >> data; + binary_archive<false> ar(iss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, data), tools::error::wallet_internal_error, "Failed to serialize auto config data"); } catch (...) { @@ -745,8 +744,8 @@ std::string message_store::get_sanitized_text(const std::string &text, size_t ma void message_store::write_to_file(const multisig_wallet_state &state, const std::string &filename) { std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << *this; + binary_archive<true> ar(oss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, *this), tools::error::wallet_internal_error, "Failed to serialize MMS state"); std::string buf = oss.str(); crypto::chacha_key key; @@ -762,14 +761,14 @@ void message_store::write_to_file(const multisig_wallet_state &state, const std: write_file_data.encrypted_data = encrypted_data; std::stringstream file_oss; - boost::archive::portable_binary_oarchive file_ar(file_oss); - file_ar << write_file_data; + binary_archive<true> file_ar(file_oss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(file_ar, write_file_data), tools::error::wallet_internal_error, "Failed to serialize MMS state"); bool success = epee::file_io_utils::save_string_to_file(filename, file_oss.str()); THROW_WALLET_EXCEPTION_IF(!success, tools::error::file_save_error, filename); } -void message_store::read_from_file(const multisig_wallet_state &state, const std::string &filename) +void message_store::read_from_file(const multisig_wallet_state &state, const std::string &filename, bool load_deprecated_formats) { boost::system::error_code ignored_ec; bool file_exists = boost::filesystem::exists(filename, ignored_ec); @@ -785,17 +784,37 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std bool success = epee::file_io_utils::load_file_to_string(filename, buf); THROW_WALLET_EXCEPTION_IF(!success, tools::error::file_read_error, filename); + bool loaded = false; file_data read_file_data; try { std::stringstream iss; iss << buf; - boost::archive::portable_binary_iarchive ar(iss); - ar >> read_file_data; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, read_file_data)) + if (::serialization::check_stream_state(ar)) + loaded = true; } - catch (const std::exception &e) + catch (...) {} + if (!loaded && load_deprecated_formats) + { + try + { + std::stringstream iss; + iss << buf; + boost::archive::portable_binary_iarchive ar(iss); + ar >> read_file_data; + loaded = true; + } + catch (const std::exception &e) + { + MERROR("MMS file " << filename << " has bad structure <iv,encrypted_data>: " << e.what()); + THROW_WALLET_EXCEPTION_IF(true, tools::error::file_read_error, filename); + } + } + if (!loaded) { - MERROR("MMS file " << filename << " has bad structure <iv,encrypted_data>: " << e.what()); + MERROR("MMS file " << filename << " has bad structure <iv,encrypted_data>"); THROW_WALLET_EXCEPTION_IF(true, tools::error::file_read_error, filename); } @@ -805,16 +824,36 @@ void message_store::read_from_file(const multisig_wallet_state &state, const std decrypted_data.resize(read_file_data.encrypted_data.size()); crypto::chacha20(read_file_data.encrypted_data.data(), read_file_data.encrypted_data.size(), key, read_file_data.iv, &decrypted_data[0]); + loaded = false; try { std::stringstream iss; iss << decrypted_data; - boost::archive::portable_binary_iarchive ar(iss); - ar >> *this; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, *this)) + if (::serialization::check_stream_state(ar)) + loaded = true; } - catch (const std::exception &e) + catch(...) {} + if (!loaded && load_deprecated_formats) + { + try + { + std::stringstream iss; + iss << decrypted_data; + boost::archive::portable_binary_iarchive ar(iss); + ar >> *this; + loaded = true; + } + catch (const std::exception &e) + { + MERROR("MMS file " << filename << " has bad structure: " << e.what()); + THROW_WALLET_EXCEPTION_IF(true, tools::error::file_read_error, filename); + } + } + if (!loaded) { - MERROR("MMS file " << filename << " has bad structure: " << e.what()); + MERROR("MMS file " << filename << " has bad structure"); THROW_WALLET_EXCEPTION_IF(true, tools::error::file_read_error, filename); } diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h index 9055fd776..0f53587d4 100644 --- a/src/wallet/message_store.h +++ b/src/wallet/message_store.h @@ -44,6 +44,9 @@ #include "common/command_line.h" #include "wipeable_string.h" #include "net/abstract_http_client.h" +#include "serialization/crypto.h" +#include "serialization/string.h" +#include "serialization/containers.h" #include "message_transporter.h" #undef MONERO_DEFAULT_LOG_CATEGORY @@ -112,6 +115,24 @@ namespace mms uint32_t round; uint32_t signature_count; std::string transport_id; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + VARINT_FIELD(id) + VARINT_FIELD(type) + VARINT_FIELD(direction) + FIELD(content) + VARINT_FIELD(created) + VARINT_FIELD(modified) + VARINT_FIELD(sent) + VARINT_FIELD(signer_index) + FIELD(hash) + VARINT_FIELD(state) + VARINT_FIELD(wallet_height) + VARINT_FIELD(round) + VARINT_FIELD(signature_count) + FIELD(transport_id) + END_SERIALIZE() }; // "wallet_height" (for lack of a short name that would describe what it is about) // is the number of transfers present in the wallet at the time of message @@ -132,6 +153,21 @@ namespace mms std::string auto_config_transport_address; bool auto_config_running; + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(label) + FIELD(transport_address) + FIELD(monero_address_known) + FIELD(monero_address) + FIELD(me) + VARINT_FIELD(index) + FIELD(auto_config_token) + FIELD(auto_config_public_key) + FIELD(auto_config_secret_key) + FIELD(auto_config_transport_address) + FIELD(auto_config_running) + END_SERIALIZE() + authorized_signer() { monero_address_known = false; @@ -164,6 +200,13 @@ namespace mms std::string label; std::string transport_address; cryptonote::account_public_address monero_address; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(label) + FIELD(transport_address) + FIELD(monero_address) + END_SERIALIZE() }; // Overal .mms file structure, with the "message_store" object serialized to and @@ -174,6 +217,13 @@ namespace mms uint32_t file_version; crypto::chacha_iv iv; std::string encrypted_data; + + BEGIN_SERIALIZE_OBJECT() + FIELD(magic_string) + FIELD(file_version) + FIELD(iv) + FIELD(encrypted_data) + END_SERIALIZE() }; // The following struct provides info about the current state of a "wallet2" object @@ -198,6 +248,19 @@ namespace mms uint32_t multisig_rounds_passed; size_t num_transfer_details; std::string mms_file; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(address) + VARINT_FIELD(nettype) + FIELD(view_secret_key) + FIELD(multisig) + FIELD(multisig_is_ready) + FIELD(has_multisig_partial_key_images) + VARINT_FIELD(multisig_rounds_passed) + VARINT_FIELD(num_transfer_details) + FIELD(mms_file) + END_SERIALIZE() }; class message_store @@ -283,7 +346,7 @@ namespace mms void stop() { m_run.store(false, std::memory_order_relaxed); m_transporter.stop(); } void write_to_file(const multisig_wallet_state &state, const std::string &filename); - void read_from_file(const multisig_wallet_state &state, const std::string &filename); + void read_from_file(const multisig_wallet_state &state, const std::string &filename, bool load_deprecated_formats = false); template <class t_archive> inline void serialize(t_archive &a, const unsigned int ver) @@ -298,6 +361,18 @@ namespace mms a & m_auto_send; } + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(m_active) + VARINT_FIELD(m_num_authorized_signers) + VARINT_FIELD(m_nettype) + VARINT_FIELD(m_num_required_signers) + FIELD(m_signers) + FIELD(m_messages) + VARINT_FIELD(m_next_message_id) + FIELD(m_auto_send) + END_SERIALIZE() + static const char* message_type_to_string(message_type type); static const char* message_direction_to_string(message_direction direction); static const char* message_state_to_string(message_state state); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ded5c7212..c67565570 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -48,6 +48,7 @@ using namespace epee; #include "wallet_rpc_helpers.h" #include "wallet2.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "net/parse.h" #include "rpc/core_rpc_server_commands_defs.h" #include "rpc/core_rpc_server_error_codes.h" #include "rpc/rpc_payment_signature.h" @@ -102,8 +103,8 @@ using namespace cryptonote; // used to target a given block weight (additional outputs may be added on top to build fee) #define TX_WEIGHT_TARGET(bytes) (bytes*2/3) -#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\004" -#define SIGNED_TX_PREFIX "Monero signed tx set\004" +#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\005" +#define SIGNED_TX_PREFIX "Monero signed tx set\005" #define MULTISIG_UNSIGNED_TX_PREFIX "Monero multisig unsigned tx set\001" #define RECENT_OUTPUT_RATIO (0.5) // 50% of outputs are from the recent zone @@ -440,30 +441,14 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl ); } - boost::asio::ip::tcp::endpoint proxy{}; + std::string proxy; if (use_proxy) { - namespace ip = boost::asio::ip; - - const auto proxy_address = command_line::get_arg(vm, opts.proxy); - - boost::string_ref proxy_port{proxy_address}; - boost::string_ref proxy_host = proxy_port.substr(0, proxy_port.rfind(":")); - if (proxy_port.size() == proxy_host.size()) - proxy_host = "127.0.0.1"; - else - proxy_port = proxy_port.substr(proxy_host.size() + 1); - - uint16_t port_value = 0; + proxy = command_line::get_arg(vm, opts.proxy); THROW_WALLET_EXCEPTION_IF( - !epee::string_tools::get_xtype_from_string(port_value, std::string{proxy_port}), + !net::get_tcp_endpoint(proxy), tools::error::wallet_internal_error, - std::string{"Invalid port specified for --"} + opts.proxy.name - ); - - boost::system::error_code error{}; - proxy = ip::tcp::endpoint{ip::address::from_string(std::string{proxy_host}, error), port_value}; - THROW_WALLET_EXCEPTION_IF(bool(error), tools::error::wallet_internal_error, std::string{"Invalid IP address specified for --"} + opts.proxy.name); + std::string{"Invalid address specified for --"} + opts.proxy.name); } boost::optional<bool> trusted_daemon; @@ -488,7 +473,10 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl } std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds, unattended)); - wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, std::move(ssl_options)); + if (!wallet->init(std::move(daemon_address), std::move(login), std::move(proxy), 0, *trusted_daemon, std::move(ssl_options))) + { + THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, tools::wallet2::tr("failed to initialize the wallet")); + } boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir); wallet->set_ring_database(ringdb_path.string()); wallet->get_message_store().set_options(vm); @@ -1125,7 +1113,7 @@ void wallet_device_callback::on_progress(const hw::device_progress& event) } wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory): - m_http_client(std::move(http_client_factory->create())), + m_http_client(http_client_factory->create()), m_multisig_rescan_info(NULL), m_multisig_rescan_k(NULL), m_upper_transaction_weight_limit(0), @@ -1195,6 +1183,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std m_offline(false), m_rpc_version(0), m_export_format(ExportFormat::Binary), + m_load_deprecated_formats(false), m_credits_target(0) { set_rpc_client_secret_key(rct::rct2sk(rct::skGen())); @@ -1325,18 +1314,17 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u return ret; } //---------------------------------------------------------------------------------------------------- -bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, boost::asio::ip::tcp::endpoint proxy, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options) +bool wallet2::set_proxy(const std::string &address) { + return m_http_client->set_proxy(address); +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, const std::string &proxy_address, uint64_t upper_transaction_weight_limit, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options) +{ + CHECK_AND_ASSERT_MES(set_proxy(proxy_address), false, "failed to set proxy address"); m_checkpoints.init_default_checkpoints(m_nettype); m_is_initialized = true; m_upper_transaction_weight_limit = upper_transaction_weight_limit; - if (proxy != boost::asio::ip::tcp::endpoint{}) - { - epee::net_utils::http::abstract_http_client* abstract_http_client = m_http_client.get(); - epee::net_utils::http::http_simple_client* http_simple_client = dynamic_cast<epee::net_utils::http::http_simple_client*>(abstract_http_client); - CHECK_AND_ASSERT_MES(http_simple_client != nullptr, false, "http_simple_client must be used to set proxy"); - http_simple_client->set_connector(net::socks::connector{std::move(proxy)}); - } return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options)); } //---------------------------------------------------------------------------------------------------- @@ -3916,6 +3904,9 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee: value2.SetInt(m_export_format); json.AddMember("export_format", value2, json.GetAllocator()); + value2.SetInt(m_load_deprecated_formats); + json.AddMember("load_deprecated_formats", value2, json.GetAllocator()); + value2.SetUint(1); json.AddMember("encrypted_secret_keys", value2, json.GetAllocator()); @@ -4085,6 +4076,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_original_keys_available = false; m_export_format = ExportFormat::Binary; + m_load_deprecated_formats = false; m_device_name = ""; m_device_derivation_path = ""; m_key_device_type = hw::device::device_type::SOFTWARE; @@ -4265,6 +4257,9 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st 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, load_deprecated_formats, int, Int, false, false); + m_load_deprecated_formats = field_load_deprecated_formats; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, device_name, std::string, String, false, std::string()); if (m_device_name.empty()) { @@ -5614,10 +5609,26 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cache_data[0]); try { - std::stringstream iss; - iss << cache_data; - boost::archive::portable_binary_iarchive ar(iss); - ar >> *this; + bool loaded = false; + + try + { + std::stringstream iss; + iss << cache_data; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, *this)) + if (::serialization::check_stream_state(ar)) + loaded = true; + } + catch(...) { } + + if (!loaded) + { + std::stringstream iss; + iss << cache_data; + boost::archive::portable_binary_iarchive ar(iss); + ar >> *this; + } } catch(...) { @@ -5714,7 +5725,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass try { if (use_fs) - m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file); + m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file, m_load_deprecated_formats); } catch (const std::exception &e) { @@ -5904,8 +5915,9 @@ boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data(const epe try { std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << *this; + binary_archive<true> ar(oss); + if (!::serialization::serialize(ar, *this)) + return boost::none; boost::optional<wallet2::cache_file_data> cache_file_data = (wallet2::cache_file_data) {}; cache_file_data.get().cache_data = oss.str(); @@ -6567,10 +6579,11 @@ std::string wallet2::dump_tx_to_str(const std::vector<pending_tx> &ptx_vector) c txs.transfers = export_outputs(); // save as binary std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); + binary_archive<true> ar(oss); try { - ar << txs; + if (!::serialization::serialize(ar, txs)) + return std::string(); } catch (...) { @@ -6614,6 +6627,11 @@ bool wallet2::parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsi s = s.substr(1); if (version == '\003') { + if (!m_load_deprecated_formats) + { + LOG_PRINT_L0("Not loading deprecated format"); + return false; + } try { std::istringstream iss(s); @@ -6628,6 +6646,11 @@ bool wallet2::parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsi } else if (version == '\004') { + if (!m_load_deprecated_formats) + { + LOG_PRINT_L0("Not loading deprecated format"); + return false; + } try { s = decrypt_with_view_secret_key(s); @@ -6649,6 +6672,26 @@ bool wallet2::parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsi return false; } } + else if (version == '\005') + { + try { s = decrypt_with_view_secret_key(s); } + catch(const std::exception &e) { LOG_PRINT_L0("Failed to decrypt unsigned tx: " << e.what()); return false; } + try + { + std::istringstream iss(s); + binary_archive<false> ar(iss); + if (!::serialization::serialize(ar, exported_txs)) + { + LOG_PRINT_L0("Failed to parse data from unsigned tx"); + return false; + } + } + catch (...) + { + LOG_PRINT_L0("Failed to parse data from unsigned tx"); + return false; + } + } else { LOG_PRINT_L0("Unsupported version in unsigned tx"); @@ -6846,10 +6889,11 @@ std::string wallet2::sign_tx_dump_to_str(unsigned_tx_set &exported_txs, std::vec // save as binary std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); + binary_archive<true> ar(oss); try { - ar << signed_txes; + if (!::serialization::serialize(ar, signed_txes)) + return std::string(); } catch(...) { @@ -6898,6 +6942,11 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too s = s.substr(1); if (version == '\003') { + if (!m_load_deprecated_formats) + { + LOG_PRINT_L0("Not loading deprecated format"); + return false; + } try { std::istringstream iss(s); @@ -6912,6 +6961,11 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too } else if (version == '\004') { + if (!m_load_deprecated_formats) + { + LOG_PRINT_L0("Not loading deprecated format"); + return false; + } try { s = decrypt_with_view_secret_key(s); @@ -6933,6 +6987,26 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too return false; } } + else if (version == '\005') + { + try { s = decrypt_with_view_secret_key(s); } + catch (const std::exception &e) { LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what()); return false; } + try + { + std::istringstream iss(s); + binary_archive<false> ar(iss); + if (!::serialization::serialize(ar, signed_txs)) + { + LOG_PRINT_L0("Failed to deserialize signed transaction"); + return false; + } + } + catch (const std::exception &e) + { + LOG_PRINT_L0("Failed to decrypt signed transaction: " << e.what()); + return false; + } + } else { LOG_PRINT_L0("Unsupported version in signed transaction"); @@ -6984,10 +7058,11 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs) // save as binary std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); + binary_archive<true> ar(oss); try { - ar << txs; + if (!::serialization::serialize(ar, txs)) + return std::string(); } catch (...) { @@ -7051,13 +7126,29 @@ bool wallet2::parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx LOG_PRINT_L0("Failed to decrypt multisig tx data: " << e.what()); return false; } + bool loaded = false; try { std::istringstream iss(multisig_tx_st); - boost::archive::portable_binary_iarchive ar(iss); - ar >> exported_txs; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, exported_txs)) + if (::serialization::check_stream_state(ar)) + loaded = true; } - catch (...) + catch (...) {} + try + { + if (!loaded && m_load_deprecated_formats) + { + std::istringstream iss(multisig_tx_st); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + loaded = true; + } + } + catch(...) {} + + if (!loaded) { LOG_PRINT_L0("Failed to parse multisig tx data"); return false; @@ -9544,8 +9635,8 @@ bool wallet2::light_wallet_parse_rct_str(const std::string& rct_string, const cr bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image, const crypto::public_key& tx_public_key, uint64_t out_index) { // Lookup key image from cache - std::map<uint64_t, crypto::key_image> index_keyimage_map; - std::unordered_map<crypto::public_key, std::map<uint64_t, crypto::key_image> >::const_iterator found_pub_key = m_key_image_cache.find(tx_public_key); + serializable_map<uint64_t, crypto::key_image> index_keyimage_map; + serializable_unordered_map<crypto::public_key, serializable_map<uint64_t, crypto::key_image> >::const_iterator found_pub_key = m_key_image_cache.find(tx_public_key); if(found_pub_key != m_key_image_cache.end()) { // pub key found. key image for index cached? index_keyimage_map = found_pub_key->second; @@ -11425,7 +11516,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]); } } - sig_str = std::string("OutProofV1"); + sig_str = std::string("OutProofV2"); } else { @@ -11461,7 +11552,7 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]); } } - sig_str = std::string("InProofV1"); + sig_str = std::string("InProofV2"); } const size_t num_sigs = shared_secret.size(); @@ -11540,8 +11631,14 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message, const std::string &sig_str, uint64_t &received) const { + // InProofV1, InProofV2, OutProofV1, OutProofV2 const bool is_out = sig_str.substr(0, 3) == "Out"; - const std::string header = is_out ? "OutProofV1" : "InProofV1"; + const std::string header = is_out ? sig_str.substr(0,10) : sig_str.substr(0,9); + int version = 2; // InProofV2 + if (is_out && sig_str.substr(8,2) == "V1") version = 1; // OutProofV1 + else if (is_out) version = 2; // OutProofV2 + else if (sig_str.substr(7,2) == "V1") version = 1; // InProofV1 + const size_t header_len = header.size(); THROW_WALLET_EXCEPTION_IF(sig_str.size() < header_len || sig_str.substr(0, header_len) != header, error::wallet_internal_error, "Signature header check error"); @@ -11588,27 +11685,27 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote if (is_out) { good_signature[0] = is_subaddress ? - crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0]) : - crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0]); + crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], sig[0], version) : + crypto::check_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], sig[0], version); for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { good_signature[i + 1] = is_subaddress ? - crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) : - crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, boost::none, shared_secret[i + 1], sig[i + 1]); + crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, address.m_spend_public_key, shared_secret[i + 1], sig[i + 1], version) : + crypto::check_tx_proof(prefix_hash, additional_tx_pub_keys[i], address.m_view_public_key, boost::none, shared_secret[i + 1], sig[i + 1], version); } } else { good_signature[0] = is_subaddress ? - crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0]) : - crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0]); + crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], sig[0], version) : + crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], sig[0], version); for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { good_signature[i + 1] = is_subaddress ? - crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], address.m_spend_public_key, shared_secret[i + 1], sig[i + 1]) : - crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], boost::none, shared_secret[i + 1], sig[i + 1]); + crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], address.m_spend_public_key, shared_secret[i + 1], sig[i + 1], version) : + crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i], boost::none, shared_secret[i + 1], sig[i + 1], version); } } @@ -11727,7 +11824,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, } // collect all subaddress spend keys that received those outputs and generate their signatures - std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys; + serializable_unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys; for (const cryptonote::subaddress_index &index : subaddr_indices) { crypto::secret_key subaddr_spend_skey = m_account.get_keys().m_spend_secret_key; @@ -11744,9 +11841,10 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, // serialize & encode std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << proofs << subaddr_spendkeys; - return "ReserveProofV1" + tools::base58::encode(oss.str()); + binary_archive<true> ar(oss); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, proofs), error::wallet_internal_error, "Failed to serialize proof"); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, subaddr_spendkeys), error::wallet_internal_error, "Failed to serialize proof"); + return "ReserveProofV2" + tools::base58::encode(oss.str()); } bool wallet2::check_reserve_proof(const cryptonote::account_public_address &address, const std::string &message, const std::string &sig_str, uint64_t &total, uint64_t &spent) @@ -11755,19 +11853,39 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address()); THROW_WALLET_EXCEPTION_IF(rpc_version < MAKE_CORE_RPC_VERSION(1, 0), error::wallet_internal_error, "Daemon RPC version is too old"); - static constexpr char header[] = "ReserveProofV1"; - THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header), error::wallet_internal_error, + static constexpr char header_v1[] = "ReserveProofV1"; + static constexpr char header_v2[] = "ReserveProofV2"; // assumes same length as header_v1 + THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header_v1) && !boost::string_ref{sig_str}.starts_with(header_v2), error::wallet_internal_error, "Signature header check error"); + int version = 2; // assume newest version + if (boost::string_ref{sig_str}.starts_with(header_v1)) + version = 1; + else if (boost::string_ref{sig_str}.starts_with(header_v2)) + version = 2; std::string sig_decoded; - THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header)), sig_decoded), error::wallet_internal_error, + THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header_v1)), sig_decoded), error::wallet_internal_error, "Signature decoding error"); - std::istringstream iss(sig_decoded); - boost::archive::portable_binary_iarchive ar(iss); + bool loaded = false; std::vector<reserve_proof_entry> proofs; - std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys; - ar >> proofs >> subaddr_spendkeys; + serializable_unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys; + try + { + std::istringstream iss(sig_decoded); + binary_archive<false> ar(iss); + if (::serialization::serialize_noeof(ar, proofs)) + if (::serialization::serialize_noeof(ar, subaddr_spendkeys)) + if (::serialization::check_stream_state(ar)) + loaded = true; + } + catch(...) {} + if (!loaded && m_load_deprecated_formats) + { + std::istringstream iss(sig_decoded); + boost::archive::portable_binary_iarchive ar(iss); + ar >> proofs >> subaddr_spendkeys.parent(); + } THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(address.m_spend_public_key) == 0, error::wallet_internal_error, "The given address isn't found in the proof"); @@ -11841,9 +11959,9 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx); // check singature for shared secret - ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig); + ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig, version); if (!ok && additional_tx_pub_keys.size() == tx.vout.size()) - ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig); + ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig, version); if (!ok) return false; @@ -12006,7 +12124,7 @@ std::string wallet2::get_description() const return ""; } -const std::pair<std::map<std::string, std::string>, std::vector<std::string>>& wallet2::get_account_tags() +const std::pair<serializable_map<std::string, std::string>, std::vector<std::string>>& wallet2::get_account_tags() { // ensure consistency if (m_account_tags.second.size() != get_num_subaddress_accounts()) @@ -12728,9 +12846,9 @@ std::string wallet2::export_outputs_to_str(bool all) const PERF_TIMER(export_outputs_to_str); std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - const auto& outputs = export_outputs(all); - ar << outputs; + binary_archive<true> ar(oss); + auto outputs = export_outputs(all); + THROW_WALLET_EXCEPTION_IF(!::serialization::serialize(ar, outputs), error::wallet_internal_error, "Failed to serialize output data"); std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC)); const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; @@ -12842,23 +12960,39 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st) } size_t imported_outputs = 0; + bool loaded = false; try { std::string body(data, headerlen); - std::stringstream iss; - iss << body; std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs; try { - boost::archive::portable_binary_iarchive ar(iss); - ar >> outputs; + std::stringstream iss; + iss << body; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, outputs)) + if (::serialization::check_stream_state(ar)) + loaded = true; } - catch (...) + catch (...) {} + + if (!loaded && m_load_deprecated_formats) { - iss.str(""); - iss << body; - boost::archive::binary_iarchive ar(iss); - ar >> outputs; + try + { + std::stringstream iss; + iss << body; + boost::archive::portable_binary_iarchive ar(iss); + ar >> outputs; + loaded = true; + } + catch (...) {} + } + + if (!loaded) + { + outputs.first = 0; + outputs.second = {}; } imported_outputs = import_outputs(outputs); @@ -13012,8 +13146,8 @@ cryptonote::blobdata wallet2::export_multisig() } std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << info; + binary_archive<true> ar(oss); + CHECK_AND_ASSERT_THROW_MES(::serialization::serialize(ar, info), "Failed to serialize multisig data"); const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; std::string header; @@ -13083,10 +13217,26 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs) seen.insert(signer); std::string body(data, headerlen); - std::istringstream iss(body); std::vector<tools::wallet2::multisig_info> i; - boost::archive::portable_binary_iarchive ar(iss); - ar >> i; + + bool loaded = false; + try + { + std::istringstream iss(body); + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, i)) + if (::serialization::check_stream_state(ar)) + loaded = true; + } + catch(...) {} + if (!loaded && m_load_deprecated_formats) + { + std::istringstream iss(body); + boost::archive::portable_binary_iarchive ar(iss); + ar >> i; + loaded = true; + } + CHECK_AND_ASSERT_THROW_MES(loaded, "Failed to load output data"); MINFO(boost::format("%u outputs found") % boost::lexical_cast<std::string>(i.size())); info.push_back(std::move(i)); } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 712f91613..92a38a01d 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -45,7 +45,7 @@ #include "cryptonote_basic/account.h" #include "cryptonote_basic/account_boost_serialization.h" #include "cryptonote_basic/cryptonote_basic_impl.h" -#include "net/http_client.h" +#include "net/http.h" #include "storages/http_abstract_invoke.h" #include "rpc/core_rpc_server_commands_defs.h" #include "cryptonote_basic/cryptonote_format_utils.h" @@ -57,7 +57,10 @@ #include "ringct/rctTypes.h" #include "ringct/rctOps.h" #include "checkpoints/checkpoints.h" +#include "serialization/crypto.h" +#include "serialization/string.h" #include "serialization/pair.h" +#include "serialization/containers.h" #include "wallet_errors.h" #include "common/password.h" @@ -205,6 +208,13 @@ private: a & m_blockchain; } + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + VARINT_FIELD(m_offset) + FIELD(m_genesis) + FIELD(m_blockchain) + END_SERIALIZE() + private: size_t m_offset; crypto::hash m_genesis; @@ -269,7 +279,7 @@ private: static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds); static bool query_device(hw::device::device_type& device_type, const std::string& keys_file_name, const epee::wipeable_string& password, uint64_t kdf_rounds = 1); - wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = std::unique_ptr<epee::net_utils::http::http_simple_client_factory>(new epee::net_utils::http::http_simple_client_factory())); + wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = std::unique_ptr<epee::net_utils::http::http_client_factory>(new net::http::client_factory())); ~wallet2(); struct multisig_info @@ -372,6 +382,19 @@ private: uint64_t m_timestamp; bool m_coinbase; cryptonote::subaddress_index m_subaddr_index; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(m_tx_hash) + VARINT_FIELD(m_amount) + FIELD(m_amounts) + VARINT_FIELD(m_fee) + VARINT_FIELD(m_block_height) + VARINT_FIELD(m_unlock_time) + VARINT_FIELD(m_timestamp) + FIELD(m_coinbase) + FIELD(m_subaddr_index) + END_SERIALIZE() }; struct address_tx : payment_details @@ -384,6 +407,12 @@ private: { payment_details m_pd; bool m_double_spend_seen; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(m_pd) + FIELD(m_double_spend_seen) + END_SERIALIZE() }; struct unconfirmed_transfer_details @@ -400,6 +429,21 @@ private: uint32_t m_subaddr_account; // subaddress account of your wallet to be used in this transfer std::set<uint32_t> m_subaddr_indices; // set of address indices used as inputs in this transfer std::vector<std::pair<crypto::key_image, std::vector<uint64_t>>> m_rings; // relative + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(m_tx) + VARINT_FIELD(m_amount_in) + VARINT_FIELD(m_amount_out) + VARINT_FIELD(m_change) + VARINT_FIELD(m_sent_time) + FIELD(m_dests) + FIELD(m_payment_id) + VARINT_FIELD(m_timestamp) + VARINT_FIELD(m_subaddr_account) + FIELD(m_subaddr_indices) + FIELD(m_rings) + END_SERIALIZE() }; struct confirmed_transfer_details @@ -419,6 +463,21 @@ private: confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(crypto::null_hash), m_timestamp(0), m_unlock_time(0), m_subaddr_account((uint32_t)-1) {} confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height): m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time), m_subaddr_account(utd.m_subaddr_account), m_subaddr_indices(utd.m_subaddr_indices), m_rings(utd.m_rings) {} + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + VARINT_FIELD(m_amount_in) + VARINT_FIELD(m_amount_out) + VARINT_FIELD(m_change) + VARINT_FIELD(m_block_height) + FIELD(m_dests) + FIELD(m_payment_id) + VARINT_FIELD(m_timestamp) + VARINT_FIELD(m_unlock_time) + VARINT_FIELD(m_subaddr_account) + FIELD(m_subaddr_indices) + FIELD(m_rings) + END_SERIALIZE() }; struct tx_construction_data @@ -451,7 +510,7 @@ private: }; typedef std::vector<transfer_details> transfer_container; - typedef std::unordered_multimap<crypto::hash, payment_details> payment_container; + typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container; struct multisig_sig { @@ -460,6 +519,15 @@ private: std::unordered_set<rct::key> used_L; std::unordered_set<crypto::public_key> signing_keys; rct::multisig_out msout; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(sigs) + FIELD(ignore) + FIELD(used_L) + FIELD(signing_keys) + FIELD(msout) + END_SERIALIZE() }; // The convention for destinations is: @@ -502,13 +570,26 @@ private: { std::vector<tx_construction_data> txes; std::pair<size_t, wallet2::transfer_container> transfers; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(txes) + FIELD(transfers) + END_SERIALIZE() }; struct signed_tx_set { std::vector<pending_tx> ptx; std::vector<crypto::key_image> key_images; - std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images; + serializable_unordered_map<crypto::public_key, crypto::key_image> tx_key_images; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(ptx) + FIELD(key_images) + FIELD(tx_key_images) + END_SERIALIZE() }; struct multisig_tx_set @@ -543,7 +624,7 @@ private: FIELD(cache_data) END_SERIALIZE() }; - + // GUI Address book struct address_book_row { @@ -552,6 +633,15 @@ private: std::string m_description; bool m_is_subaddress; bool m_has_payment_id; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(m_address) + FIELD(m_payment_id) + FIELD(m_description) + FIELD(m_is_subaddress) + FIELD(m_has_payment_id) + END_SERIALIZE() }; struct reserve_proof_entry @@ -562,6 +652,16 @@ private: crypto::key_image key_image; crypto::signature shared_secret_sig; crypto::signature key_image_sig; + + BEGIN_SERIALIZE_OBJECT() + VERSION_FIELD(0) + FIELD(txid) + VARINT_FIELD(index_in_tx) + FIELD(shared_secret) + FIELD(key_image) + FIELD(shared_secret_sig) + FIELD(key_image_sig) + END_SERIALIZE() }; typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry; @@ -753,13 +853,14 @@ private: bool deinit(); bool init(std::string daemon_address = "http://localhost:8080", boost::optional<epee::net_utils::http::login> daemon_login = boost::none, - boost::asio::ip::tcp::endpoint proxy = {}, + const std::string &proxy = "", uint64_t upper_transaction_weight_limit = 0, bool trusted_daemon = true, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); bool set_daemon(std::string daemon_address = "http://localhost:8080", boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); + bool set_proxy(const std::string &address); void stop() { m_run.store(false, std::memory_order_relaxed); m_message_store.stop(); } @@ -917,6 +1018,7 @@ private: { std::vector<crypto::hash> blockchain; a & blockchain; + m_blockchain.clear(); for (const auto &b: blockchain) { m_blockchain.push_back(b); @@ -928,25 +1030,25 @@ private: } a & m_transfers; a & m_account_public_address; - a & m_key_images; + a & m_key_images.parent(); if(ver < 6) return; - a & m_unconfirmed_txs; + a & m_unconfirmed_txs.parent(); if(ver < 7) return; - a & m_payments; + a & m_payments.parent(); if(ver < 8) return; - a & m_tx_keys; + a & m_tx_keys.parent(); if(ver < 9) return; - a & m_confirmed_txs; + a & m_confirmed_txs.parent(); if(ver < 11) return; a & dummy_refresh_height; if(ver < 12) return; - a & m_tx_notes; + a & m_tx_notes.parent(); if(ver < 13) return; if (ver < 17) @@ -954,6 +1056,7 @@ private: // we're loading an old version, where m_unconfirmed_payments was a std::map std::unordered_map<crypto::hash, payment_details> m; a & m; + m_unconfirmed_payments.clear(); for (std::unordered_map<crypto::hash, payment_details>::const_iterator i = m.begin(); i != m.end(); ++i) m_unconfirmed_payments.insert(std::make_pair(i->first, pool_payment_details{i->second, false})); } @@ -962,6 +1065,7 @@ private: if(ver < 15) { // we're loading an older wallet without a pubkey map, rebuild it + m_pub_keys.clear(); for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details &td = m_transfers[i]; @@ -971,7 +1075,7 @@ private: } return; } - a & m_pub_keys; + a & m_pub_keys.parent(); if(ver < 16) return; a & m_address_book; @@ -982,6 +1086,7 @@ private: // we're loading an old version, where m_unconfirmed_payments payload was payment_details std::unordered_multimap<crypto::hash, payment_details> m; a & m; + m_unconfirmed_payments.clear(); for (const auto &i: m) m_unconfirmed_payments.insert(std::make_pair(i.first, pool_payment_details{i.second, false})); } @@ -991,20 +1096,20 @@ private: a & m_scanned_pool_txs[1]; if (ver < 20) return; - a & m_subaddresses; + a & m_subaddresses.parent(); std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv; a & dummy_subaddresses_inv; a & m_subaddress_labels; - a & m_additional_tx_keys; + a & m_additional_tx_keys.parent(); if(ver < 21) return; - a & m_attributes; + a & m_attributes.parent(); if(ver < 22) return; - a & m_unconfirmed_payments; + a & m_unconfirmed_payments.parent(); if(ver < 23) return; - a & m_account_tags; + a & (std::pair<std::map<std::string, std::string>, std::vector<std::string>>&)m_account_tags; if(ver < 24) return; a & m_ring_history_saved; @@ -1013,18 +1118,48 @@ private: a & m_last_block_reward; if(ver < 26) return; - a & m_tx_device; + a & m_tx_device.parent(); if(ver < 27) return; a & m_device_last_key_image_sync; if(ver < 28) return; - a & m_cold_key_images; + a & m_cold_key_images.parent(); if(ver < 29) return; a & m_rpc_client_secret_key; } + BEGIN_SERIALIZE_OBJECT() + MAGIC_FIELD("monero wallet cache") + VERSION_FIELD(0) + FIELD(m_blockchain) + FIELD(m_transfers) + FIELD(m_account_public_address) + FIELD(m_key_images) + FIELD(m_unconfirmed_txs) + FIELD(m_payments) + FIELD(m_tx_keys) + FIELD(m_confirmed_txs) + FIELD(m_tx_notes) + FIELD(m_unconfirmed_payments) + FIELD(m_pub_keys) + FIELD(m_address_book) + FIELD(m_scanned_pool_txs[0]) + FIELD(m_scanned_pool_txs[1]) + FIELD(m_subaddresses) + FIELD(m_subaddress_labels) + FIELD(m_additional_tx_keys) + FIELD(m_attributes) + FIELD(m_account_tags) + FIELD(m_ring_history_saved) + FIELD(m_last_block_reward) + FIELD(m_tx_device) + FIELD(m_device_last_key_image_sync) + FIELD(m_cold_key_images) + FIELD(m_rpc_client_secret_key) + END_SERIALIZE() + /*! * \brief Check if wallet keys and bin files exist * \param file_path Wallet file path @@ -1096,6 +1231,8 @@ private: 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 load_deprecated_formats() const { return m_load_deprecated_formats; } + void load_deprecated_formats(bool load) { m_load_deprecated_formats = load; } bool persistent_rpc_client_id() const { return m_persistent_rpc_client_id; } void persistent_rpc_client_id(bool persistent) { m_persistent_rpc_client_id = persistent; } void auto_mine_for_rpc_payment_threshold(float threshold) { m_auto_mine_for_rpc_payment_threshold = threshold; } @@ -1187,7 +1324,7 @@ private: * \brief Get the list of registered account tags. * \return first.Key=(tag's name), first.Value=(tag's label), second[i]=(i-th account's tag) */ - const std::pair<std::map<std::string, std::string>, std::vector<std::string>>& get_account_tags(); + const std::pair<serializable_map<std::string, std::string>, std::vector<std::string>>& get_account_tags(); /*! * \brief Set a tag to the given accounts. * \param account_indices Indices of accounts. @@ -1527,28 +1664,28 @@ private: std::string m_mms_file; const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client; hashchain m_blockchain; - std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs; - std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs; - std::unordered_multimap<crypto::hash, pool_payment_details> m_unconfirmed_payments; - std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys; + serializable_unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs; + serializable_unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs; + serializable_unordered_multimap<crypto::hash, pool_payment_details> m_unconfirmed_payments; + serializable_unordered_map<crypto::hash, crypto::secret_key> m_tx_keys; cryptonote::checkpoints m_checkpoints; - std::unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_additional_tx_keys; + serializable_unordered_map<crypto::hash, std::vector<crypto::secret_key>> m_additional_tx_keys; transfer_container m_transfers; payment_container m_payments; - std::unordered_map<crypto::key_image, size_t> m_key_images; - std::unordered_map<crypto::public_key, size_t> m_pub_keys; + serializable_unordered_map<crypto::key_image, size_t> m_key_images; + serializable_unordered_map<crypto::public_key, size_t> m_pub_keys; cryptonote::account_public_address m_account_public_address; - std::unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses; + serializable_unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses; std::vector<std::vector<std::string>> m_subaddress_labels; - std::unordered_map<crypto::hash, std::string> m_tx_notes; - std::unordered_map<std::string, std::string> m_attributes; + serializable_unordered_map<crypto::hash, std::string> m_tx_notes; + serializable_unordered_map<std::string, std::string> m_attributes; std::vector<tools::wallet2::address_book_row> m_address_book; - std::pair<std::map<std::string, std::string>, std::vector<std::string>> m_account_tags; + std::pair<serializable_map<std::string, std::string>, std::vector<std::string>> m_account_tags; uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info; const std::vector<std::vector<rct::key>> *m_multisig_rescan_k; - std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images; + serializable_unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images; std::atomic<bool> m_run; @@ -1615,7 +1752,7 @@ private: uint64_t m_credits_target; // Aux transaction data from device - std::unordered_map<crypto::hash, std::string> m_tx_device; + serializable_unordered_map<crypto::hash, std::string> m_tx_device; // Light wallet bool m_light_wallet; /* sends view key to daemon for scanning */ @@ -1629,7 +1766,7 @@ private: // We save the info from the first call in m_light_wallet_address_txs for easier lookup. std::unordered_map<crypto::hash, address_tx> m_light_wallet_address_txs; // store calculated key image for faster lookup - std::unordered_map<crypto::public_key, std::map<uint64_t, crypto::key_image> > m_key_image_cache; + serializable_unordered_map<crypto::public_key, serializable_map<uint64_t, crypto::key_image> > m_key_image_cache; std::string m_ring_database; bool m_ring_history_saved; @@ -1656,6 +1793,7 @@ private: std::unique_ptr<wallet_device_callback> m_device_callback; ExportFormat m_export_format; + bool m_load_deprecated_formats; static boost::mutex default_daemon_address_lock; static std::string default_daemon_address; @@ -2052,7 +2190,7 @@ namespace boost a & x.key_images; if (ver < 1) return; - a & x.tx_key_images; + a & x.tx_key_images.parent(); } template <class Archive> diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index fcaaf7616..0ed749cb7 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -80,7 +80,7 @@ namespace return pwd_container; } //------------------------------------------------------------------------------------------------------------------------------ - void set_confirmations(tools::wallet_rpc::transfer_entry &entry, uint64_t blockchain_height, uint64_t block_reward) + void set_confirmations(tools::wallet_rpc::transfer_entry &entry, uint64_t blockchain_height, uint64_t block_reward, uint64_t unlock_time) { if (entry.height >= blockchain_height || (entry.height == 0 && (!strcmp(entry.type.c_str(), "pending") || !strcmp(entry.type.c_str(), "pool")))) entry.confirmations = 0; @@ -91,6 +91,18 @@ namespace entry.suggested_confirmations_threshold = 0; else entry.suggested_confirmations_threshold = (entry.amount + block_reward - 1) / block_reward; + + if (unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) + { + if (unlock_time > blockchain_height) + entry.suggested_confirmations_threshold = std::max(entry.suggested_confirmations_threshold, unlock_time - blockchain_height); + } + else + { + const uint64_t now = time(NULL); + if (unlock_time > now) + entry.suggested_confirmations_threshold = std::max(entry.suggested_confirmations_threshold, (unlock_time - now + DIFFICULTY_TARGET_V2 - 1) / DIFFICULTY_TARGET_V2); + } } } @@ -335,7 +347,7 @@ namespace tools entry.subaddr_index = pd.m_subaddr_index; entry.subaddr_indices.push_back(pd.m_subaddr_index); entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index); - set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward()); + set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time); } //------------------------------------------------------------------------------------------------------------------------------ void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd) @@ -365,7 +377,7 @@ namespace tools for (uint32_t i: pd.m_subaddr_indices) entry.subaddr_indices.push_back({pd.m_subaddr_account, i}); entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0}); - set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward()); + set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time); } //------------------------------------------------------------------------------------------------------------------------------ void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd) @@ -396,7 +408,7 @@ namespace tools for (uint32_t i: pd.m_subaddr_indices) entry.subaddr_indices.push_back({pd.m_subaddr_account, i}); entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0}); - set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward()); + set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_tx.unlock_time); } //------------------------------------------------------------------------------------------------------------------------------ void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd) @@ -419,7 +431,7 @@ namespace tools entry.subaddr_index = pd.m_subaddr_index; entry.subaddr_indices.push_back(pd.m_subaddr_index); entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index); - set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward()); + set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time); } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, const connection_context *ctx) @@ -826,10 +838,11 @@ namespace tools static std::string ptx_to_string(const tools::wallet2::pending_tx &ptx) { std::ostringstream oss; - boost::archive::portable_binary_oarchive ar(oss); + binary_archive<true> ar(oss); try { - ar << ptx; + if (!::serialization::serialize(ar, const_cast<tools::wallet2::pending_tx&>(ptx))) + return ""; } catch (...) { @@ -1538,14 +1551,31 @@ namespace tools return false; } + bool loaded = false; tools::wallet2::pending_tx ptx; + try { std::istringstream iss(blob); - boost::archive::portable_binary_iarchive ar(iss); - ar >> ptx; + binary_archive<false> ar(iss); + if (::serialization::serialize(ar, ptx)) + loaded = true; } - catch (...) + catch(...) {} + + if (!loaded && !m_restricted) + { + try + { + std::istringstream iss(blob); + boost::archive::portable_binary_iarchive ar(iss); + ar >> ptx; + loaded = true; + } + catch (...) {} + } + + if (!loaded) { er.code = WALLET_RPC_ERROR_CODE_BAD_TX_METADATA; er.message = "Failed to parse tx metadata."; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index ae861d177..5b2536bf1 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 18 +#define WALLET_RPC_VERSION_MINOR 19 #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 |