diff options
Diffstat (limited to 'src')
23 files changed, 532 insertions, 183 deletions
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index b38ec9e05..9628a5c4d 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -1306,6 +1306,21 @@ public: virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const = 0; /** + * @brief Get all txids in the database (chain and pool) that match a certain nbits txid template + * + * To be more specific, for all `dbtxid` txids in the database, return `dbtxid` if + * `0 == cryptonote::compare_hash32_reversed_nbits(txid_template, dbtxid, nbits)`. + * + * @param txid_template the transaction id template + * @param nbits number of bits to compare against in the template + * @param max_num_txs The maximum number of txids to match, if we hit this limit, throw early + * @return std::vector<crypto::hash> the list of all matching txids + * + * @throw TX_EXISTS if the number of txids that match exceed `max_num_txs` + */ + virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& txid_template, std::uint32_t nbits, uint64_t max_num_txs = 0) = 0; + + /** * @brief fetches a variable number of blocks and transactions from the given height, in canonical blockchain order * * The subclass should return the blocks and transactions stored from the one with the given diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 4178c862b..2c015faee 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -3144,6 +3144,58 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun return true; } +std::vector<crypto::hash> BlockchainLMDB::get_txids_loose(const crypto::hash& txid_template, std::uint32_t bits, uint64_t max_num_txs) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + std::vector<crypto::hash> matching_hashes; + + TXN_PREFIX_RDONLY(); // Start a read-only transaction + RCURSOR(tx_indices); // Open cursors to the tx_indices and txpool_meta databases + RCURSOR(txpool_meta); + + // Search on-chain and pool transactions together, starting with on-chain txs + MDB_cursor* cursor = m_cur_tx_indices; + MDB_val k = zerokval; // tx_indicies DB uses a dummy key + MDB_val_set(v, txid_template); // tx_indicies DB indexes data values by crypto::hash value on front + MDB_cursor_op op = MDB_GET_BOTH_RANGE; // Set the cursor to the first key/value pair >= the given key + bool doing_chain = true; // this variable tells us whether we are processing chain or pool txs + while (1) + { + const int get_result = mdb_cursor_get(cursor, &k, &v, op); + op = doing_chain ? MDB_NEXT_DUP : MDB_NEXT; // Set the cursor to the next key/value pair + if (get_result && get_result != MDB_NOTFOUND) + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch txid range", get_result).c_str())); + + // In tx_indicies, the hash is stored at the data, in txpool_meta at the key + const crypto::hash* const p_dbtxid = (const crypto::hash*)(doing_chain ? v.mv_data : k.mv_data); + + // Check if we reached the end of a DB or the hashes no longer match the template + if (get_result == MDB_NOTFOUND || compare_hash32_reversed_nbits(txid_template, *p_dbtxid, bits)) + { + if (doing_chain) // done with chain processing, switch to pool processing + { + k.mv_size = sizeof(crypto::hash); // txpool_meta DB is indexed using crypto::hash as keys + k.mv_data = (void*) txid_template.data; + cursor = m_cur_txpool_meta; // switch databases + op = MDB_SET_RANGE; // Set the cursor to the first key >= the given key + doing_chain = false; + continue; + } + break; // if we get to this point, then we finished pool processing and we are done + } + else if (matching_hashes.size() >= max_num_txs && max_num_txs != 0) + throw0(TX_EXISTS("number of tx hashes in template range exceeds maximum")); + + matching_hashes.push_back(*p_dbtxid); + } + + TXN_POSTFIX_RDONLY(); // End the read-only transaction + + return matching_hashes; +} + bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index c352458b4..95e7b2aa4 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -262,6 +262,8 @@ public: virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const; virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const; + virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0); + virtual uint64_t get_tx_count() const; virtual std::vector<transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const; diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h index 946f26270..a27183b2c 100644 --- a/src/blockchain_db/testdb.h +++ b/src/blockchain_db/testdb.h @@ -71,6 +71,7 @@ public: virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; } virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override { return false; } virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; } + virtual std::vector<crypto::hash> get_txids_loose(const crypto::hash& h, std::uint32_t bits, uint64_t max_num_txs = 0) override { return {}; } virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; } virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; } virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; } diff --git a/src/cryptonote_basic/account_generators.h b/src/cryptonote_basic/account_generators.h new file mode 100644 index 000000000..c1102db60 --- /dev/null +++ b/src/cryptonote_basic/account_generators.h @@ -0,0 +1,71 @@ +// Copyright (c) 2021, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include "crypto/crypto.h" +#include "crypto/generators.h" + + +namespace cryptonote +{ + +enum class account_generator_era : unsigned char +{ + unknown = 0, + cryptonote = 1 //and ringct +}; + +struct account_generators +{ + crypto::public_key m_primary; //e.g. for spend key + crypto::public_key m_secondary; //e.g. for view key +}; + +inline crypto::public_key get_primary_generator(const account_generator_era era) +{ + if (era == account_generator_era::cryptonote) + return crypto::get_G(); + else + return crypto::null_pkey; //error +} + +inline crypto::public_key get_secondary_generator(const account_generator_era era) +{ + if (era == account_generator_era::cryptonote) + return crypto::get_G(); + else + return crypto::null_pkey; //error +} + +inline account_generators get_account_generators(const account_generator_era era) +{ + return account_generators{get_primary_generator(era), get_secondary_generator(era)}; +} + +} //namespace cryptonote diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp index 9bde20609..7fe398283 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.cpp +++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp @@ -310,6 +310,53 @@ namespace cryptonote { bool operator ==(const cryptonote::block& a, const cryptonote::block& b) { return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b); } + //-------------------------------------------------------------------------------- + int compare_hash32_reversed_nbits(const crypto::hash& ha, const crypto::hash& hb, unsigned int nbits) + { + static_assert(sizeof(uint64_t) * 4 == sizeof(crypto::hash), "hash is wrong size"); + + // We have to copy these buffers b/c of the strict aliasing rule + uint64_t va[4]; + memcpy(va, &ha, sizeof(crypto::hash)); + uint64_t vb[4]; + memcpy(vb, &hb, sizeof(crypto::hash)); + + for (int n = 3; n >= 0 && nbits; --n) + { + const unsigned int msb_nbits = std::min<unsigned int>(64, nbits); + const uint64_t lsb_nbits_dropped = static_cast<uint64_t>(64 - msb_nbits); + const uint64_t van = SWAP64LE(va[n]) >> lsb_nbits_dropped; + const uint64_t vbn = SWAP64LE(vb[n]) >> lsb_nbits_dropped; + nbits -= msb_nbits; + + if (van < vbn) return -1; else if (van > vbn) return 1; + } + + return 0; + } + + crypto::hash make_hash32_loose_template(unsigned int nbits, const crypto::hash& h) + { + static_assert(sizeof(uint64_t) * 4 == sizeof(crypto::hash), "hash is wrong size"); + + // We have to copy this buffer b/c of the strict aliasing rule + uint64_t vh[4]; + memcpy(vh, &h, sizeof(crypto::hash)); + + for (int n = 3; n >= 0; --n) + { + const unsigned int msb_nbits = std::min<unsigned int>(64, nbits); + const uint64_t mask = msb_nbits ? (~((std::uint64_t(1) << (64 - msb_nbits)) - 1)) : 0; + nbits -= msb_nbits; + + vh[n] &= SWAP64LE(mask); + } + + crypto::hash res; + memcpy(&res, vh, sizeof(crypto::hash)); + return res; + } + //-------------------------------------------------------------------------------- } //-------------------------------------------------------------------------------- diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h index 984bee19f..53dbc47d7 100644 --- a/src/cryptonote_basic/cryptonote_basic_impl.h +++ b/src/cryptonote_basic/cryptonote_basic_impl.h @@ -112,6 +112,41 @@ namespace cryptonote { bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b); bool operator ==(const cryptonote::block& a, const cryptonote::block& b); + + /************************************************************************/ + /* K-anonymity helper functions */ + /************************************************************************/ + + /** + * @brief Compares two hashes up to `nbits` bits in reverse byte order ("LMDB key order") + * + * The comparison essentially goes from the 31th, 30th, 29th, ..., 0th byte and compares the MSBs + * to the LSBs in each byte, up to `nbits` bits. If we use up `nbits` bits before finding a + * difference in the bits between the two hashes, we return 0. If we encounter a zero bit in `ha` + * where `hb` has a one in that bit place, then we reutrn -1. If the converse scenario happens, + * we return a 1. When `nbits` == 256 (there are 256 bits in `crypto::hash`), calling this is + * functionally identical to `BlockchainLMDB::compare_hash32`. + * + * @param ha left hash + * @param hb right hash + * @param nbits the number of bits to consider, a higher value means a finer comparison + * @return int 0 if ha == hb, -1 if ha < hb, 1 if ha > hb + */ + int compare_hash32_reversed_nbits(const crypto::hash& ha, const crypto::hash& hb, unsigned int nbits); + + /** + * @brief Make a template which matches `h` in LMDB order up to `nbits` bits, safe for k-anonymous fetching + * + * To be more technical, this function creates a hash which satifies the following property: + * For all `H_prime` s.t. `0 == compare_hash32_reversed_nbits(real_hash, H_prime, nbits)`, + * `1 > compare_hash32_reversed_nbits(real_hash, H_prime, 256)`. + * In other words, we return the "least" hash nbit-equal to `real_hash`. + * + * @param nbits The number of "MSB" bits to include in the template + * @param real_hash The original hash which contains more information than we want to disclose + * @return crypto::hash hash template that contains `nbits` bits matching real_hash and no more + */ + crypto::hash make_hash32_loose_template(unsigned int nbits, const crypto::hash& real_hash); } bool parse_hash256(const std::string &str_hash, crypto::hash& hash); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 8036c84cd..7c9bd9163 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4615,40 +4615,9 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti } else { - const uint64_t block_weight = m_db->get_block_weight(db_height - 1); + const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height); + const uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks); - uint64_t long_term_median; - if (db_height == 1) - { - long_term_median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5; - } - else - { - uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height); - if (nblocks == db_height) - --nblocks; - long_term_median = get_long_term_block_weight_median(db_height - nblocks - 1, nblocks); - } - - m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median); - - uint64_t short_term_constraint = m_long_term_effective_median_block_weight; - if (hf_version >= HF_VERSION_2021_SCALING) - short_term_constraint += m_long_term_effective_median_block_weight * 7 / 10; - else - short_term_constraint += m_long_term_effective_median_block_weight * 2 / 5; - uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint); - - if (db_height == 1) - { - long_term_median = long_term_block_weight; - } - else - { - m_long_term_block_weights_cache_tip_hash = m_db->get_block_hash_from_height(db_height - 1); - m_long_term_block_weights_cache_rolling_median.insert(long_term_block_weight); - long_term_median = m_long_term_block_weights_cache_rolling_median.median(); - } m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median); std::vector<uint64_t> weights; diff --git a/src/device_trezor/CMakeLists.txt b/src/device_trezor/CMakeLists.txt index c30fb2b16..2d5614507 100644 --- a/src/device_trezor/CMakeLists.txt +++ b/src/device_trezor/CMakeLists.txt @@ -65,12 +65,16 @@ set(trezor_private_headers) # Protobuf and LibUSB processed by CheckTrezor if(DEVICE_TREZOR_READY) - message(STATUS "Trezor support enabled") + message(STATUS "Trezor: support enabled") if(USE_DEVICE_TREZOR_DEBUG) list(APPEND trezor_headers trezor/debug_link.hpp trezor/messages/messages-debug.pb.h) list(APPEND trezor_sources trezor/debug_link.cpp trezor/messages/messages-debug.pb.cc) - message(STATUS "Trezor debugging enabled") + message(STATUS "Trezor: debugging enabled") + endif() + + if(ANDROID) + set(TREZOR_EXTRA_LIBRARIES "log") endif() monero_private_headers(device_trezor @@ -93,10 +97,11 @@ if(DEVICE_TREZOR_READY) ${Protobuf_LIBRARY} ${TREZOR_LIBUSB_LIBRARIES} PRIVATE - ${EXTRA_LIBRARIES}) + ${EXTRA_LIBRARIES} + ${TREZOR_EXTRA_LIBRARIES}) else() - message(STATUS "Trezor support disabled") + message(STATUS "Trezor: support disabled") monero_private_headers(device_trezor) monero_add_library(device_trezor device_trezor.cpp) target_link_libraries(device_trezor PUBLIC cncrypto) diff --git a/src/device_trezor/README.md b/src/device_trezor/README.md new file mode 100644 index 000000000..ce08c0009 --- /dev/null +++ b/src/device_trezor/README.md @@ -0,0 +1,74 @@ +# Trezor hardware wallet support + +This module adds [Trezor] hardware support to Monero. + + +## Basic information + +Trezor integration is based on the following original proposal: https://github.com/ph4r05/monero-trezor-doc + +A custom high-level transaction signing protocol uses Trezor in a similar way a cold wallet is used. +Transaction is build incrementally on the device. + +Trezor implements the signing protocol in [trezor-firmware] repository, in the [monero](https://github.com/trezor/trezor-firmware/tree/master/core/src/apps/monero) application. +Please, refer to [monero readme](https://github.com/trezor/trezor-firmware/blob/master/core/src/apps/monero/README.md) for more information. + +## Dependencies + +Trezor uses [Protobuf](https://protobuf.dev/) library. As Monero is compiled with C++14, the newest Protobuf library version cannot be compiled because it requires C++17 (through its dependency Abseil library). +This can result in a compilation failure. + +Protobuf v21 is the latest compatible protobuf version. + +If you want to compile Monero with Trezor support, please make sure the Protobuf v21 is installed. + +More about this limitation: [PR #8752](https://github.com/monero-project/monero/pull/8752), +[1](https://github.com/monero-project/monero/pull/8752#discussion_r1246174755), [2](https://github.com/monero-project/monero/pull/8752#discussion_r1246480393) + +### OSX + +To build with installed, but not linked protobuf: + +```bash +CMAKE_PREFIX_PATH=$(find /opt/homebrew/Cellar/protobuf@21 -maxdepth 1 -type d -name "21.*" -print -quit) \ +make release +``` + +or to install and link as a default protobuf version: +```bash +# Either install all requirements as +brew update && brew bundle --file=contrib/brew/Brewfile + +# or install protobufv21 specifically +brew install protobuf@21 && brew link protobuf@21 +``` + +### MSYS32 + +```bash +curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst +curl -O https://repo.msys2.org/mingw/mingw64/mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst +pacman --noconfirm -U mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst mingw-w64-x86_64-protobuf-21.9-1-any.pkg.tar.zst +``` + +### Other systems + +- install protobufv21 +- point `CMAKE_PREFIX_PATH` environment variable to Protobuf v21 installation. + +## Troubleshooting + +To disable Trezor support, set `USE_DEVICE_TREZOR=OFF`, e.g.: + +```shell +USE_DEVICE_TREZOR=OFF make release +``` + +## Resources: + +- First pull request https://github.com/monero-project/monero/pull/4241 +- Integration proposal https://github.com/ph4r05/monero-trezor-doc +- Integration readme in trezor-firmware https://github.com/trezor/trezor-firmware/blob/master/core/src/apps/monero/README.md + +[Trezor]: https://trezor.io/ +[trezor-firmware]: https://github.com/trezor/trezor-firmware/
\ No newline at end of file diff --git a/src/device_trezor/device_trezor.cpp b/src/device_trezor/device_trezor.cpp index 9c8148ed6..fa1e7c088 100644 --- a/src/device_trezor/device_trezor.cpp +++ b/src/device_trezor/device_trezor.cpp @@ -165,7 +165,7 @@ namespace trezor { auto res = get_address(); cryptonote::address_parse_info info{}; - bool r = cryptonote::get_account_address_from_str(info, this->network_type, res->address()); + bool r = cryptonote::get_account_address_from_str(info, this->m_network_type, res->address()); CHECK_AND_ASSERT_MES(r, false, "Could not parse returned address. Address parse failed: " + res->address()); CHECK_AND_ASSERT_MES(!info.is_subaddress, false, "Trezor returned a sub address"); @@ -693,14 +693,11 @@ namespace trezor { unsigned device_trezor::client_version() { auto trezor_version = get_version(); - if (trezor_version < pack_version(2, 4, 3)){ - throw exc::TrezorException("Minimal Trezor firmware version is 2.4.3. Please update."); + if (trezor_version < pack_version(2, 5, 2)){ + throw exc::TrezorException("Minimal Trezor firmware version is 2.5.2. Please update."); } - unsigned client_version = 3; - if (trezor_version >= pack_version(2, 5, 2)){ - client_version = 4; - } + unsigned client_version = 4; // since 2.5.2 #ifdef WITH_TREZOR_DEBUGGING // Override client version for tests diff --git a/src/device_trezor/device_trezor.hpp b/src/device_trezor/device_trezor.hpp index 35bb78927..804ed62c8 100644 --- a/src/device_trezor/device_trezor.hpp +++ b/src/device_trezor/device_trezor.hpp @@ -102,7 +102,7 @@ namespace trezor { bool has_ki_cold_sync() const override { return true; } bool has_tx_cold_sign() const override { return true; } - void set_network_type(cryptonote::network_type network_type) override { this->network_type = network_type; } + void set_network_type(cryptonote::network_type network_type) override { this->m_network_type = network_type; } void set_live_refresh_enabled(bool enabled) { m_live_refresh_enabled = enabled; } bool live_refresh_enabled() const { return m_live_refresh_enabled; } diff --git a/src/device_trezor/device_trezor_base.cpp b/src/device_trezor/device_trezor_base.cpp index a8a3d9f67..f65870be5 100644 --- a/src/device_trezor/device_trezor_base.cpp +++ b/src/device_trezor/device_trezor_base.cpp @@ -300,9 +300,6 @@ namespace trezor { case messages::MessageType_PassphraseRequest: on_passphrase_request(input, dynamic_cast<const messages::common::PassphraseRequest*>(input.m_msg.get())); return true; - case messages::MessageType_Deprecated_PassphraseStateRequest: - on_passphrase_state_request(input, dynamic_cast<const messages::common::Deprecated_PassphraseStateRequest*>(input.m_msg.get())); - return true; case messages::MessageType_PinMatrixRequest: on_pin_request(input, dynamic_cast<const messages::common::PinMatrixRequest*>(input.m_msg.get())); return true; @@ -475,21 +472,9 @@ namespace trezor { CHECK_AND_ASSERT_THROW_MES(msg, "Empty message"); MDEBUG("on_passhprase_request"); - // Backward compatibility, migration clause. - if (msg->has__on_device() && msg->_on_device()){ - messages::common::PassphraseAck m; - resp = call_raw(&m); - return; - } - m_seen_passphrase_entry_message = true; - bool on_device = true; - if (msg->has__on_device() && !msg->_on_device()){ - on_device = false; // do not enter on device, old devices. - } - - if (on_device && m_features && m_features->capabilities_size() > 0){ - on_device = false; + bool on_device = false; + if (m_features){ for (auto it = m_features->capabilities().begin(); it != m_features->capabilities().end(); it++) { if (*it == messages::management::Features::Capability_PassphraseEntry){ on_device = true; @@ -526,18 +511,6 @@ namespace trezor { resp = call_raw(&m); } - void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg) - { - MDEBUG("on_passhprase_state_request"); - CHECK_AND_ASSERT_THROW_MES(msg, "Empty message"); - - if (msg->has_state()) { - m_device_session_id = msg->state(); - } - messages::common::Deprecated_PassphraseStateAck m; - resp = call_raw(&m); - } - #ifdef WITH_TREZOR_DEBUGGING void device_trezor_base::wipe_device() { diff --git a/src/device_trezor/device_trezor_base.hpp b/src/device_trezor/device_trezor_base.hpp index 3ec21e157..df6e42b1f 100644 --- a/src/device_trezor/device_trezor_base.hpp +++ b/src/device_trezor/device_trezor_base.hpp @@ -100,7 +100,7 @@ namespace trezor { boost::optional<epee::wipeable_string> m_passphrase; messages::MessageType m_last_msg_type; - cryptonote::network_type network_type; + cryptonote::network_type m_network_type; bool m_reply_with_empty_passphrase; bool m_always_use_empty_passphrase; bool m_seen_passphrase_entry_message; @@ -227,9 +227,9 @@ namespace trezor { } if (network_type){ - msg->set_network_type(static_cast<uint32_t>(network_type.get())); + msg->set_network_type(static_cast<messages::monero::MoneroNetworkType>(network_type.get())); } else { - msg->set_network_type(static_cast<uint32_t>(this->network_type)); + msg->set_network_type(static_cast<messages::monero::MoneroNetworkType>(this->m_network_type)); } } @@ -318,7 +318,6 @@ namespace trezor { void on_button_pressed(); void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg); void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg); - void on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg); #ifdef WITH_TREZOR_DEBUGGING void set_debug(bool debug){ diff --git a/src/device_trezor/trezor/debug_link.cpp b/src/device_trezor/trezor/debug_link.cpp index ff7cf0ad6..76adcb164 100644 --- a/src/device_trezor/trezor/debug_link.cpp +++ b/src/device_trezor/trezor/debug_link.cpp @@ -67,7 +67,7 @@ namespace trezor{ void DebugLink::input_button(bool button){ messages::debug::DebugLinkDecision decision; - decision.set_yes_no(button); + decision.set_button(button ? messages::debug::DebugLinkDecision_DebugButton_YES : messages::debug::DebugLinkDecision_DebugButton_NO); call(decision, boost::none, true); } diff --git a/src/device_trezor/trezor/transport.cpp b/src/device_trezor/trezor/transport.cpp index 8c6b30787..23a04f9c7 100644 --- a/src/device_trezor/trezor/transport.cpp +++ b/src/device_trezor/trezor/transport.cpp @@ -154,6 +154,7 @@ namespace trezor{ // Helpers // +#define PROTO_MAGIC_SIZE 3 #define PROTO_HEADER_SIZE 6 static size_t message_size(const google::protobuf::Message &req){ @@ -193,7 +194,7 @@ namespace trezor{ } serialize_message_header(buff, msg_wire_num, msg_size); - if (!req.SerializeToArray(buff + 6, msg_size)){ + if (!req.SerializeToArray(buff + PROTO_HEADER_SIZE, msg_size)){ throw exc::EncodingException("Message serialization error"); } } @@ -252,16 +253,16 @@ namespace trezor{ throw exc::CommunicationException("Read chunk has invalid size"); } - if (memcmp(chunk_buff_raw, "?##", 3) != 0){ + if (memcmp(chunk_buff_raw, "?##", PROTO_MAGIC_SIZE) != 0){ throw exc::CommunicationException("Malformed chunk"); } uint16_t tag; uint32_t len; - nread -= 3 + 6; - deserialize_message_header(chunk_buff_raw + 3, tag, len); + nread -= PROTO_MAGIC_SIZE + PROTO_HEADER_SIZE; + deserialize_message_header(chunk_buff_raw + PROTO_MAGIC_SIZE, tag, len); - epee::wipeable_string data_acc(chunk_buff_raw + 3 + 6, nread); + epee::wipeable_string data_acc(chunk_buff_raw + PROTO_MAGIC_SIZE + PROTO_HEADER_SIZE, nread); data_acc.reserve(len); while(nread < len){ @@ -482,7 +483,7 @@ namespace trezor{ uint16_t msg_tag; uint32_t msg_len; deserialize_message_header(bin_data->data(), msg_tag, msg_len); - if (bin_data->size() != msg_len + 6){ + if (bin_data->size() != msg_len + PROTO_HEADER_SIZE){ throw exc::CommunicationException("Response is not well hexcoded"); } @@ -491,7 +492,7 @@ namespace trezor{ } std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(msg_tag)); - if (!msg_wrap->ParseFromArray(bin_data->data() + 6, msg_len)){ + if (!msg_wrap->ParseFromArray(bin_data->data() + PROTO_HEADER_SIZE, msg_len)){ throw exc::EncodingException("Response is not well hexcoded"); } msg = msg_wrap; diff --git a/src/multisig/multisig_kex_msg.cpp b/src/multisig/multisig_kex_msg.cpp index 49350948a..321305283 100644 --- a/src/multisig/multisig_kex_msg.cpp +++ b/src/multisig/multisig_kex_msg.cpp @@ -206,8 +206,13 @@ namespace multisig //---------------------------------------------------------------------------------------------------------------------- void multisig_kex_msg::parse_and_validate_msg() { + CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(), + "Multisig kex msg magic inconsistency."); + CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() >= MULTISIG_KEX_V1_MAGIC.size(), + "Multisig kex msg magic inconsistency."); + // check message type - CHECK_AND_ASSERT_THROW_MES(m_msg.size() > 0, "Kex message unexpectedly empty."); + CHECK_AND_ASSERT_THROW_MES(m_msg.size() >= MULTISIG_KEX_MSG_V2_MAGIC_1.size(), "Kex message unexpectedly small."); CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_V1_MAGIC.size()) != MULTISIG_KEX_V1_MAGIC, "V1 multisig kex messages are deprecated (unsafe)."); CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_MSG_V1_MAGIC.size()) != MULTISIG_KEX_MSG_V1_MAGIC, @@ -215,8 +220,6 @@ namespace multisig // deserialize the message std::string msg_no_magic; - CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(), - "Multisig kex msg magic inconsistency."); CHECK_AND_ASSERT_THROW_MES(tools::base58::decode(m_msg.substr(MULTISIG_KEX_MSG_V2_MAGIC_1.size()), msg_no_magic), "Multisig kex msg decoding error."); binary_archive<false> b_archive{epee::strspan<std::uint8_t>(msg_no_magic)}; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 03e9ec494..a6162c3f9 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -3535,6 +3535,82 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_txids_loose(const COMMAND_RPC_GET_TXIDS_LOOSE::request& req, COMMAND_RPC_GET_TXIDS_LOOSE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) + { + RPC_TRACKER(get_txids_loose); + + // Maybe don't use bootstrap since this endpoint is meant to retreive TXIDs w/ k-anonymity, + // so shunting this request to a random node seems counterproductive. + +#if BYTE_ORDER == LITTLE_ENDIAN + const uint64_t max_num_txids = RESTRICTED_SPENT_KEY_IMAGES_COUNT * (m_restricted ? 1 : 10); + + // Sanity check parameters + if (req.num_matching_bits > 256) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "There are only 256 bits in a hash, you gave too many"; + return false; + } + + // Attempt to guess when bit count is too low before fetching, within a certain margin of error + const uint64_t num_txs_ever = m_core.get_blockchain_storage().get_db().get_tx_count(); + const uint64_t num_expected_fetch = (num_txs_ever >> std::min((int) req.num_matching_bits, 63)); + const uint64_t max_num_txids_with_margin = 2 * max_num_txids; + if (num_expected_fetch > max_num_txids_with_margin) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Trying to search with too few matching bits, detected before fetching"; + return false; + } + + // Convert txid template to a crypto::hash + crypto::hash search_hash; + if (!epee::string_tools::hex_to_pod(req.txid_template, search_hash)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Could not decode hex txid"; + return false; + } + // Check that txid template is zeroed correctly for number of given matchign bits + else if (search_hash != make_hash32_loose_template(req.num_matching_bits, search_hash)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Txid template is not zeroed correctly for number of bits. You could be leaking true txid!"; + return false; + } + + try + { + // Do the DB fetch + const auto txids = m_core.get_blockchain_storage().get_db().get_txids_loose(search_hash, req.num_matching_bits, max_num_txids); + // Fill out response form + for (const auto& txid : txids) + res.txids.emplace_back(epee::string_tools::pod_to_hex(txid)); + } + catch (const TX_EXISTS&) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Trying to search with too few matching bits"; + return false; + } + catch (const std::exception& e) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = std::string("Error during get_txids_loose: ") + e.what(); + return false; + } + + res.status = CORE_RPC_STATUS_OK; + return true; +#else // BYTE_ORDER == BIG_ENDIAN + // BlockchainLMDB::compare_hash32 has different key ordering (thus different txid templates) on BE systems + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Due to implementation details, this feature is not available on big-endian daemons"; + return false; +#endif + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx) { RPC_TRACKER(rpc_access_submit_nonce); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 790d5eb23..7c31d2539 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -178,6 +178,7 @@ namespace cryptonote MAP_JON_RPC_WE("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION) MAP_JON_RPC_WE_IF("prune_blockchain", on_prune_blockchain, COMMAND_RPC_PRUNE_BLOCKCHAIN, !m_restricted) MAP_JON_RPC_WE_IF("flush_cache", on_flush_cache, COMMAND_RPC_FLUSH_CACHE, !m_restricted) + MAP_JON_RPC_WE("get_txids_loose", on_get_txids_loose, COMMAND_RPC_GET_TXIDS_LOOSE) MAP_JON_RPC_WE("rpc_access_info", on_rpc_access_info, COMMAND_RPC_ACCESS_INFO) MAP_JON_RPC_WE("rpc_access_submit_nonce",on_rpc_access_submit_nonce, COMMAND_RPC_ACCESS_SUBMIT_NONCE) MAP_JON_RPC_WE("rpc_access_pay", on_rpc_access_pay, COMMAND_RPC_ACCESS_PAY) @@ -255,6 +256,7 @@ namespace cryptonote bool on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); bool on_prune_blockchain(const COMMAND_RPC_PRUNE_BLOCKCHAIN::request& req, COMMAND_RPC_PRUNE_BLOCKCHAIN::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); bool on_flush_cache(const COMMAND_RPC_FLUSH_CACHE::request& req, COMMAND_RPC_FLUSH_CACHE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); + bool on_get_txids_loose(const COMMAND_RPC_GET_TXIDS_LOOSE::request& req, COMMAND_RPC_GET_TXIDS_LOOSE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); bool on_rpc_access_info(const COMMAND_RPC_ACCESS_INFO::request& req, COMMAND_RPC_ACCESS_INFO::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); bool on_rpc_access_submit_nonce(const COMMAND_RPC_ACCESS_SUBMIT_NONCE::request& req, COMMAND_RPC_ACCESS_SUBMIT_NONCE::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); bool on_rpc_access_pay(const COMMAND_RPC_ACCESS_PAY::request& req, COMMAND_RPC_ACCESS_PAY::response& res, epee::json_rpc::error& error_resp, const connection_context *ctx = NULL); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 819d77c1f..c0330eed9 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -617,7 +617,7 @@ namespace cryptonote bool do_sanity_checks; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_PARENT(rpc_access_request_base); + KV_SERIALIZE_PARENT(rpc_access_request_base) KV_SERIALIZE(tx_as_hex) KV_SERIALIZE_OPT(do_not_relay, false) KV_SERIALIZE_OPT(do_sanity_checks, true) @@ -693,7 +693,7 @@ namespace cryptonote struct request_t: public rpc_access_request_base { BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_PARENT(rpc_access_request_base); + KV_SERIALIZE_PARENT(rpc_access_request_base) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1217,7 +1217,7 @@ namespace cryptonote BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_access_request_base) - KV_SERIALIZE_OPT(fill_pow_hash, false); + KV_SERIALIZE_OPT(fill_pow_hash, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1247,7 +1247,7 @@ namespace cryptonote KV_SERIALIZE_PARENT(rpc_access_request_base) KV_SERIALIZE(hash) KV_SERIALIZE(hashes) - KV_SERIALIZE_OPT(fill_pow_hash, false); + KV_SERIALIZE_OPT(fill_pow_hash, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1276,7 +1276,7 @@ namespace cryptonote BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_access_request_base) KV_SERIALIZE(height) - KV_SERIALIZE_OPT(fill_pow_hash, false); + KV_SERIALIZE_OPT(fill_pow_hash, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1305,7 +1305,7 @@ namespace cryptonote KV_SERIALIZE_PARENT(rpc_access_request_base) KV_SERIALIZE(hash) KV_SERIALIZE(height) - KV_SERIALIZE_OPT(fill_pow_hash, false); + KV_SERIALIZE_OPT(fill_pow_hash, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1763,7 +1763,7 @@ namespace cryptonote KV_SERIALIZE_PARENT(rpc_access_request_base) KV_SERIALIZE(start_height) KV_SERIALIZE(end_height) - KV_SERIALIZE_OPT(fill_pow_hash, false); + KV_SERIALIZE_OPT(fill_pow_hash, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2124,12 +2124,12 @@ namespace cryptonote uint64_t recent_cutoff; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_PARENT(rpc_access_request_base); - KV_SERIALIZE(amounts); - KV_SERIALIZE(min_count); - KV_SERIALIZE(max_count); - KV_SERIALIZE(unlocked); - KV_SERIALIZE(recent_cutoff); + KV_SERIALIZE_PARENT(rpc_access_request_base) + KV_SERIALIZE(amounts) + KV_SERIALIZE(min_count) + KV_SERIALIZE(max_count) + KV_SERIALIZE(unlocked) + KV_SERIALIZE(recent_cutoff) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2142,10 +2142,10 @@ namespace cryptonote uint64_t recent_instances; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(amount); - KV_SERIALIZE(total_instances); - KV_SERIALIZE(unlocked_instances); - KV_SERIALIZE(recent_instances); + KV_SERIALIZE(amount) + KV_SERIALIZE(total_instances) + KV_SERIALIZE(unlocked_instances) + KV_SERIALIZE(recent_instances) END_KV_SERIALIZE_MAP() entry(uint64_t amount, uint64_t total_instances, uint64_t unlocked_instances, uint64_t recent_instances): @@ -2216,9 +2216,9 @@ namespace cryptonote uint64_t count; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_PARENT(rpc_access_request_base); - KV_SERIALIZE(height); - KV_SERIALIZE(count); + KV_SERIALIZE_PARENT(rpc_access_request_base) + KV_SERIALIZE(height) + KV_SERIALIZE(count) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2793,4 +2793,31 @@ namespace cryptonote typedef epee::misc_utils::struct_init<response_t> response; }; + struct COMMAND_RPC_GET_TXIDS_LOOSE + { + struct request_t: public rpc_request_base + { + std::string txid_template; + std::uint32_t num_matching_bits; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_PARENT(rpc_request_base) + KV_SERIALIZE(txid_template) + KV_SERIALIZE(num_matching_bits) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<request_t> request; + + struct response_t: public rpc_response_base + { + std::vector<std::string> txids; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_PARENT(rpc_response_base) + KV_SERIALIZE(txids) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init<response_t> response; + }; + } diff --git a/src/wallet/message_transporter.cpp b/src/wallet/message_transporter.cpp index 7aa765c87..b4f6ce7bd 100644 --- a/src/wallet/message_transporter.cpp +++ b/src/wallet/message_transporter.cpp @@ -61,7 +61,7 @@ namespace bitmessage_rpc KV_SERIALIZE(toAddress) KV_SERIALIZE(read) KV_SERIALIZE(msgid) - KV_SERIALIZE(message); + KV_SERIALIZE(message) KV_SERIALIZE(fromAddress) KV_SERIALIZE(receivedTime) KV_SERIALIZE(subject) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index fa9bbfde8..743a49ccb 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3317,7 +3317,7 @@ void check_block_hard_fork_version(cryptonote::network_type nettype, uint8_t hf_ if (wallet_hard_forks[fork_index].version == hf_version) break; THROW_WALLET_EXCEPTION_IF(fork_index == wallet_num_hard_forks, error::wallet_internal_error, "Fork not found in table"); - uint64_t start_height = wallet_hard_forks[fork_index].height; + uint64_t start_height = hf_version == 1 ? 0 : wallet_hard_forks[fork_index].height; uint64_t end_height = fork_index == wallet_num_hard_forks - 1 ? std::numeric_limits<uint64_t>::max() : wallet_hard_forks[fork_index + 1].height; @@ -4402,7 +4402,7 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee: value2.SetInt(m_key_device_type); json.AddMember("key_on_device", value2, json.GetAllocator()); - value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ?? + value2.SetInt((watch_only || m_watch_only) ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ?? json.AddMember("watch_only", value2, json.GetAllocator()); value2.SetInt(m_multisig ? 1 :0); @@ -6314,7 +6314,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas if (!same_file || force_rewrite_keys) { - bool r = store_keys(m_keys_file, password, false); + bool r = store_keys(m_keys_file, password, m_watch_only); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index c00271030..33afefb80 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -68,8 +68,8 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(account_index) KV_SERIALIZE(address_indices) - KV_SERIALIZE_OPT(all_accounts, false); - KV_SERIALIZE_OPT(strict, false); + KV_SERIALIZE_OPT(all_accounts, false) + KV_SERIALIZE_OPT(strict, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -348,9 +348,9 @@ namespace wallet_rpc std::vector<uint32_t> accounts; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tag); - KV_SERIALIZE(label); - KV_SERIALIZE(accounts); + KV_SERIALIZE(tag) + KV_SERIALIZE(label) + KV_SERIALIZE(accounts) END_KV_SERIALIZE_MAP() }; @@ -1029,7 +1029,7 @@ namespace wallet_rpc KV_SERIALIZE(tx_hash) KV_SERIALIZE(subaddr_index) KV_SERIALIZE(key_image) - KV_SERIALIZE(pubkey); + KV_SERIALIZE(pubkey) KV_SERIALIZE(block_height) KV_SERIALIZE(frozen) KV_SERIALIZE(unlocked) @@ -1165,7 +1165,7 @@ namespace wallet_rpc bool hard; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_OPT(hard, false); + KV_SERIALIZE_OPT(hard, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1408,21 +1408,21 @@ namespace wallet_rpc uint64_t suggested_confirmations_threshold; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(txid); - KV_SERIALIZE(payment_id); - KV_SERIALIZE(height); - KV_SERIALIZE(timestamp); - KV_SERIALIZE(amount); - KV_SERIALIZE(amounts); - KV_SERIALIZE(fee); - KV_SERIALIZE(note); - KV_SERIALIZE(destinations); - KV_SERIALIZE(type); + KV_SERIALIZE(txid) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(height) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(amount) + KV_SERIALIZE(amounts) + KV_SERIALIZE(fee) + KV_SERIALIZE(note) + KV_SERIALIZE(destinations) + KV_SERIALIZE(type) KV_SERIALIZE(unlock_time) KV_SERIALIZE(locked) - KV_SERIALIZE(subaddr_index); - KV_SERIALIZE(subaddr_indices); - KV_SERIALIZE(address); + KV_SERIALIZE(subaddr_index) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(address) KV_SERIALIZE(double_spend_seen) KV_SERIALIZE_OPT(confirmations, (uint64_t)0) KV_SERIALIZE_OPT(suggested_confirmations_threshold, (uint64_t)0) @@ -1559,17 +1559,17 @@ namespace wallet_rpc bool all_accounts; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(in); - KV_SERIALIZE(out); - KV_SERIALIZE(pending); - KV_SERIALIZE(failed); - KV_SERIALIZE(pool); - KV_SERIALIZE(filter_by_height); - KV_SERIALIZE(min_height); - KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER); - KV_SERIALIZE(account_index); - KV_SERIALIZE(subaddr_indices); - KV_SERIALIZE_OPT(all_accounts, false); + KV_SERIALIZE(in) + KV_SERIALIZE(out) + KV_SERIALIZE(pending) + KV_SERIALIZE(failed) + KV_SERIALIZE(pool) + KV_SERIALIZE(filter_by_height) + KV_SERIALIZE(min_height) + KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER) + KV_SERIALIZE(account_index) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE_OPT(all_accounts, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1583,11 +1583,11 @@ namespace wallet_rpc std::list<transfer_entry> pool; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(in); - KV_SERIALIZE(out); - KV_SERIALIZE(pending); - KV_SERIALIZE(failed); - KV_SERIALIZE(pool); + KV_SERIALIZE(in) + KV_SERIALIZE(out) + KV_SERIALIZE(pending) + KV_SERIALIZE(failed) + KV_SERIALIZE(pool) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1601,7 +1601,7 @@ namespace wallet_rpc uint32_t account_index; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(txid); + KV_SERIALIZE(txid) KV_SERIALIZE_OPT(account_index, (uint32_t)0) END_KV_SERIALIZE_MAP() }; @@ -1613,8 +1613,8 @@ namespace wallet_rpc std::list<transfer_entry> transfers; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(transfer); - KV_SERIALIZE(transfers); + KV_SERIALIZE(transfer) + KV_SERIALIZE(transfers) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1643,7 +1643,7 @@ namespace wallet_rpc std::string signature; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(signature); + KV_SERIALIZE(signature) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1658,9 +1658,9 @@ namespace wallet_rpc std::string signature; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(data); - KV_SERIALIZE(address); - KV_SERIALIZE(signature); + KV_SERIALIZE(data) + KV_SERIALIZE(address) + KV_SERIALIZE(signature) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1673,10 +1673,10 @@ namespace wallet_rpc std::string signature_type; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(good); - KV_SERIALIZE(version); - KV_SERIALIZE(old); - KV_SERIALIZE(signature_type); + KV_SERIALIZE(good) + KV_SERIALIZE(version) + KV_SERIALIZE(old) + KV_SERIALIZE(signature_type) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1703,7 +1703,7 @@ namespace wallet_rpc std::string outputs_data_hex; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(outputs_data_hex); + KV_SERIALIZE(outputs_data_hex) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1716,7 +1716,7 @@ namespace wallet_rpc std::string outputs_data_hex; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(outputs_data_hex); + KV_SERIALIZE(outputs_data_hex) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1726,7 +1726,7 @@ namespace wallet_rpc uint64_t num_imported; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(num_imported); + KV_SERIALIZE(num_imported) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1739,7 +1739,7 @@ namespace wallet_rpc bool all; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_OPT(all, false); + KV_SERIALIZE_OPT(all, false) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1750,8 +1750,8 @@ namespace wallet_rpc std::string signature; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(key_image); - KV_SERIALIZE(signature); + KV_SERIALIZE(key_image) + KV_SERIALIZE(signature) END_KV_SERIALIZE_MAP() }; @@ -1761,8 +1761,8 @@ namespace wallet_rpc std::vector<signed_key_image> signed_key_images; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(offset); - KV_SERIALIZE(signed_key_images); + KV_SERIALIZE(offset) + KV_SERIALIZE(signed_key_images) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1776,8 +1776,8 @@ namespace wallet_rpc std::string signature; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(key_image); - KV_SERIALIZE(signature); + KV_SERIALIZE(key_image) + KV_SERIALIZE(signature) END_KV_SERIALIZE_MAP() }; @@ -1787,8 +1787,8 @@ namespace wallet_rpc std::vector<signed_key_image> signed_key_images; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE_OPT(offset, (uint32_t)0); - KV_SERIALIZE(signed_key_images); + KV_SERIALIZE_OPT(offset, (uint32_t)0) + KV_SERIALIZE(signed_key_images) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -1817,11 +1817,11 @@ namespace wallet_rpc std::string recipient_name; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(address); - KV_SERIALIZE(payment_id); - KV_SERIALIZE(amount); - KV_SERIALIZE(tx_description); - KV_SERIALIZE(recipient_name); + KV_SERIALIZE(address) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(amount) + KV_SERIALIZE(tx_description) + KV_SERIALIZE(recipient_name) END_KV_SERIALIZE_MAP() }; @@ -1861,8 +1861,8 @@ namespace wallet_rpc std::vector<std::string> unknown_parameters; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(uri); - KV_SERIALIZE(unknown_parameters); + KV_SERIALIZE(uri) + KV_SERIALIZE(unknown_parameters) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1887,7 +1887,7 @@ namespace wallet_rpc uint64_t index; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(index); + KV_SERIALIZE(index) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; @@ -1964,7 +1964,7 @@ namespace wallet_rpc uint64_t index; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(index); + KV_SERIALIZE(index) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<request_t> request; @@ -2012,8 +2012,8 @@ namespace wallet_rpc bool received_money; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(blocks_fetched); - KV_SERIALIZE(received_money); + KV_SERIALIZE(blocks_fetched) + KV_SERIALIZE(received_money) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; |