aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/util.cpp36
-rw-r--r--src/common/util.h2
-rw-r--r--src/crypto/CMakeLists.txt2
-rw-r--r--src/cryptonote_core/blockchain.cpp44
-rw-r--r--src/cryptonote_core/blockchain.h2
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h7
-rw-r--r--src/daemon/command_parser_executor.cpp7
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp5
-rw-r--r--src/daemon/daemon.cpp2
-rw-r--r--src/daemon/rpc_command_executor.cpp60
-rw-r--r--src/daemon/rpc_command_executor.h2
-rw-r--r--src/device/CMakeLists.txt2
-rw-r--r--src/device/device.hpp21
-rw-r--r--src/device/device_default.cpp10
-rw-r--r--src/device/device_default.hpp6
-rw-r--r--src/device/device_ledger.cpp264
-rw-r--r--src/device/device_ledger.hpp20
-rw-r--r--src/device/log.hpp13
-rw-r--r--src/p2p/net_node.inl8
-rw-r--r--src/ringct/rctSigs.cpp8
-rw-r--r--src/rpc/core_rpc_server.cpp18
-rw-r--r--src/rpc/core_rpc_server.h2
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h37
-rw-r--r--src/simplewallet/simplewallet.cpp92
-rw-r--r--src/simplewallet/simplewallet.h6
-rw-r--r--src/wallet/wallet2.cpp147
-rw-r--r--src/wallet/wallet2.h26
-rw-r--r--src/wallet/wallet_rpc_server.cpp40
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h8
30 files changed, 729 insertions, 170 deletions
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 80b8a9e81..728efc294 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -80,6 +80,7 @@ using namespace epee;
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
+#include <boost/format.hpp>
#include <openssl/sha.h>
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -1063,4 +1064,39 @@ std::string get_nix_version_display_string()
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
return std::string(buffer);
}
+
+ std::string get_human_readable_bytes(uint64_t bytes)
+ {
+ // Use 1024 for "kilo", 1024*1024 for "mega" and so on instead of the more modern and standard-conforming
+ // 1000, 1000*1000 and so on, to be consistent with other Monero code that also uses base 2 units
+ struct byte_map
+ {
+ const char* const format;
+ const std::uint64_t bytes;
+ };
+
+ static constexpr const byte_map sizes[] =
+ {
+ {"%.0f B", 1024},
+ {"%.2f KB", 1024 * 1024},
+ {"%.2f MB", std::uint64_t(1024) * 1024 * 1024},
+ {"%.2f GB", std::uint64_t(1024) * 1024 * 1024 * 1024},
+ {"%.2f TB", std::uint64_t(1024) * 1024 * 1024 * 1024 * 1024}
+ };
+
+ struct bytes_less
+ {
+ bool operator()(const byte_map& lhs, const byte_map& rhs) const noexcept
+ {
+ return lhs.bytes < rhs.bytes;
+ }
+ };
+
+ const auto size = std::upper_bound(
+ std::begin(sizes), std::end(sizes) - 1, byte_map{"", bytes}, bytes_less{}
+ );
+ const std::uint64_t divisor = size->bytes / 1024;
+ return (boost::format(size->format) % (double(bytes) / divisor)).str();
+ }
+
}
diff --git a/src/common/util.h b/src/common/util.h
index ef2305bf4..77a5a9af6 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -244,4 +244,6 @@ namespace tools
void closefrom(int fd);
std::string get_human_readable_timestamp(uint64_t ts);
+
+ std::string get_human_readable_bytes(uint64_t bytes);
}
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index d22d59b36..3a4d09fd8 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -49,7 +49,7 @@ set(crypto_sources
CryptonightR_JIT.c
tree-hash.c)
-if(ARCH_ID STREQUAL "i386" OR ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64")
+if(ARCH_ID STREQUAL "i386" OR ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64")
list(APPEND crypto_sources CryptonightR_template.S)
endif()
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 263227148..83d3044f8 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -178,6 +178,7 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
m_long_term_effective_median_block_weight(0),
+ m_long_term_block_weights_cache_tip_hash(crypto::null_hash),
m_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1),
m_btc_valid(false)
@@ -1281,7 +1282,50 @@ void Blockchain::get_long_term_block_weights(std::vector<uint64_t>& weights, uin
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ PERF_TIMER(get_long_term_block_weights);
+
+ if (count == 0)
+ return;
+
+ bool cached = false;
+ uint64_t blockchain_height = m_db->height();
+ uint64_t tip_height = start_height + count - 1;
+ crypto::hash tip_hash = crypto::null_hash;
+ if (tip_height < blockchain_height && count == m_long_term_block_weights_cache.size())
+ {
+ tip_hash = m_db->get_block_hash_from_height(tip_height);
+ cached = tip_hash == m_long_term_block_weights_cache_tip_hash;
+ }
+
+ if (cached)
+ {
+ MTRACE("requesting " << count << " from " << start_height << ", cached");
+ weights = m_long_term_block_weights_cache;
+ return;
+ }
+
+ // in the vast majority of uncached cases, most is still cached,
+ // as we just move the window one block up:
+ if (tip_height > 0 && count == m_long_term_block_weights_cache.size() && tip_height < blockchain_height)
+ {
+ crypto::hash old_tip_hash = m_db->get_block_hash_from_height(tip_height - 1);
+ if (old_tip_hash == m_long_term_block_weights_cache_tip_hash)
+ {
+ weights = m_long_term_block_weights_cache;
+ for (size_t i = 1; i < weights.size(); ++i)
+ weights[i - 1] = weights[i];
+ MTRACE("requesting " << count << " from " << start_height << ", incremental");
+ weights.back() = m_db->get_block_long_term_weight(tip_height);
+ m_long_term_block_weights_cache = weights;
+ m_long_term_block_weights_cache_tip_hash = tip_hash;
+ return;
+ }
+ }
+
+ MTRACE("requesting " << count << " from " << start_height << ", uncached");
weights = m_db->get_long_term_block_weights(start_height, count);
+ m_long_term_block_weights_cache = weights;
+ m_long_term_block_weights_cache_tip_hash = tip_hash;
}
//------------------------------------------------------------------
uint64_t Blockchain::get_current_cumulative_block_weight_limit() const
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 89d8e7572..2cd4dc31b 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1060,6 +1060,8 @@ namespace cryptonote
uint64_t m_timestamps_and_difficulties_height;
uint64_t m_long_term_block_weights_window;
uint64_t m_long_term_effective_median_block_weight;
+ mutable crypto::hash m_long_term_block_weights_cache_tip_hash;
+ mutable std::vector<uint64_t> m_long_term_block_weights_cache;
epee::critical_section m_difficulty_lock;
crypto::hash m_difficulty_for_next_block_top_hash;
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index cb1561c2d..d38aa7474 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -104,6 +104,13 @@ namespace cryptonote
std::vector<rct::key> &amount_keys,
crypto::public_key &out_eph_public_key) ;
+ bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key,
+ const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index,
+ const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys,
+ std::vector<crypto::public_key> &additional_tx_public_keys,
+ std::vector<rct::key> &amount_keys,
+ crypto::public_key &out_eph_public_key) ;
+
bool generate_genesis_block(
block& bl
, std::string const & genesis_tx
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index b324ab99d..17b945c9a 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -127,6 +127,13 @@ bool t_command_parser_executor::print_connections(const std::vector<std::string>
return m_executor.print_connections();
}
+bool t_command_parser_executor::print_net_stats(const std::vector<std::string>& args)
+{
+ if (!args.empty()) return false;
+
+ return m_executor.print_net_stats();
+}
+
bool t_command_parser_executor::print_blockchain_info(const std::vector<std::string>& args)
{
if(!args.size())
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index bec6e4522..098018642 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -148,6 +148,8 @@ public:
bool prune_blockchain(const std::vector<std::string>& args);
bool check_blockchain_pruning(const std::vector<std::string>& args);
+
+ bool print_net_stats(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 94e4a8bf1..69ad6ff10 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -78,6 +78,11 @@ t_command_server::t_command_server(
, "Print the current connections."
);
m_command_lookup.set_handler(
+ "print_net_stats"
+ , std::bind(&t_command_parser_executor::print_net_stats, &m_parser, p::_1)
+ , "Print network statistics."
+ );
+ m_command_lookup.set_handler(
"print_bc"
, std::bind(&t_command_parser_executor::print_blockchain_info, &m_parser, p::_1)
, "print_bc <begin_height> [<end_height>]"
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 3d1d893ea..531c080de 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -115,6 +115,7 @@ t_daemon::t_daemon(t_daemon && other)
{
mp_internals = std::move(other.mp_internals);
other.mp_internals.reset(nullptr);
+ public_rpc_port = other.public_rpc_port;
}
}
@@ -125,6 +126,7 @@ t_daemon & t_daemon::operator=(t_daemon && other)
{
mp_internals = std::move(other.mp_internals);
other.mp_internals.reset(nullptr);
+ public_rpc_port = other.public_rpc_port;
}
return *this;
}
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 4ee67f571..c9ec5109e 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -627,6 +627,66 @@ bool t_rpc_command_executor::print_connections() {
return true;
}
+bool t_rpc_command_executor::print_net_stats()
+{
+ cryptonote::COMMAND_RPC_GET_NET_STATS::request net_stats_req;
+ cryptonote::COMMAND_RPC_GET_NET_STATS::response net_stats_res;
+ cryptonote::COMMAND_RPC_GET_LIMIT::request limit_req;
+ cryptonote::COMMAND_RPC_GET_LIMIT::response limit_res;
+
+ std::string fail_message = "Unsuccessful";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->json_rpc_request(net_stats_req, net_stats_res, "get_net_stats", fail_message.c_str()))
+ {
+ return true;
+ }
+ if (!m_rpc_client->json_rpc_request(limit_req, limit_res, "get_limit", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_net_stats(net_stats_req, net_stats_res) || net_stats_res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, net_stats_res.status);
+ return true;
+ }
+ if (!m_rpc_server->on_get_limit(limit_req, limit_res) || limit_res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, limit_res.status);
+ return true;
+ }
+ }
+
+ uint64_t seconds = (uint64_t)time(NULL) - net_stats_res.start_time;
+ uint64_t average = seconds > 0 ? net_stats_res.total_bytes_in / seconds : 0;
+ uint64_t limit = limit_res.limit_down * 1024; // convert to bytes, as limits are always kB/s
+ double percent = (double)average / (double)limit * 100.0;
+ tools::success_msg_writer() << boost::format("Received %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s")
+ % net_stats_res.total_bytes_in
+ % tools::get_human_readable_bytes(net_stats_res.total_bytes_in)
+ % net_stats_res.total_packets_in
+ % tools::get_human_readable_bytes(average)
+ % percent
+ % tools::get_human_readable_bytes(limit);
+
+ average = seconds > 0 ? net_stats_res.total_bytes_out / seconds : 0;
+ limit = limit_res.limit_up * 1024;
+ percent = (double)average / (double)limit * 100.0;
+ tools::success_msg_writer() << boost::format("Sent %u bytes (%s) in %u packets, average %s/s = %.2f%% of the limit of %s/s")
+ % net_stats_res.total_bytes_out
+ % tools::get_human_readable_bytes(net_stats_res.total_bytes_out)
+ % net_stats_res.total_packets_out
+ % tools::get_human_readable_bytes(average)
+ % percent
+ % tools::get_human_readable_bytes(limit);
+
+ return true;
+}
+
bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) {
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req;
cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 423132b79..3c2686b3f 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -160,6 +160,8 @@ public:
bool prune_blockchain();
bool check_blockchain_pruning();
+
+ bool print_net_stats();
};
} // namespace daemonize
diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt
index ffa1458b0..0b0686f61 100644
--- a/src/device/CMakeLists.txt
+++ b/src/device/CMakeLists.txt
@@ -75,4 +75,6 @@ target_link_libraries(device
${OPENSSL_CRYPTO_LIBRARIES}
${Boost_SERIALIZATION_LIBRARY}
PRIVATE
+ version
+ ${Blocks}
${EXTRA_LIBRARIES})
diff --git a/src/device/device.hpp b/src/device/device.hpp
index 65b38361b..2e485b1d6 100644
--- a/src/device/device.hpp
+++ b/src/device/device.hpp
@@ -27,21 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-
-/* Note about debug:
- * To debug Device you can def the following :
- * #define DEBUG_HWDEVICE
- * Activate debug mechanism:
- * - Add more trace
- * - All computation done by device are checked by default device.
- * Required IODUMMYCRYPT_HWDEVICE or IONOCRYPT_HWDEVICE for fully working
- * #define IODUMMYCRYPT_HWDEVICE 1
- * - It assumes sensitive data encryption is is off on device side. a XOR with 0x55. This allow Ledger Class to make check on clear value
- * #define IONOCRYPT_HWDEVICE 1
- * - It assumes sensitive data encryption is off on device side.
- */
-
-
#pragma once
#include "crypto/crypto.h"
@@ -211,6 +196,10 @@ namespace hw {
/* TRANSACTION */
/* ======================================================================= */
+ virtual void generate_tx_proof(const crypto::hash &prefix_hash,
+ const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
+ crypto::signature &sig) = 0;
+
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0;
@@ -220,6 +209,8 @@ namespace hw {
return encrypt_payment_id(payment_id, public_key, secret_key);
}
+ virtual rct::key genCommitmentMask(const rct::key &amount_key) = 0;
+
virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec, bool short_amount) = 0;
virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec, bool short_amount) = 0;
diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp
index 999fbc22f..dc06ce237 100644
--- a/src/device/device_default.cpp
+++ b/src/device/device_default.cpp
@@ -37,7 +37,6 @@
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "ringct/rctOps.h"
-#include "log.hpp"
#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d
#define CHACHA8_KEY_TAIL 0x8c
@@ -273,6 +272,11 @@ namespace hw {
/* ======================================================================= */
/* TRANSACTION */
/* ======================================================================= */
+ void device_default::generate_tx_proof(const crypto::hash &prefix_hash,
+ const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
+ crypto::signature &sig) {
+ crypto::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
+ }
bool device_default::open_tx(crypto::secret_key &tx_key) {
cryptonote::keypair txkey = cryptonote::keypair::generate(*this);
@@ -349,6 +353,10 @@ namespace hw {
return true;
}
+ rct::key device_default::genCommitmentMask(const rct::key &amount_key) {
+ return rct::genCommitmentMask(amount_key);
+ }
+
bool device_default::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec, bool short_amount) {
rct::ecdhEncode(unmasked, sharedSec, short_amount);
return true;
diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp
index 90d39495b..5252d4129 100644
--- a/src/device/device_default.hpp
+++ b/src/device/device_default.hpp
@@ -107,10 +107,16 @@ namespace hw {
/* TRANSACTION */
/* ======================================================================= */
+ void generate_tx_proof(const crypto::hash &prefix_hash,
+ const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
+ crypto::signature &sig) override;
+
bool open_tx(crypto::secret_key &tx_key) override;
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
+ rct::key genCommitmentMask(const rct::key &amount_key) override;
+
bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec, bool short_amount) override;
bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec, bool short_amount) override;
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 0f197272c..d6033e189 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -27,8 +27,8 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
+#include "version.h"
#include "device_ledger.hpp"
-#include "log.hpp"
#include "ringct/rctOps.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/subaddress_index.h"
@@ -173,6 +173,7 @@ namespace hw {
#define INS_SET_SIGNATURE_MODE 0x72
#define INS_GET_ADDITIONAL_KEY 0x74
#define INS_STEALTH 0x76
+ #define INS_GEN_COMMITMENT_MASK 0x77
#define INS_BLIND 0x78
#define INS_UNBLIND 0x7A
#define INS_GEN_TXOUT_KEYS 0x7B
@@ -180,6 +181,7 @@ namespace hw {
#define INS_MLSAG 0x7E
#define INS_CLOSE_TX 0x80
+ #define INS_GET_TX_PROOF 0xA0
#define INS_GET_RESPONSE 0xc0
@@ -302,8 +304,24 @@ namespace hw {
}
bool device_ledger::reset() {
- send_simple(INS_RESET);
- return true;
+ reset_buffer();
+ int offset = set_command_header_noopt(INS_RESET);
+ memmove(this->buffer_send+offset, MONERO_VERSION, strlen(MONERO_VERSION));
+ offset += strlen(MONERO_VERSION);
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ ASSERT_X(this->length_recv>=3, "Communication error, less than three bytes received. Check your application version.");
+
+ unsigned int device_version = 0;
+ device_version = VERSION(this->buffer_recv[0], this->buffer_recv[1], this->buffer_recv[2]);
+
+ ASSERT_X (device_version >= MINIMAL_APP_VERSION,
+ "Unsupported device application version: " << VERSION_MAJOR(device_version)<<"."<<VERSION_MINOR(device_version)<<"."<<VERSION_MICRO(device_version) <<
+ " At least " << MINIMAL_APP_VERSION_MAJOR<<"."<<MINIMAL_APP_VERSION_MINOR<<"."<<MINIMAL_APP_VERSION_MICRO<<" is required.");
+
+ return true;
}
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
@@ -314,9 +332,9 @@ namespace hw {
this->length_recv -= 2;
this->sw = (this->buffer_recv[length_recv]<<8) | this->buffer_recv[length_recv+1];
+ logRESP();
ASSERT_SW(this->sw,ok,msk);
- logRESP();
return this->sw;
}
@@ -790,7 +808,11 @@ namespace hw {
const crypto::secret_key a_x = hw::ledger::decrypt(a);
const crypto::secret_key b_x = hw::ledger::decrypt(b);
crypto::secret_key r_x;
+ rct::key aG_x;
+ log_hexbuffer("sc_secret_add: [[IN]] a ", (char*)a_x.data, 32);
+ log_hexbuffer("sc_secret_add: [[IN]] b ", (char*)b_x.data, 32);
this->controle_device->sc_secret_add(r_x, a_x, b_x);
+ log_hexbuffer("sc_secret_add: [[OUT]] aG", (char*)r_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_SECRET_KEY_ADD);
@@ -825,6 +847,11 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
crypto::public_key pub_x;
crypto::secret_key sec_x;
+ crypto::secret_key recovery_key_x;
+ if (recover) {
+ recovery_key_x = hw::ledger::decrypt(recovery_key);
+ log_hexbuffer("generate_keys: [[IN]] pub", (char*)recovery_key_x.data, 32);
+ }
#endif
send_simple(INS_GENERATE_KEYPAIR);
@@ -836,6 +863,9 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
crypto::secret_key sec_clear = hw::ledger::decrypt(sec);
sec_x = sec_clear;
+ log_hexbuffer("generate_keys: [[OUT]] pub", (char*)pub.data, 32);
+ log_hexbuffer("generate_keys: [[OUT]] sec", (char*)sec_clear.data, 32);
+
crypto::secret_key_to_public_key(sec_x,pub_x);
hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data);
#endif
@@ -850,7 +880,7 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
const crypto::public_key pub_x = pub;
- const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ const crypto::secret_key sec_x = (sec == rct::rct2sk(rct::I)) ? sec: hw::ledger::decrypt(sec);
crypto::key_derivation derivation_x;
log_hexbuffer("generate_key_derivation: [[IN]] pub ", pub_x.data, 32);
log_hexbuffer("generate_key_derivation: [[IN]] sec ", sec_x.data, 32);
@@ -866,7 +896,6 @@ namespace hw {
assert(is_fake_view_key(sec));
r = crypto::generate_key_derivation(pub, this->viewkey, derivation);
} else {
-
int offset = set_command_header_noopt(INS_GEN_KEY_DERIVATION);
//pub
memmove(this->buffer_send+offset, pub.data, 32);
@@ -885,11 +914,11 @@ namespace hw {
}
#ifdef DEBUG_HWDEVICE
crypto::key_derivation derivation_clear ;
- if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
- derivation_clear = derivation;
- }else {
- derivation_clear = hw::ledger::decrypt(derivation);
- }
+ if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
+ derivation_clear = derivation;
+ } else {
+ derivation_clear = hw::ledger::decrypt(derivation);
+ }
hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data);
#endif
@@ -1050,7 +1079,7 @@ namespace hw {
bool rc = this->controle_device->secret_key_to_public_key(sec_x, pub_x);
log_hexbuffer("secret_key_to_public_key: [[OUT]] pub", pub_x.data, 32);
if (!rc){
- log_message("secret_key_to_public_key", "secret_key rejected");
+ log_message("FAIL secret_key_to_public_key", "secret_key rejected");
}
#endif
@@ -1112,6 +1141,75 @@ namespace hw {
/* TRANSACTION */
/* ======================================================================= */
+ void device_ledger::generate_tx_proof(const crypto::hash &prefix_hash,
+ const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
+ crypto::signature &sig) {
+
+ AUTO_LOCK_CMD();
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::hash prefix_hash_x = prefix_hash;
+ const crypto::public_key R_x = R;
+ const crypto::public_key A_x = A;
+ const boost::optional<crypto::public_key> B_x = B;
+ const crypto::public_key D_x = D;
+ const crypto::secret_key r_x = hw::ledger::decrypt(r);
+ crypto::signature sig_x;
+ log_hexbuffer("generate_tx_proof: [[IN]] prefix_hash ", prefix_hash_x.data, 32);
+ log_hexbuffer("generate_tx_proof: [[IN]] R ", R_x.data, 32);
+ log_hexbuffer("generate_tx_proof: [[IN]] A ", A_x.data, 32);
+ if (B_x) {
+ log_hexbuffer("generate_tx_proof: [[IN]] B ", (*B_x).data, 32);
+ }
+ log_hexbuffer("generate_tx_proof: [[IN]] D ", D_x.data, 32);
+ log_hexbuffer("generate_tx_proof: [[IN]] r ", r_x.data, 32);
+ #endif
+
+
+ int offset = set_command_header(INS_GET_TX_PROOF);
+ //options
+ this->buffer_send[offset] = B?0x01:0x00;
+ offset += 1;
+ //prefix_hash
+ memmove(&this->buffer_send[offset], prefix_hash.data, 32);
+ offset += 32;
+ // R
+ memmove(&this->buffer_send[offset], R.data, 32);
+ offset += 32;
+ // A
+ memmove(&this->buffer_send[offset], A.data, 32);
+ offset += 32;
+ // B
+ if (B) {
+ memmove(&this->buffer_send[offset], (*B).data, 32);
+ } else {
+ memset(&this->buffer_send[offset], 0, 32);
+ }
+ offset += 32;
+ // D
+ memmove(&this->buffer_send[offset], D.data, 32);
+ offset += 32;
+ // r
+ memmove(&this->buffer_send[offset], r.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(sig.c.data, &this->buffer_recv[0], 32);
+ memmove(sig.r.data, &this->buffer_recv[32], 32);
+ #ifdef DEBUG_HWDEVICE
+ log_hexbuffer("GENERATE_TX_PROOF: **c** ", sig.c.data, sizeof( sig.c.data));
+ log_hexbuffer("GENERATE_TX_PROOF: **r** ", sig.r.data, sizeof( sig.r.data));
+
+ this->controle_device->generate_tx_proof(prefix_hash_x, R_x, A_x, B_x, D_x, r_x, sig_x);
+ hw::ledger::check32("generate_tx_proof", "c", sig_x.c.data, sig.c.data);
+ hw::ledger::check32("generate_tx_proof", "r", sig_x.r.data, sig.r.data);
+
+ #endif
+ }
+
bool device_ledger::open_tx(crypto::secret_key &tx_key) {
AUTO_LOCK_CMD();
@@ -1130,7 +1228,11 @@ namespace hw {
this->exchange();
memmove(tx_key.data, &this->buffer_recv[32], 32);
-
+ #ifdef DEBUG_HWDEVICE
+ const crypto::secret_key r_x = hw::ledger::decrypt(tx_key);
+ log_hexbuffer("open_tx: [[OUT]] R ", (char*)&this->buffer_recv[0], 32);
+ log_hexbuffer("open_tx: [[OUT]] r ", r_x.data, 32);
+ #endif
return true;
}
@@ -1141,7 +1243,11 @@ namespace hw {
const crypto::public_key public_key_x = public_key;
const crypto::secret_key secret_key_x = hw::ledger::decrypt(secret_key);
crypto::hash8 payment_id_x = payment_id;
+ log_hexbuffer("encrypt_payment_id: [[IN]] payment_id ", payment_id_x.data, 32);
+ log_hexbuffer("encrypt_payment_id: [[IN]] public_key ", public_key_x.data, 32);
+ log_hexbuffer("encrypt_payment_id: [[IN]] secret_key ", secret_key_x.data, 32);
this->controle_device->encrypt_payment_id(payment_id_x, public_key_x, secret_key_x);
+ log_hexbuffer("encrypt_payment_id: [[OUT]] payment_id ", payment_id_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_STEALTH);
@@ -1178,49 +1284,58 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
const size_t &tx_version_x = tx_version;
- const cryptonote::account_keys sender_account_keys_x = sender_account_keys;
+ const cryptonote::account_keys sender_account_keys_x = hw::ledger::decrypt(sender_account_keys);
memmove((void*)sender_account_keys_x.m_view_secret_key.data, dbg_viewkey.data, 32);
- const crypto::public_key &txkey_pub_x = txkey_pub;
- const crypto::secret_key &tx_key_x = tx_key;
- const cryptonote::tx_destination_entry &dst_entr_x = dst_entr;
- const boost::optional<cryptonote::account_public_address> &change_addr_x = change_addr;
- const size_t &output_index_x = output_index;
- const bool &need_additional_txkeys_x = need_additional_txkeys;
- const std::vector<crypto::secret_key> &additional_tx_keys_x = additional_tx_keys;
+ const crypto::public_key txkey_pub_x = txkey_pub;
+ const crypto::secret_key tx_key_x = hw::ledger::decrypt(tx_key);
+ const cryptonote::tx_destination_entry dst_entr_x = dst_entr;
+ const boost::optional<cryptonote::account_public_address> change_addr_x = change_addr;
+ const size_t output_index_x = output_index;
+ const bool need_additional_txkeys_x = need_additional_txkeys;
+
+ std::vector<crypto::secret_key> additional_tx_keys_x;
+ for (const auto k: additional_tx_keys) {
+ additional_tx_keys_x.push_back(hw::ledger::decrypt(k));
+ }
+
std::vector<crypto::public_key> additional_tx_public_keys_x;
std::vector<rct::key> amount_keys_x;
crypto::public_key out_eph_public_key_x;
+
+ log_message ("generate_output_ephemeral_keys: [[IN]] tx_version", std::to_string(tx_version_x));
+ //log_hexbuffer("generate_output_ephemeral_keys: [[IN]] sender_account_keys.view", sender_account_keys.m_sview_secret_key.data, 32);
+ //log_hexbuffer("generate_output_ephemeral_keys: [[IN]] sender_account_keys.spend", sender_account_keys.m_spend_secret_key.data, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] txkey_pub", txkey_pub_x.data, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] tx_key", tx_key_x.data, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] dst_entr.view", dst_entr_x.addr.m_view_public_key.data, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] dst_entr.spend", dst_entr_x.addr.m_spend_public_key.data, 32);
+ if (change_addr) {
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] change_addr.view", (*change_addr_x).m_view_public_key.data, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] change_addr.spend", (*change_addr_x).m_spend_public_key.data, 32);
+ }
+ log_message ("generate_output_ephemeral_keys: [[IN]] output_index", std::to_string(output_index_x));
+ log_message ("generate_output_ephemeral_keys: [[IN]] need_additional_txkeys", std::to_string(need_additional_txkeys_x));
+ if(need_additional_txkeys_x) {
+ log_hexbuffer("generate_output_ephemeral_keys: [[IN]] additional_tx_keys[oi]", additional_tx_keys_x[output_index].data, 32);
+ }
this->controle_device->generate_output_ephemeral_keys(tx_version_x, sender_account_keys_x, txkey_pub_x, tx_key_x, dst_entr_x, change_addr_x, output_index_x, need_additional_txkeys_x, additional_tx_keys_x,
additional_tx_public_keys_x, amount_keys_x, out_eph_public_key_x);
+ if(need_additional_txkeys_x) {
+ log_hexbuffer("additional_tx_public_keys_x: [[OUT]] additional_tx_public_keys_x", additional_tx_public_keys_x.back().data, 32);
+ }
+ log_hexbuffer("generate_output_ephemeral_keys: [[OUT]] amount_keys ", (char*)amount_keys_x.back().bytes, 32);
+ log_hexbuffer("generate_output_ephemeral_keys: [[OUT]] out_eph_public_key ", out_eph_public_key_x.data, 32);
#endif
+ ASSERT_X(tx_version > 1, "TX version not supported"<<tx_version);
+
// make additional tx pubkey if necessary
cryptonote::keypair additional_txkey;
if (need_additional_txkeys) {
additional_txkey.sec = additional_tx_keys[output_index];
}
- //compute derivation, out_eph_public_key, and amount key in one shot on device, to ensure checkable link
- const crypto::secret_key *sec;
- bool is_change;
-
- if (change_addr && dst_entr.addr == *change_addr)
- {
- // sending change to yourself; derivation = a*R
- is_change = true;
- sec = &sender_account_keys.m_view_secret_key;
- }
- else
- {
- is_change = false;
- if (dst_entr.is_subaddress && need_additional_txkeys) {
- sec = &additional_txkey.sec;
- } else {
- sec = &tx_key;
- }
- }
-
int offset = set_command_header_noopt(INS_GEN_TXOUT_KEYS);
//tx_version
this->buffer_send[offset+0] = tx_version>>24;
@@ -1228,8 +1343,11 @@ namespace hw {
this->buffer_send[offset+2] = tx_version>>8;
this->buffer_send[offset+3] = tx_version>>0;
offset += 4;
- //tx_sec
- memmove(&this->buffer_send[offset], sec->data, 32);
+ //tx_key
+ memmove(&this->buffer_send[offset], tx_key.data, 32);
+ offset += 32;
+ //txkey_pub
+ memmove(&this->buffer_send[offset], txkey_pub.data, 32);
offset += 32;
//Aout
memmove(&this->buffer_send[offset], dst_entr.addr.m_view_public_key.data, 32);
@@ -1244,6 +1362,7 @@ namespace hw {
this->buffer_send[offset+3] = output_index>>0;
offset += 4;
//is_change,
+ bool is_change = (change_addr && dst_entr.addr == *change_addr);
this->buffer_send[offset] = is_change;
offset++;
//is_subaddress
@@ -1252,6 +1371,13 @@ namespace hw {
//need_additional_key
this->buffer_send[offset] = need_additional_txkeys;
offset++;
+ //additional_tx_key
+ if (need_additional_txkeys) {
+ memmove(&this->buffer_send[offset], additional_txkey.sec.data, 32);
+ } else {
+ memset(&this->buffer_send[offset], 0, 32);
+ }
+ offset += 32;
this->buffer_send[4] = offset-5;
this->length_send = offset;
@@ -1259,15 +1385,8 @@ namespace hw {
offset = 0;
unsigned int recv_len = this->length_recv;
- if (need_additional_txkeys)
- {
- ASSERT_X(recv_len>=32, "Not enought data from device");
- memmove(additional_txkey.pub.data, &this->buffer_recv[offset], 32);
- additional_tx_public_keys.push_back(additional_txkey.pub);
- offset += 32;
- recv_len -= 32;
- }
- if (tx_version > 1)
+
+ //if (tx_version > 1)
{
ASSERT_X(recv_len>=32, "Not enought data from device");
crypto::secret_key scalar1;
@@ -1279,6 +1398,16 @@ namespace hw {
ASSERT_X(recv_len>=32, "Not enought data from device");
memmove(out_eph_public_key.data, &this->buffer_recv[offset], 32);
recv_len -= 32;
+ offset += 32;
+
+ if (need_additional_txkeys)
+ {
+ ASSERT_X(recv_len>=32, "Not enought data from device");
+ memmove(additional_txkey.pub.data, &this->buffer_recv[offset], 32);
+ additional_tx_public_keys.push_back(additional_txkey.pub);
+ offset += 32;
+ recv_len -= 32;
+ }
// add ABPkeys
this->add_output_key_mapping(dst_entr.addr.m_view_public_key, dst_entr.addr.m_spend_public_key, dst_entr.is_subaddress, is_change,
@@ -1286,9 +1415,10 @@ namespace hw {
amount_keys.back(), out_eph_public_key);
#ifdef DEBUG_HWDEVICE
+ log_hexbuffer("generate_output_ephemeral_keys: clear amount_key", (const char*)hw::ledger::decrypt(amount_keys.back()).bytes, 32);
hw::ledger::check32("generate_output_ephemeral_keys", "amount_key", (const char*)amount_keys_x.back().bytes, (const char*)hw::ledger::decrypt(amount_keys.back()).bytes);
if (need_additional_txkeys) {
- hw::ledger::check32("generate_output_ephemeral_keys", "additional_tx_key", additional_tx_keys_x.back().data, additional_tx_keys.back().data);
+ hw::ledger::check32("generate_output_ephemeral_keys", "additional_tx_key", additional_tx_public_keys_x.back().data, additional_tx_public_keys.back().data);
}
hw::ledger::check32("generate_output_ephemeral_keys", "out_eph_public_key", out_eph_public_key_x.data, out_eph_public_key.data);
#endif
@@ -1303,6 +1433,32 @@ namespace hw {
return true;
}
+ rct::key device_ledger::genCommitmentMask(const rct::key &AKout) {
+ #ifdef DEBUG_HWDEVICE
+ const rct::key AKout_x = hw::ledger::decrypt(AKout);
+ rct::key mask_x;
+ mask_x = this->controle_device->genCommitmentMask(AKout_x);
+ #endif
+
+ rct::key mask;
+ int offset = set_command_header_noopt(INS_GEN_COMMITMENT_MASK);
+ // AKout
+ memmove(this->buffer_send+offset, AKout.bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(mask.bytes, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("genCommitmentMask", "mask", (const char*)mask_x.bytes, (const char*)mask.bytes);
+ #endif
+
+ return mask;
+ }
+
bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout, bool short_amount) {
AUTO_LOCK_CMD();
@@ -1334,6 +1490,7 @@ namespace hw {
memmove(unmasked.mask.bytes, &this->buffer_recv[32], 32);
#ifdef DEBUG_HWDEVICE
+ MDEBUG("ecdhEncode: Akout: "<<AKout_x);
hw::ledger::check32("ecdhEncode", "amount", (char*)unmasked_x.amount.bytes, (char*)unmasked.amount.bytes);
hw::ledger::check32("ecdhEncode", "mask", (char*)unmasked_x.mask.bytes, (char*)unmasked.mask.bytes);
@@ -1374,6 +1531,7 @@ namespace hw {
memmove(masked.mask.bytes, &this->buffer_recv[32], 32);
#ifdef DEBUG_HWDEVICE
+ MDEBUG("ecdhEncode: Akout: "<<AKout_x);
hw::ledger::check32("ecdhDecode", "amount", (char*)masked_x.amount.bytes, (char*)masked.amount.bytes);
hw::ledger::check32("ecdhDecode", "mask", (char*)masked_x.mask.bytes,(char*) masked.mask.bytes);
#endif
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
index 252354e1c..d4d98ce4a 100644
--- a/src/device/device_ledger.hpp
+++ b/src/device/device_ledger.hpp
@@ -33,6 +33,7 @@
#include <cstddef>
#include <string>
#include "device.hpp"
+#include "log.hpp"
#include "device_io_hid.hpp"
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
@@ -41,6 +42,18 @@ namespace hw {
namespace ledger {
+ /* Minimal supported version */
+ #define MINIMAL_APP_VERSION_MAJOR 1
+ #define MINIMAL_APP_VERSION_MINOR 3
+ #define MINIMAL_APP_VERSION_MICRO 1
+
+ #define VERSION(M,m,u) ((M)<<16|(m)<<8|(u))
+ #define VERSION_MAJOR(v) (((v)>>16)&0xFF)
+ #define VERSION_MINOR(v) (((v)>>8)&0xFF)
+ #define VERSION_MICRO(v) (((v)>>0)&0xFF)
+
+ #define MINIMAL_APP_VERSION VERSION(MINIMAL_APP_VERSION_MAJOR, MINIMAL_APP_VERSION_MINOR, MINIMAL_APP_VERSION_MICRO)
+
void register_all(std::map<std::string, std::unique_ptr<device>> &registry);
#ifdef WITH_DEVICE_LEDGER
@@ -190,11 +203,16 @@ namespace hw {
/* ======================================================================= */
/* TRANSACTION */
/* ======================================================================= */
-
+ void generate_tx_proof(const crypto::hash &prefix_hash,
+ const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
+ crypto::signature &sig) override;
+
bool open_tx(crypto::secret_key &tx_key) override;
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
+ rct::key genCommitmentMask(const rct::key &amount_key) override;
+
bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec, bool short_format) override;
bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec, bool short_format) override;
diff --git a/src/device/log.hpp b/src/device/log.hpp
index fb7ba1fb0..bfe6e9edc 100644
--- a/src/device/log.hpp
+++ b/src/device/log.hpp
@@ -40,6 +40,19 @@
namespace hw {
+ /* Note about debug:
+ * To debug Device you can def the following :
+ * #define DEBUG_HWDEVICE
+ * Activate debug mechanism:
+ * - Add more trace
+ * - All computation done by device are checked by default device.
+ * Required IODUMMYCRYPT_HWDEVICE or IONOCRYPT_HWDEVICE for fully working
+ * #define IODUMMYCRYPT_HWDEVICE 1
+ * - It assumes sensitive data encryption is is off on device side. a XOR with 0x55. This allow Ledger Class to make check on clear value
+ * #define IONOCRYPT_HWDEVICE 1
+ * - It assumes sensitive data encryption is off on device side.
+ */
+
void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
void log_hexbuffer(const std::string &msg, const char* buff, size_t len);
void log_message(const std::string &msg, const std::string &info );
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index ba6e79d3f..f0aef384f 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -502,7 +502,7 @@ namespace nodetool
else
{
memcpy(&m_network_id, &::config::NETWORK_ID, 16);
- if (m_exclusive_peers.empty())
+ if (m_exclusive_peers.empty() && !m_offline)
{
// for each hostname in the seed nodes list, attempt to DNS resolve and
// add the result addresses as seed nodes
@@ -2236,11 +2236,10 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit)
{
- this->islimitup=true;
+ this->islimitup=(limit != -1) && (limit != default_limit_up);
if (limit==-1) {
limit=default_limit_up;
- this->islimitup=false;
}
epee::net_utils::connection<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_up_limit( limit );
@@ -2251,10 +2250,9 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit)
{
- this->islimitdown=true;
+ this->islimitdown=(limit != -1) && (limit != default_limit_down);
if(limit==-1) {
limit=default_limit_down;
- this->islimitdown=false;
}
epee::net_utils::connection<epee::levin::async_protocol_handler<p2p_connection_context> >::set_rate_down_limit( limit );
MINFO("Set limit-down to " << limit << " kB/s");
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 25571238e..e877c13ce 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -79,12 +79,12 @@ namespace
}
namespace rct {
- Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk)
+ Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk, hw::device &hwdev)
{
CHECK_AND_ASSERT_THROW_MES(amounts.size() == sk.size(), "Invalid amounts/sk sizes");
masks.resize(amounts.size());
for (size_t i = 0; i < masks.size(); ++i)
- masks[i] = genCommitmentMask(sk[i]);
+ masks[i] = hwdev.genCommitmentMask(sk[i]);
Bulletproof proof = bulletproof_PROVE(amounts, masks);
CHECK_AND_ASSERT_THROW_MES(proof.V.size() == amounts.size(), "V does not have the expected size");
C = proof.V;
@@ -804,7 +804,7 @@ namespace rct {
else
{
const epee::span<const key> keys{&amount_keys[0], amount_keys.size()};
- rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys));
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, outamounts, keys, hwdev));
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
#endif
@@ -833,7 +833,7 @@ namespace rct {
else
{
const epee::span<const key> keys{&amount_keys[amounts_proved], batch_size};
- rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys));
+ rv.p.bulletproofs.push_back(proveRangeBulletproof(C, masks, batch_amounts, keys, hwdev));
#ifdef DBG
CHECK_AND_ASSERT_THROW_MES(verBulletproof(rv.p.bulletproofs.back()), "verBulletproof failed on newly created proof");
#endif
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index e6a09606b..f5f1a2f9a 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -268,6 +268,23 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx)
+ {
+ PERF_TIMER(on_get_net_stats);
+ // No bootstrap daemon check: Only ever get stats about local server
+ res.start_time = (uint64_t)m_core.get_start_time();
+ {
+ CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in);
+ epee::net_utils::network_throttle_manager::get_global_throttle_in().get_stats(res.total_packets_in, res.total_bytes_in);
+ }
+ {
+ CRITICAL_REGION_LOCAL(epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_out);
+ epee::net_utils::network_throttle_manager::get_global_throttle_out().get_stats(res.total_packets_out, res.total_bytes_out);
+ }
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
class pruned_transaction {
transaction& tx;
public:
@@ -1394,6 +1411,7 @@ namespace cryptonote
response.num_txes = blk.tx_hashes.size();
response.pow_hash = fill_pow_hash ? string_tools::pod_to_hex(get_block_longhash(blk, height)) : "";
response.long_term_weight = m_core.get_blockchain_storage().get_db().get_block_long_term_weight(height);
+ response.miner_tx_hash = string_tools::pod_to_hex(cryptonote::get_transaction_hash(blk.miner_tx));
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index fe066b31b..8f5d83f1b 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -115,6 +115,7 @@ namespace cryptonote
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
+ MAP_URI_AUTO_JON2_IF("/get_net_stats", on_get_net_stats, COMMAND_RPC_GET_NET_STATS, !m_restricted)
MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT)
MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted)
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
@@ -179,6 +180,7 @@ namespace cryptonote
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res, const connection_context *ctx = NULL);
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res, const connection_context *ctx = NULL);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, const connection_context *ctx = NULL);
+ bool on_get_net_stats(const COMMAND_RPC_GET_NET_STATS::request& req, COMMAND_RPC_GET_NET_STATS::response& res, const connection_context *ctx = NULL);
bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res, const connection_context *ctx = NULL);
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res, const connection_context *ctx = NULL);
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res, 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 4786f7a9b..1f14267f6 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -84,7 +84,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 2
-#define CORE_RPC_VERSION_MINOR 4
+#define CORE_RPC_VERSION_MINOR 5
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -739,6 +739,39 @@ namespace cryptonote
//-----------------------------------------------
+ struct COMMAND_RPC_GET_NET_STATS
+ {
+ struct request_t
+ {
+
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+
+ struct response_t
+ {
+ std::string status;
+ uint64_t start_time;
+ uint64_t total_packets_in;
+ uint64_t total_bytes_in;
+ uint64_t total_packets_out;
+ uint64_t total_bytes_out;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(start_time)
+ KV_SERIALIZE(total_packets_in)
+ KV_SERIALIZE(total_bytes_in)
+ KV_SERIALIZE(total_packets_out)
+ KV_SERIALIZE(total_bytes_out)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
+ //-----------------------------------------------
struct COMMAND_RPC_STOP_MINING
{
struct request_t
@@ -967,6 +1000,7 @@ namespace cryptonote
uint64_t num_txes;
std::string pow_hash;
uint64_t long_term_weight;
+ std::string miner_tx_hash;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(major_version)
@@ -990,6 +1024,7 @@ namespace cryptonote
KV_SERIALIZE(num_txes)
KV_SERIALIZE(pow_hash)
KV_SERIALIZE_OPT(long_term_weight, (uint64_t)0)
+ KV_SERIALIZE(miner_tx_hash)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 91a8f6348..8974bd1e0 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -239,6 +239,9 @@ namespace
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
const char* USAGE_IS_OUTPUT_SPENT("is_output_spent <amount>/<offset>");
+ const char* USAGE_FREEZE("freeze <key_image>");
+ const char* USAGE_THAW("thaw <key_image>");
+ const char* USAGE_FROZEN("frozen <key_image>");
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
@@ -2027,6 +2030,74 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::freeze_thaw(const std::vector<std::string> &args, bool freeze)
+{
+ if (args.empty())
+ {
+ fail_msg_writer() << boost::format(tr("usage: %s <key_image>|<pubkey>")) % (freeze ? "freeze" : "thaw");
+ return true;
+ }
+ crypto::key_image ki;
+ if (!epee::string_tools::hex_to_pod(args[0], ki))
+ {
+ fail_msg_writer() << tr("failed to parse key image");
+ return true;
+ }
+ try
+ {
+ if (freeze)
+ m_wallet->freeze(ki);
+ else
+ m_wallet->thaw(ki);
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << e.what();
+ return true;
+ }
+
+ return true;
+}
+
+bool simple_wallet::freeze(const std::vector<std::string> &args)
+{
+ return freeze_thaw(args, true);
+}
+
+bool simple_wallet::thaw(const std::vector<std::string> &args)
+{
+ return freeze_thaw(args, false);
+}
+
+bool simple_wallet::frozen(const std::vector<std::string> &args)
+{
+ if (args.empty())
+ {
+ size_t ntd = m_wallet->get_num_transfer_details();
+ for (size_t i = 0; i < ntd; ++i)
+ {
+ if (!m_wallet->frozen(i))
+ continue;
+ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i);
+ message_writer() << tr("Frozen: ") << td.m_key_image << " " << cryptonote::print_money(td.amount());
+ }
+ }
+ else
+ {
+ crypto::key_image ki;
+ if (!epee::string_tools::hex_to_pod(args[0], ki))
+ {
+ fail_msg_writer() << tr("failed to parse key image");
+ return true;
+ }
+ if (m_wallet->frozen(ki))
+ message_writer() << tr("Frozen: ") << ki;
+ else
+ message_writer() << tr("Not frozen: ") << ki;
+ }
+ return true;
+}
+
bool simple_wallet::version(const std::vector<std::string> &args)
{
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
@@ -2602,7 +2673,7 @@ simple_wallet::simple_wallet()
tr(USAGE_INCOMING_TRANSFERS),
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
"Output format:\n"
- "Amount, Spent(\"T\"|\"F\"), \"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
+ "Amount, Spent(\"T\"|\"F\"), \"frozen\"|\"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
m_cmd_binder.set_handler("payments",
boost::bind(&simple_wallet::show_payments, this, _1),
tr(USAGE_PAYMENTS),
@@ -3014,6 +3085,18 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::blackballed, this, _1),
tr(USAGE_IS_OUTPUT_SPENT),
tr("Checks whether an output is marked as spent"));
+ m_cmd_binder.set_handler("freeze",
+ boost::bind(&simple_wallet::freeze, this, _1),
+ tr(USAGE_FREEZE),
+ tr("Freeze a single output by key image so it will not be used"));
+ m_cmd_binder.set_handler("thaw",
+ boost::bind(&simple_wallet::thaw, this, _1),
+ tr(USAGE_THAW),
+ tr("Thaw a single output by key image so it may be used again"));
+ m_cmd_binder.set_handler("frozen",
+ boost::bind(&simple_wallet::frozen, this, _1),
+ tr(USAGE_FROZEN),
+ tr("Checks whether a given output is currently frozen by key image"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
tr(USAGE_VERSION),
@@ -4989,7 +5072,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) %
(td.m_spent ? tr("T") : tr("F")) %
- (m_wallet->is_transfer_unlocked(td) ? tr("unlocked") : tr("locked")) %
+ (m_wallet->frozen(td) ? tr("[frozen]") : m_wallet->is_transfer_unlocked(td) ? tr("unlocked") : tr("locked")) %
(td.is_rct() ? tr("RingCT") : tr("-")) %
td.m_global_output_index %
td.m_txid %
@@ -6873,11 +6956,6 @@ bool simple_wallet::set_tx_key(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_tx_proof(const std::vector<std::string> &args)
{
- if (m_wallet->key_on_device() && m_wallet->get_account().get_device().get_type() != hw::device::TREZOR)
- {
- fail_msg_writer() << tr("command not supported by HW wallet");
- return true;
- }
if (args.size() != 2 && args.size() != 3)
{
PRINT_USAGE(USAGE_GET_TX_PROOF);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 7bcb92190..c9a5c55e8 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -238,9 +238,12 @@ namespace cryptonote
bool blackball(const std::vector<std::string>& args);
bool unblackball(const std::vector<std::string>& args);
bool blackballed(const std::vector<std::string>& args);
+ bool freeze(const std::vector<std::string>& args);
+ bool thaw(const std::vector<std::string>& args);
+ bool frozen(const std::vector<std::string>& args);
bool version(const std::vector<std::string>& args);
- bool cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func);
+ bool cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func);
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
bool ask_wallet_create_if_needed();
@@ -253,6 +256,7 @@ namespace cryptonote
void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
+ bool freeze_thaw(const std::vector<std::string>& args, bool freeze);
struct transfer_view
{
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 439873932..d59ded49f 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1441,6 +1441,58 @@ void wallet2::set_unspent(size_t idx)
td.m_spent_height = 0;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::freeze(size_t idx)
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ transfer_details &td = m_transfers[idx];
+ td.m_frozen = true;
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::thaw(size_t idx)
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ transfer_details &td = m_transfers[idx];
+ td.m_frozen = false;
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(size_t idx) const
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ const transfer_details &td = m_transfers[idx];
+ return td.m_frozen;
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::freeze(const crypto::key_image &ki)
+{
+ freeze(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::thaw(const crypto::key_image &ki)
+{
+ thaw(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(const crypto::key_image &ki) const
+{
+ return frozen(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+size_t wallet2::get_transfer_details(const crypto::key_image &ki) const
+{
+ for (size_t idx = 0; idx < m_transfers.size(); ++idx)
+ {
+ const transfer_details &td = m_transfers[idx];
+ if (td.m_key_image_known && td.m_key_image == ki)
+ return idx;
+ }
+ CHECK_AND_ASSERT_THROW_MES(false, "Key image not found");
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(const transfer_details &td) const
+{
+ return td.m_frozen;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const
{
hw::device &hwdev = m_account.get_device();
@@ -1858,6 +1910,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ td.m_frozen = false;
set_unspent(m_transfers.size()-1);
if (td.m_key_image_known)
m_key_images[td.m_key_image] = m_transfers.size()-1;
@@ -3205,8 +3258,9 @@ void wallet2::detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, ui
wallet2::transfer_details &td = m_transfers[i];
if (td.m_spent && td.m_spent_height >= height)
{
- LOG_PRINT_L1("Resetting spent status for output " << i << ": " << td.m_key_image);
+ LOG_PRINT_L1("Resetting spent/frozen status for output " << i << ": " << td.m_key_image);
set_unspent(i);
+ thaw(i);
}
}
@@ -5391,7 +5445,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
std::map<uint32_t, uint64_t> amount_per_subaddr;
for (const auto& td: m_transfers)
{
- if (td.m_subaddr_index.major == index_major && !td.m_spent)
+ if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
@@ -5420,7 +5474,7 @@ std::map<uint32_t, uint64_t> wallet2::unlocked_balance_per_subaddress(uint32_t i
std::map<uint32_t, uint64_t> amount_per_subaddr;
for(const transfer_details& td: m_transfers)
{
- if(td.m_subaddr_index.major == index_major && !td.m_spent && is_transfer_unlocked(td))
+ if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen && is_transfer_unlocked(td))
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
@@ -8314,7 +8368,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount()));
picks.push_back(i);
@@ -8329,13 +8383,13 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
for (size_t j = i + 1; j < m_transfers.size(); ++j)
{
const transfer_details& td2 = m_transfers[j];
- if (!td2.m_spent && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
+ if (!td2.m_spent && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
{
// update our picks if those outputs are less related than any we
// already found. If the same, don't update, and oldest suitable outputs
@@ -8562,6 +8616,7 @@ void wallet2::light_wallet_get_unspent_outs()
td.m_pk_index = 0;
td.m_internal_output_index = o.index;
td.m_spent = spent;
+ td.m_frozen = false;
tx_out txout;
txout.target = txout_to_key(public_key);
@@ -9036,7 +9091,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
continue;
}
- if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
const uint32_t index_minor = td.m_subaddr_index.minor;
auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
@@ -9468,7 +9523,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, s
THROW_WALLET_EXCEPTION_IF(ptx.change_dts.addr != ptx_vector[0].change_dts.addr, error::wallet_internal_error,
"Change goes to several different addresses");
const auto it = m_subaddresses.find(ptx_vector[0].change_dts.addr.m_spend_public_key);
- THROW_WALLET_EXCEPTION_IF(it == m_subaddresses.end(), error::wallet_internal_error, "Change address is not ours");
+ THROW_WALLET_EXCEPTION_IF(change > 0 && it == m_subaddresses.end(), error::wallet_internal_error, "Change address is not ours");
required[ptx_vector[0].change_dts.addr].first += change;
required[ptx_vector[0].change_dts.addr].second = ptx_vector[0].change_dts.is_subaddress;
@@ -9516,7 +9571,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
{
fund_found = true;
if (below == 0 || td.amount() < below)
@@ -9564,7 +9619,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
+ if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
{
if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
unused_transfers_indices.push_back(i);
@@ -9784,8 +9839,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
}
uint64_t a = 0;
- for (size_t idx: unused_transfers_indices) a += m_transfers[idx].amount();
- for (size_t idx: unused_dust_indices) a += m_transfers[idx].amount();
+ for (const TX &tx: txes)
+ {
+ for (size_t idx: tx.selected_transfers)
+ {
+ a += m_transfers[idx].amount();
+ }
+ a -= tx.ptx.fee;
+ }
std::vector<cryptonote::tx_destination_entry> synthetic_dsts(1, cryptonote::tx_destination_entry("", a, address, is_subaddress));
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, synthetic_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
@@ -9896,6 +9957,8 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
{
if (i->m_spent)
continue;
+ if (i->m_frozen)
+ continue;
if (i->m_key_image_partial)
continue;
if (!is_transfer_unlocked(*i))
@@ -9911,7 +9974,7 @@ std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
std::set<uint64_t> set;
for (const auto &td: m_transfers)
{
- if (!td.m_spent)
+ if (!td.m_spent && !td.m_frozen)
set.insert(td.is_rct() ? 0 : td.amount());
}
std::vector<uint64_t> vector;
@@ -10037,7 +10100,7 @@ void wallet2::discard_unmixable_outputs()
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
for (size_t idx : unmixable_outputs)
{
- m_transfers[idx].m_spent = true;
+ freeze(idx);
}
}
@@ -10424,7 +10487,7 @@ void wallet2::check_tx_key(const crypto::hash &txid, const crypto::secret_key &t
void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, const cryptonote::account_public_address &address, uint64_t &received) const
{
received = 0;
- hw::device &hwdev = m_account.get_device();
+
for (size_t n = 0; n < tx.vout.size(); ++n)
{
const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target));
@@ -10432,13 +10495,13 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
continue;
crypto::public_key derived_out_key;
- bool r = hwdev.derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key);
+ bool r = crypto::derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
bool found = out_key->key == derived_out_key;
crypto::key_derivation found_derivation = derivation;
if (!found && !additional_derivations.empty())
{
- r = hwdev.derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key);
+ r = crypto::derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key");
found = out_key->key == derived_out_key;
found_derivation = additional_derivations[n];
@@ -10454,9 +10517,9 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
else
{
crypto::secret_key scalar1;
- hwdev.derivation_to_scalar(found_derivation, n, scalar1);
+ crypto::derivation_to_scalar(found_derivation, n, scalar1);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
- hwdev.ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2);
+ rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), tx.rct_signatures.type == rct::RCTTypeBulletproof2);
const rct::key C = tx.rct_signatures.outPk[n].mask;
rct::key Ctmp;
THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
@@ -10567,6 +10630,8 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const cryptonote::account_public_address &address, bool is_subaddress, const std::string &message) const
{
+ hw::device &hwdev = m_account.get_device();
+ rct::key aP;
// determine if the address is found in the subaddress hash table (i.e. whether the proof is outbound or inbound)
const bool is_out = m_subaddresses.count(address.m_spend_public_key) == 0;
@@ -10585,30 +10650,34 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
shared_secret.resize(num_sigs);
sig.resize(num_sigs);
- shared_secret[0] = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key)));
+ hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(tx_key));
+ shared_secret[0] = rct::rct2pk(aP);
crypto::public_key tx_pub_key;
if (is_subaddress)
{
- tx_pub_key = rct2pk(rct::scalarmultKey(rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key)));
- crypto::generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]);
+ hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(tx_key));
+ tx_pub_key = rct2pk(aP);
+ hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[0], tx_key, sig[0]);
}
else
{
- crypto::secret_key_to_public_key(tx_key, tx_pub_key);
- crypto::generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
+ hwdev.secret_key_to_public_key(tx_key, tx_pub_key);
+ hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[0], tx_key, sig[0]);
}
for (size_t i = 1; i < num_sigs; ++i)
{
- shared_secret[i] = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1])));
+ hwdev.scalarmultKey(aP, rct::pk2rct(address.m_view_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
+ shared_secret[i] = rct::rct2pk(aP);
if (is_subaddress)
{
- tx_pub_key = rct2pk(rct::scalarmultKey(rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1])));
- crypto::generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
+ hwdev.scalarmultKey(aP, rct::pk2rct(address.m_spend_public_key), rct::sk2rct(additional_tx_keys[i - 1]));
+ tx_pub_key = rct2pk(aP);
+ hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, address.m_spend_public_key, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
}
else
{
- crypto::secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key);
- crypto::generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
+ hwdev.secret_key_to_public_key(additional_tx_keys[i - 1], tx_pub_key);
+ hwdev.generate_tx_proof(prefix_hash, tx_pub_key, address.m_view_public_key, boost::none, shared_secret[i], additional_tx_keys[i - 1], sig[i]);
}
}
sig_str = std::string("OutProofV1");
@@ -10624,25 +10693,27 @@ std::string wallet2::get_tx_proof(const cryptonote::transaction &tx, const crypt
sig.resize(num_sigs);
const crypto::secret_key& a = m_account.get_keys().m_view_secret_key;
- shared_secret[0] = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(tx_pub_key), rct::sk2rct(a)));
+ hwdev.scalarmultKey(aP, rct::pk2rct(tx_pub_key), rct::sk2rct(a));
+ shared_secret[0] = rct2pk(aP);
if (is_subaddress)
{
- crypto::generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], a, sig[0]);
+ hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, address.m_spend_public_key, shared_secret[0], a, sig[0]);
}
else
{
- crypto::generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]);
+ hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, shared_secret[0], a, sig[0]);
}
for (size_t i = 1; i < num_sigs; ++i)
{
- shared_secret[i] = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(additional_tx_pub_keys[i - 1]), rct::sk2rct(a)));
+ hwdev.scalarmultKey(aP,rct::pk2rct(additional_tx_pub_keys[i - 1]), rct::sk2rct(a));
+ shared_secret[i] = rct2pk(aP);
if (is_subaddress)
{
- crypto::generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], address.m_spend_public_key, shared_secret[i], a, sig[i]);
+ hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], address.m_spend_public_key, shared_secret[i], a, sig[i]);
}
else
{
- crypto::generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]);
+ hwdev.generate_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[i - 1], boost::none, shared_secret[i], a, sig[i]);
}
}
sig_str = std::string("InProofV1");
@@ -10820,7 +10891,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details &td = m_transfers[i];
- if (!td.m_spent && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
+ if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
selected_transfers.push_back(i);
}
@@ -11567,6 +11638,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
for(size_t i = 0; i < offset; ++i)
{
const transfer_details &td = m_transfers[i];
+ if (td.m_frozen)
+ continue;
uint64_t amount = td.amount();
if (td.m_spent)
spent += amount;
@@ -11578,6 +11651,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
for(size_t i = 0; i < signed_key_images.size(); ++i)
{
const transfer_details &td = m_transfers[i + offset];
+ if (td.m_frozen)
+ continue;
uint64_t amount = td.amount();
if (td.m_spent)
spent += amount;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 28ebd6704..5a67c20d0 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -266,6 +266,7 @@ namespace tools
size_t m_internal_output_index;
uint64_t m_global_output_index;
bool m_spent;
+ bool m_frozen;
uint64_t m_spent_height;
crypto::key_image m_key_image; //TODO: key_image stored twice :(
rct::key m_mask;
@@ -291,6 +292,7 @@ namespace tools
FIELD(m_internal_output_index)
FIELD(m_global_output_index)
FIELD(m_spent)
+ FIELD(m_frozen)
FIELD(m_spent_height)
FIELD(m_key_image)
FIELD(m_mask)
@@ -1246,6 +1248,14 @@ namespace tools
bool unblackball_output(const std::pair<uint64_t, uint64_t> &output);
bool is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) const;
+ void freeze(size_t idx);
+ void thaw(size_t idx);
+ bool frozen(size_t idx) const;
+ void freeze(const crypto::key_image &ki);
+ void thaw(const crypto::key_image &ki);
+ bool frozen(const crypto::key_image &ki) const;
+ bool frozen(const transfer_details &td) const;
+
// MMS -------------------------------------------------------------------------------------------------
mms::message_store& get_message_store() { return m_message_store; };
const mms::message_store& get_message_store() const { return m_message_store; };
@@ -1328,6 +1338,7 @@ namespace tools
bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
crypto::chacha_key get_ringdb_key();
void setup_keys(const epee::wipeable_string &password);
+ size_t get_transfer_details(const crypto::key_image &ki) const;
void register_devices();
hw::device& lookup_device(const std::string & device_descriptor);
@@ -1482,7 +1493,7 @@ namespace tools
};
}
BOOST_CLASS_VERSION(tools::wallet2, 28)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@@ -1544,6 +1555,10 @@ namespace boost
{
x.m_key_image_request = false;
}
+ if (ver < 12)
+ {
+ x.m_frozen = false;
+ }
}
template <class Archive>
@@ -1632,8 +1647,17 @@ namespace boost
}
a & x.m_key_image_request;
if (ver < 11)
+ {
+ initialize_transfer_details(a, x, ver);
return;
+ }
a & x.m_uses;
+ if (ver < 12)
+ {
+ initialize_transfer_details(a, x, ver);
+ return;
+ }
+ a & x.m_frozen;
}
template <class Archive>
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 18b2de33f..f80263007 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -901,15 +901,7 @@ namespace tools
try
{
- uint64_t mixin;
- if(req.ring_size != 0)
- {
- mixin = m_wallet->adjust_mixin(req.ring_size - 1);
- }
- else
- {
- mixin = m_wallet->adjust_mixin(req.mixin);
- }
+ uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
@@ -961,15 +953,7 @@ namespace tools
try
{
- uint64_t mixin;
- if(req.ring_size != 0)
- {
- mixin = m_wallet->adjust_mixin(req.ring_size - 1);
- }
- else
- {
- mixin = m_wallet->adjust_mixin(req.mixin);
- }
+ uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
@@ -1379,15 +1363,7 @@ namespace tools
try
{
- uint64_t mixin;
- if(req.ring_size != 0)
- {
- mixin = m_wallet->adjust_mixin(req.ring_size - 1);
- }
- else
- {
- mixin = m_wallet->adjust_mixin(req.mixin);
- }
+ uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
@@ -1442,15 +1418,7 @@ namespace tools
try
{
- uint64_t mixin;
- if(req.ring_size != 0)
- {
- mixin = m_wallet->adjust_mixin(req.ring_size - 1);
- }
- else
- {
- mixin = m_wallet->adjust_mixin(req.mixin);
- }
+ uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index df4370949..de3067a52 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -446,7 +446,6 @@ namespace wallet_rpc
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
uint32_t priority;
- uint64_t mixin;
uint64_t ring_size;
uint64_t unlock_time;
std::string payment_id;
@@ -460,7 +459,6 @@ namespace wallet_rpc
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
KV_SERIALIZE(priority)
- KV_SERIALIZE_OPT(mixin, (uint64_t)0)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
@@ -505,7 +503,6 @@ namespace wallet_rpc
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
uint32_t priority;
- uint64_t mixin;
uint64_t ring_size;
uint64_t unlock_time;
std::string payment_id;
@@ -519,7 +516,6 @@ namespace wallet_rpc
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
KV_SERIALIZE(priority)
- KV_SERIALIZE_OPT(mixin, (uint64_t)0)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(payment_id)
@@ -746,7 +742,6 @@ namespace wallet_rpc
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
uint32_t priority;
- uint64_t mixin;
uint64_t ring_size;
uint64_t outputs;
uint64_t unlock_time;
@@ -762,7 +757,6 @@ namespace wallet_rpc
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
KV_SERIALIZE(priority)
- KV_SERIALIZE_OPT(mixin, (uint64_t)0)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE_OPT(outputs, (uint64_t)1)
KV_SERIALIZE(unlock_time)
@@ -816,7 +810,6 @@ namespace wallet_rpc
{
std::string address;
uint32_t priority;
- uint64_t mixin;
uint64_t ring_size;
uint64_t outputs;
uint64_t unlock_time;
@@ -830,7 +823,6 @@ namespace wallet_rpc
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(priority)
- KV_SERIALIZE_OPT(mixin, (uint64_t)0)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE_OPT(outputs, (uint64_t)1)
KV_SERIALIZE(unlock_time)