diff options
-rw-r--r-- | .github/workflows/build.yml | 15 | ||||
-rw-r--r-- | README.md | 51 | ||||
-rw-r--r-- | src/cryptonote_basic/miner.cpp | 2 | ||||
-rw-r--r-- | src/daemon/daemon.cpp | 9 | ||||
-rw-r--r-- | src/daemon/rpc.h | 3 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 3 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.h | 3 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 32 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 30 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 7 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 2 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 3 |
12 files changed, 112 insertions, 48 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 425ca8955..ce460ef04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,21 @@ jobs: - name: build run: make -j3 + libwallet-ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + submodules: recursive + - name: remove bundled boost + run: sudo rm -rf /usr/local/share/boost + - name: update apt + run: sudo apt update + - name: install monero dependencies + run: sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev + - name: build + run: cmake -DBUILD_GUI_DEPS=ON && make -j3 + test-ubuntu: needs: build-ubuntu runs-on: ubuntu-latest @@ -34,6 +34,7 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers. - Mail: [dev@getmonero.org](mailto:dev@getmonero.org) - GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero) - IRC: [#monero-dev on Freenode](https://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4) +- It is HIGHLY recommended that you join the #monero-dev IRC channel if you are developing software that uses Monero. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments in the Monero ecosystem. All you need to do is join the IRC channel and idle to stay updated with the latest in Monero development. If you do not, you risk wasting resources on developing integrations that are not compatible with the Monero network. The Monero core team and community continuously make efforts to communicate updates, developments, and documentation via other platforms – but for the best information, you need to talk to other Monero developers, and they are on IRC. #monero-dev is about Monero development, not getting help about using Monero, or help about development of other software, including yours, unless it also pertains to Monero code itself. For these cases, checkout #monero. ## Vulnerability response @@ -157,31 +158,31 @@ sources are also used for statically-linked builds because distribution packages often include only shared library binaries (`.so`) but not static library archives (`.a`). -| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Fedora | Optional | Purpose | -| ------------ | ------------- | -------- | -------------------- | ------------ | ------------------- | -------- | --------------- | -| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `gcc` | NO | | -| CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | NO | | -| pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | | -| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | NO | C++ libraries | -| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum | -| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `zeromq-devel` | NO | ZeroMQ library | -| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | `openpgm-devel` | NO | For ZeroMQ | -| libnorm[2] | ? | NO | `libnorm-dev` | | | YES | For ZeroMQ | -| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver | -| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | NO | cryptography | -| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces | -| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind | -| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing | -| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `ldns-devel` | YES | SSL toolkit | -| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | YES | XML parsing | -| GTest | 1.5 | YES | `libgtest-dev`[1] | `gtest` | `gtest-devel` | YES | Test suite | -| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation | -| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation | -| lrelease | ? | NO | `qttools5-dev-tools` | `qt5-tools` | `qt5-linguist` | YES | Translations | -| libhidapi | ? | NO | `libhidapi-dev` | `hidapi` | `hidapi-devel` | YES | Hardware wallet | -| libusb | ? | NO | `libusb-dev` | `libusb` | `libusb-devel` | YES | Hardware wallet | -| libprotobuf | ? | NO | `libprotobuf-dev` | `protobuf` | `protobuf-devel` | YES | Hardware wallet | -| protoc | ? | NO | `protobuf-compiler` | `protobuf` | `protobuf-compiler` | YES | Hardware wallet | +| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Void pkg | Fedora pkg | Optional | Purpose | +| ------------ | ------------- | -------- | -------------------- | ------------ | ------------------ | ------------------- | -------- | --------------- | +| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `base-devel` | `gcc` | NO | | +| CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | `cmake` | NO | | +| pkg-config | any | NO | `pkg-config` | `base-devel` | `base-devel` | `pkgconf` | NO | | +| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | `boost-devel` | NO | C++ libraries | +| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `libressl-devel` | `openssl-devel` | NO | sha256 sum | +| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `zeromq-devel` | `zeromq-devel` | NO | ZeroMQ library | +| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | | `openpgm-devel` | NO | For ZeroMQ | +| libnorm[2] | ? | NO | `libnorm-dev` | | | | YES | For ZeroMQ | +| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | `unbound-devel` | NO | DNS resolver | +| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | `libsodium-devel` | NO | cryptography | +| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | `libunwind-devel` | YES | Stack traces | +| liblzma | any | NO | `liblzma-dev` | `xz` | `liblzma-devel` | `xz-devel` | YES | For libunwind | +| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | `readline-devel` | YES | Input editing | +| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `libldns-devel` | `ldns-devel` | YES | SSL toolkit | +| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | `expat-devel` | YES | XML parsing | +| GTest | 1.5 | YES | `libgtest-dev`[1] | `gtest` | `gtest-devel` | `gtest-devel` | YES | Test suite | +| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | `doxygen` | YES | Documentation | +| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | `graphviz` | YES | Documentation | +| lrelease | ? | NO | `qttools5-dev-tools` | `qt5-tools` | `qt5-tools` | `qt5-linguist` | YES | Translations | +| libhidapi | ? | NO | `libhidapi-dev` | `hidapi` | `hidapi-devel` | `hidapi-devel` | YES | Hardware wallet | +| libusb | ? | NO | `libusb-dev` | `libusb` | `libusb-devel` | `libusb-devel` | YES | Hardware wallet | +| libprotobuf | ? | NO | `libprotobuf-dev` | `protobuf` | `protobuf-devel` | `protobuf-devel` | YES | Hardware wallet | +| protoc | ? | NO | `protobuf-compiler` | `protobuf` | `protobuf` | `protobuf-compiler` | YES | Hardware wallet | [1] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 688aeaea3..c1e8365ac 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -476,7 +476,7 @@ namespace cryptonote for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++) { crypto::hash h; - gbh(bl, height, tools::get_max_concurrency(), h); + gbh(bl, height, diffic <= 100 ? 0 : tools::get_max_concurrency(), h); if(check_hash(h, diffic)) { diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index cb96b37b6..056f2f320 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -78,13 +78,14 @@ public: const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc); const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); - rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, main_rpc_port, "core"}); + const auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; + const bool has_restricted_rpc_port_arg = !command_line::is_arg_defaulted(vm, restricted_rpc_port_arg); + rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, main_rpc_port, "core", !has_restricted_rpc_port_arg}); - auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; - if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg)) + if(has_restricted_rpc_port_arg) { auto restricted_rpc_port = command_line::get_arg(vm, restricted_rpc_port_arg); - rpcs.emplace_back(new t_rpc{vm, core, p2p, true, restricted_rpc_port, "restricted"}); + rpcs.emplace_back(new t_rpc{vm, core, p2p, true, restricted_rpc_port, "restricted", true}); } } }; diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h index 213593aa7..6f545a3b7 100644 --- a/src/daemon/rpc.h +++ b/src/daemon/rpc.h @@ -56,12 +56,13 @@ public: , const bool restricted , const std::string & port , const std::string & description + , bool allow_rpc_payment ) : m_server{core.get(), p2p.get()}, m_description{description} { MGINFO("Initializing " << m_description << " RPC server..."); - if (!m_server.init(vm, restricted, port)) + if (!m_server.init(vm, restricted, port, allow_rpc_payment)) { throw std::runtime_error("Failed to initialize " + m_description + " RPC server."); } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index e92ae7c08..409c8a01c 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -236,6 +236,7 @@ namespace cryptonote const boost::program_options::variables_map& vm , const bool restricted , const std::string& port + , bool allow_rpc_payment ) { m_restricted = restricted; @@ -247,7 +248,7 @@ namespace cryptonote return false; std::string address = command_line::get_arg(vm, arg_rpc_payment_address); - if (!address.empty()) + if (!address.empty() && allow_rpc_payment) { if (!m_restricted && nettype() != FAKECHAIN) { diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 23c611470..fbcffd120 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -88,7 +88,8 @@ namespace cryptonote bool init( const boost::program_options::variables_map& vm, const bool restricted, - const std::string& port + const std::string& port, + bool allow_rpc_payment ); network_type nettype() const { return m_core.get_nettype(); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 74e793669..d5181f654 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -5469,20 +5469,28 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, std::vector<tx_extra_field> tx_extra_fields; parse_tx_extra(tx.extra, tx_extra_fields); // failure ok tx_extra_nonce extra_nonce; - if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + tx_extra_pub_key extra_pub_key; + crypto::hash8 payment_id8 = crypto::null_hash8; + if (find_tx_extra_field_by_type(tx_extra_fields, extra_pub_key)) { - crypto::hash payment_id = crypto::null_hash; - crypto::hash8 payment_id8 = crypto::null_hash8; - if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + const crypto::public_key &tx_pub_key = extra_pub_key.pub_key; + if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { - if (payment_id8 != crypto::null_hash8) - message_writer() << - tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead"); - } - else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) - message_writer(console_color_red, false) << - tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete and ignored. Use subaddresses instead."); - } + if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + { + m_wallet->get_account().get_device().decrypt_payment_id(payment_id8, tx_pub_key, m_wallet->get_account().get_keys().m_view_secret_key); + } + } + } + + if (payment_id8 != crypto::null_hash8) + message_writer() << + tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead"); + + crypto::hash payment_id = crypto::null_hash; + if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + message_writer(console_color_red, false) << + tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete and ignored. Use subaddresses instead."); } if (unlock_time && !cryptonote::is_coinbase(tx)) message_writer() << tr("NOTE: This transaction is locked, see details with: show_transfer ") + epee::string_tools::pod_to_hex(txid); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 870aa65ac..6a622d953 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1842,7 +1842,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // (that is, the prunable stuff may or may not be included) if (!miner_tx && !pool) process_unconfirmed(txid, tx, height); - std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; // per receiving subaddress index + + // per receiving subaddress index + std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; + std::unordered_map<cryptonote::subaddress_index, amounts_container> tx_amounts_individual_outs; + crypto::public_key tx_pub_key = null_pkey; bool notify = false; @@ -1971,6 +1975,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -1994,6 +2002,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -2010,6 +2022,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote hwdev.set_mode(hw::device::NONE); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + if (!tx_scan_info[i].error) + { + tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered); + } } } } @@ -2118,6 +2134,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount, error::wallet_internal_error, "Unexpected values of new and old outputs"); tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount; + + amounts_container& tx_amounts_this_out = tx_amounts_individual_outs[tx_scan_info[o].received->index]; // Only for readability on the following lines + auto amount_iterator = std::find(tx_amounts_this_out.begin(), tx_amounts_this_out.end(), tx_scan_info[o].amount); + THROW_WALLET_EXCEPTION_IF(amount_iterator == tx_amounts_this_out.end(), + error::wallet_internal_error, "Unexpected values of new and old outputs"); + tx_amounts_this_out.erase(amount_iterator); } else { @@ -2183,6 +2205,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } } + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs.size() != tx_amounts_individual_outs.size(), error::wallet_internal_error, "Inconsistent size of output arrays"); + uint64_t tx_money_spent_in_ins = 0; // The line below is equivalent to "boost::optional<uint32_t> subaddr_account;", but avoids the GCC warning: ‘*((void*)& subaddr_account +4)’ may be used uninitialized in this function // It's a GCC bug with boost::optional, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47679 @@ -2286,6 +2310,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (subaddr_account && i->first.major == *subaddr_account) { sub_change += i->second; + tx_amounts_individual_outs.erase(i->first); i = tx_money_got_in_outs.erase(i); } else @@ -2363,6 +2388,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote payment.m_tx_hash = txid; payment.m_fee = fee; payment.m_amount = i.second; + payment.m_amounts = tx_amounts_individual_outs[i.first]; payment.m_block_height = height; payment.m_unlock_time = tx.unlock_time; payment.m_timestamp = ts; @@ -4256,7 +4282,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); if(!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD) r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); - THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); if (r) setup_keys(password); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index b17fe6f3a..810c002fe 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -360,10 +360,12 @@ private: END_SERIALIZE() }; + typedef std::vector<uint64_t> amounts_container; struct payment_details { crypto::hash m_tx_hash; uint64_t m_amount; + amounts_container m_amounts; uint64_t m_fee; uint64_t m_block_height; uint64_t m_unlock_time; @@ -1631,7 +1633,7 @@ BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0) BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1) -BOOST_CLASS_VERSION(tools::wallet2::payment_details, 4) +BOOST_CLASS_VERSION(tools::wallet2::payment_details, 5) BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1) BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 8) BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6) @@ -1942,6 +1944,9 @@ namespace boost return; } a & x.m_coinbase; + if (ver < 5) + return; + a & x.m_amounts; } template <class Archive> diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d282d7cb2..2a051553b 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -326,6 +326,7 @@ namespace tools entry.height = pd.m_block_height; entry.timestamp = pd.m_timestamp; entry.amount = pd.m_amount; + entry.amounts = pd.m_amounts; entry.unlock_time = pd.m_unlock_time; entry.locked = !m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height); entry.fee = pd.m_fee; @@ -408,6 +409,7 @@ namespace tools entry.height = 0; entry.timestamp = pd.m_timestamp; entry.amount = pd.m_amount; + entry.amounts = pd.m_amounts; entry.unlock_time = pd.m_unlock_time; entry.locked = true; entry.fee = pd.m_fee; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index d6735e117..614e7af08 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -1370,6 +1370,7 @@ namespace wallet_rpc typedef epee::misc_utils::struct_init<response_t> response; }; + typedef std::vector<uint64_t> amounts_container; struct transfer_entry { std::string txid; @@ -1377,6 +1378,7 @@ namespace wallet_rpc uint64_t height; uint64_t timestamp; uint64_t amount; + amounts_container amounts; uint64_t fee; std::string note; std::list<transfer_destination> destinations; @@ -1396,6 +1398,7 @@ namespace wallet_rpc KV_SERIALIZE(height); KV_SERIALIZE(timestamp); KV_SERIALIZE(amount); + KV_SERIALIZE(amounts); KV_SERIALIZE(fee); KV_SERIALIZE(note); KV_SERIALIZE(destinations); |