aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/blockchain_db/blockchain_db.h15
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/blockchain_db/testdb.h1
-rw-r--r--src/blockchain_utilities/blockchain_stats.cpp1
-rw-r--r--src/crypto/jh.c17
-rw-r--r--src/cryptonote_basic/account_generators.h71
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h4
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp47
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h35
-rw-r--r--src/cryptonote_basic/miner.cpp1
-rw-r--r--src/cryptonote_config.h1
-rw-r--r--src/cryptonote_core/blockchain.h2
-rw-r--r--src/cryptonote_core/blockchain_and_pool.h6
-rw-r--r--src/cryptonote_core/tx_pool.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h1
-rw-r--r--src/device/device_ledger.cpp9
-rw-r--r--src/device/device_ledger.hpp7
-rw-r--r--src/device_trezor/CMakeLists.txt13
-rw-r--r--src/device_trezor/README.md74
-rw-r--r--src/device_trezor/device_trezor.cpp11
-rw-r--r--src/device_trezor/device_trezor.hpp2
-rw-r--r--src/device_trezor/device_trezor_base.cpp31
-rw-r--r--src/device_trezor/device_trezor_base.hpp22
-rw-r--r--src/device_trezor/trezor/debug_link.cpp2
-rw-r--r--src/device_trezor/trezor/transport.cpp15
-rw-r--r--src/multisig/multisig_kex_msg.cpp9
-rw-r--r--src/p2p/net_node.inl1
-rw-r--r--src/ringct/rctTypes.h16
-rw-r--r--src/rpc/core_rpc_server.cpp77
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h67
-rw-r--r--src/seraphis_crypto/CMakeLists.txt51
-rw-r--r--src/seraphis_crypto/dummy.cpp0
-rw-r--r--src/seraphis_crypto/sp_transcript.h397
-rw-r--r--src/wallet/api/wallet.cpp3
-rw-r--r--src/wallet/message_transporter.cpp2
-rw-r--r--src/wallet/wallet2.cpp87
-rw-r--r--src/wallet/wallet_rpc_server.h1
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h140
41 files changed, 1100 insertions, 198 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fed042ce2..93643af24 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -96,6 +96,7 @@ add_subdirectory(hardforks)
add_subdirectory(blockchain_db)
add_subdirectory(mnemonics)
add_subdirectory(rpc)
+add_subdirectory(seraphis_crypto)
if(NOT IOS)
add_subdirectory(serialization)
endif()
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/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp
index f65054fc5..f0a8e5adc 100644
--- a/src/blockchain_utilities/blockchain_stats.cpp
+++ b/src/blockchain_utilities/blockchain_stats.cpp
@@ -33,6 +33,7 @@
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_core/cryptonote_core.h"
#include "blockchain_db/blockchain_db.h"
+#include "time_helper.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
diff --git a/src/crypto/jh.c b/src/crypto/jh.c
index 12d536375..738c681f8 100644
--- a/src/crypto/jh.c
+++ b/src/crypto/jh.c
@@ -34,7 +34,7 @@ typedef struct {
unsigned long long databitlen; /*the message size in bits*/
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
- unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
+ DATA_ALIGN16(unsigned char buffer[64]); /*the 512-bit message block to be hashed;*/
} hashState;
@@ -213,16 +213,24 @@ static void E8(hashState *state)
/*The compression function F8 */
static void F8(hashState *state)
{
- uint64 i;
+ uint64_t* x = (uint64_t*)state->x;
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
- for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i];
+ for (int i = 0; i < 8; ++i) {
+ uint64 b;
+ memcpy(&b, &state->buffer[i << 3], sizeof(b));
+ x[i] ^= b;
+ }
/*the bijective function E8 */
E8(state);
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
- for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i];
+ for (int i = 0; i < 8; ++i) {
+ uint64 b;
+ memcpy(&b, &state->buffer[i << 3], sizeof(b));
+ x[i + 8] ^= b;
+ }
}
/*before hashing a message, initialize the hash state as H0 */
@@ -240,6 +248,7 @@ static HashReturn Init(hashState *state, int hashbitlen)
case 224: memcpy(state->x,JH224_H0,128); break;
case 256: memcpy(state->x,JH256_H0,128); break;
case 384: memcpy(state->x,JH384_H0,128); break;
+ default:
case 512: memcpy(state->x,JH512_H0,128); break;
}
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.h b/src/cryptonote_basic/cryptonote_basic.h
index ae112c31f..0531439d6 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -77,7 +77,7 @@ namespace cryptonote
// outputs <= HF_VERSION_VIEW_TAGS
struct txout_to_key
{
- txout_to_key() { }
+ txout_to_key(): key() { }
txout_to_key(const crypto::public_key &_key) : key(_key) { }
crypto::public_key key;
};
@@ -85,7 +85,7 @@ namespace cryptonote
// outputs >= HF_VERSION_VIEW_TAGS
struct txout_to_tagged_key
{
- txout_to_tagged_key() { }
+ txout_to_tagged_key(): key(), view_tag() { }
txout_to_tagged_key(const crypto::public_key &_key, const crypto::view_tag &_view_tag) : key(_key), view_tag(_view_tag) { }
crypto::public_key key;
crypto::view_tag view_tag; // optimization to reduce scanning time
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_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 91ee86d60..4b0e43213 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -42,6 +42,7 @@
#include "string_coding.h"
#include "string_tools.h"
#include "storages/portable_storage_template_helper.h"
+#include "time_helper.h"
#include "boost/logic/tribool.hpp"
#include <boost/filesystem.hpp>
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 45da75b66..fec905928 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -30,6 +30,7 @@
#pragma once
+#include <cstdint>
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 3ad051fc3..be2848d09 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1609,6 +1609,6 @@ namespace cryptonote
*/
void send_miner_notifications(uint64_t height, const crypto::hash &seed_hash, const crypto::hash &prev_id, uint64_t already_generated_coins);
- friend class BlockchainAndPool;
+ friend struct BlockchainAndPool;
};
} // namespace cryptonote
diff --git a/src/cryptonote_core/blockchain_and_pool.h b/src/cryptonote_core/blockchain_and_pool.h
index c0f607f64..497342aea 100644
--- a/src/cryptonote_core/blockchain_and_pool.h
+++ b/src/cryptonote_core/blockchain_and_pool.h
@@ -37,6 +37,7 @@
#include "blockchain.h"
#include "tx_pool.h"
+#include "warnings.h"
namespace cryptonote
{
@@ -52,7 +53,10 @@ struct BlockchainAndPool
{
Blockchain blockchain;
tx_memory_pool tx_pool;
-
+
+PUSH_WARNINGS
+DISABLE_GCC_WARNING(uninitialized)
BlockchainAndPool(): blockchain(tx_pool), tx_pool(blockchain) {}
+POP_WARNINGS
};
}
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index 47268efb6..3bb96d3a8 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -676,7 +676,7 @@ private:
//! Next timestamp that a DB check for relayable txes is allowed
std::atomic<time_t> m_next_check;
- friend class BlockchainAndPool;
+ friend struct BlockchainAndPool;
};
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index a29ee8287..80582fad2 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -39,6 +39,7 @@
#include "byte_slice.h"
#include "math_helper.h"
+#include "syncobj.h"
#include "storages/levin_abstract_invoke2.h"
#include "warnings.h"
#include "cryptonote_protocol_defs.h"
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 27d080a1c..009ee16ca 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -34,9 +34,6 @@
#include "cryptonote_basic/subaddress_index.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
-#include <boost/thread/locks.hpp>
-#include <boost/thread/lock_guard.hpp>
-
namespace hw {
namespace ledger {
@@ -322,10 +319,10 @@ namespace hw {
//automatic lock one more level on device ensuring the current thread is allowed to use it
#define AUTO_LOCK_CMD() \
/* lock both mutexes without deadlock*/ \
- boost::lock(device_locker, command_locker); \
+ std::lock(device_locker, command_locker); \
/* make sure both already-locked mutexes are unlocked at the end of scope */ \
- boost::lock_guard<boost::recursive_mutex> lock1(device_locker, boost::adopt_lock); \
- boost::lock_guard<boost::mutex> lock2(command_locker, boost::adopt_lock)
+ std::lock_guard<std::recursive_mutex> lock1(device_locker, std::adopt_lock); \
+ std::lock_guard<std::mutex> lock2(command_locker, std::adopt_lock)
//lock the device for a long sequence
void device_ledger::lock(void) {
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index 071274160..b65943f0c 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -35,8 +35,7 @@
#include "device.hpp"
#include "log.hpp"
#include "device_io_hid.hpp"
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/recursive_mutex.hpp>
+#include <mutex>
namespace hw {
@@ -140,8 +139,8 @@ namespace hw {
class device_ledger : public hw::device {
private:
// Locker for concurrent access
- mutable boost::recursive_mutex device_locker;
- mutable boost::mutex command_locker;
+ mutable std::recursive_mutex device_locker;
+ mutable std::mutex command_locker;
//IO
hw::io::device_io_hid hw_device;
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..e0fc2aafb 100644
--- a/src/device_trezor/device_trezor_base.hpp
+++ b/src/device_trezor/device_trezor_base.hpp
@@ -32,13 +32,12 @@
#include <cstddef>
+#include <mutex>
#include <string>
#include "device/device.hpp"
#include "device/device_default.hpp"
#include "device/device_cold.hpp"
#include <boost/scope_exit.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/recursive_mutex.hpp>
#include "cryptonote_config.h"
#include "trezor.hpp"
@@ -49,12 +48,12 @@
//automatic lock one more level on device ensuring the current thread is allowed to use it
#define TREZOR_AUTO_LOCK_CMD() \
/* lock both mutexes without deadlock*/ \
- boost::lock(device_locker, command_locker); \
+ std::lock(device_locker, command_locker); \
/* make sure both already-locked mutexes are unlocked at the end of scope */ \
- boost::lock_guard<boost::recursive_mutex> lock1(device_locker, boost::adopt_lock); \
- boost::lock_guard<boost::mutex> lock2(command_locker, boost::adopt_lock)
+ std::lock_guard<std::recursive_mutex> lock1(device_locker, std::adopt_lock); \
+ std::lock_guard<std::mutex> lock2(command_locker, std::adopt_lock)
-#define TREZOR_AUTO_LOCK_DEVICE() boost::lock_guard<boost::recursive_mutex> lock1_device(device_locker)
+#define TREZOR_AUTO_LOCK_DEVICE() std::lock_guard<std::recursive_mutex> lock1_device(device_locker)
namespace hw {
namespace trezor {
@@ -86,8 +85,8 @@ namespace trezor {
protected:
// Locker for concurrent access
- mutable boost::recursive_mutex device_locker;
- mutable boost::mutex command_locker;
+ mutable std::recursive_mutex device_locker;
+ mutable std::mutex command_locker;
std::shared_ptr<Transport> m_transport;
i_device_callback * m_callback;
@@ -100,7 +99,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 +226,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 +317,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/p2p/net_node.inl b/src/p2p/net_node.inl
index 4f77ce834..815c1b354 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -51,7 +51,6 @@
#include "common/dns_utils.h"
#include "common/pruning.h"
#include "net/error.h"
-#include "math_helper.h"
#include "misc_log_ex.h"
#include "p2p_protocol_defs.h"
#include "crypto/crypto.h"
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 380ca2f53..585d5fb49 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -218,7 +218,7 @@ namespace rct {
rct::key a, b, t;
Bulletproof():
- A({}), S({}), T1({}), T2({}), taux({}), mu({}), a({}), b({}), t({}) {}
+ A({}), S({}), T1({}), T2({}), taux({}), mu({}), a({}), b({}), t({}), V({}), L({}), R({}) {}
Bulletproof(const rct::key &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
V({V}), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
Bulletproof(const rct::keyV &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
@@ -253,7 +253,7 @@ namespace rct {
rct::key r1, s1, d1;
rct::keyV L, R;
- BulletproofPlus() {}
+ BulletproofPlus(): V(), A(), A1(), B(), r1(), s1(), d1(), L(), R() {}
BulletproofPlus(const rct::key &V, const rct::key &A, const rct::key &A1, const rct::key &B, const rct::key &r1, const rct::key &s1, const rct::key &d1, const rct::keyV &L, const rct::keyV &R):
V({V}), A(A), A1(A1), B(B), r1(r1), s1(s1), d1(d1), L(L), R(R) {}
BulletproofPlus(const rct::keyV &V, const rct::key &A, const rct::key &A1, const rct::key &B, const rct::key &r1, const rct::key &s1, const rct::key &d1, const rct::keyV &L, const rct::keyV &R):
@@ -362,11 +362,17 @@ namespace rct {
{
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus)
{
+ // Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
+ // first 8 bytes of ecdhInfo[i].amount
ar.begin_object();
- if (!typename Archive<W>::is_saving())
+ crypto::hash8 trunc_amount; // placeholder variable needed to maintain "strict aliasing"
+ if (!typename Archive<W>::is_saving()) // loading
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
- crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
- FIELD(amount);
+ else // saving
+ memcpy(trunc_amount.data, ecdhInfo[i].amount.bytes, sizeof(trunc_amount));
+ FIELD(trunc_amount);
+ if (!typename Archive<W>::is_saving()) // loading
+ memcpy(ecdhInfo[i].amount.bytes, trunc_amount.data, sizeof(trunc_amount));
ar.end_object();
}
else
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 03e9ec494..fbca32f80 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -2358,6 +2358,7 @@ namespace cryptonote
bool core_rpc_server::use_bootstrap_daemon_if_necessary(const invoke_http_mode &mode, const std::string &command_name, const typename COMMAND_TYPE::request& req, typename COMMAND_TYPE::response& res, bool &r)
{
res.untrusted = false;
+ r = false;
boost::upgrade_lock<boost::shared_mutex> upgrade_lock(m_bootstrap_daemon_mutex);
@@ -3535,6 +3536,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/seraphis_crypto/CMakeLists.txt b/src/seraphis_crypto/CMakeLists.txt
new file mode 100644
index 000000000..aeae61ad1
--- /dev/null
+++ b/src/seraphis_crypto/CMakeLists.txt
@@ -0,0 +1,51 @@
+# 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.
+
+set(seraphis_crypto_sources
+ dummy.cpp)
+
+monero_find_all_headers(seraphis_crypto_headers, "${CMAKE_CURRENT_SOURCE_DIR}")
+
+monero_add_library(seraphis_crypto
+ ${seraphis_crypto_sources}
+ ${seraphis_crypto_headers})
+
+target_link_libraries(seraphis_crypto
+ PUBLIC
+ cncrypto
+ common
+ epee
+ ringct
+ PRIVATE
+ ${EXTRA_LIBRARIES})
+
+target_include_directories(seraphis_crypto
+ PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+ PRIVATE
+ ${Boost_INCLUDE_DIRS})
diff --git a/src/seraphis_crypto/dummy.cpp b/src/seraphis_crypto/dummy.cpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/seraphis_crypto/dummy.cpp
diff --git a/src/seraphis_crypto/sp_transcript.h b/src/seraphis_crypto/sp_transcript.h
new file mode 100644
index 000000000..c2fbd88c2
--- /dev/null
+++ b/src/seraphis_crypto/sp_transcript.h
@@ -0,0 +1,397 @@
+// Copyright (c) 2022, 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.
+
+// Transcript class for assembling data that needs to be hashed.
+
+#pragma once
+
+//local headers
+#include "crypto/crypto.h"
+#include "cryptonote_config.h"
+#include "ringct/rctTypes.h"
+#include "wipeable_string.h"
+
+//third party headers
+#include <boost/utility/string_ref.hpp>
+
+//standard headers
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+//forward declarations
+
+
+namespace sp
+{
+
+////
+// SpTranscriptBuilder
+// - build a transcript
+// - the user must provide a label when trying to append something to the transcript; labels are prepended to objects in
+// the transcript
+// - data types
+// - unsigned int: uint_flag || varint(uint_variable)
+// - signed int: int_flag || uchar{int_variable < 0 ? 1 : 0} || varint(abs(int_variable))
+// - byte buffer (assumed little-endian): buffer_flag || buffer_length || buffer
+// - all labels are treated as byte buffers
+// - named container: container_flag || container_name || data_member1 || ... || container_terminator_flag
+// - list-type container (same-type elements only): list_flag || list_length || element1 || element2 || ...
+// - the transcript can be used like a string via the .data() and .size() member functions
+// - simple mode: exclude all labels, flags, and lengths
+///
+class SpTranscriptBuilder final
+{
+public:
+//public member types
+ /// transcript builder mode
+ enum class Mode
+ {
+ FULL,
+ SIMPLE
+ };
+
+//constructors
+ /// normal constructor
+ SpTranscriptBuilder(const std::size_t estimated_data_size, const Mode mode) :
+ m_mode{mode}
+ {
+ m_transcript.reserve(2 * estimated_data_size + 20);
+ }
+
+//overloaded operators
+ /// disable copy/move (this is a scoped manager [of the 'transcript' concept])
+ SpTranscriptBuilder& operator=(SpTranscriptBuilder&&) = delete;
+
+//member functions
+ /// append a value to the transcript
+ template <typename T>
+ void append(const boost::string_ref label, const T &value)
+ {
+ this->append_impl(label, value);
+ }
+
+ /// access the transcript data
+ const void* data() const { return m_transcript.data(); }
+ std::size_t size() const { return m_transcript.size(); }
+
+private:
+//member variables
+ /// in simple mode, exclude labels, flags, and lengths
+ Mode m_mode;
+ /// the transcript buffer (wipeable in case it contains sensitive data)
+ epee::wipeable_string m_transcript;
+
+//private member types
+ /// flags for separating items added to the transcript
+ enum SpTranscriptBuilderFlag : unsigned char
+ {
+ UNSIGNED_INTEGER = 0,
+ SIGNED_INTEGER = 1,
+ BYTE_BUFFER = 2,
+ NAMED_CONTAINER = 3,
+ NAMED_CONTAINER_TERMINATOR = 4,
+ LIST_TYPE_CONTAINER = 5
+ };
+
+//transcript builders
+ void append_character(const unsigned char character)
+ {
+ m_transcript += static_cast<char>(character);
+ }
+ void append_uint(const std::uint64_t unsigned_integer)
+ {
+ unsigned char v_variable[(sizeof(std::uint64_t) * 8 + 6) / 7];
+ unsigned char *v_variable_end = v_variable;
+
+ // append uint to string as a varint
+ tools::write_varint(v_variable_end, unsigned_integer);
+ assert(v_variable_end <= v_variable + sizeof(v_variable));
+ m_transcript.append(reinterpret_cast<const char*>(v_variable), v_variable_end - v_variable);
+ }
+ void append_flag(const SpTranscriptBuilderFlag flag)
+ {
+ if (m_mode == Mode::SIMPLE)
+ return;
+
+ static_assert(sizeof(SpTranscriptBuilderFlag) == sizeof(unsigned char), "");
+ this->append_character(static_cast<unsigned char>(flag));
+ }
+ void append_length(const std::size_t length)
+ {
+ if (m_mode == Mode::SIMPLE)
+ return;
+
+ static_assert(sizeof(std::size_t) <= sizeof(std::uint64_t), "");
+ this->append_uint(static_cast<std::uint64_t>(length));
+ }
+ void append_buffer(const void *data, const std::size_t length)
+ {
+ this->append_flag(SpTranscriptBuilderFlag::BYTE_BUFFER);
+ this->append_length(length);
+ m_transcript.append(reinterpret_cast<const char*>(data), length);
+ }
+ void append_label(const boost::string_ref label)
+ {
+ if (m_mode == Mode::SIMPLE ||
+ label.size() == 0)
+ return;
+
+ this->append_buffer(label.data(), label.size());
+ }
+ void append_labeled_buffer(const boost::string_ref label, const void *data, const std::size_t length)
+ {
+ this->append_label(label);
+ this->append_buffer(data, length);
+ }
+ void begin_named_container(const boost::string_ref container_name)
+ {
+ this->append_flag(SpTranscriptBuilderFlag::NAMED_CONTAINER);
+ this->append_label(container_name);
+ }
+ void end_named_container()
+ {
+ this->append_flag(SpTranscriptBuilderFlag::NAMED_CONTAINER_TERMINATOR);
+ }
+ void begin_list_type_container(const std::size_t list_length)
+ {
+ this->append_flag(SpTranscriptBuilderFlag::LIST_TYPE_CONTAINER);
+ this->append_length(list_length);
+ }
+
+//append overloads
+ void append_impl(const boost::string_ref label, const rct::key &key_buffer)
+ {
+ this->append_labeled_buffer(label, key_buffer.bytes, sizeof(key_buffer));
+ }
+ void append_impl(const boost::string_ref label, const rct::ctkey &ctkey)
+ {
+ this->append_label(label);
+ this->append_impl("ctmask", ctkey.mask);
+ this->append_impl("ctdest", ctkey.dest);
+ }
+ void append_impl(const boost::string_ref label, const crypto::secret_key &point_buffer)
+ {
+ this->append_labeled_buffer(label, point_buffer.data, sizeof(point_buffer));
+ }
+ void append_impl(const boost::string_ref label, const crypto::public_key &scalar_buffer)
+ {
+ this->append_labeled_buffer(label, scalar_buffer.data, sizeof(scalar_buffer));
+ }
+ void append_impl(const boost::string_ref label, const crypto::key_derivation &derivation_buffer)
+ {
+ this->append_labeled_buffer(label, derivation_buffer.data, sizeof(derivation_buffer));
+ }
+ void append_impl(const boost::string_ref label, const crypto::key_image &key_image_buffer)
+ {
+ this->append_labeled_buffer(label, key_image_buffer.data, sizeof(key_image_buffer));
+ }
+ void append_impl(const boost::string_ref label, const std::string &string_buffer)
+ {
+ this->append_labeled_buffer(label, string_buffer.data(), string_buffer.size());
+ }
+ void append_impl(const boost::string_ref label, const epee::wipeable_string &string_buffer)
+ {
+ this->append_labeled_buffer(label, string_buffer.data(), string_buffer.size());
+ }
+ void append_impl(const boost::string_ref label, const boost::string_ref string_buffer)
+ {
+ this->append_labeled_buffer(label, string_buffer.data(), string_buffer.size());
+ }
+ template<std::size_t Sz>
+ void append_impl(const boost::string_ref label, const unsigned char(&uchar_buffer)[Sz])
+ {
+ this->append_labeled_buffer(label, uchar_buffer, Sz);
+ }
+ template<std::size_t Sz>
+ void append_impl(const boost::string_ref label, const char(&char_buffer)[Sz])
+ {
+ this->append_labeled_buffer(label, char_buffer, Sz);
+ }
+ void append_impl(const boost::string_ref label, const std::vector<unsigned char> &vector_buffer)
+ {
+ this->append_labeled_buffer(label, vector_buffer.data(), vector_buffer.size());
+ }
+ void append_impl(const boost::string_ref label, const std::vector<char> &vector_buffer)
+ {
+ this->append_labeled_buffer(label, vector_buffer.data(), vector_buffer.size());
+ }
+ void append_impl(const boost::string_ref label, const char single_character)
+ {
+ this->append_label(label);
+ this->append_character(static_cast<unsigned char>(single_character));
+ }
+ void append_impl(const boost::string_ref label, const unsigned char single_character)
+ {
+ this->append_label(label);
+ this->append_character(single_character);
+ }
+ template<typename T,
+ std::enable_if_t<std::is_unsigned<T>::value, bool> = true>
+ void append_impl(const boost::string_ref label, const T unsigned_integer)
+ {
+ static_assert(sizeof(T) <= sizeof(std::uint64_t), "SpTranscriptBuilder: unsupported unsigned integer type.");
+ this->append_label(label);
+ this->append_flag(SpTranscriptBuilderFlag::UNSIGNED_INTEGER);
+ this->append_uint(unsigned_integer);
+ }
+ template<typename T,
+ std::enable_if_t<std::is_integral<T>::value, bool> = true,
+ std::enable_if_t<!std::is_unsigned<T>::value, bool> = true>
+ void append_impl(const boost::string_ref label, const T signed_integer)
+ {
+ using unsigned_type = std::make_unsigned<T>::type;
+ static_assert(sizeof(unsigned_type) <= sizeof(std::uint64_t),
+ "SpTranscriptBuilder: unsupported signed integer type.");
+ this->append_label(label);
+ this->append_flag(SpTranscriptBuilderFlag::SIGNED_INTEGER);
+ this->append_uint(static_cast<std::uint64_t>(static_cast<unsigned_type>(signed_integer)));
+ }
+ template<typename T,
+ std::enable_if_t<!std::is_integral<T>::value, bool> = true>
+ void append_impl(const boost::string_ref label, const T &named_container)
+ {
+ // named containers must satisfy two concepts:
+ // const boost::string_ref container_name(const T &container);
+ // void append_to_transcript(const T &container, SpTranscriptBuilder &transcript_inout);
+ //todo: container_name() and append_to_transcript() must be defined in the sp namespace, but that is not generic
+ this->append_label(label);
+ this->begin_named_container(container_name(named_container));
+ append_to_transcript(named_container, *this); //non-member function assumed to be implemented elsewhere
+ this->end_named_container();
+ }
+ template<typename T>
+ void append_impl(const boost::string_ref label, const std::vector<T> &list_container)
+ {
+ this->append_label(label);
+ this->begin_list_type_container(list_container.size());
+ for (const T &element : list_container)
+ this->append_impl("", element);
+ }
+ template<typename T>
+ void append_impl(const boost::string_ref label, const std::list<T> &list_container)
+ {
+ this->append_label(label);
+ this->begin_list_type_container(list_container.size());
+ for (const T &element : list_container)
+ this->append_impl("", element);
+ }
+};
+
+////
+// SpFSTranscript
+// - build a Fiat-Shamir transcript
+// - main format: prefix || domain_separator || object1_label || object1 || object2_label || object2 || ...
+// note: prefix defaults to "monero"
+///
+class SpFSTranscript final
+{
+public:
+//constructors
+ /// normal constructor: start building a transcript with the domain separator
+ SpFSTranscript(const boost::string_ref domain_separator,
+ const std::size_t estimated_data_size,
+ const boost::string_ref prefix = config::TRANSCRIPT_PREFIX) :
+ m_transcript_builder{15 + domain_separator.size() + estimated_data_size + prefix.size(),
+ SpTranscriptBuilder::Mode::FULL}
+ {
+ // transcript = prefix || domain_separator
+ m_transcript_builder.append("FSp", prefix);
+ m_transcript_builder.append("ds", domain_separator);
+ }
+
+//overloaded operators
+ /// disable copy/move (this is a scoped manager [of the 'transcript' concept])
+ SpFSTranscript& operator=(SpFSTranscript&&) = delete;
+
+//member functions
+ /// build the transcript
+ template<typename T>
+ void append(const boost::string_ref label, const T &value)
+ {
+ m_transcript_builder.append(label, value);
+ }
+
+ /// access the transcript data
+ const void* data() const { return m_transcript_builder.data(); }
+ std::size_t size() const { return m_transcript_builder.size(); }
+
+//member variables
+private:
+ /// underlying transcript builder
+ SpTranscriptBuilder m_transcript_builder;
+};
+
+////
+// SpKDFTranscript
+// - build a data string for a key-derivation function
+// - mainly intended for short transcripts (~128 bytes or less) with fixed-length and statically ordered components
+// - main format: prefix || domain_separator || object1 || object2 || ...
+// - simple transcript mode: no labels, flags, or lengths
+// note: prefix defaults to "monero"
+///
+class SpKDFTranscript final
+{
+public:
+//constructors
+ /// normal constructor: start building a transcript with the domain separator
+ SpKDFTranscript(const boost::string_ref domain_separator,
+ const std::size_t estimated_data_size,
+ const boost::string_ref prefix = config::TRANSCRIPT_PREFIX) :
+ m_transcript_builder{10 + domain_separator.size() + estimated_data_size + prefix.size(),
+ SpTranscriptBuilder::Mode::SIMPLE}
+ {
+ // transcript = prefix || domain_separator
+ m_transcript_builder.append("", prefix);
+ m_transcript_builder.append("", domain_separator);
+ }
+
+//overloaded operators
+ /// disable copy/move (this is a scoped manager [of the 'transcript' concept])
+ SpKDFTranscript& operator=(SpKDFTranscript&&) = delete;
+
+//member functions
+ /// build the transcript
+ template<typename T>
+ void append(const boost::string_ref, const T &value)
+ {
+ m_transcript_builder.append("", value);
+ }
+
+ /// access the transcript data
+ const void* data() const { return m_transcript_builder.data(); }
+ std::size_t size() const { return m_transcript_builder.size(); }
+
+//member variables
+private:
+ /// underlying transcript builder
+ SpTranscriptBuilder m_transcript_builder;
+};
+
+} //namespace sp
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 0c3aaf853..7f4dbbc79 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -45,7 +45,10 @@
#include <sstream>
#include <unordered_map>
+#ifdef WIN32
#include <boost/locale.hpp>
+#endif
+
#include <boost/filesystem.hpp>
using namespace std;
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 ddca6256d..12e4621bf 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;
@@ -6163,6 +6163,20 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file);
}
+ // Wallets used to wipe, but not erase, old unused multisig key info, which lead to huge memory leaks.
+ // Here we erase these multisig keys if they're zero'd out to free up space.
+ for (auto &td : m_transfers)
+ {
+ auto mk_it = td.m_multisig_k.begin();
+ while (mk_it != td.m_multisig_k.end())
+ {
+ if (*mk_it == rct::zero())
+ mk_it = td.m_multisig_k.erase(mk_it);
+ else
+ ++mk_it;
+ }
+ }
+
cryptonote::block genesis;
generate_genesis(genesis);
crypto::hash genesis_hash = get_block_hash(genesis);
@@ -7036,7 +7050,10 @@ void wallet2::commit_tx(pending_tx& ptx)
// tx generated, get rid of used k values
for (size_t idx: ptx.selected_transfers)
+ {
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
+ m_transfers[idx].m_multisig_k.clear();
+ }
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
@@ -7538,7 +7555,10 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// txes generated, get rid of used k values
for (size_t n = 0; n < txs.m_ptx.size(); ++n)
for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
+ {
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
+ m_transfers[idx].m_multisig_k.clear();
+ }
// zero out some data we don't want to share
for (auto &ptx: txs.m_ptx)
@@ -7862,7 +7882,10 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
// inputs in the transactions worked on here)
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
+ {
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
+ m_transfers[idx].m_multisig_k.clear();
+ }
exported_txs.m_signers.insert(get_multisig_signer_public_key());
@@ -8660,6 +8683,26 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
+ // The secret picking order contains outputs in the order that we selected them.
+ //
+ // We will later sort the output request entries in a pre-determined order so that the daemon
+ // that we're requesting information from doesn't learn any information about the true spend
+ // for each ring. However, internally, we want to prefer to construct our rings using the
+ // outputs that we picked first versus outputs picked later.
+ //
+ // The reason why is because each consecutive output pick within a ring becomes increasing less
+ // statistically independent from other picks, since we pick outputs from a finite set
+ // *without replacement*, due to the protocol not allowing duplicate ring members. This effect
+ // is exacerbated by the fact that we pick 1.5x + 75 as many outputs as we need per RPC
+ // request to account for unusable outputs. This effect is small, but non-neglibile and gets
+ // worse with larger ring sizes.
+ std::vector<get_outputs_out> secret_picking_order;
+
+ // Convenience/safety lambda to make sure that both output lists req.outputs and secret_picking_order are updated together
+ // Each ring section of req.outputs gets sorted later after selecting all outputs for that ring
+ const auto add_output_to_lists = [&req, &secret_picking_order](const get_outputs_out &goo)
+ { req.outputs.push_back(goo); secret_picking_order.push_back(goo); };
+
std::unique_ptr<gamma_picker> gamma;
if (has_rct)
gamma.reset(new gamma_picker(rct_offsets));
@@ -8794,7 +8837,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (out < num_outs)
{
MINFO("Using it");
- req.outputs.push_back({amount, out});
+ add_output_to_lists({amount, out});
++num_found;
seen_indices.emplace(out);
if (out == td.m_global_output_index)
@@ -8816,12 +8859,12 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (num_outs <= requested_outputs_count)
{
for (uint64_t i = 0; i < num_outs; i++)
- req.outputs.push_back({amount, i});
+ add_output_to_lists({amount, i});
// duplicate to make up shortfall: this will be caught after the RPC call,
// so we can also output the amounts for which we can't reach the required
// mixin after checking the actual unlockedness
for (uint64_t i = num_outs; i < requested_outputs_count; ++i)
- req.outputs.push_back({amount, num_outs - 1});
+ add_output_to_lists({amount, num_outs - 1});
}
else
{
@@ -8830,7 +8873,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
num_found = 1;
seen_indices.emplace(td.m_global_output_index);
- req.outputs.push_back({amount, td.m_global_output_index});
+ add_output_to_lists({amount, td.m_global_output_index});
LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << " for " << print_money(amount));
}
@@ -8938,7 +8981,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
seen_indices.emplace(i);
picks[type].insert(i);
- req.outputs.push_back({amount, i});
+ add_output_to_lists({amount, i});
++num_found;
MDEBUG("picked " << i << ", " << num_found << " now picked");
}
@@ -8952,7 +8995,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// we'll error out later
while (num_found < requested_outputs_count)
{
- req.outputs.push_back({amount, 0});
+ add_output_to_lists({amount, 0});
++num_found;
}
}
@@ -8962,6 +9005,10 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
[](const get_outputs_out &a, const get_outputs_out &b) { return a.index < b.index; });
}
+ THROW_WALLET_EXCEPTION_IF(req.outputs.size() != secret_picking_order.size(), error::wallet_internal_error,
+ "bug: we did not update req.outputs/secret_picking_order in tandem");
+
+ // List all requested outputs to debug log
if (ELPP->vRegistry()->allowed(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY))
{
std::map<uint64_t, std::set<uint64_t>> outs;
@@ -9079,18 +9126,21 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
}
- // then pick others in random order till we reach the required number
- // since we use an equiprobable pick here, we don't upset the triangular distribution
- std::vector<size_t> order;
- order.resize(requested_outputs_count);
- for (size_t n = 0; n < order.size(); ++n)
- order[n] = n;
- std::shuffle(order.begin(), order.end(), crypto::random_device{});
-
+ // While we are still lacking outputs in this result ring, in our secret pick order...
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs of size " << print_money(td.is_rct() ? 0 : td.amount()));
- for (size_t o = 0; o < requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
+ for (size_t ring_pick_idx = base; ring_pick_idx < base + requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++ring_pick_idx)
{
- size_t i = base + order[o];
+ const get_outputs_out attempted_output = secret_picking_order[ring_pick_idx];
+
+ // Find the index i of our pick in the request/response arrays
+ size_t i;
+ for (i = base; i < base + requested_outputs_count; ++i)
+ if (req.outputs[i].index == attempted_output.index)
+ break;
+ THROW_WALLET_EXCEPTION_IF(i == base + requested_outputs_count, error::wallet_internal_error,
+ "Could not find index of picked output in requested outputs");
+
+ // Try adding this output's information to result ring if output isn't invalid
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key);
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
}
@@ -13509,7 +13559,10 @@ cryptonote::blobdata wallet2::export_multisig()
transfer_details &td = m_transfers[n];
crypto::key_image ki;
if (td.m_multisig_k.size())
+ {
memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0]));
+ td.m_multisig_k.clear();
+ }
info[n].m_LR.clear();
info[n].m_partial_key_images.clear();
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 282035052..97fc0a278 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -35,7 +35,6 @@
#include <string>
#include "common/util.h"
#include "net/http_server_impl_base.h"
-#include "math_helper.h"
#include "wallet_rpc_server_commands_defs.h"
#include "wallet2.h"
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;