aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp2
-rw-r--r--src/blockchain_db/blockchain_db.h5
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp48
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h1
-rw-r--r--src/blockchain_utilities/blockchain_export.cpp7
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp3
-rw-r--r--src/blockchain_utilities/blocksdat_file.cpp2
-rw-r--r--src/common/command_line.h47
-rw-r--r--src/common/dns_utils.cpp28
-rw-r--r--src/common/dns_utils.h2
-rw-r--r--src/common/int-util.h9
-rw-r--r--src/common/password.cpp15
-rw-r--r--src/common/password.h2
-rw-r--r--src/common/perf_timer.cpp7
-rw-r--r--src/common/rpc_client.h16
-rw-r--r--src/common/threadpool.cpp18
-rw-r--r--src/common/threadpool.h3
-rw-r--r--src/common/util.cpp2
-rw-r--r--src/common/util.h6
-rw-r--r--src/common/varint.h4
-rw-r--r--src/crypto/CMakeLists.txt2
-rw-r--r--src/crypto/chacha.c2
-rw-r--r--src/crypto/chacha.h4
-rw-r--r--src/crypto/crypto.cpp23
-rw-r--r--src/crypto/crypto.h21
-rw-r--r--src/crypto/crypto_device.cpp79
-rw-r--r--src/crypto/hash-ops.h1
-rw-r--r--src/crypto/keccak.c22
-rw-r--r--src/crypto/oaes_lib.c14
-rw-r--r--src/crypto/random.c5
-rw-r--r--src/crypto/slow-hash.c12
-rw-r--r--src/crypto/tree-hash.c4
-rw-r--r--src/cryptonote_basic/CMakeLists.txt1
-rw-r--r--src/cryptonote_basic/account.cpp40
-rw-r--r--src/cryptonote_basic/account.h11
-rw-r--r--src/cryptonote_basic/connection_context.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h6
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h8
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp176
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h17
-rw-r--r--src/cryptonote_basic/hardfork.h1
-rw-r--r--src/cryptonote_basic/miner.cpp21
-rw-r--r--src/cryptonote_config.h3
-rw-r--r--src/cryptonote_core/CMakeLists.txt1
-rw-r--r--src/cryptonote_core/blockchain.cpp24
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp48
-rw-r--r--src/cryptonote_core/cryptonote_core.h3
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp61
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp95
-rw-r--r--src/cryptonote_core/tx_pool.h27
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h4
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl15
-rw-r--r--src/daemon/command_line_args.h41
-rw-r--r--src/daemon/command_parser_executor.cpp17
-rw-r--r--src/daemon/command_parser_executor.h4
-rw-r--r--src/daemon/command_server.cpp6
-rw-r--r--src/daemon/core.h3
-rw-r--r--src/daemon/daemon.cpp16
-rw-r--r--src/daemon/main.cpp22
-rw-r--r--src/daemon/protocol.h4
-rw-r--r--src/daemon/rpc.h18
-rw-r--r--src/daemon/rpc_command_executor.cpp59
-rw-r--r--src/daemon/rpc_command_executor.h4
-rw-r--r--src/debug_utilities/cn_deserialize.cpp34
-rw-r--r--src/device/CMakeLists.txt77
-rw-r--r--src/device/device.cpp71
-rw-r--r--src/device/device.hpp146
-rw-r--r--src/device/device_declare.hpp42
-rw-r--r--src/device/device_default.cpp263
-rw-r--r--src/device/device_default.hpp126
-rw-r--r--src/device/device_ledger.cpp2069
-rw-r--r--src/device/device_ledger.hpp202
-rw-r--r--src/device/log.cpp164
-rw-r--r--src/device/log.hpp69
-rw-r--r--src/multisig/multisig.cpp3
-rw-r--r--src/p2p/CMakeLists.txt1
-rw-r--r--src/p2p/net_node.cpp14
-rw-r--r--src/p2p/net_node.h13
-rw-r--r--src/p2p/net_node.inl93
-rw-r--r--src/p2p/p2p_protocol_defs.h6
-rw-r--r--src/ringct/CMakeLists.txt2
-rw-r--r--src/ringct/bulletproofs.cc103
-rw-r--r--src/ringct/rctOps.h6
-rw-r--r--src/ringct/rctOps_device.cpp66
-rw-r--r--src/ringct/rctSigs.cpp132
-rw-r--r--src/ringct/rctSigs.h24
-rw-r--r--src/ringct/rctTypes.cpp1
-rw-r--r--src/ringct/rctTypes.h18
-rw-r--r--src/rpc/core_rpc_server.cpp308
-rw-r--r--src/rpc/core_rpc_server.h20
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h88
-rw-r--r--src/rpc/rpc_args.cpp2
-rw-r--r--src/serialization/binary_archive.h2
-rw-r--r--src/serialization/variant.h2
-rw-r--r--src/simplewallet/simplewallet.cpp216
-rw-r--r--src/simplewallet/simplewallet.h2
-rw-r--r--src/wallet/api/address_book.cpp2
-rw-r--r--src/wallet/api/wallet.cpp7
-rw-r--r--src/wallet/api/wallet2_api.h4
-rw-r--r--src/wallet/api/wallet_manager.cpp4
-rw-r--r--src/wallet/wallet2.cpp341
-rw-r--r--src/wallet/wallet2.h23
-rw-r--r--src/wallet/wallet_rpc_server.cpp54
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h5
-rw-r--r--src/wallet/wallet_rpc_server_error_codes.h6
107 files changed, 5380 insertions, 629 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 357495960..3b71c38cd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -143,3 +143,5 @@ endif()
if(PER_BLOCK_CHECKPOINT)
add_subdirectory(blocks)
endif()
+
+add_subdirectory(device)
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index f540ce133..3a66ecb93 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -770,13 +770,13 @@ BlockchainBDB::~BlockchainBDB()
}
BlockchainBDB::BlockchainBDB(bool batch_transactions) :
+ BlockchainDB(),
m_buffer(DB_BUFFER_COUNT, DB_BUFFER_LENGTH)
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
// initialize folder to something "safe" just in case
// someone accidentally misuses this class...
m_folder = "thishsouldnotexistbecauseitisgibberish";
- m_open = false;
m_run_checkpoint = 0;
m_batch_transactions = batch_transactions;
m_write_txn = nullptr;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 227169614..cce288793 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -538,6 +538,11 @@ protected:
public:
/**
+ * @brief An empty constructor.
+ */
+ BlockchainDB(): m_open(false) { }
+
+ /**
* @brief An empty destructor.
*/
virtual ~BlockchainDB() { };
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 6b81a4c90..51dcb49a8 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -338,6 +338,12 @@ mdb_txn_safe::~mdb_txn_safe()
num_active_txns--;
}
+void mdb_txn_safe::uncheck()
+{
+ num_active_txns--;
+ m_check = false;
+}
+
void mdb_txn_safe::commit(std::string message)
{
if (message.size() == 0)
@@ -466,7 +472,7 @@ void BlockchainLMDB::do_resize(uint64_t increase_size)
// add 1Gb per resize, instead of doing a percentage increase
uint64_t new_mapsize = (double) mei.me_mapsize + add_size;
- // If given, use increase_size intead of above way of resizing.
+ // If given, use increase_size instead of above way of resizing.
// This is currently used for increasing by an estimated size at start of new
// batch txn.
if (increase_size > 0)
@@ -1074,13 +1080,12 @@ BlockchainLMDB::~BlockchainLMDB()
close();
}
-BlockchainLMDB::BlockchainLMDB(bool batch_transactions)
+BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
// initialize folder to something "safe" just in case
// someone accidentally misuses this class...
m_folder = "thishsouldnotexistbecauseitisgibberish";
- m_open = false;
m_batch_transactions = batch_transactions;
m_write_txn = nullptr;
@@ -1439,9 +1444,10 @@ void BlockchainLMDB::unlock()
#define TXN_PREFIX_RDONLY() \
MDB_txn *m_txn; \
mdb_txn_cursors *m_cursors; \
+ mdb_txn_safe auto_txn; \
bool my_rtxn = block_rtxn_start(&m_txn, &m_cursors); \
- mdb_txn_safe auto_txn(my_rtxn); \
- if (my_rtxn) auto_txn.m_tinfo = m_tinfo.get()
+ if (my_rtxn) auto_txn.m_tinfo = m_tinfo.get(); \
+ else auto_txn.uncheck()
#define TXN_POSTFIX_RDONLY()
#define TXN_POSTFIX_SUCCESS() \
@@ -2434,7 +2440,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
RCURSOR(spent_keys);
MDB_val k, v;
- bool ret = true;
+ bool fret = true;
k = zerokval;
MDB_cursor_op op = MDB_FIRST;
@@ -2448,14 +2454,14 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
throw0(DB_ERROR("Failed to enumerate key images"));
const crypto::key_image k_image = *(const crypto::key_image*)v.mv_data;
if (!f(k_image)) {
- ret = false;
+ fret = false;
break;
}
}
TXN_POSTFIX_RDONLY();
- return ret;
+ return fret;
}
bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)> f) const
@@ -2468,7 +2474,7 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st
MDB_val k;
MDB_val v;
- bool ret = true;
+ bool fret = true;
MDB_cursor_op op;
if (h1)
@@ -2497,7 +2503,7 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st
if (!get_block_hash(b, hash))
throw0(DB_ERROR("Failed to get block hash from blob retrieved from the db"));
if (!f(height, hash, b)) {
- ret = false;
+ fret = false;
break;
}
if (height >= h2)
@@ -2506,7 +2512,7 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st
TXN_POSTFIX_RDONLY();
- return ret;
+ return fret;
}
bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
@@ -2520,7 +2526,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
MDB_val k;
MDB_val v;
- bool ret = true;
+ bool fret = true;
MDB_cursor_op op = MDB_FIRST;
while (1)
@@ -2547,14 +2553,14 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
if (!parse_and_validate_tx_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
if (!f(hash, tx)) {
- ret = false;
+ fret = false;
break;
}
}
TXN_POSTFIX_RDONLY();
- return ret;
+ return fret;
}
bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)> f) const
@@ -2567,7 +2573,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
MDB_val k;
MDB_val v;
- bool ret = true;
+ bool fret = true;
MDB_cursor_op op = MDB_FIRST;
while (1)
@@ -2582,14 +2588,14 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
outkey *ok = (outkey *)v.mv_data;
tx_out_index toi = get_output_tx_and_index_from_global(ok->output_id);
if (!f(amount, toi.first, toi.second)) {
- ret = false;
+ fret = false;
break;
}
}
TXN_POSTFIX_RDONLY();
- return ret;
+ return fret;
}
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
@@ -3140,8 +3146,12 @@ void BlockchainLMDB::drop_hard_fork_info()
TXN_PREFIX(0);
- mdb_drop(*txn_ptr, m_hf_starting_heights, 1);
- mdb_drop(*txn_ptr, m_hf_versions, 1);
+ auto result = mdb_drop(*txn_ptr, m_hf_starting_heights, 1);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error dropping hard fork starting heights db: ", result).c_str()));
+ result = mdb_drop(*txn_ptr, m_hf_versions, 1);
+ if (result)
+ throw1(DB_ERROR(lmdb_error("Error dropping hard fork versions db: ", result).c_str()));
TXN_POSTFIX_SUCCESS();
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index ceae2f084..1b76abf35 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -112,6 +112,7 @@ struct mdb_txn_safe
// BlockchainLMDB destructor to call mdb_txn_safe destructor, as that's too late
// to properly abort, since mdb_env_close would have been called earlier.
void abort();
+ void uncheck();
operator MDB_txn*()
{
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp
index fcf020057..b3e11605d 100644
--- a/src/blockchain_utilities/blockchain_export.cpp
+++ b/src/blockchain_utilities/blockchain_export.cpp
@@ -59,7 +59,6 @@ int main(int argc, char* argv[])
tools::on_startup();
boost::filesystem::path default_data_path {tools::get_default_data_dir()};
- boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"};
boost::filesystem::path output_file_path;
po::options_description desc_cmd_only("Command line options");
@@ -73,8 +72,7 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<bool> arg_blocks_dat = {"blocksdat", "Output in blocks.dat format", blocks_dat};
- command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir, default_data_path.string());
- command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_data_dir, default_testnet_data_path.string());
+ command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
command_line::add_arg(desc_cmd_sett, arg_output_file);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
command_line::add_arg(desc_cmd_sett, arg_log_level);
@@ -118,8 +116,7 @@ int main(int argc, char* argv[])
std::string m_config_folder;
- auto data_dir_arg = opt_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir;
- m_config_folder = command_line::get_arg(vm, data_dir_arg);
+ m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
std::string db_type = command_line::get_arg(vm, arg_database);
if (!cryptonote::blockchain_valid_db_type(db_type))
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index ce08022fc..6195e47e7 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -671,8 +671,7 @@ int main(int argc, char* argv[])
}
opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
- auto data_dir_arg = opt_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir;
- m_config_folder = command_line::get_arg(vm, data_dir_arg);
+ m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
db_arg_str = command_line::get_arg(vm, arg_database);
mlog_configure(mlog_get_default_log_path("monero-blockchain-import.log"), true);
diff --git a/src/blockchain_utilities/blocksdat_file.cpp b/src/blockchain_utilities/blocksdat_file.cpp
index 2bad86dfd..45ef33acb 100644
--- a/src/blockchain_utilities/blocksdat_file.cpp
+++ b/src/blockchain_utilities/blocksdat_file.cpp
@@ -106,7 +106,7 @@ void BlocksdatFile::write_block(const crypto::hash& block_hash)
{
crypto::hash hash;
crypto::cn_fast_hash(m_hashes.data(), HASH_OF_HASHES_STEP * sizeof(crypto::hash), hash);
- memmove(m_hashes.data(), m_hashes.data() + HASH_OF_HASHES_STEP * sizeof(crypto::hash), (m_hashes.size() - HASH_OF_HASHES_STEP) * sizeof(crypto::hash));
+ memmove(m_hashes.data(), m_hashes.data() + HASH_OF_HASHES_STEP, (m_hashes.size() - HASH_OF_HASHES_STEP) * sizeof(crypto::hash));
m_hashes.resize(m_hashes.size() - HASH_OF_HASHES_STEP);
const std::string data(hash.data, sizeof(hash));
*m_raw_data_file << data;
diff --git a/src/common/command_line.h b/src/common/command_line.h
index 7b183d86b..f67efcf86 100644
--- a/src/common/command_line.h
+++ b/src/common/command_line.h
@@ -30,7 +30,9 @@
#pragma once
+#include <functional>
#include <iostream>
+#include <sstream>
#include <type_traits>
#include <boost/program_options/parsers.hpp>
@@ -46,7 +48,7 @@ namespace command_line
//! \return True if `str` is `is_iequal("n" || "no" || `tr("no"))`.
bool is_no(const std::string& str);
- template<typename T, bool required = false>
+ template<typename T, bool required = false, bool dependent = false>
struct arg_descriptor;
template<typename T>
@@ -81,6 +83,22 @@ namespace command_line
};
template<typename T>
+ struct arg_descriptor<T, false, true>
+ {
+ typedef T value_type;
+
+ const char* name;
+ const char* description;
+
+ T default_value;
+
+ const arg_descriptor<bool, false>& ref;
+ std::function<T(bool, bool, T)> depf;
+
+ bool not_use_default;
+ };
+
+ template<typename T>
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, true>& /*arg*/)
{
return boost::program_options::value<T>()->required();
@@ -96,6 +114,20 @@ namespace command_line
}
template<typename T>
+ boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false, true>& arg)
+ {
+ auto semantic = boost::program_options::value<T>();
+ if (!arg.not_use_default) {
+ std::ostringstream format;
+ format << arg.depf(false, true, arg.default_value) << ", "
+ << arg.depf(true, true, arg.default_value) << " if '"
+ << arg.ref.name << "'";
+ semantic->default_value(arg.depf(arg.ref.default_value, true, arg.default_value), format.str());
+ }
+ return semantic;
+ }
+
+ template<typename T>
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
{
auto semantic = boost::program_options::value<T>();
@@ -112,8 +144,8 @@ namespace command_line
return semantic;
}
- template<typename T, bool required>
- void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required>& arg, bool unique = true)
+ template<typename T, bool required, bool dependent>
+ void add_arg(boost::program_options::options_description& description, const arg_descriptor<T, required, dependent>& arg, bool unique = true)
{
if (0 != description.find_nothrow(arg.name, false))
{
@@ -189,12 +221,17 @@ namespace command_line
return !value.empty();
}
- template<typename T, bool required>
- bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
+ template<typename T, bool required, bool dependent>
+ bool is_arg_defaulted(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, dependent>& arg)
{
return vm[arg.name].defaulted();
}
+ template<typename T, bool required>
+ T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required, true>& arg)
+ {
+ return arg.depf(get_arg(vm, arg.ref), is_arg_defaulted(vm, arg), vm[arg.name].template as<T>());
+ }
template<typename T, bool required>
T get_arg(const boost::program_options::variables_map& vm, const arg_descriptor<T, required>& arg)
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index 06f127c25..1ecdae8ec 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -36,13 +36,21 @@
#include <boost/filesystem/fstream.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
+#include <boost/algorithm/string/join.hpp>
using namespace epee;
namespace bf = boost::filesystem;
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.dns"
-#define DEFAULT_DNS_PUBLIC_ADDR "8.8.4.4"
+static const char *DEFAULT_DNS_PUBLIC_ADDR[] =
+{
+ "194.150.168.168", // CCC (Germany)
+ "81.3.27.54", // Lightning Wire Labs (Germany)
+ "31.3.135.232", // OpenNIC (Switzerland)
+ "80.67.169.40", // FDN (France)
+ "209.58.179.186", // Cyberghost (Singapore)
+};
static boost::mutex instance_lock;
@@ -201,13 +209,13 @@ public:
DNSResolver::DNSResolver() : m_data(new DNSResolverData())
{
int use_dns_public = 0;
- std::string dns_public_addr = DEFAULT_DNS_PUBLIC_ADDR;
+ std::vector<std::string> dns_public_addr;
if (auto res = getenv("DNS_PUBLIC"))
{
dns_public_addr = tools::dns_utils::parse_dns_public(res);
if (!dns_public_addr.empty())
{
- MGINFO("Using public DNS server: " << dns_public_addr << " (TCP)");
+ MGINFO("Using public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)");
use_dns_public = 1;
}
else
@@ -221,7 +229,8 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData())
if (use_dns_public)
{
- ub_ctx_set_fwd(m_data->m_ub_context, dns_public_addr.c_str());
+ for (const auto &ip: dns_public_addr)
+ ub_ctx_set_fwd(m_data->m_ub_context, ip.c_str());
ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no"));
ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes"));
}
@@ -526,15 +535,16 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
return true;
}
-std::string parse_dns_public(const char *s)
+std::vector<std::string> parse_dns_public(const char *s)
{
unsigned ip0, ip1, ip2, ip3;
char c;
- std::string dns_public_addr;
+ std::vector<std::string> dns_public_addr;
if (!strcmp(s, "tcp"))
{
- dns_public_addr = DEFAULT_DNS_PUBLIC_ADDR;
- LOG_PRINT_L0("Using default public DNS server: " << dns_public_addr << " (TCP)");
+ for (size_t i = 0; i < sizeof(DEFAULT_DNS_PUBLIC_ADDR) / sizeof(DEFAULT_DNS_PUBLIC_ADDR[0]); ++i)
+ dns_public_addr.push_back(DEFAULT_DNS_PUBLIC_ADDR[i]);
+ LOG_PRINT_L0("Using default public DNS server(s): " << boost::join(dns_public_addr, ", ") << " (TCP)");
}
else if (sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4)
{
@@ -544,7 +554,7 @@ std::string parse_dns_public(const char *s)
}
else
{
- dns_public_addr = std::string(s + strlen("tcp://"));
+ dns_public_addr.push_back(std::string(s + strlen("tcp://")));
}
}
else
diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h
index d5dc03283..f46bca3dd 100644
--- a/src/common/dns_utils.h
+++ b/src/common/dns_utils.h
@@ -167,7 +167,7 @@ std::string get_account_address_as_str_from_url(const std::string& url, bool& dn
bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);
-std::string parse_dns_public(const char *s);
+std::vector<std::string> parse_dns_public(const char *s);
} // namespace tools::dns_utils
diff --git a/src/common/int-util.h b/src/common/int-util.h
index 11e39895e..3bcc085e2 100644
--- a/src/common/int-util.h
+++ b/src/common/int-util.h
@@ -34,7 +34,10 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
+
+#ifndef _MSC_VER
#include <sys/param.h>
+#endif
#if defined(__ANDROID__)
#include <byteswap.h>
@@ -206,6 +209,12 @@ static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
}
}
+#ifdef _MSC_VER
+# define LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not enabled");
#endif
diff --git a/src/common/password.cpp b/src/common/password.cpp
index ef026c979..9336a14fc 100644
--- a/src/common/password.cpp
+++ b/src/common/password.cpp
@@ -42,12 +42,10 @@
#include <unistd.h>
#endif
-#ifdef HAVE_READLINE
- #include "readline_buffer.h"
-#endif
-
#include "memwipe.h"
+#define EOT 0x4
+
namespace
{
#if defined(_WIN32)
@@ -134,7 +132,7 @@ namespace
while (aPass.size() < tools::password_container::max_password_size)
{
int ch = getch();
- if (EOF == ch)
+ if (EOF == ch || ch == EOT)
{
return false;
}
@@ -229,13 +227,20 @@ namespace tools
m_password.clear();
}
+ std::atomic<bool> password_container::is_prompting(false);
+
boost::optional<password_container> password_container::prompt(const bool verify, const char *message)
{
+ is_prompting = true;
password_container pass1{};
password_container pass2{};
if (is_cin_tty() ? read_from_tty(verify, message, pass1.m_password, pass2.m_password) : read_from_file(pass1.m_password))
+ {
+ is_prompting = false;
return {std::move(pass1)};
+ }
+ is_prompting = false;
return boost::none;
}
diff --git a/src/common/password.h b/src/common/password.h
index 7c29effe4..61937b93a 100644
--- a/src/common/password.h
+++ b/src/common/password.h
@@ -31,6 +31,7 @@
#pragma once
#include <string>
+#include <atomic>
#include <boost/optional/optional.hpp>
#include "wipeable_string.h"
@@ -49,6 +50,7 @@ namespace tools
//! \return A password from stdin TTY prompt or `std::cin` pipe.
static boost::optional<password_container> prompt(bool verify, const char *mesage = "Password");
+ static std::atomic<bool> is_prompting;
password_container(const password_container&) = delete;
password_container(password_container&& rhs) = default;
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index 41e23130d..16abdfd99 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -49,16 +49,15 @@ namespace
#ifdef __x86_64__
uint64_t get_ticks_per_ns()
{
- uint64_t t0 = epee::misc_utils::get_ns_count();
+ uint64_t t0 = epee::misc_utils::get_ns_count(), t1;
uint64_t r0 = get_tick_count();
while (1)
{
- uint64_t t = epee::misc_utils::get_ns_count();
- if (t - t0 > 1*1000000000) break; // work one second
+ t1 = epee::misc_utils::get_ns_count();
+ if (t1 - t0 > 1*1000000000) break; // work one second
}
- uint64_t t1 = epee::misc_utils::get_ns_count();
uint64_t r1 = get_tick_count();
uint64_t tpns256 = 256 * (r1 - r0) / (t1 - t0);
return tpns256 ? tpns256 : 1;
diff --git a/src/common/rpc_client.h b/src/common/rpc_client.h
index 64c84ed19..9665966ae 100644
--- a/src/common/rpc_client.h
+++ b/src/common/rpc_client.h
@@ -72,10 +72,10 @@ namespace tools
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
+ ok = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
- fail_msg_writer() << "Daemon request failed";
+ fail_msg_writer() << "basic_json_rpc_request: Daemon request failed";
return false;
}
else
@@ -95,15 +95,15 @@ namespace tools
t_http_connection connection(&m_http_client);
bool ok = connection.is_open();
- ok = ok && epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
+ ok = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, res, m_http_client, t_http_connection::TIMEOUT());
+ if (!ok || res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
- fail_msg_writer() << fail_msg << " -- " << res.status;
+ fail_msg_writer() << fail_msg << " -- json_rpc_request: " << res.status;
return false;
}
else
@@ -123,15 +123,15 @@ namespace tools
t_http_connection connection(&m_http_client);
bool ok = connection.is_open();
- ok = ok && epee::net_utils::invoke_http_json(relative_url, req, res, m_http_client, t_http_connection::TIMEOUT());
if (!ok)
{
fail_msg_writer() << "Couldn't connect to daemon: " << m_http_client.get_host() << ":" << m_http_client.get_port();
return false;
}
- else if (res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
+ ok = epee::net_utils::invoke_http_json(relative_url, req, res, m_http_client, t_http_connection::TIMEOUT());
+ if (!ok || res.status != CORE_RPC_STATUS_OK) // TODO - handle CORE_RPC_STATUS_BUSY ?
{
- fail_msg_writer() << fail_msg << " -- " << res.status;
+ fail_msg_writer() << fail_msg << "-- rpc_request: " << res.status;
return false;
}
else
diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp
index 7fd16ceaf..51e071577 100644
--- a/src/common/threadpool.cpp
+++ b/src/common/threadpool.cpp
@@ -25,6 +25,7 @@
// 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.
+#include "misc_log_ex.h"
#include "common/threadpool.h"
#include <cassert>
@@ -81,6 +82,23 @@ int threadpool::get_max_concurrency() {
return max;
}
+threadpool::waiter::~waiter()
+{
+ {
+ boost::unique_lock<boost::mutex> lock(mt);
+ if (num)
+ MERROR("wait should have been called before waiter dtor - waiting now");
+ }
+ try
+ {
+ wait();
+ }
+ catch (const std::exception &e)
+ {
+ /* ignored */
+ }
+}
+
void threadpool::waiter::wait() {
boost::unique_lock<boost::mutex> lock(mt);
while(num) cv.wait(lock);
diff --git a/src/common/threadpool.h b/src/common/threadpool.h
index a0e53b011..34152541c 100644
--- a/src/common/threadpool.h
+++ b/src/common/threadpool.h
@@ -34,6 +34,7 @@
#include <functional>
#include <utility>
#include <vector>
+#include <stdexcept>
namespace tools
{
@@ -57,7 +58,7 @@ public:
void dec();
void wait(); //! Wait for a set of tasks to finish.
waiter() : num(0){}
- ~waiter() { wait(); }
+ ~waiter();
};
// Submit a task to the pool. The waiter pointer may be
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 659ea31b8..e0f3cd655 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -552,8 +552,6 @@ std::string get_nix_version_display_string()
}
bool on_startup()
{
- wipeable_string::set_wipe(&memwipe);
-
mlog_configure("", true);
sanitize_locale();
diff --git a/src/common/util.h b/src/common/util.h
index 5afb42c97..d3ba47a4f 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -153,8 +153,12 @@ namespace tools
}
return r;
#else
+ static struct sigaction sa;
+ memset(&sa, 0, sizeof(struct sigaction));
+ sa.sa_handler = posix_handler;
+ sa.sa_flags = 0;
/* Only blocks SIGINT, SIGTERM and SIGPIPE */
- signal(SIGINT, posix_handler);
+ sigaction(SIGINT, &sa, NULL);
signal(SIGTERM, posix_handler);
signal(SIGPIPE, SIG_IGN);
m_handler = t;
diff --git a/src/common/varint.h b/src/common/varint.h
index 262bd1360..151d13dbf 100644
--- a/src/common/varint.h
+++ b/src/common/varint.h
@@ -45,7 +45,7 @@
* is as follows: Strip the msb of each byte, then from left to right,
* read in what remains, placing it in reverse, into the buffer. Thus,
* the following bit stream: 0xff02 would return 0x027f. 0xff turns
- * into 0x7f, is placed on the beggining of the buffer, then 0x02 is
+ * into 0x7f, is placed on the beginning of the buffer, then 0x02 is
* unchanged, since its msb is not set, and placed at the end of the
* buffer.
*/
@@ -108,7 +108,7 @@ namespace tools {
return EVARINT_REPRESENT;
}
- write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actualy placing into write, stripping the first bit */
+ write |= static_cast<T>(byte & 0x7f) << shift; /* Does the actually placing into write, stripping the first bit */
/* If there is no next */
if ((byte & 0x80) == 0) {
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 71dcedcab..35c099697 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -33,6 +33,7 @@ set(crypto_sources
crypto-ops-data.c
crypto-ops.c
crypto.cpp
+ crypto_device.cpp
groestl.c
hash-extra-blake.c
hash-extra-groestl.c
@@ -77,6 +78,7 @@ monero_add_library(cncrypto
target_link_libraries(cncrypto
PUBLIC
epee
+ device
${Boost_SYSTEM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
diff --git a/src/crypto/chacha.c b/src/crypto/chacha.c
index f573083be..5d3edb98d 100644
--- a/src/crypto/chacha.c
+++ b/src/crypto/chacha.c
@@ -6,7 +6,9 @@ Public domain.
#include <memory.h>
#include <stdio.h>
+#ifndef _MSC_VER
#include <sys/param.h>
+#endif
#include "chacha.h"
#include "common/int-util.h"
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index f74d0c352..b45c3d7c7 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -69,10 +69,10 @@ namespace crypto {
chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
}
- inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) {
+ inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, bool prehashed=false) {
static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key");
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
- crypto::cn_slow_hash(data, size, pwd_hash.data());
+ crypto::cn_slow_hash_pre(data, size, pwd_hash.data(), prehashed);
memcpy(&key, pwd_hash.data(), sizeof(key));
}
diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp
index b28854a13..0c70b9eeb 100644
--- a/src/crypto/crypto.cpp
+++ b/src/crypto/crypto.cpp
@@ -28,6 +28,7 @@
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+#include <unistd.h>
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -43,6 +44,18 @@
#include "crypto.h"
#include "hash.h"
+namespace {
+ static void local_abort(const char *msg)
+ {
+ fprintf(stderr, "%s\n", msg);
+#ifdef NDEBUG
+ _exit(1);
+#else
+ abort();
+#endif
+ }
+}
+
namespace crypto {
using std::abort;
@@ -94,7 +107,7 @@ namespace crypto {
/*
* generate public and secret keys from a random 256-bit integer
- * TODO: allow specifiying random value (for wallet recovery)
+ * TODO: allow specifying random value (for wallet recovery)
*
*/
secret_key crypto_ops::generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover) {
@@ -423,7 +436,7 @@ namespace crypto {
return sc_isnonzero(&c2) == 0;
}
- static void hash_to_ec(const public_key &key, ge_p3 &res) {
+ void crypto_ops::hash_to_ec(const public_key &key, ge_p3 &res) {
hash h;
ge_p2 point;
ge_p1p1 point2;
@@ -467,7 +480,7 @@ POP_WARNINGS
ec_scalar sum, k, h;
boost::shared_ptr<rs_comm> buf(reinterpret_cast<rs_comm *>(malloc(rs_comm_size(pubs_count))), free);
if (!buf)
- abort();
+ local_abort("malloc failure");
assert(sec_index < pubs_count);
#if !defined(NDEBUG)
{
@@ -486,7 +499,7 @@ POP_WARNINGS
}
#endif
if (ge_frombytes_vartime(&image_unp, &image) != 0) {
- abort();
+ local_abort("invalid key image");
}
ge_dsm_precomp(image_pre, &image_unp);
sc_0(&sum);
@@ -505,7 +518,7 @@ POP_WARNINGS
random_scalar(sig[i].c);
random_scalar(sig[i].r);
if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
- abort();
+ local_abort("invalid pubkey");
}
ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
ge_tobytes(&buf->ab[i].a, &tmp2);
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 81ebfb9e2..75b333473 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -46,6 +46,10 @@
#include "hex.h"
#include "span.h"
#include "hash.h"
+#include "device/device_declare.hpp"
+extern "C" {
+ #include "crypto-ops.h"
+}
namespace crypto {
@@ -113,6 +117,9 @@ namespace crypto {
void operator=(const crypto_ops &);
~crypto_ops();
+ static void hash_to_ec(const public_key &key, ge_p3 &res) ;
+ friend void hash_to_ec(const public_key &key, ge_p3 &res) ;
+
static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
static bool check_key(const public_key &);
@@ -149,6 +156,17 @@ namespace crypto {
const public_key *const *, std::size_t, const signature *);
};
+ secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev);
+ secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev);
+ bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev);
+ bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev);
+ void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) ;
+ bool derive_public_key(const key_derivation &derivation, size_t output_index, const public_key &base, public_key &derived_key, hw::device &hwdev);
+ void derive_secret_key(const key_derivation &derivation, size_t output_index, const secret_key &base, secret_key &derived_key, hw::device &hwdev);
+ bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev);
+ void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev);
+
+
/* Generate N random bytes
*/
inline void rand(size_t N, uint8_t *bytes) {
@@ -166,6 +184,9 @@ namespace crypto {
return res;
}
+ inline void hash_to_ec(const public_key &key, ge_p3 &res) {
+ crypto_ops::hash_to_ec(key,res);
+ }
/* Generate a new key pair
*/
inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) {
diff --git a/src/crypto/crypto_device.cpp b/src/crypto/crypto_device.cpp
new file mode 100644
index 000000000..5536857c8
--- /dev/null
+++ b/src/crypto/crypto_device.cpp
@@ -0,0 +1,79 @@
+// Copyright (c) 2014-2018, 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.
+//
+
+
+#include "crypto.h"
+#include "device/device.hpp"
+#include "device/log.hpp"
+
+namespace crypto {
+
+ secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev) {
+ secret_key rng;
+ hwdev.generate_keys(pub, sec, recovery_key, recover, rng);
+ return rng;
+ }
+
+ secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev) {
+ secret_key rng;
+ hwdev.generate_keys(pub, sec, secret_key(), false, rng);
+ return rng;
+ }
+
+
+ bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev) {
+ return hwdev.secret_key_to_public_key(sec, pub);
+ }
+
+ bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev) {
+ return hwdev.generate_key_derivation(key1, key2, derivation);
+ }
+
+ void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) {
+ hwdev.derivation_to_scalar(derivation, output_index, res);
+ }
+
+ bool derive_public_key(const key_derivation &derivation, size_t output_index,
+ const public_key &base, public_key &derived_key, hw::device &hwdev) {
+ return hwdev.derive_public_key(derivation, output_index, base, derived_key);
+ }
+
+ void derive_secret_key(const key_derivation &derivation, size_t output_index,
+ const secret_key &base, secret_key &derived_key, hw::device &hwdev) {
+ hwdev.derive_secret_key(derivation, output_index, base, derived_key);
+ }
+
+ bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev) {
+ return hwdev.derive_subaddress_public_key(out_key, derivation, output_index, derived_key);
+ }
+
+ void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev) {
+ hwdev.generate_key_image(pub,sec,image);
+ }
+} \ No newline at end of file
diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h
index 47c6f6425..130bf02db 100644
--- a/src/crypto/hash-ops.h
+++ b/src/crypto/hash-ops.h
@@ -80,6 +80,7 @@ enum {
void cn_fast_hash(const void *data, size_t length, char *hash);
void cn_slow_hash(const void *data, size_t length, char *hash);
+void cn_slow_hash_pre(const void *data, size_t length, char *hash, bool pre);
void hash_extra_blake(const void *data, size_t length, char *hash);
void hash_extra_groestl(const void *data, size_t length, char *hash);
diff --git a/src/crypto/keccak.c b/src/crypto/keccak.c
index fc6d487c2..de8e2a5b3 100644
--- a/src/crypto/keccak.c
+++ b/src/crypto/keccak.c
@@ -4,9 +4,20 @@
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include "hash-ops.h"
#include "keccak.h"
+static void local_abort(const char *msg)
+{
+ fprintf(stderr, "%s\n", msg);
+#ifdef NDEBUG
+ _exit(1);
+#else
+ abort();
+#endif
+}
+
const uint64_t keccakf_rndc[24] =
{
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
@@ -81,10 +92,10 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
uint8_t temp[144];
size_t i, rsiz, rsizw;
- if (mdlen <= 0 || mdlen > 200 || sizeof(st) != 200)
+ static_assert(HASH_DATA_AREA <= sizeof(temp), "Bad keccak preconditions");
+ if (mdlen <= 0 || (mdlen > 100 && sizeof(st) != (size_t)mdlen))
{
- fprintf(stderr, "Bad keccak use");
- abort();
+ local_abort("Bad keccak use");
}
rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen;
@@ -99,10 +110,9 @@ void keccak(const uint8_t *in, size_t inlen, uint8_t *md, int mdlen)
}
// last block and padding
- if (inlen >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp))
+ if (inlen + 1 >= sizeof(temp) || inlen > rsiz || rsiz - inlen + inlen + 1 >= sizeof(temp) || rsiz == 0 || rsiz - 1 >= sizeof(temp) || rsizw * 8 > sizeof(temp))
{
- fprintf(stderr, "Bad keccak use");
- abort();
+ local_abort("Bad keccak use");
}
memcpy(temp, in, inlen);
diff --git a/src/crypto/oaes_lib.c b/src/crypto/oaes_lib.c
index 0afec6212..9e31ebf46 100644
--- a/src/crypto/oaes_lib.c
+++ b/src/crypto/oaes_lib.c
@@ -53,6 +53,12 @@
#include <unistd.h>
#endif
+#ifdef _MSC_VER
+#define GETPID() _getpid()
+#else
+#define GETPID() getpid()
+#endif
+
#include "oaes_config.h"
#include "oaes_lib.h"
@@ -478,7 +484,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d",
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm,
- _test + timer.millitm, getpid() );
+ _test + timer.millitm, GETPID() );
#else
struct timeval timer;
struct tm *gmTimer;
@@ -490,7 +496,7 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d",
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.tv_usec/1000,
- _test + timer.tv_usec/1000, getpid() );
+ _test + timer.tv_usec/1000, GETPID() );
#endif
if( _test )
@@ -510,7 +516,7 @@ static uint32_t oaes_get_seed(void)
_test = (char *) calloc( sizeof( char ), timer.millitm );
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm +
- (uintptr_t) ( _test + timer.millitm ) + getpid();
+ (uintptr_t) ( _test + timer.millitm ) + GETPID();
#else
struct timeval timer;
struct tm *gmTimer;
@@ -522,7 +528,7 @@ static uint32_t oaes_get_seed(void)
_test = (char *) calloc( sizeof( char ), timer.tv_usec/1000 );
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.tv_usec/1000 +
- (uintptr_t) ( _test + timer.tv_usec/1000 ) + getpid();
+ (uintptr_t) ( _test + timer.tv_usec/1000 ) + GETPID();
#endif
if( _test )
diff --git a/src/crypto/random.c b/src/crypto/random.c
index cd46a1362..9e1a70a2d 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -42,10 +42,15 @@ static void generate_system_random_bytes(size_t n, void *result);
#include <windows.h>
#include <wincrypt.h>
+#include <stdio.h>
static void generate_system_random_bytes(size_t n, void *result) {
HCRYPTPROV prov;
+#ifdef NDEBUG
+#define must_succeed(x) do if (!(x)) { fprintf(stderr, "Failed: " #x); _exit(1); } while (0)
+#else
#define must_succeed(x) do if (!(x)) abort(); while (0)
+#endif
must_succeed(CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT));
must_succeed(CryptGenRandom(prov, (DWORD)n, result));
must_succeed(CryptReleaseContext(prov, 0));
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index f921b2455..36bfba9fd 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -515,8 +515,11 @@ void slow_hash_free_state(void)
* @param length the length in bytes of the data
* @param hash a pointer to a buffer in which the final 256 bit hash will be stored
*/
+void cn_slow_hash(const void *data, size_t length, char *hash) {
+ cn_slow_hash_pre(data,length,hash,false);
+}
-void cn_slow_hash(const void *data, size_t length, char *hash)
+void cn_slow_hash_pre(const void *data, size_t length, char *hash, bool prehashed)
{
RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */
@@ -543,8 +546,11 @@ void cn_slow_hash(const void *data, size_t length, char *hash)
slow_hash_allocate_state();
/* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
-
- hash_process(&state.hs, data, length);
+ if (prehashed) {
+ memcpy(&state.hs, data, length);
+ } else {
+ hash_process(&state.hs, data, length);
+ }
memcpy(text, state.init, INIT_SIZE_BYTE);
/* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill
diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c
index 59fd20bf9..e6d6a267c 100644
--- a/src/crypto/tree-hash.c
+++ b/src/crypto/tree-hash.c
@@ -34,7 +34,9 @@
#include "hash-ops.h"
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
+#ifdef _MSC_VER
+#include <malloc.h>
+#elif !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
#include <alloca.h>
#else
#include <stdlib.h>
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
index de986b6aa..d50a9df67 100644
--- a/src/cryptonote_basic/CMakeLists.txt
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -68,6 +68,7 @@ target_link_libraries(cryptonote_basic
common
cncrypto
checkpoints
+ device
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp
index 1b38d99b3..26c823c2a 100644
--- a/src/cryptonote_basic/account.cpp
+++ b/src/cryptonote_basic/account.cpp
@@ -40,6 +40,7 @@ extern "C"
}
#include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h"
+#include "device/device.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "account"
@@ -50,6 +51,17 @@ DISABLE_VS_WARNINGS(4244 4345)
namespace cryptonote
{
+
+ //-----------------------------------------------------------------
+ hw::device& account_keys::get_device() const {
+ return *m_device;
+ }
+ //-----------------------------------------------------------------
+ void account_keys::set_device( hw::device &hwdev) {
+ m_device = &hwdev;
+ MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name());
+ }
+
//-----------------------------------------------------------------
account_base::account_base()
{
@@ -116,6 +128,34 @@ DISABLE_VS_WARNINGS(4244 4345)
if (m_creation_timestamp == (uint64_t)-1) // failure
m_creation_timestamp = 0; // lowest value
}
+
+ //-----------------------------------------------------------------
+ void account_base::create_from_device(const std::string &device_name)
+ {
+
+ hw::device &hwdev = hw::get_device(device_name);
+ m_keys.set_device(hwdev);
+ hwdev.set_name(device_name);
+ MCDEBUG("ledger", "device type: "<<typeid(hwdev).name());
+ hwdev.init();
+ hwdev.connect();
+ hwdev.get_public_address(m_keys.m_account_address);
+ #ifdef DEBUG_HWDEVICE
+ hwdev.get_secret_keys(m_keys.m_view_secret_key, m_keys.m_spend_secret_key);
+ #endif
+ struct tm timestamp = {0};
+ timestamp.tm_year = 2014 - 1900; // year 2014
+ timestamp.tm_mon = 4 - 1; // month april
+ timestamp.tm_mday = 15; // 15th of april
+ timestamp.tm_hour = 0;
+ timestamp.tm_min = 0;
+ timestamp.tm_sec = 0;
+
+ m_creation_timestamp = mktime(&timestamp);
+ if (m_creation_timestamp == (uint64_t)-1) // failure
+ m_creation_timestamp = 0; // lowest value
+ }
+
//-----------------------------------------------------------------
void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
{
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
index 79601f99c..d734599a3 100644
--- a/src/cryptonote_basic/account.h
+++ b/src/cryptonote_basic/account.h
@@ -33,6 +33,7 @@
#include "cryptonote_basic.h"
#include "crypto/crypto.h"
#include "serialization/keyvalue_serialization.h"
+#include "device/device_declare.hpp"
namespace cryptonote
{
@@ -43,6 +44,7 @@ namespace cryptonote
crypto::secret_key m_spend_secret_key;
crypto::secret_key m_view_secret_key;
std::vector<crypto::secret_key> m_multisig_keys;
+ hw::device *m_device = &hw::get_device("default");
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_account_address)
@@ -50,6 +52,11 @@ namespace cryptonote
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
END_KV_SERIALIZE_MAP()
+
+ account_keys& operator=(account_keys const&) = default;
+
+ hw::device& get_device() const ;
+ void set_device( hw::device &hwdev) ;
};
/************************************************************************/
@@ -60,6 +67,7 @@ namespace cryptonote
public:
account_base();
crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
+ void create_from_device(const std::string &device_name) ;
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
@@ -68,6 +76,9 @@ namespace cryptonote
std::string get_public_address_str(bool testnet) const;
std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const;
+ hw::device& get_device() const {return m_keys.get_device();}
+ void set_device( hw::device &hwdev) {m_keys.set_device(hwdev);}
+
uint64_t get_createtime() const { return m_creation_timestamp; }
void set_createtime(uint64_t val) { m_creation_timestamp = val; }
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index 705af978a..5cd1709ab 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -40,7 +40,7 @@ namespace cryptonote
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
- m_callback_request_count(0), m_last_known_hash(crypto::null_hash) {}
+ m_last_request_time(boost::posix_time::microsec_clock::universal_time()), m_callback_request_count(0), m_last_known_hash(crypto::null_hash) {}
enum state
{
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 54227ad92..4c5f32a09 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -434,6 +434,12 @@ namespace cryptonote
generate_keys(k.pub, k.sec);
return k;
}
+ static inline keypair generate(hw::device &hwdev)
+ {
+ keypair k;
+ generate_keys(k.pub, k.sec, hwdev);
+ return k;
+ }
};
//---------------------------------------------------------------
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 80bd2fdc9..143133163 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -299,7 +299,7 @@ namespace boost
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
- if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
+ if (x.type == rct::RCTTypeSimple) // moved to prunable with bulletproofs
a & x.pseudoOuts;
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
@@ -313,6 +313,8 @@ namespace boost
if (x.rangeSigs.empty())
a & x.bulletproofs;
a & x.MGs;
+ if (x.rangeSigs.empty())
+ a & x.pseudoOuts;
}
template <class Archive>
@@ -325,7 +327,7 @@ namespace boost
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
- if (x.type == rct::RCTTypeSimple || x.type == rct::RCTTypeSimpleBulletproof)
+ if (x.type == rct::RCTTypeSimple)
a & x.pseudoOuts;
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
@@ -335,6 +337,8 @@ namespace boost
if (x.p.rangeSigs.empty())
a & x.p.bulletproofs;
a & x.p.MGs;
+ if (x.type == rct::RCTTypeSimpleBulletproof)
+ a & x.p.pseudoOuts;
}
}
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index aab4f380c..f462d1ca9 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -41,6 +41,8 @@ using namespace epee;
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "ringct/rctSigs.h"
+#include "device/device.hpp"
+#include "device/log.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "cn"
@@ -104,6 +106,16 @@ namespace cryptonote
ge_p1p1_to_p3(&A2, &tmp3);
ge_p3_tobytes(&AB, &A2);
}
+
+ // a copy of rct::scalarmultKey, since we can't link to libringct to avoid circular dependencies
+ static void secret_key_mult_public_key(crypto::public_key & aP, const crypto::public_key &P, const crypto::secret_key &a) {
+ ge_p3 A;
+ ge_p2 R;
+ //CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_frombytes_vartime(&A, (const unsigned char*)P.data);
+ ge_scalarmult(&R, (const unsigned char*)a.data, &A);
+ ge_tobytes((unsigned char*)aP.data, &R);
+ }
}
namespace cryptonote
@@ -171,29 +183,83 @@ namespace cryptonote
crypto::hash_to_scalar(data, sizeof(data), m);
return m;
}
+ crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev)
+ {
+ crypto::secret_key m;
+ hwdev.get_subaddress_secret_key(a, index, m);
+ return m;
+ }
+
//---------------------------------------------------------------
- bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
+ std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end)
+ {
+ CHECK_AND_ASSERT_THROW_MES(begin <= end, "begin > end");
+
+ std::vector<crypto::public_key> pkeys;
+ pkeys.reserve(end - begin);
+ cryptonote::subaddress_index index = {account, begin};
+
+ ge_p3 p3;
+ ge_cached cached;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&p3, (const unsigned char*)keys.m_account_address.m_spend_public_key.data) == 0,
+ "ge_frombytes_vartime failed to convert spend public key");
+ ge_p3_to_cached(&cached, &p3);
+
+ for (uint32_t idx = begin; idx < end; ++idx)
+ {
+ index.minor = idx;
+ if (index.is_zero())
+ {
+ pkeys.push_back(keys.m_account_address.m_spend_public_key);
+ continue;
+ }
+ const crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index);
+
+ // M = m*G
+ ge_scalarmult_base(&p3, (const unsigned char*)m.data);
+
+ // D = B + M
+ crypto::public_key D;
+ ge_p1p1 p1p1;
+ ge_add(&p1p1, &p3, &cached);
+ ge_p1p1_to_p3(&p3, &p1p1);
+ ge_p3_tobytes((unsigned char*)D.data, &p3);
+
+ pkeys.push_back(D);
+ }
+ return pkeys;
+ }
+
+ std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev)
+ {
+ std::vector<crypto::public_key> pkeys;
+ hwdev.get_subaddress_spend_public_keys(keys, account, begin, end, pkeys);
+ return pkeys;
+ }
+
+ //---------------------------------------------------------------
+ bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev)
{
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
- bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
+ bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation, hwdev);
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
std::vector<crypto::key_derivation> additional_recv_derivations;
for (size_t i = 0; i < additional_tx_public_keys.size(); ++i)
{
crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation);
- r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
+ r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation, hwdev);
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
additional_recv_derivations.push_back(additional_recv_derivation);
}
- boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index);
+ boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);
CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
- return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki);
+ return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev);
}
//---------------------------------------------------------------
- bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki)
+ bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev)
{
if (ack.m_spend_secret_key == crypto::null_skey)
{
@@ -205,7 +271,7 @@ namespace cryptonote
{
// derive secret key with subaddress - step 1: original CN derivation
crypto::secret_key scalar_step1;
- crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b
+ crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1, hwdev); // computes Hs(a*R || idx) + b
// step 2: add Hs(a || index_major || index_minor)
crypto::secret_key subaddr_sk;
@@ -216,8 +282,8 @@ namespace cryptonote
}
else
{
- subaddr_sk = get_subaddress_secret_key(ack.m_view_secret_key, received_index);
- sc_add((unsigned char*)&scalar_step2, (unsigned char*)&scalar_step1, (unsigned char*)&subaddr_sk);
+ hwdev.get_subaddress_secret_key(ack.m_view_secret_key, received_index, subaddr_sk);
+ hwdev.sc_secret_add(scalar_step2, scalar_step1,subaddr_sk);
}
in_ephemeral.sec = scalar_step2;
@@ -225,17 +291,17 @@ namespace cryptonote
if (ack.m_multisig_keys.empty())
{
// when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase
- CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key");
+ CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub, hwdev), false, "Failed to derive public key");
}
else
{
// when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation
- CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key");
+ CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub, hwdev), false, "Failed to derive public key");
// and don't forget to add the contribution from the subaddress part
if (!received_index.is_zero())
{
crypto::public_key subaddr_pk;
- CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key");
+ CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk, hwdev), false, "Failed to derive public key");
add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk);
}
}
@@ -244,7 +310,7 @@ namespace cryptonote
false, "key image helper precomp: given output pubkey doesn't match the derived one");
}
- crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
+ crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki, hwdev);
return true;
}
//---------------------------------------------------------------
@@ -531,6 +597,17 @@ namespace cryptonote
// Encryption and decryption are the same operation (xor with a key)
return encrypt_payment_id(payment_id, public_key, secret_key);
}
+
+ //---------------------------------------------------------------
+ bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key,hw::device &hwdev)
+ {
+ return hwdev.encrypt_payment_id(public_key, secret_key, payment_id);
+ }
+ bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev)
+ {
+ // Encryption and decryption are the same operation (xor with a key)
+ return encrypt_payment_id(payment_id, public_key, secret_key, hwdev);
+ }
//---------------------------------------------------------------
bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
{
@@ -631,10 +708,10 @@ namespace cryptonote
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, size_t output_index)
{
crypto::key_derivation derivation;
- bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
+ bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation, acc.get_device());
CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
crypto::public_key pk;
- r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
+ r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device());
CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
if (pk == out_key.key)
return true;
@@ -642,20 +719,20 @@ namespace cryptonote
if (!additional_tx_pub_keys.empty())
{
CHECK_AND_ASSERT_MES(output_index < additional_tx_pub_keys.size(), false, "wrong number of additional tx pubkeys");
- r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation);
+ r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation, acc.get_device());
CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation");
- r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
+ r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device());
CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key");
return pk == out_key.key;
}
return false;
}
//---------------------------------------------------------------
- boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index)
+ boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev)
{
// try the shared tx pubkey
crypto::public_key subaddress_spendkey;
- derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey);
+ derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey,hwdev);
auto found = subaddresses.find(subaddress_spendkey);
if (found != subaddresses.end())
return subaddress_receive_info{ found->second, derivation };
@@ -663,7 +740,7 @@ namespace cryptonote
if (!additional_derivations.empty())
{
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
- derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey);
+ derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey, hwdev);
found = subaddresses.find(subaddress_spendkey);
if (found != subaddresses.end())
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
@@ -1063,4 +1140,63 @@ namespace cryptonote
return key;
}
+ //---------------------------------------------------------------
+ #define CHACHA8_KEY_TAIL 0x8c
+ bool generate_chacha_key_from_secret_keys(const account_keys &keys, crypto::chacha_key &key)
+ {
+ const crypto::secret_key &view_key = keys.m_view_secret_key;
+ const crypto::secret_key &spend_key = keys.m_spend_secret_key;
+ tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data;
+ memcpy(data.data(), &view_key, sizeof(view_key));
+ memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key));
+ data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
+ crypto::generate_chacha_key(data.data(), sizeof(data), key);
+ return true;
+ }
+
+ //---------------------------------------------------------------
+ crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index)
+ {
+ if (index.is_zero())
+ return keys.m_account_address.m_spend_public_key;
+
+ // m = Hs(a || index_major || index_minor)
+ crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index);
+
+ // M = m*G
+ crypto::public_key M;
+ crypto::secret_key_to_public_key(m, M);
+
+ // D = B + M
+ crypto::public_key D;
+ add_public_key(D, keys.m_account_address.m_spend_public_key, M); // could have defined add_public_key() under src/crypto
+ return D;
+ }
+
+ //---------------------------------------------------------------
+ cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index)
+ {
+ if (index.is_zero())
+ return keys.m_account_address;
+
+ crypto::public_key D = get_subaddress_spend_public_key(keys, index);
+
+ // C = a*D
+ crypto::public_key C;
+ secret_key_mult_public_key(C, D, keys.m_view_secret_key); // could have defined secret_key_mult_public_key() under src/crypto
+
+ // result: (C, D)
+ cryptonote::account_public_address address;
+ address.m_view_public_key = C;
+ address.m_spend_public_key = D;
+ return address;
+ }
+
+ //---------------------------------------------------------------
+ bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub)
+ {
+ crypto::public_key pub;
+ bool r = crypto::secret_key_to_public_key(sec, pub);
+ return r && expected_pub == pub;
+ }
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 29e180c41..7bd34ea87 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -37,6 +37,7 @@
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include <unordered_map>
+#include "device/device_declare.hpp"
namespace epee
{
@@ -52,7 +53,9 @@ namespace cryptonote
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx);
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key);
+ bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev);
bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key);
+ bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev);
template<typename T>
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0)
@@ -87,14 +90,17 @@ namespace cryptonote
subaddress_index index;
crypto::key_derivation derivation;
};
- boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index);
+ boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_public_keys, std::vector<size_t>& outs, uint64_t& money_transfered);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
bool get_tx_fee(const transaction& tx, uint64_t & fee);
uint64_t get_tx_fee(const transaction& tx);
crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index);
- bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
- bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki);
+ crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev);
+ std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end);
+ std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev);
+ bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
+ bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
void get_blob_hash(const blobdata& blob, crypto::hash& res);
crypto::hash get_blob_hash(const blobdata& blob);
std::string short_hash_str(const crypto::hash& h);
@@ -237,4 +243,9 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
specific_type& variable_name = boost::get<specific_type>(variant_var);
+ cryptonote::account_public_address get_subaddress(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index);
+ crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index);
+ bool generate_chacha_key_from_secret_keys(const cryptonote::account_keys &keys, crypto::chacha_key &key);
+ bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub);
+
}
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index 1ec601660..ee5ec0596 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -79,7 +79,6 @@ namespace cryptonote
* returns true if no error, false otherwise
*
* @param version the major block version for the fork
- * @param voting_version the minor block version for the fork, used for voting
* @param height The height the hardfork takes effect
* @param time Approximate time of the hardfork (seconds since epoch)
*/
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 6c4ecf58c..7af9b3487 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -198,7 +198,8 @@ namespace cryptonote
{
uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
- std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
+ const auto precision = std::cout.precision();
+ std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << precision << ENDL;
}
}
m_last_hr_merge_time = misc_utils::get_tick_count();
@@ -601,7 +602,7 @@ namespace cryptonote
// this should take care of the case where mining is started with bg-enabled,
// and then the user decides to un-check background mining, and just do
// regular full-speed mining. I might just be over-doing it and thinking up
- // non-existant use-cases, so if the concensus is to simplify, we can remove all this fluff.
+ // non-existant use-cases, so if the consensus is to simplify, we can remove all this fluff.
/*
while( !m_is_background_mining_enabled )
{
@@ -623,21 +624,15 @@ namespace cryptonote
continue; // if interrupted because stop called, loop should end ..
}
- boost::tribool battery_powered(on_battery_power());
- bool on_ac_power = false;
- if(indeterminate( battery_powered ))
+ bool on_ac_power = m_ignore_battery;
+ if(!m_ignore_battery)
{
- // name could be better, only ignores battery requirement if we failed
- // to get the status of the system
- if( m_ignore_battery )
+ boost::tribool battery_powered(on_battery_power());
+ if(!indeterminate( battery_powered ))
{
- on_ac_power = true;
+ on_ac_power = !battery_powered;
}
}
- else
- {
- on_ac_power = !battery_powered;
- }
if( m_is_background_mining_started )
{
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 0ece65028..f9460e7db 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -92,7 +92,7 @@
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading
-#define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day
+#define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000
@@ -138,6 +138,7 @@
#define HASH_OF_HASHES_STEP 256
+#define DEFAULT_TXPOOL_MAX_SIZE 648000000ull // 3 days at 300000, in bytes
// New constants are intended to go here
namespace config
diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt
index d8a21ae31..72844db66 100644
--- a/src/cryptonote_core/CMakeLists.txt
+++ b/src/cryptonote_core/CMakeLists.txt
@@ -61,6 +61,7 @@ target_link_libraries(cryptonote_core
blockchain_db
multisig
ringct
+ device
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 178479f3c..376f9ca5e 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -127,7 +127,8 @@ static const struct {
{ 5, 802660, 0, 1472415036 + 86400*180 }, // add 5 months on testnet to shut the update warning up since there's a large gap to v6
{ 6, 971400, 0, 1501709789 },
- { 7, 1057028, 0, 1512211236 },
+ { 7, 1057027, 0, 1512211236 },
+ { 8, 1057058, 0, 1515967497 },
};
static const uint64_t testnet_hard_fork_version_1_till = 624633;
@@ -2395,11 +2396,11 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
- // from v7, allow bulletproofs
- if (hf_version < 7 || !m_testnet) {
+ // from v8, allow bulletproofs
+ if (hf_version < 8) {
if (!tx.rct_signatures.p.bulletproofs.empty())
{
- MERROR("Bulletproofs are not allowed before v7 or on mainnet");
+ MERROR("Bulletproofs are not allowed before v8");
tvc.m_invalid_output = true;
return false;
}
@@ -2738,7 +2739,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
{
- // check all this, either recontructed (so should really pass), or not
+ // check all this, either reconstructed (so should really pass), or not
{
if (pubkeys.size() != rv.mixRing.size())
{
@@ -2796,7 +2797,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
{
- // check all this, either recontructed (so should really pass), or not
+ // check all this, either reconstructed (so should really pass), or not
{
bool size_matches = true;
for (size_t i = 0; i < pubkeys.size(); ++i)
@@ -3753,6 +3754,10 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::list<c
if (height >= m_blocks_hash_of_hashes.size() * HASH_OF_HASHES_STEP)
return hashes.size();
+ // if we're getting old blocks, we might have jettisoned the hashes already
+ if (m_blocks_hash_check.empty())
+ return hashes.size();
+
// find hashes encompassing those block
size_t first_index = height / HASH_OF_HASHES_STEP;
size_t last_index = (height + hashes.size() - 1) / HASH_OF_HASHES_STEP;
@@ -4343,8 +4348,13 @@ void Blockchain::load_compiled_in_block_hashes()
{
const unsigned char *p = get_blocks_dat_start(m_testnet);
const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24);
+ if (nblocks > (std::numeric_limits<uint32_t>::max() - 4) / sizeof(hash))
+ {
+ MERROR("Block hash data is too large");
+ return;
+ }
const size_t size_needed = 4 + nblocks * sizeof(crypto::hash);
- if(nblocks > 0 && nblocks * HASH_OF_HASHES_STEP > m_db->height() && get_blocks_dat_size(m_testnet) >= size_needed)
+ if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && get_blocks_dat_size(m_testnet) >= size_needed)
{
p += sizeof(uint32_t);
m_blocks_hash_of_hashes.reserve(nblocks);
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 81a7b4724..8b837f2e4 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -66,19 +66,22 @@ DISABLE_VS_WARNINGS(4355)
namespace cryptonote
{
- const command_line::arg_descriptor<std::string> arg_data_dir = {
- "data-dir"
- , "Specify data directory"
- };
- const command_line::arg_descriptor<std::string> arg_testnet_data_dir = {
- "testnet-data-dir"
- , "Specify testnet data directory"
- };
const command_line::arg_descriptor<bool, false> arg_testnet_on = {
"testnet"
, "Run on testnet. The wallet must be launched with --testnet flag."
, false
};
+ const command_line::arg_descriptor<std::string, false, true> arg_data_dir = {
+ "data-dir"
+ , "Specify data directory"
+ , tools::get_default_data_dir()
+ , arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet)
+ return (boost::filesystem::path(val) / "testnet").string();
+ return val;
+ }
+ };
const command_line::arg_descriptor<bool> arg_offline = {
"offline"
, "Do not listen for peers, nor connect to any"
@@ -134,9 +137,19 @@ namespace cryptonote
};
static const command_line::arg_descriptor<bool> arg_fluffy_blocks = {
"fluffy-blocks"
- , "Relay blocks as fluffy blocks where possible (automatic on testnet)"
+ , "Relay blocks as fluffy blocks (obsolete, now default)"
+ , true
+ };
+ static const command_line::arg_descriptor<bool> arg_no_fluffy_blocks = {
+ "no-fluffy-blocks"
+ , "Relay blocks as normal blocks"
, false
};
+ static const command_line::arg_descriptor<size_t> arg_max_txpool_size = {
+ "max-txpool-size"
+ , "Set maximum txpool size in bytes."
+ , DEFAULT_TXPOOL_MAX_SIZE
+ };
//-----------------------------------------------------------------------------------------------
core::core(i_cryptonote_protocol* pprotocol):
@@ -224,8 +237,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------
void core::init_options(boost::program_options::options_description& desc)
{
- command_line::add_arg(desc, arg_data_dir, tools::get_default_data_dir());
- command_line::add_arg(desc, arg_testnet_data_dir, (boost::filesystem::path(tools::get_default_data_dir()) / "testnet").string());
+ command_line::add_arg(desc, arg_data_dir);
command_line::add_arg(desc, arg_test_drop_download);
command_line::add_arg(desc, arg_test_drop_download_height);
@@ -238,9 +250,11 @@ namespace cryptonote
command_line::add_arg(desc, arg_block_sync_size);
command_line::add_arg(desc, arg_check_updates);
command_line::add_arg(desc, arg_fluffy_blocks);
+ command_line::add_arg(desc, arg_no_fluffy_blocks);
command_line::add_arg(desc, arg_test_dbg_lock_sleep);
command_line::add_arg(desc, arg_offline);
command_line::add_arg(desc, arg_disable_dns_checkpoints);
+ command_line::add_arg(desc, arg_max_txpool_size);
miner::init_options(desc);
BlockchainDB::init_options(desc);
@@ -250,8 +264,7 @@ namespace cryptonote
{
m_testnet = command_line::get_arg(vm, arg_testnet_on);
- auto data_dir_arg = m_testnet ? arg_testnet_data_dir : arg_data_dir;
- m_config_folder = command_line::get_arg(vm, data_dir_arg);
+ m_config_folder = command_line::get_arg(vm, arg_data_dir);
auto data_dir = boost::filesystem::path(m_config_folder);
@@ -273,9 +286,11 @@ namespace cryptonote
set_enforce_dns_checkpoints(command_line::get_arg(vm, arg_dns_checkpoints));
test_drop_download_height(command_line::get_arg(vm, arg_test_drop_download_height));
- m_fluffy_blocks_enabled = m_testnet || get_arg(vm, arg_fluffy_blocks);
+ m_fluffy_blocks_enabled = !get_arg(vm, arg_no_fluffy_blocks);
m_offline = get_arg(vm, arg_offline);
m_disable_dns_checkpoints = get_arg(vm, arg_disable_dns_checkpoints);
+ if (!command_line::is_arg_defaulted(vm, arg_fluffy_blocks))
+ MWARNING(arg_fluffy_blocks.name << " is obsolete, it is now default");
if (command_line::get_arg(vm, arg_test_drop_download) == true)
test_drop_download();
@@ -359,6 +374,7 @@ namespace cryptonote
bool fast_sync = command_line::get_arg(vm, arg_fast_block_sync) != 0;
uint64_t blocks_threads = command_line::get_arg(vm, arg_prep_blocks_threads);
std::string check_updates_string = command_line::get_arg(vm, arg_check_updates);
+ size_t max_txpool_size = command_line::get_arg(vm, arg_max_txpool_size);
boost::filesystem::path folder(m_config_folder);
if (m_fakechain)
@@ -477,7 +493,7 @@ namespace cryptonote
r = m_blockchain_storage.init(db.release(), m_testnet, m_offline, test_options);
- r = m_mempool.init();
+ r = m_mempool.init(max_txpool_size);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");
// now that we have a valid m_blockchain_storage, we can clean out any
@@ -1372,7 +1388,7 @@ namespace cryptonote
break;
case HardFork::UpdateNeeded:
MCLOG_RED(level, "global", "**********************************************************************");
- MCLOG_RED(level, "global", "Last scheduled hard fork time shows a daemon update is needed now.");
+ MCLOG_RED(level, "global", "Last scheduled hard fork time shows a daemon update is needed soon.");
MCLOG_RED(level, "global", "**********************************************************************");
break;
default:
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 429f6b820..ce39aaddf 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -58,8 +58,7 @@ namespace cryptonote
const std::pair<uint8_t, uint64_t> *hard_forks;
};
- extern const command_line::arg_descriptor<std::string> arg_data_dir;
- extern const command_line::arg_descriptor<std::string> arg_testnet_data_dir;
+ extern const command_line::arg_descriptor<std::string, false, true> arg_data_dir;
extern const command_line::arg_descriptor<bool, false> arg_testnet_on;
extern const command_line::arg_descriptor<bool> arg_offline;
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 431d71556..d641caf80 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -41,6 +41,7 @@ using namespace epee;
#include "crypto/hash.h"
#include "ringct/rctSigs.h"
#include "multisig/multisig.h"
+#include "device/device.hpp"
using namespace crypto;
@@ -172,24 +173,30 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys)
+ crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr)
{
- if (destinations.empty())
- return null_pkey;
- for (size_t n = 1; n < destinations.size(); ++n)
+ account_public_address addr = {null_pkey, null_pkey};
+ size_t count = 0;
+ for (const auto &i : destinations)
{
- if (!memcmp(&destinations[n].addr, &sender_keys.m_account_address, sizeof(destinations[0].addr)))
+ if (i.amount == 0)
continue;
- if (destinations[n].amount == 0)
+ if (change_addr && i.addr == *change_addr)
continue;
- if (memcmp(&destinations[n].addr, &destinations[0].addr, sizeof(destinations[0].addr)))
+ if (i.addr == addr)
+ continue;
+ if (count > 0)
return null_pkey;
+ addr = i.addr;
+ ++count;
}
- return destinations[0].addr.m_view_public_key;
+ return addr.m_view_public_key;
}
//---------------------------------------------------------------
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
{
+ hw::device &hwdev = sender_account_keys.get_device();
+
if (sources.empty())
{
LOG_ERROR("Empty sources");
@@ -221,14 +228,14 @@ namespace cryptonote
if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
{
LOG_PRINT_L2("Encrypting payment id " << payment_id);
- crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, sender_account_keys);
+ crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, change_addr);
if (view_key_pub == null_pkey)
{
LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids");
return false;
}
- if (!encrypt_payment_id(payment_id, view_key_pub, tx_key))
+ if (!encrypt_payment_id(payment_id, view_key_pub, tx_key, hwdev))
{
LOG_ERROR("Failed to encrypt payment id");
return false;
@@ -276,7 +283,7 @@ namespace cryptonote
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
crypto::key_image img;
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
- if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img))
+ if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev))
{
LOG_ERROR("Key image generation failed!");
return false;
@@ -334,11 +341,11 @@ namespace cryptonote
// if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D
if (num_stdaddresses == 0 && num_subaddresses == 1)
{
- txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key)));
+ txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key), hwdev));
}
else
{
- txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key)));
+ txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key), hwdev));
}
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key));
add_tx_pub_key_to_extra(tx, txkey_pub);
@@ -367,22 +374,22 @@ namespace cryptonote
{
additional_txkey.sec = additional_tx_keys[output_index];
if (dst_entr.is_subaddress)
- additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec)));
+ additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec),hwdev));
else
- additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec)));
+ additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec), hwdev));
}
bool r;
if (change_addr && dst_entr.addr == *change_addr)
{
// sending change to yourself; derivation = a*R
- r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation);
+ r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation, hwdev);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
}
else
{
// sending to the recipient; derivation = r*A (or s*C in the subaddress scheme)
- r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation);
+ r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation, hwdev);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")");
}
@@ -394,12 +401,14 @@ namespace cryptonote
if (tx.version > 1)
{
crypto::secret_key scalar1;
- crypto::derivation_to_scalar(derivation, output_index, scalar1);
+ crypto::derivation_to_scalar(derivation, output_index, scalar1, hwdev);
amount_keys.push_back(rct::sk2rct(scalar1));
}
- r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key);
+ r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key, hwdev);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")");
+ hwdev.add_output_key_mapping(dst_entr.addr.m_view_public_key, dst_entr.addr.m_spend_public_key, output_index, amount_keys.back(), out_eph_public_key);
+
tx_out out;
out.amount = dst_entr.amount;
txout_to_key tk;
@@ -575,9 +584,9 @@ namespace cryptonote
get_transaction_prefix_hash(tx, tx_prefix_hash);
rct::ctkeyV outSk;
if (use_simple_rct)
- tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof);
+ tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof, hwdev);
else
- tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof); // same index assumption
+ tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof, hwdev); // same index assumption
CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout");
@@ -591,8 +600,8 @@ namespace cryptonote
//---------------------------------------------------------------
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout)
{
- keypair txkey = keypair::generate();
- tx_key = txkey.sec;
+ hw::device &hwdev = sender_account_keys.get_device();
+ hwdev.open_tx(tx_key);
// figure out if we need to make additional tx pubkeys
size_t num_stdaddresses = 0;
@@ -604,10 +613,12 @@ namespace cryptonote
{
additional_tx_keys.clear();
for (const auto &d: destinations)
- additional_tx_keys.push_back(keypair::generate().sec);
+ additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec);
}
- return construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout);
+ bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout);
+ hwdev.close_tx();
+ return r;
}
//---------------------------------------------------------------
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time)
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index e3b7a4f8c..1c390078d 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -88,7 +88,7 @@ namespace cryptonote
};
//---------------------------------------------------------------
- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
+ crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL);
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index e75584bce..762feb5ee 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -102,7 +102,7 @@ namespace cryptonote
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
- tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs)
+ tx_memory_pool::tx_memory_pool(Blockchain& bchs): m_blockchain(bchs), m_txpool_max_size(DEFAULT_TXPOOL_MAX_SIZE), m_txpool_size(0)
{
}
@@ -151,13 +151,20 @@ namespace cryptonote
}
uint64_t outputs_amount = get_outs_money_amount(tx);
- if(outputs_amount >= inputs_amount)
+ if(outputs_amount > inputs_amount)
{
LOG_PRINT_L1("transaction use more money then it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount));
tvc.m_verifivation_failed = true;
tvc.m_overspend = true;
return false;
}
+ else if(outputs_amount == inputs_amount)
+ {
+ LOG_PRINT_L1("transaction fee is zero: outputs_amount == inputs_amount, rejecting.");
+ tvc.m_verifivation_failed = true;
+ tvc.m_fee_too_low = true;
+ return false;
+ }
fee = inputs_amount - outputs_amount;
}
@@ -174,7 +181,7 @@ namespace cryptonote
}
size_t tx_size_limit = get_transaction_size_limit(version);
- if (!kept_by_block && blob_size >= tx_size_limit)
+ if (!kept_by_block && blob_size > tx_size_limit)
{
LOG_PRINT_L1("transaction is too big: " << blob_size << " bytes, maximum size: " << tx_size_limit);
tvc.m_verifivation_failed = true;
@@ -295,8 +302,12 @@ namespace cryptonote
}
tvc.m_verifivation_failed = false;
+ m_txpool_size += blob_size;
MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size));
+
+ prune(m_txpool_max_size);
+
return true;
}
//---------------------------------------------------------------------------------
@@ -309,6 +320,72 @@ namespace cryptonote
return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
}
//---------------------------------------------------------------------------------
+ size_t tx_memory_pool::get_txpool_size() const
+ {
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ return m_txpool_size;
+ }
+ //---------------------------------------------------------------------------------
+ void tx_memory_pool::set_txpool_max_size(size_t bytes)
+ {
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ m_txpool_max_size = bytes;
+ }
+ //---------------------------------------------------------------------------------
+ void tx_memory_pool::prune(size_t bytes)
+ {
+ CRITICAL_REGION_LOCAL(m_transactions_lock);
+ if (bytes == 0)
+ bytes = m_txpool_max_size;
+ CRITICAL_REGION_LOCAL1(m_blockchain);
+ LockedTXN lock(m_blockchain);
+
+ // this will never remove the first one, but we don't care
+ auto it = --m_txs_by_fee_and_receive_time.end();
+ while (it != m_txs_by_fee_and_receive_time.begin())
+ {
+ if (m_txpool_size <= bytes)
+ break;
+ try
+ {
+ const crypto::hash &txid = it->second;
+ txpool_tx_meta_t meta;
+ if (!m_blockchain.get_txpool_tx_meta(txid, meta))
+ {
+ MERROR("Failed to find tx in txpool");
+ return;
+ }
+ // don't prune the kept_by_block ones, they're likely added because we're adding a block with those
+ if (meta.kept_by_block)
+ {
+ --it;
+ continue;
+ }
+ cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid);
+ cryptonote::transaction tx;
+ if (!parse_and_validate_tx_from_blob(txblob, tx))
+ {
+ MERROR("Failed to parse tx from txpool");
+ return;
+ }
+ // remove first, in case this throws, so key images aren't removed
+ MINFO("Pruning tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first);
+ m_blockchain.remove_txpool_tx(txid);
+ m_txpool_size -= txblob.size();
+ remove_transaction_keyimages(tx);
+ MINFO("Pruned tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first);
+ m_txs_by_fee_and_receive_time.erase(it--);
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Error while pruning txpool: " << e.what());
+ return;
+ }
+ }
+ if (m_txpool_size > bytes)
+ MINFO("Pool size after pruning is larger than limit: " << m_txpool_size << "/" << bytes);
+ }
+ //---------------------------------------------------------------------------------
bool tx_memory_pool::insert_key_images(const transaction &tx, bool kept_by_block)
{
for(const auto& in: tx.vin)
@@ -391,6 +468,7 @@ namespace cryptonote
// remove first, in case this throws, so key images aren't removed
m_blockchain.remove_txpool_tx(id);
+ m_txpool_size -= blob_size;
remove_transaction_keyimages(tx);
}
catch (const std::exception &e)
@@ -463,6 +541,7 @@ namespace cryptonote
{
// remove first, so we only remove key images if the tx removal succeeds
m_blockchain.remove_txpool_tx(txid);
+ m_txpool_size -= bd.size();
remove_transaction_keyimages(tx);
}
}
@@ -1125,8 +1204,10 @@ namespace cryptonote
size_t tx_size_limit = get_transaction_size_limit(version);
std::unordered_set<crypto::hash> remove;
+ m_txpool_size = 0;
m_blockchain.for_all_txpool_txes([this, &remove, tx_size_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
- if (meta.blob_size >= tx_size_limit) {
+ m_txpool_size += meta.blob_size;
+ if (meta.blob_size > tx_size_limit) {
LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.blob_size << " bytes), removing it from pool");
remove.insert(txid);
}
@@ -1154,6 +1235,7 @@ namespace cryptonote
}
// remove tx from db first
m_blockchain.remove_txpool_tx(txid);
+ m_txpool_size -= txblob.size();
remove_transaction_keyimages(tx);
auto sorted_it = find_tx_in_sorted_container(txid);
if (sorted_it == m_txs_by_fee_and_receive_time.end())
@@ -1176,13 +1258,15 @@ namespace cryptonote
return n_removed;
}
//---------------------------------------------------------------------------------
- bool tx_memory_pool::init()
+ bool tx_memory_pool::init(size_t max_txpool_size)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
+ m_txpool_max_size = max_txpool_size ? max_txpool_size : DEFAULT_TXPOOL_MAX_SIZE;
m_txs_by_fee_and_receive_time.clear();
m_spent_key_images.clear();
+ m_txpool_size = 0;
std::vector<crypto::hash> remove;
bool r = m_blockchain.for_all_txpool_txes([this, &remove](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd) {
cryptonote::transaction tx;
@@ -1197,6 +1281,7 @@ namespace cryptonote
return false;
}
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.blob_size, meta.receive_time), txid);
+ m_txpool_size += meta.blob_size;
return true;
}, true);
if (!r)
diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h
index b4ea5a8f4..19cd83ed9 100644
--- a/src/cryptonote_core/tx_pool.h
+++ b/src/cryptonote_core/tx_pool.h
@@ -198,11 +198,11 @@ namespace cryptonote
/**
* @brief loads pool state (if any) from disk, and initializes pool
*
- * @param config_folder folder name where pool state will be
+ * @param max_txpool_size the max size in bytes
*
* @return true
*/
- bool init();
+ bool init(size_t max_txpool_size = 0);
/**
* @brief attempts to save the transaction pool state to disk
@@ -362,6 +362,19 @@ namespace cryptonote
*/
size_t validate(uint8_t version);
+ /**
+ * @brief get the cumulative txpool size in bytes
+ *
+ * @return the cumulative txpool size in bytes
+ */
+ size_t get_txpool_size() const;
+
+ /**
+ * @brief set the max cumulative txpool size in bytes
+ *
+ * @param bytes the max cumulative txpool size in bytes
+ */
+ void set_txpool_max_size(size_t bytes);
#define CURRENT_MEMPOOL_ARCHIVE_VER 11
#define CURRENT_MEMPOOL_TX_DETAILS_ARCHIVE_VER 12
@@ -496,6 +509,13 @@ namespace cryptonote
*/
void mark_double_spend(const transaction &tx);
+ /**
+ * @brief prune lowest fee/byte txes till we're not above bytes
+ *
+ * if bytes is 0, use m_txpool_max_size
+ */
+ void prune(size_t bytes = 0);
+
//TODO: confirm the below comments and investigate whether or not this
// is the desired behavior
//! map key images to transactions which spent them
@@ -542,6 +562,9 @@ private:
std::unordered_set<crypto::hash> m_timed_out_transactions;
Blockchain& m_blockchain; //!< reference to the Blockchain object
+
+ size_t m_txpool_max_size;
+ size_t m_txpool_size;
};
}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index cbb8273e9..d7b74c06d 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -1,6 +1,6 @@
/// @file
/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
-/// @brief This is the orginal cryptonote protocol network-events handler, modified by us
+/// @brief This is the original cryptonote protocol network-events handler, modified by us
// Copyright (c) 2014-2018, The Monero Project
//
@@ -79,7 +79,7 @@ namespace cryptonote
typedef t_cryptonote_protocol_handler<t_core> cryptonote_protocol_handler;
typedef CORE_SYNC_DATA payload_type;
- t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout);
+ t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout, bool offline = false);
BEGIN_INVOKE_MAP2(cryptonote_protocol_handler)
HANDLE_NOTIFY_T2(NOTIFY_NEW_BLOCK, &cryptonote_protocol_handler::handle_notify_new_block)
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index bc11ab6e4..14c3fb298 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1,6 +1,6 @@
/// @file
/// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote)
-/// @brief This is the orginal cryptonote protocol network-events handler, modified by us
+/// @brief This is the original cryptonote protocol network-events handler, modified by us
// Copyright (c) 2014-2018, The Monero Project
//
@@ -61,10 +61,10 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------------------------
template<class t_core>
- t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout):m_core(rcore),
+ t_cryptonote_protocol_handler<t_core>::t_cryptonote_protocol_handler(t_core& rcore, nodetool::i_p2p_endpoint<connection_context>* p_net_layout, bool offline):m_core(rcore),
m_p2p(p_net_layout),
m_syncronized_connections_count(0),
- m_synchronized(false),
+ m_synchronized(offline),
m_stopping(false)
{
@@ -1333,6 +1333,15 @@ skip:
break;
}
+ // this one triggers if all threads are in standby, which should not happen,
+ // but happened at least once, so we unblock at least one thread if so
+ const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
+ if (sync.owns_lock())
+ {
+ LOG_DEBUG_CC(context, "No other thread is adding blocks, resuming");
+ break;
+ }
+
if (should_download_next_span(context))
{
MDEBUG(context << " we should try for that next span too, we think we could get it faster, resuming");
diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h
index ee6167b6a..efbae488c 100644
--- a/src/daemon/command_line_args.h
+++ b/src/daemon/command_line_args.h
@@ -31,20 +31,35 @@
#include "common/command_line.h"
#include "cryptonote_config.h"
+#include "daemonizer/daemonizer.h"
namespace daemon_args
{
std::string const WINDOWS_SERVICE_NAME = "Monero Daemon";
- const command_line::arg_descriptor<std::string> arg_config_file = {
+ const command_line::arg_descriptor<std::string, false, true> arg_config_file = {
"config-file"
, "Specify configuration file"
- , std::string(CRYPTONOTE_NAME ".conf")
+ , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".conf")).string()
+ , cryptonote::arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet && defaulted)
+ return (daemonizer::get_default_data_dir() / "testnet" /
+ std::string(CRYPTONOTE_NAME ".conf")).string();
+ return val;
+ }
};
- const command_line::arg_descriptor<std::string> arg_log_file = {
+ const command_line::arg_descriptor<std::string, false, true> arg_log_file = {
"log-file"
, "Specify log file"
- , ""
+ , (daemonizer::get_default_data_dir() / std::string(CRYPTONOTE_NAME ".log")).string()
+ , cryptonote::arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet && defaulted)
+ return (daemonizer::get_default_data_dir() / "testnet" /
+ std::string(CRYPTONOTE_NAME ".log")).string();
+ return val;
+ }
};
const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = {
"max-log-file-size"
@@ -76,16 +91,16 @@ namespace daemon_args
, "127.0.0.1"
};
- const command_line::arg_descriptor<std::string> arg_zmq_rpc_bind_port = {
+ const command_line::arg_descriptor<std::string, false, true> arg_zmq_rpc_bind_port = {
"zmq-rpc-bind-port"
- , "Port for ZMQ RPC server to listen on"
- , std::to_string(config::ZMQ_RPC_DEFAULT_PORT)
- };
-
- const command_line::arg_descriptor<std::string> arg_zmq_testnet_rpc_bind_port = {
- "zmq-testnet-rpc-bind-port"
- , "Port for testnet ZMQ RPC server to listen on"
- , std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT)
+ , "Port for ZMQ RPC server to listen on"
+ , std::to_string(config::ZMQ_RPC_DEFAULT_PORT)
+ , cryptonote::arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet && defaulted)
+ return std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT);
+ return val;
+ }
};
} // namespace daemon_args
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 3ec74ff79..09e425dd1 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -428,6 +428,23 @@ bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
return m_executor.out_peers(limit);
}
+bool t_command_parser_executor::in_peers(const std::vector<std::string>& args)
+{
+ if (args.empty()) return false;
+
+ unsigned int limit;
+ try {
+ limit = std::stoi(args[0]);
+ }
+
+ catch(const std::exception& ex) {
+ _erro("stoi exception");
+ return false;
+ }
+
+ return m_executor.in_peers(limit);
+}
+
bool t_command_parser_executor::start_save_graph(const std::vector<std::string>& args)
{
if (!args.empty()) return false;
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index 37e900b8f..2c09a4748 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -108,7 +108,9 @@ public:
bool set_limit_down(const std::vector<std::string>& args);
bool out_peers(const std::vector<std::string>& args);
-
+
+ bool in_peers(const std::vector<std::string>& args);
+
bool start_save_graph(const std::vector<std::string>& args);
bool stop_save_graph(const std::vector<std::string>& args);
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 1f8981fa2..a50dbea69 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -197,6 +197,12 @@ t_command_server::t_command_server(
, "Set the <max_number> of out peers."
);
m_command_lookup.set_handler(
+ "in_peers"
+ , std::bind(&t_command_parser_executor::in_peers, &m_parser, p::_1)
+ , "in_peers <max_number>"
+ , "Set the <max_number> of in peers."
+ );
+ m_command_lookup.set_handler(
"start_save_graph"
, std::bind(&t_command_parser_executor::start_save_graph, &m_parser, p::_1)
, "Start saving data for dr monero."
diff --git a/src/daemon/core.h b/src/daemon/core.h
index f00dffccc..1ff696bef 100644
--- a/src/daemon/core.h
+++ b/src/daemon/core.h
@@ -69,8 +69,7 @@ public:
std::string get_config_subdir() const
{
bool testnet = command_line::get_arg(m_vm_HACK, cryptonote::arg_testnet_on);
- auto p2p_bind_arg = testnet ? nodetool::arg_testnet_p2p_bind_port : nodetool::arg_p2p_bind_port;
- std::string port = command_line::get_arg(m_vm_HACK, p2p_bind_arg);
+ std::string port = command_line::get_arg(m_vm_HACK, nodetool::arg_p2p_bind_port);
if ((!testnet && port != std::to_string(::config::P2P_DEFAULT_PORT))
|| (testnet && port != std::to_string(::config::testnet::P2P_DEFAULT_PORT))) {
return port;
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index 2d662b7d3..8053932fe 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -68,7 +68,7 @@ public:
boost::program_options::variables_map const & vm
)
: core{vm}
- , protocol{vm, core}
+ , protocol{vm, core, command_line::get_arg(vm, cryptonote::arg_offline)}
, p2p{vm, protocol}
{
// Handle circular dependencies
@@ -77,10 +77,10 @@ public:
const auto testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc);
- const auto main_rpc_port = command_line::get_arg(vm, testnet ? cryptonote::core_rpc_server::arg_testnet_rpc_bind_port : cryptonote::core_rpc_server::arg_rpc_bind_port);
+ const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port);
rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet, main_rpc_port, "core"});
- auto restricted_rpc_port_arg = testnet ? cryptonote::core_rpc_server::arg_testnet_rpc_restricted_bind_port : cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
+ auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port;
if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg))
{
auto restricted_rpc_port = command_line::get_arg(vm, restricted_rpc_port_arg);
@@ -101,15 +101,7 @@ t_daemon::t_daemon(
)
: mp_internals{new t_internals{vm}}
{
- bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
- if (testnet)
- {
- zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_testnet_rpc_bind_port);
- }
- else
- {
- zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_port);
- }
+ zmq_rpc_bind_port = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_port);
zmq_rpc_bind_address = command_line::get_arg(vm, daemon_args::arg_zmq_rpc_bind_ip);
}
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index f4d8fad5e..752a92ba4 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -73,26 +73,20 @@ int main(int argc, char const * argv[])
po::options_description core_settings("Settings");
po::positional_options_description positional_options;
{
- bf::path default_data_dir = daemonizer::get_default_data_dir();
- bf::path default_testnet_data_dir = {default_data_dir / "testnet"};
-
// Misc Options
command_line::add_arg(visible_options, command_line::arg_help);
command_line::add_arg(visible_options, command_line::arg_version);
command_line::add_arg(visible_options, daemon_args::arg_os_version);
- bf::path default_conf = default_data_dir / std::string(CRYPTONOTE_NAME ".conf");
- command_line::add_arg(visible_options, daemon_args::arg_config_file, default_conf.string());
+ command_line::add_arg(visible_options, daemon_args::arg_config_file);
// Settings
- bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log");
- command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string());
+ command_line::add_arg(core_settings, daemon_args::arg_log_file);
command_line::add_arg(core_settings, daemon_args::arg_log_level);
command_line::add_arg(core_settings, daemon_args::arg_max_log_file_size);
command_line::add_arg(core_settings, daemon_args::arg_max_concurrency);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
- command_line::add_arg(core_settings, daemon_args::arg_zmq_testnet_rpc_bind_port);
daemonizer::init_options(hidden_options, visible_options);
daemonize::t_executor::init_options(core_settings);
@@ -154,10 +148,6 @@ int main(int argc, char const * argv[])
return 0;
}
- bool testnet_mode = command_line::get_arg(vm, cryptonote::arg_testnet_on);
-
- auto data_dir_arg = testnet_mode ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir;
-
// data_dir
// default: e.g. ~/.bitmonero/ or ~/.bitmonero/testnet
// if data-dir argument given:
@@ -166,7 +156,7 @@ int main(int argc, char const * argv[])
// Create data dir if it doesn't exist
boost::filesystem::path data_dir = boost::filesystem::absolute(
- command_line::get_arg(vm, data_dir_arg));
+ command_line::get_arg(vm, cryptonote::arg_data_dir));
// FIXME: not sure on windows implementation default, needs further review
//bf::path relative_path_base = daemonizer::get_relative_path_base(vm);
@@ -226,10 +216,6 @@ int main(int argc, char const * argv[])
const cryptonote::rpc_args::descriptors arg{};
auto rpc_ip_str = command_line::get_arg(vm, arg.rpc_bind_ip);
auto rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port);
- if (testnet_mode)
- {
- rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_testnet_rpc_bind_port);
- }
uint32_t rpc_ip;
uint16_t rpc_port;
@@ -287,7 +273,7 @@ int main(int argc, char const * argv[])
MINFO("Moving from main() into the daemonize now.");
- return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm);
+ return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm) ? 0 : 1;
}
catch (std::exception const & ex)
{
diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h
index a251ae47c..fd1d1b638 100644
--- a/src/daemon/protocol.h
+++ b/src/daemon/protocol.h
@@ -46,9 +46,9 @@ private:
public:
t_protocol(
boost::program_options::variables_map const & vm
- , t_core & core
+ , t_core & core, bool offline = false
)
- : m_protocol{core.get(), nullptr}
+ : m_protocol{core.get(), nullptr, offline}
{
MGINFO("Initializing cryptonote protocol...");
if (!m_protocol.init(vm))
diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h
index c1c2329ac..17f6c7f67 100644
--- a/src/daemon/rpc.h
+++ b/src/daemon/rpc.h
@@ -60,28 +60,28 @@ public:
)
: m_server{core.get(), p2p.get()}, m_description{description}
{
- MGINFO("Initializing " << m_description << " rpc server...");
+ MGINFO("Initializing " << m_description << " RPC server...");
if (!m_server.init(vm, restricted, testnet, port))
{
- throw std::runtime_error("Failed to initialize " + m_description + " rpc server.");
+ throw std::runtime_error("Failed to initialize " + m_description + " RPC server.");
}
- MGINFO(m_description << " rpc server initialized OK on port: " << m_server.get_binded_port());
+ MGINFO(m_description << " RPC server initialized OK on port: " << m_server.get_binded_port());
}
void run()
{
- MGINFO("Starting " << m_description << " rpc server...");
+ MGINFO("Starting " << m_description << " RPC server...");
if (!m_server.run(2, false))
{
- throw std::runtime_error("Failed to start " + m_description + " rpc server.");
+ throw std::runtime_error("Failed to start " + m_description + " RPC server.");
}
- MGINFO(m_description << " rpc server started ok");
+ MGINFO(m_description << " RPC server started ok");
}
void stop()
{
- MGINFO("Stopping " << m_description << " rpc server...");
+ MGINFO("Stopping " << m_description << " RPC server...");
m_server.send_stop_signal();
m_server.timed_wait_server_stop(5000);
}
@@ -93,11 +93,11 @@ public:
~t_rpc()
{
- MGINFO("Deinitializing " << m_description << " rpc server...");
+ MGINFO("Deinitializing " << m_description << " RPC server...");
try {
m_server.deinit();
} catch (...) {
- MERROR("Failed to deinitialize " << m_description << " rpc server...");
+ MERROR("Failed to deinitialize " << m_description << " RPC server...");
}
}
};
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 2da4f3e6e..5ef799d40 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -353,15 +353,18 @@ static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_
return "";
}
-static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
+static float get_sync_percentage(uint64_t height, uint64_t target_height)
{
- uint64_t height = ires.height;
- uint64_t target_height = ires.target_height ? ires.target_height < ires.height ? ires.height : ires.target_height : ires.height;
+ target_height = target_height ? target_height < height ? height : target_height : height;
float pc = 100.0f * height / target_height;
if (height < target_height && pc > 99.9f)
return 99.9f; // to avoid 100% when not fully synced
return pc;
}
+static float get_sync_percentage(const cryptonote::COMMAND_RPC_GET_INFO::response &ires)
+{
+ return get_sync_percentage(ires.height, ires.target_height);
+}
bool t_rpc_command_executor::show_status() {
cryptonote::COMMAND_RPC_GET_INFO::request ireq;
@@ -421,12 +424,26 @@ bool t_rpc_command_executor::show_status() {
std::time_t uptime = std::time(nullptr) - ires.start_time;
uint64_t net_height = ires.target_height > ires.height ? ires.target_height : ires.height;
+ std::string bootstrap_msg;
+ if (ires.was_bootstrap_ever_used)
+ {
+ bootstrap_msg = ", bootstrapping from " + ires.bootstrap_daemon_address;
+ if (ires.untrusted)
+ {
+ bootstrap_msg += (boost::format(", local height: %llu (%.1f%%)") % ires.height_without_bootstrap % get_sync_percentage(ires.height_without_bootstrap, net_height)).str();
+ }
+ else
+ {
+ bootstrap_msg += " was used before";
+ }
+ }
- tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
+ tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
% (ires.testnet ? "testnet" : "mainnet")
+ % bootstrap_msg
% (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed) ) : "not mining")
% get_mining_speed(ires.difficulty / ires.target)
% (unsigned)hfres.version
@@ -1262,7 +1279,7 @@ bool t_rpc_command_executor::out_peers(uint64_t limit)
if (m_is_rpc)
{
- if (!m_rpc_client->json_rpc_request(req, res, "out_peers", fail_message.c_str()))
+ if (!m_rpc_client->rpc_request(req, res, "/out_peers", fail_message.c_str()))
{
return true;
}
@@ -1281,6 +1298,38 @@ bool t_rpc_command_executor::out_peers(uint64_t limit)
return true;
}
+bool t_rpc_command_executor::in_peers(uint64_t limit)
+{
+ cryptonote::COMMAND_RPC_IN_PEERS::request req;
+ cryptonote::COMMAND_RPC_IN_PEERS::response res;
+
+ epee::json_rpc::error error_resp;
+
+ req.in_peers = limit;
+
+ std::string fail_message = "Unsuccessful";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/in_peers", fail_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_in_peers(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ std::cout << "Max number of in peers set to " << limit << std::endl;
+
+ return true;
+}
+
bool t_rpc_command_executor::start_save_graph()
{
cryptonote::COMMAND_RPC_START_SAVE_GRAPH::request req;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index f0781180a..fa83d8988 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -122,7 +122,9 @@ public:
bool set_limit(int64_t limit_down, int64_t limit_up);
bool out_peers(uint64_t limit);
-
+
+ bool in_peers(uint64_t limit);
+
bool start_save_graph();
bool stop_save_graph();
diff --git a/src/debug_utilities/cn_deserialize.cpp b/src/debug_utilities/cn_deserialize.cpp
index 4f274a66e..dfbd3b864 100644
--- a/src/debug_utilities/cn_deserialize.cpp
+++ b/src/debug_utilities/cn_deserialize.cpp
@@ -41,6 +41,22 @@ using namespace epee;
using namespace cryptonote;
+static void print_extra_fields(const std::vector<cryptonote::tx_extra_field> &fields)
+{
+ std::cout << "tx_extra has " << fields.size() << " field(s)" << std::endl;
+ for (size_t n = 0; n < fields.size(); ++n)
+ {
+ std::cout << "field " << n << ": ";
+ if (typeid(cryptonote::tx_extra_padding) == fields[n].type()) std::cout << "extra padding: " << boost::get<cryptonote::tx_extra_padding>(fields[n]).size << " bytes";
+ else if (typeid(cryptonote::tx_extra_pub_key) == fields[n].type()) std::cout << "extra pub key: " << boost::get<cryptonote::tx_extra_pub_key>(fields[n]).pub_key;
+ else if (typeid(cryptonote::tx_extra_nonce) == fields[n].type()) std::cout << "extra nonce: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_nonce>(fields[n]).nonce);
+ else if (typeid(cryptonote::tx_extra_merge_mining_tag) == fields[n].type()) std::cout << "extra merge mining tag: depth " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).depth << ", merkle root " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).merkle_root;
+ else if (typeid(cryptonote::tx_extra_mysterious_minergate) == fields[n].type()) std::cout << "extra minergate custom: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_mysterious_minergate>(fields[n]).data);
+ else std::cout << "unknown";
+ std::cout << std::endl;
+ }
+}
+
int main(int argc, char* argv[])
{
uint32_t log_level = 0;
@@ -160,24 +176,18 @@ int main(int argc, char* argv[])
if (!fields.empty())
{
- std::cout << "tx_extra has " << fields.size() << " field(s)" << std::endl;
- for (size_t n = 0; n < fields.size(); ++n)
- {
- std::cout << "field " << n << ": ";
- if (typeid(cryptonote::tx_extra_padding) == fields[n].type()) std::cout << "extra padding: " << boost::get<cryptonote::tx_extra_padding>(fields[n]).size << " bytes";
- else if (typeid(cryptonote::tx_extra_pub_key) == fields[n].type()) std::cout << "extra pub key: " << boost::get<cryptonote::tx_extra_pub_key>(fields[n]).pub_key;
- else if (typeid(cryptonote::tx_extra_nonce) == fields[n].type()) std::cout << "extra nonce: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_nonce>(fields[n]).nonce);
- else if (typeid(cryptonote::tx_extra_merge_mining_tag) == fields[n].type()) std::cout << "extra merge mining tag: depth " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).depth << ", merkle root " << boost::get<cryptonote::tx_extra_merge_mining_tag>(fields[n]).merkle_root;
- else if (typeid(cryptonote::tx_extra_mysterious_minergate) == fields[n].type()) std::cout << "extra minergate custom: " << epee::string_tools::buff_to_hex_nodelimer(boost::get<cryptonote::tx_extra_mysterious_minergate>(fields[n]).data);
- else std::cout << "unknown";
- std::cout << std::endl;
- }
+ print_extra_fields(fields);
}
else
{
std::cout << "No fields were found in tx_extra" << std::endl;
}
}
+ else if (cryptonote::parse_tx_extra(std::vector<uint8_t>(blob.begin(), blob.end()), fields) && !fields.empty())
+ {
+ std::cout << "Parsed tx_extra:" << std::endl;
+ print_extra_fields(fields);
+ }
else
{
std::cerr << "Not a recognized CN type" << std::endl;
diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt
new file mode 100644
index 000000000..26389220f
--- /dev/null
+++ b/src/device/CMakeLists.txt
@@ -0,0 +1,77 @@
+# Copyright (c) 2014-2017, 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(device_sources
+ device.cpp
+ device_default.cpp
+ log.cpp
+ )
+
+if(PCSC_FOUND)
+ set(device_sources ${device_sources} device_ledger.cpp)
+endif()
+
+set(device_headers
+ device_declare.hpp
+ device.hpp
+ device_default.hpp
+ log.hpp
+ )
+
+if(PCSC_FOUND)
+ set(device_headers ${device_headers} device_ledger.hpp)
+endif()
+
+set(device_private_headers)
+
+
+if(PER_BLOCK_CHECKPOINT)
+ set(Blocks "blocks")
+else()
+ set(Blocks "")
+endif()
+
+monero_private_headers(device
+ ${device_private_headers})
+
+monero_add_library(device
+ ${device_sources}
+ ${device_headers}
+ ${device_private_headers})
+
+target_link_libraries(device
+ PUBLIC
+ ${PCSC_LIBRARIES}
+ cncrypto
+ ringct
+ ${OPENSSL_CRYPTO_LIBRARIES}
+ ${GNU_READLINE_LIBRARY}
+ ${EPEE_READLINE}
+ PRIVATE
+ ${Blocks}
+ ${EXTRA_LIBRARIES})
diff --git a/src/device/device.cpp b/src/device/device.cpp
new file mode 100644
index 000000000..080d83c7e
--- /dev/null
+++ b/src/device/device.cpp
@@ -0,0 +1,71 @@
+// Copyright (c) 2017-2018, 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.
+//
+
+#include "device.hpp"
+#include "device_default.hpp"
+#ifdef HAVE_PCSC
+#include "device_ledger.hpp"
+#endif
+#include "common/scoped_message_writer.h"
+
+
+namespace hw {
+
+ /* ======================================================================= */
+ /* SETUP */
+ /* ======================================================================= */
+ device& get_device(const std::string device_descriptor) {
+
+ struct s_devices {
+ std::map<std::string, std::unique_ptr<device>> registry;
+ s_devices() : registry() {
+ hw::core::register_all(registry);
+ #ifdef HAVE_PCSC
+ hw::ledger::register_all(registry);
+ #endif
+ };
+ };
+
+ static const s_devices devices;
+
+ auto device = devices.registry.find(device_descriptor);
+ if (device == devices.registry.end()) {
+ auto logger = tools::fail_msg_writer();
+ logger << "device not found in registry '"<<device_descriptor<<"'\n" <<
+ "known devices:"<<device_descriptor<<"'";
+
+ for( const auto& sm_pair : devices.registry ) {
+ logger<< " - " << sm_pair.first ;
+ }
+ throw std::runtime_error("device not found: "+ device_descriptor);
+ }
+ return *device->second;
+ }
+
+} \ No newline at end of file
diff --git a/src/device/device.hpp b/src/device/device.hpp
new file mode 100644
index 000000000..bdea7b8f6
--- /dev/null
+++ b/src/device/device.hpp
@@ -0,0 +1,146 @@
+// Copyright (c) 2017-2018, 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 "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/account.h"
+#include "cryptonote_basic/subaddress_index.h"
+
+#ifndef USE_DEVICE_LEDGER
+#define USE_DEVICE_LEDGER 1
+#endif
+
+#if !defined(HAVE_PCSC)
+#undef USE_DEVICE_LEDGER
+#define USE_DEVICE_LEDGER 0
+#endif
+
+#if USE_DEVICE_LEDGER
+#define WITH_DEVICE_LEDGER
+#endif
+
+namespace hw {
+ namespace {
+ //device funcion not supported
+ #define dfns() \
+ throw std::runtime_error(std::string("device function not supported: ")+ std::string(__FUNCTION__) + \
+ std::string(" (device.hpp line ")+std::to_string(__LINE__)+std::string(").")); \
+ return false;
+ }
+
+
+ class device {
+ public:
+
+ device() {}
+ device(const device &hwdev) {}
+ virtual ~device() {}
+
+ explicit virtual operator bool() const = 0;
+
+ static const int SIGNATURE_REAL = 0;
+ static const int SIGNATURE_FAKE = 1;
+
+
+ std::string name;
+
+ /* ======================================================================= */
+ /* SETUP/TEARDOWN */
+ /* ======================================================================= */
+ virtual bool set_name(const std::string &name) = 0;
+ virtual const std::string get_name() const = 0;
+
+ virtual bool init(void) = 0;
+ virtual bool release() = 0;
+
+ virtual bool connect(void) = 0;
+ virtual bool disconnect() = 0;
+
+ /* ======================================================================= */
+ /* WALLET & ADDRESS */
+ /* ======================================================================= */
+ virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0;
+ virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0;
+ virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0;
+
+ /* ======================================================================= */
+ /* SUB ADDRESS */
+ /* ======================================================================= */
+ virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) = 0;
+ virtual bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) = 0;
+ virtual bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) = 0;
+ virtual bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) = 0;
+ virtual bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) = 0;
+
+ /* ======================================================================= */
+ /* DERIVATION & KEY */
+ /* ======================================================================= */
+ virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) = 0;
+ virtual bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) = 0;
+ virtual bool scalarmultBase(rct::key &aG, const rct::key &a) = 0;
+ virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0;
+ virtual bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) = 0;
+ virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0;
+ virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0;
+ virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0;
+ virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0;
+ virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) = 0;
+ virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) = 0;
+
+ /* ======================================================================= */
+ /* TRANSACTION */
+ /* ======================================================================= */
+
+ virtual bool open_tx(crypto::secret_key &tx_key) = 0;
+
+ virtual bool set_signature_mode(unsigned int sig_mode) = 0;
+
+ virtual bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) = 0;
+
+ virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) = 0;
+ virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) = 0;
+
+ virtual bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index,
+ const rct::key &amount_key, const crypto::public_key &out_eph_public_key) = 0;
+
+
+ virtual bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) = 0;
+ virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) = 0;
+ virtual bool mlsag_prepare(rct::key &a, rct::key &aG) = 0;
+ virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c) = 0;
+ virtual bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) = 0;
+
+ virtual bool close_tx(void) = 0;
+ } ;
+
+ device& get_device(const std::string device_descriptor) ;
+}
+
diff --git a/src/device/device_declare.hpp b/src/device/device_declare.hpp
new file mode 100644
index 000000000..799052ad2
--- /dev/null
+++ b/src/device/device_declare.hpp
@@ -0,0 +1,42 @@
+// Copyright (c) 2017-2018, 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
+
+
+//#define DEBUG_HWDEVICE
+//#define IODUMMYCRYPT 1
+//#define IONOCRYPT 1
+
+namespace hw {
+ class device;
+
+ device& get_device(std::string device_descriptor);
+}
+
diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp
new file mode 100644
index 000000000..a38d96c15
--- /dev/null
+++ b/src/device/device_default.cpp
@@ -0,0 +1,263 @@
+// Copyright (c) 2017-2018, 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.
+//
+
+
+
+
+#include "device_default.hpp"
+
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "ringct/rctOps.h"
+
+namespace hw {
+
+ namespace core {
+
+ device_default::device_default() { }
+
+ device_default::~device_default() { }
+
+ /* ===================================================================== */
+ /* === Misc ==== */
+ /* ===================================================================== */
+ static inline unsigned char *operator &(crypto::ec_scalar &scalar) {
+ return &reinterpret_cast<unsigned char &>(scalar);
+ }
+ static inline const unsigned char *operator &(const crypto::ec_scalar &scalar) {
+ return &reinterpret_cast<const unsigned char &>(scalar);
+ }
+
+ /* ======================================================================= */
+ /* SETUP/TEARDOWN */
+ /* ======================================================================= */
+ bool device_default::set_name(const std::string &name) {
+ this->name = name;
+ return true;
+ }
+ const std::string device_default::get_name() const {
+ return this->name;
+ }
+
+ bool device_default::init(void) {
+ dfns();
+ }
+ bool device_default::release() {
+ dfns();
+ }
+
+ bool device_default::connect(void) {
+ dfns();
+ }
+ bool device_default::disconnect() {
+ dfns();
+ }
+
+ /* ======================================================================= */
+ /* WALLET & ADDRESS */
+ /* ======================================================================= */
+
+ bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) {
+ return cryptonote::generate_chacha_key_from_secret_keys(keys, key);
+ }
+ bool device_default::get_public_address(cryptonote::account_public_address &pubkey) {
+ dfns();
+ }
+ bool device_default::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) {
+ dfns();
+ }
+ /* ======================================================================= */
+ /* SUB ADDRESS */
+ /* ======================================================================= */
+
+ bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_key) {
+ return crypto::derive_subaddress_public_key(out_key, derivation, output_index,derived_key);
+ }
+
+ bool device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) {
+ D = cryptonote::get_subaddress_spend_public_key(keys,index);
+ return true;
+ }
+
+ bool device_default::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) {
+ pkeys = cryptonote::get_subaddress_spend_public_keys(keys, account, begin, end);
+ return true;
+ }
+
+ bool device_default::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) {
+ address = cryptonote::get_subaddress(keys,index);
+ return true;
+ }
+
+ bool device_default::get_subaddress_secret_key(const crypto::secret_key &a, const cryptonote::subaddress_index &index, crypto::secret_key &m) {
+ m = cryptonote::get_subaddress_secret_key(a,index);
+ return true;
+ }
+
+ /* ======================================================================= */
+ /* DERIVATION & KEY */
+ /* ======================================================================= */
+
+ bool device_default::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) {
+ return cryptonote::verify_keys(secret_key, public_key);
+ }
+
+ bool device_default::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) {
+ rct::scalarmultKey(aP, P,a);
+ return true;
+ }
+
+ bool device_default::scalarmultBase(rct::key &aG, const rct::key &a) {
+ rct::scalarmultBase(aG,a);
+ return true;
+ }
+
+ bool device_default::sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
+ sc_add(&r, &a, &b);
+ return true;
+ }
+
+ bool device_default::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) {
+ rng = crypto::generate_keys(pub, sec, recovery_key, recover);
+ return true;
+ }
+
+ bool device_default::generate_key_derivation(const crypto::public_key &key1, const crypto::secret_key &key2, crypto::key_derivation &derivation) {
+ return crypto::generate_key_derivation(key1, key2, derivation);
+ }
+
+ bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){
+ crypto::derivation_to_scalar(derivation,output_index, res);
+ return true;
+ }
+
+ bool device_default::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &base, crypto::secret_key &derived_key){
+ crypto::derive_secret_key(derivation, output_index, base, derived_key);
+ return true;
+ }
+
+ bool device_default::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &base, crypto::public_key &derived_key){
+ return crypto::derive_public_key(derivation, output_index, base, derived_key);
+ }
+
+ bool device_default::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) {
+ return crypto::secret_key_to_public_key(sec,pub);
+ }
+
+ bool device_default::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){
+ crypto::generate_key_image(pub, sec,image);
+ return true;
+ }
+
+ /* ======================================================================= */
+ /* TRANSACTION */
+ /* ======================================================================= */
+
+ bool device_default::open_tx(crypto::secret_key &tx_key) {
+ cryptonote::keypair txkey = cryptonote::keypair::generate();
+ tx_key = txkey.sec;
+ return true;
+ }
+
+
+ bool device_default::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index,
+ const rct::key &amount_key, const crypto::public_key &out_eph_public_key) {
+ return true;
+ }
+
+ bool device_default::set_signature_mode(unsigned int sig_mode) {
+ return true;
+ }
+
+ bool device_default::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) {
+ return cryptonote::encrypt_payment_id(payment_id, public_key, secret_key);
+ }
+
+ bool device_default::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) {
+ rct::ecdhEncode(unmasked, sharedSec);
+ return true;
+ }
+
+ bool device_default::ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) {
+ rct::ecdhDecode(masked, sharedSec);
+ return true;
+ }
+
+ bool device_default::mlsag_prepare(const rct::key &H, const rct::key &xx,
+ rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) {
+ rct::skpkGen(a, aG);
+ rct::scalarmultKey(aHP, H, a);
+ rct::scalarmultKey(II, H, xx);
+ return true;
+ }
+ bool device_default::mlsag_prepare(rct::key &a, rct::key &aG) {
+ rct::skpkGen(a, aG);
+ return true;
+ }
+ bool device_default::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) {
+ prehash = rct::cn_fast_hash(hashes);
+ return true;
+ }
+
+
+ bool device_default::mlsag_hash(const rct::keyV &toHash, rct::key &c_old) {
+ c_old = rct::hash_to_scalar(toHash);
+ return true;
+ }
+
+ bool device_default::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss ) {
+ CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows");
+ CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows");
+ CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows");
+ CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows");
+ for (size_t j = 0; j < rows; j++) {
+ sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
+ }
+ return true;
+ }
+
+ bool device_default::close_tx() {
+ return true;
+ }
+
+
+ /* ---------------------------------------------------------- */
+ static device_default *default_core_device = NULL;
+ void register_all(std::map<std::string, std::unique_ptr<device>> &registry) {
+ if (!default_core_device) {
+ default_core_device = new device_default();
+ default_core_device->set_name("default_core_device");
+
+ }
+ registry.insert(std::make_pair("default",default_core_device));
+ }
+
+
+ }
+
+} \ No newline at end of file
diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp
new file mode 100644
index 000000000..f5b158a3b
--- /dev/null
+++ b/src/device/device_default.hpp
@@ -0,0 +1,126 @@
+// Copyright (c) 2017-2018, 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 "device.hpp"
+
+namespace hw {
+
+ namespace core {
+
+ void register_all(std::map<std::string, std::unique_ptr<device>> &registry);
+
+ class device_default : public hw::device {
+ public:
+ device_default();
+ ~device_default();
+
+ device_default(const device_default &device) = delete;
+ device_default& operator=(const device_default &device) = delete;
+
+ explicit operator bool() const override { return false; };
+
+ /* ======================================================================= */
+ /* SETUP/TEARDOWN */
+ /* ======================================================================= */
+ bool set_name(const std::string &name) override;
+ const std::string get_name() const override;
+
+ bool init(void) override;
+ bool release() override;
+
+ bool connect(void) override;
+ bool disconnect() override;
+
+ /* ======================================================================= */
+ /* WALLET & ADDRESS */
+ /* ======================================================================= */
+ bool get_public_address(cryptonote::account_public_address &pubkey) override;
+ bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
+ bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override;
+
+ /* ======================================================================= */
+ /* SUB ADDRESS */
+ /* ======================================================================= */
+ bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override;
+ bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override;
+ bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) override;
+ bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override;
+ bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override;
+
+ /* ======================================================================= */
+ /* DERIVATION & KEY */
+ /* ======================================================================= */
+ bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override;
+ bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override;
+ bool scalarmultBase(rct::key &aG, const rct::key &a) override;
+ bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override;
+ bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override;
+ bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
+ bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override;
+ bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
+ bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
+ bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override;
+ bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override;
+
+
+ /* ======================================================================= */
+ /* TRANSACTION */
+ /* ======================================================================= */
+
+ bool open_tx(crypto::secret_key &tx_key) override;
+
+ //bool get_additional_key(const bool subaddr, cryptonote::keypair &additional_txkey) override;
+ bool set_signature_mode(unsigned int sig_mode) override;
+
+ bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override;
+
+ bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override;
+ bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override;
+
+ bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index,
+ const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override;
+
+
+ bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) override;
+ bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override;
+ bool mlsag_prepare(rct::key &a, rct::key &aG) override;
+ bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override;
+ bool mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) override;
+
+ bool close_tx(void) override;
+ };
+
+ }
+
+
+
+}
+
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
new file mode 100644
index 000000000..e8eb7cc8b
--- /dev/null
+++ b/src/device/device_ledger.cpp
@@ -0,0 +1,2069 @@
+// Copyright (c) 2017-2018, 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.
+//
+
+#include "device_ledger.hpp"
+#include "log.hpp"
+#include "ringct/rctOps.h"
+
+
+
+namespace hw {
+
+ namespace ledger {
+
+ #ifdef WITH_DEVICE_LEDGER
+
+ #undef MONERO_DEFAULT_LOG_CATEGORY
+ #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
+
+ /* ===================================================================== */
+ /* === Debug ==== */
+ /* ===================================================================== */
+ void set_apdu_verbose(bool verbose) {
+ apdu_verbose = verbose;
+ }
+
+ #define TRACKD MTRACE("hw")
+ #define ASSERT_RV(rv) CHECK_AND_ASSERT_THROW_MES((rv)==SCARD_S_SUCCESS, "Fail SCard API : (" << (rv) << ") "<< pcsc_stringify_error(rv)<<" Device="<<this->id<<", hCard="<<hCard<<", hContext="<<hContext);
+ #define ASSERT_SW(sw,ok,msk) CHECK_AND_ASSERT_THROW_MES(((sw)&(mask))==(ok), "Wrong Device Status : SW=" << std::hex << (sw) << " (EXPECT=" << std::hex << (ok) << ", MASK=" << std::hex << (mask) << ")") ;
+ #define ASSERT_T0(exp) CHECK_AND_ASSERT_THROW_MES(exp, "Protocol assert failure: "#exp ) ;
+
+ #ifdef DEBUG_HWDEVICE
+ #define DEVICE_CONTROLE :controle_device(hw::get_device("default"))
+ crypto::secret_key viewkey;
+ crypto::secret_key spendkey;
+ #else
+ #define DEVICE_CONTROLE
+ #endif
+
+ /* ===================================================================== */
+ /* === Keymap ==== */
+ /* ===================================================================== */
+
+ ABPkeys::ABPkeys(const rct::key& A, const rct::key& B, size_t real_output_index, const rct::key& P, const rct::key& AK) {
+ Aout = A;
+ Bout = B;
+ index = real_output_index;
+ Pout = P;
+ AKout = AK;
+ }
+
+ ABPkeys::ABPkeys(const ABPkeys& keys) {
+ Aout = keys.Aout;
+ Bout = keys.Bout;
+ index = keys.index;
+ Pout = keys.Pout;
+ AKout = keys.AKout;
+ }
+
+ bool Keymap::find(const rct::key& P, ABPkeys& keys) const {
+ size_t sz = ABP.size();
+ for (size_t i=0; i<sz; i++) {
+ if (ABP[i].Pout == P) {
+ keys = ABP[i];
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void Keymap::add(const ABPkeys& keys) {
+ ABP.push_back(keys);
+ }
+
+ void Keymap::clear() {
+ ABP.clear();
+ }
+
+ #ifdef DEBUG_HWDEVICE
+ void Keymap::log() {
+ log_message("keymap", "content");
+ size_t sz = ABP.size();
+ for (size_t i=0; i<sz; i++) {
+ log_message(" keymap", std::to_string(i));
+ log_hexbuffer(" Aout", (char*)ABP[i].Aout.bytes, 32);
+ log_hexbuffer(" Bout", (char*)ABP[i].Bout.bytes, 32);
+ log_message (" index", std::to_string(ABP[i].index));
+ log_hexbuffer(" Pout", (char*)ABP[i].Pout.bytes, 32);
+ }
+ }
+ #endif
+
+ /* ===================================================================== */
+ /* === Device ==== */
+ /* ===================================================================== */
+
+ static int device_id = 0;
+
+ #define INS_NONE 0x00
+ #define INS_RESET 0x02
+
+ #define INS_GET_KEY 0x20
+ #define INS_PUT_KEY 0x22
+ #define INS_GET_CHACHA8_PREKEY 0x24
+ #define INS_VERIFY_KEY 0x26
+
+ #define INS_SECRET_KEY_TO_PUBLIC_KEY 0x30
+ #define INS_GEN_KEY_DERIVATION 0x32
+ #define INS_DERIVATION_TO_SCALAR 0x34
+ #define INS_DERIVE_PUBLIC_KEY 0x36
+ #define INS_DERIVE_SECRET_KEY 0x38
+ #define INS_GEN_KEY_IMAGE 0x3A
+ #define INS_SECRET_KEY_ADD 0x3C
+ #define INS_SECRET_KEY_SUB 0x3E
+ #define INS_GENERATE_KEYPAIR 0x40
+ #define INS_SECRET_SCAL_MUL_KEY 0x42
+ #define INS_SECRET_SCAL_MUL_BASE 0x44
+
+ #define INS_DERIVE_SUBADDRESS_PUBLIC_KEY 0x46
+ #define INS_GET_SUBADDRESS 0x48
+ #define INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY 0x4A
+ #define INS_GET_SUBADDRESS_SECRET_KEY 0x4C
+
+ #define INS_OPEN_TX 0x70
+ #define INS_SET_SIGNATURE_MODE 0x72
+ #define INS_GET_ADDITIONAL_KEY 0x74
+ #define INS_STEALTH 0x76
+ #define INS_BLIND 0x78
+ #define INS_UNBLIND 0x7A
+ #define INS_VALIDATE 0x7C
+ #define INS_MLSAG 0x7E
+ #define INS_CLOSE_TX 0x80
+
+
+ #define INS_GET_RESPONSE 0xc0
+
+
+ void device_ledger::logCMD() {
+ if (apdu_verbose) {
+ char strbuffer[1024];
+ sprintf(strbuffer, "%.02x %.02x %.02x %.02x %.02x ",
+ this->buffer_send[0],
+ this->buffer_send[1],
+ this->buffer_send[2],
+ this->buffer_send[3],
+ this->buffer_send[4]
+ );
+ buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_send+5), this->length_send-5);
+ MDEBUG( "CMD :" << strbuffer);
+ }
+ }
+
+ void device_ledger::logRESP() {
+ if (apdu_verbose) {
+ char strbuffer[1024];
+ sprintf(strbuffer, "%.02x%.02x ",
+ this->buffer_recv[this->length_recv-2],
+ this->buffer_recv[this->length_recv-1]
+ );
+ buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_recv), this->length_recv-2);
+ MDEBUG( "RESP :" << strbuffer);
+
+ }
+ }
+
+ /* -------------------------------------------------------------- */
+ device_ledger::device_ledger() DEVICE_CONTROLE {
+ this->id = device_id++;
+ this->hCard = 0;
+ this->hContext = 0;
+ this->reset_buffer();
+ MDEBUG( "Device "<<this->id <<" Created");
+ }
+
+ device_ledger::~device_ledger() {
+ this->release();
+ MDEBUG( "Device "<<this->id <<" Destroyed");
+ }
+
+
+ /* ======================================================================= */
+ /* MISC */
+ /* ======================================================================= */
+ bool device_ledger::reset() {
+
+ lock_device();
+ try {
+ int offset;
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_RESET;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
+ LONG rv;
+ int sw;
+
+ ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE);
+ logCMD();
+ this->length_recv = BUFFER_RECV_SIZE;
+ rv = SCardTransmit(this->hCard,
+ SCARD_PCI_T0, this->buffer_send, this->length_send,
+ NULL, this->buffer_recv, &this->length_recv);
+ ASSERT_RV(rv);
+ ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE);
+ logRESP();
+
+ sw = (this->buffer_recv[this->length_recv-2]<<8) | this->buffer_recv[this->length_recv-1];
+ ASSERT_SW(sw,ok,msk);
+ return sw;
+ }
+
+ void device_ledger::reset_buffer() {
+ this->length_send = 0;
+ memset(this->buffer_send, 0, BUFFER_SEND_SIZE);
+ this->length_recv = 0;
+ memset(this->buffer_recv, 0, BUFFER_RECV_SIZE);
+ }
+
+ void device_ledger::lock_device() {
+ MDEBUG( "Ask for LOCKING for device "<<this->id);
+ device_locker.lock();
+ MDEBUG( "Device "<<this->id << " LOCKed");
+ }
+ void device_ledger::unlock_device() {
+ try {
+ MDEBUG( "Ask for UNLOCKING for device "<<this->id);
+ } catch (...) {
+ }
+ device_locker.unlock();
+ MDEBUG( "Device "<<this->id << " UNLOCKed");
+ }
+ void device_ledger::lock_tx() {
+ MDEBUG( "Ask for LOCKING for TX "<<this->id);
+ //tx_locker.lock();
+ MDEBUG( "TX "<<this->id << " LOCKed");
+ }
+ void device_ledger::unlock_tx() {
+ MDEBUG( "Ask for UNLOCKING for TX "<<this->id);
+ //tx_locker.unlock();
+ MDEBUG( "TX "<<this->id << " UNLOCKed");
+ }
+
+ /* ======================================================================= */
+ /* SETUP/TEARDOWN */
+ /* ======================================================================= */
+
+ bool device_ledger::set_name(const std::string & name) {
+ this->name = name;
+ return true;
+ }
+
+ const std::string device_ledger::get_name() const {
+ if (this->full_name.empty() || (this->hCard == 0)) {
+ return std::string("<disconnected:").append(this->name).append(">");
+ }
+ return this->full_name;
+ }
+
+ bool device_ledger::init(void) {
+ LONG rv;
+ this->release();
+ rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM,0,0, &this->hContext);
+ ASSERT_RV(rv);
+ MDEBUG( "Device "<<this->id <<" SCardContext created: hContext="<<this->hContext);
+ this->hCard = 0;
+ return true;
+ }
+
+ bool device_ledger::release() {
+ this->disconnect();
+ if (this->hContext) {
+ SCardReleaseContext(this->hContext);
+ MDEBUG( "Device "<<this->id <<" SCardContext released: hContext="<<this->hContext);
+ this->hContext = 0;
+ this->full_name.clear();
+ }
+ return true;
+ }
+
+ bool device_ledger::connect(void) {
+ BYTE pbAtr[MAX_ATR_SIZE];
+ LPSTR mszReaders;
+ DWORD dwReaders;
+ LONG rv;
+ DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen;
+
+ this->disconnect();
+#ifdef SCARD_AUTOALLOCATE
+ dwReaders = SCARD_AUTOALLOCATE;
+ rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders);
+#else
+ dwReaders = 0;
+ rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders);
+ if (rv != SCARD_S_SUCCESS)
+ return false;
+ mszReaders = (LPSTR)calloc(dwReaders, sizeof(char));
+ rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders);
+#endif
+ if (rv == SCARD_S_SUCCESS) {
+ char* p;
+ const char* prefix = this->name.c_str();
+
+ p = mszReaders;
+ MDEBUG( "Looking for " << std::string(prefix));
+ while (*p) {
+ MDEBUG( "Device Found: " << std::string(p));
+ if ((strncmp(prefix, p, strlen(prefix))==0)) {
+ MDEBUG( "Device Match: " << std::string(p));
+ if ((rv = SCardConnect(this->hContext,
+ p, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0,
+ &this->hCard, &dwProtocol))!=SCARD_S_SUCCESS) {
+ break;
+ }
+ MDEBUG( "Device "<<this->id <<" Connected: hCard="<<this->hCard);
+ dwAtrLen = sizeof(pbAtr);
+ if ((rv = SCardStatus(this->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen))!=SCARD_S_SUCCESS) {
+ break;
+ }
+ MDEBUG( "Device "<<this->id <<" Status OK");
+ rv = SCARD_S_SUCCESS ;
+ this->full_name = std::string(p);
+ break;
+ }
+ p += strlen(p) +1;
+ }
+ }
+
+ if (mszReaders) {
+ #ifdef SCARD_AUTOALLOCATE
+ SCardFreeMemory(this->hContext, mszReaders);
+ #else
+ free(mszReaders);
+ #endif
+ mszReaders = NULL;
+ }
+ if (rv != SCARD_S_SUCCESS) {
+ if ( hCard) {
+ SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
+ MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard);
+ this->hCard = 0;
+ }
+ }
+ ASSERT_RV(rv);
+
+ this->reset();
+ #ifdef DEBUG_HWDEVICE
+ cryptonote::account_public_address pubkey;
+ this->get_public_address(pubkey);
+ crypto::secret_key vkey;
+ crypto::secret_key skey;
+ this->get_secret_keys(vkey,skey);
+ #endif
+
+ return rv==SCARD_S_SUCCESS;
+ }
+
+ bool device_ledger::disconnect() {
+ if (this->hCard) {
+ SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD);
+ MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard);
+ this->hCard = 0;
+ }
+ return true;
+ }
+
+
+ /* ======================================================================= */
+ /* WALLET & ADDRESS */
+ /* ======================================================================= */
+
+ bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) {
+ memset(viewkey.data, 0x00, 32);
+ memset(spendkey.data, 0xFF, 32);
+ return true;
+ }
+
+ /* Application API */
+ bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){
+
+ lock_device();
+ try {
+ int offset;
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_KEY;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32);
+ memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32);
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ #ifdef DEBUG_HWDEVICE
+ bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) {
+ lock_device();
+ try {
+ //spcialkey, normal conf handled in decrypt
+ int offset;
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_KEY;
+ this->buffer_send[2] = 0x02;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //clear key
+ memmove(ledger::viewkey.data, this->buffer_recv+64, 32);
+ memmove(ledger::spendkey.data, this->buffer_recv+96, 32);
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+ #endif
+
+ bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) {
+ lock_device();
+ try {
+ int offset;
+
+ #ifdef DEBUG_HWDEVICE
+ const cryptonote::account_keys keys_x = decrypt(keys);
+ crypto::chacha_key key_x;
+ this->controle_device.generate_chacha_key(keys_x, key_x);
+ #endif
+
+ reset_buffer();
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_CHACHA8_PREKEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ char prekey[200];
+ memmove(prekey, &this->buffer_recv[0], 200);
+ crypto::generate_chacha_key(&prekey[0], sizeof(prekey), key, true);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("generate_chacha_key", "key", (char*)key_x.data(), (char*)key.data());
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ /* ======================================================================= */
+ /* SUB ADDRESS */
+ /* ======================================================================= */
+
+ bool device_ledger::derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub){
+
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::public_key pub_x = pub;
+ const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
+ const std::size_t output_index_x = output_index;
+ crypto::public_key derived_pub_x;
+ this->controle_device.derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //pub
+ memmove(this->buffer_send+offset, pub.data, 32);
+ offset += 32;
+ //derivation
+ memmove(this->buffer_send+offset, derivation.data, 32);
+ offset += 32;
+ //index
+ this->buffer_send[offset+0] = output_index>>24;
+ this->buffer_send[offset+1] = output_index>>16;
+ this->buffer_send[offset+2] = output_index>>8;
+ this->buffer_send[offset+3] = output_index>>0;
+ offset += 4;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(derived_pub.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
+ const cryptonote::subaddress_index index_x = index;
+ crypto::public_key D_x;
+ this->controle_device.get_subaddress_spend_public_key(keys_x, index_x, D_x);
+ #endif
+
+ if (index.is_zero()) {
+ D = keys.m_account_address.m_spend_public_key;
+ } else {
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //index
+ static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
+ memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
+ offset +=8 ;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(D.data, &this->buffer_recv[0], 32);
+ }
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("get_subaddress_spend_public_key", "D", D_x.data, D.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) {
+ cryptonote::subaddress_index index = {account, begin};
+ crypto::public_key D;
+ for (uint32_t idx = begin; idx < end; ++idx) {
+ index.minor = idx;
+ this->get_subaddress_spend_public_key(keys, index, D);
+ pkeys.push_back(D);
+ }
+ return true;
+ }
+
+ bool device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
+ const cryptonote::subaddress_index index_x = index;
+ cryptonote::account_public_address address_x;
+ this->controle_device.get_subaddress(keys_x, index_x, address_x);
+ #endif
+
+ if (index.is_zero()) {
+ address = keys.m_account_address;
+ } else {
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_SUBADDRESS;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //index
+ static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
+ memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
+ offset +=8 ;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(address.m_view_public_key.data, &this->buffer_recv[0], 32);
+ memmove(address.m_spend_public_key.data, &this->buffer_recv[32], 32);
+ }
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("get_subaddress", "address.m_view_public_key.data", address_x.m_view_public_key.data, address.m_view_public_key.data);
+ hw::ledger::check32("get_subaddress", "address.m_spend_public_key.data", address_x.m_spend_public_key.data, address.m_spend_public_key.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ const cryptonote::subaddress_index index_x = index;
+ crypto::secret_key sub_sec_x;
+ this->controle_device.get_subaddress_secret_key(sec_x, index_x, sub_sec_x);
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GET_SUBADDRESS_SECRET_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //sec
+ memmove(this->buffer_send+offset, sec.data, 32);
+ offset += 32;
+ //index
+ static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
+ memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
+ offset +=8 ;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(sub_sec.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::secret_key sub_sec_clear = hw::ledger::decrypt(sub_sec);
+ hw::ledger::check32("get_subaddress_secret_key", "sub_sec", sub_sec_x.data, sub_sec_clear.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ /* ======================================================================= */
+ /* DERIVATION & KEY */
+ /* ======================================================================= */
+
+ bool device_ledger::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) {
+ lock_device();
+ try {
+ int offset =0,sw;
+ unsigned char options = 0;
+ reset_buffer();
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VERIFY_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //sec
+ memmove(this->buffer_send+offset, secret_key.data, 32);
+ offset += 32;
+ //pub
+ memmove(this->buffer_send+offset, public_key.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ uint32_t verified =
+ this->buffer_recv[0] << 24 |
+ this->buffer_recv[1] << 16 |
+ this->buffer_recv[2] << 8 |
+ this->buffer_recv[3] << 0 ;
+
+ unlock_device();
+ return verified == 1;
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return false;
+ }
+
+ bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key pub_x = pub;
+ const rct::key sec_x = hw::ledger::decrypt(sec);
+ rct::key mulkey_x;
+ this->controle_device.scalarmultKey(pub_x, sec_x, mulkey_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //pub
+ memmove(this->buffer_send+offset, P.bytes, 32);
+ offset += 32;
+ //sec
+ memmove(this->buffer_send+offset, a.bytes, 32);
+ offset += 32;
+
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(aP.bytes, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("scalarmultKey", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key sec_x = hw::ledger::decrypt(sec);
+ rct::key mulkey_x;
+ this->controle_device.scalarmultBase(sec_x, mulkey_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //sec
+ memmove(this->buffer_send+offset, a.bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(aG.bytes, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("scalarmultBase", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
+
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ 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;
+ this->controle_device.sc_secret_add(r_x, a_x, b_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_SECRET_KEY_ADD;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //sec key
+ memmove(this->buffer_send+offset, a.data, 32);
+ offset += 32;
+ //sec key
+ memmove(this->buffer_send+offset, b.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(r.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::secret_key r_clear = hw::ledger::decrypt(r);
+ hw::ledger::check32("sc_secret_add", "r", r_x.data, r_clear.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) {
+ if (recover) {
+ throw std::runtime_error("device generate key does not support recover");
+ }
+
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ bool recover_x = recover;
+ const crypto::secret_key recovery_key_x = recovery_key;
+ crypto::public_key pub_x;
+ crypto::secret_key sec_x;
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GENERATE_KEYPAIR;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(pub.data, &this->buffer_recv[0], 32);
+ memmove(sec.data, &this->buffer_recv[32], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::secret_key sec_clear = hw::ledger::decrypt(sec);
+ sec_x = sec_clear;
+ crypto::secret_key_to_public_key(sec_x,pub_x);
+ hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+
+ }
+
+ bool device_ledger::generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::public_key pub_x = pub;
+ const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ crypto::key_derivation derivation_x;
+ this->controle_device.generate_key_derivation(pub_x, sec_x, derivation_x);
+ hw::ledger::log_hexbuffer("generate_key_derivation: sec_x.data", sec_x.data, 32);
+ hw::ledger::log_hexbuffer("generate_key_derivation: pub_x.data", pub_x.data, 32);
+ hw::ledger::log_hexbuffer("generate_key_derivation: derivation_x.data", derivation_x.data, 32);
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GEN_KEY_DERIVATION;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //pub
+ memmove(this->buffer_send+offset, pub.data, 32);
+ offset += 32;
+ //sec
+ memmove(this->buffer_send+offset, sec.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //derivattion data
+ memmove(derivation.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::key_derivation derivation_clear = hw::ledger::decrypt(derivation);
+ hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) {
+ lock_device();
+ try {
+ int offset;
+ unsigned char options;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
+ const size_t output_index_x = output_index;
+ crypto::ec_scalar res_x;
+ this->controle_device.derivation_to_scalar(derivation_x, output_index_x, res_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_DERIVATION_TO_SCALAR;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //derivattion
+ memmove(this->buffer_send+offset, derivation.data, 32);
+ offset += 32;
+ //index
+ this->buffer_send[offset+0] = output_index>>24;
+ this->buffer_send[offset+1] = output_index>>16;
+ this->buffer_send[offset+2] = output_index>>8;
+ this->buffer_send[offset+3] = output_index>>0;
+ offset += 4;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //derivattion data
+ memmove(res.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::ec_scalar res_clear = hw::ledger::decrypt(res);
+ hw::ledger::check32("derivation_to_scalar", "res", res_x.data, res_clear.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) {
+ lock_device();
+ try {
+ int offset;
+ unsigned char options;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
+ const std::size_t output_index_x = output_index;
+ const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ crypto::secret_key derived_sec_x;
+ this->controle_device.derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_DERIVE_SECRET_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //derivation
+ memmove(this->buffer_send+offset, derivation.data, 32);
+ offset += 32;
+ //index
+ this->buffer_send[offset+0] = output_index>>24;
+ this->buffer_send[offset+1] = output_index>>16;
+ this->buffer_send[offset+2] = output_index>>8;
+ this->buffer_send[offset+3] = output_index>>0;
+ offset += 4;
+ //sec
+ memmove(this->buffer_send+offset, sec.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(derived_sec.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ crypto::secret_key derived_sec_clear = hw::ledger::decrypt(derived_sec);
+ hw::ledger::check32("derive_secret_key", "derived_sec", derived_sec_x.data, derived_sec_clear.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){
+ lock_device();
+ try {
+ int offset;
+ unsigned char options;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
+ const std::size_t output_index_x = output_index;
+ const crypto::public_key pub_x = pub;
+ crypto::public_key derived_pub_x;
+ this->controle_device.derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //derivation
+ memmove(this->buffer_send+offset, derivation.data, 32);
+ offset += 32;
+ //index
+ this->buffer_send[offset+0] = output_index>>24;
+ this->buffer_send[offset+1] = output_index>>16;
+ this->buffer_send[offset+2] = output_index>>8;
+ this->buffer_send[offset+3] = output_index>>0;
+ offset += 4;
+ //pub
+ memmove(this->buffer_send+offset, pub.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(derived_pub.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("derive_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) {
+ lock_device();
+ try {
+ int offset;
+ unsigned char options;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ crypto::public_key pub_x;
+ this->controle_device.secret_key_to_public_key(sec_x, pub_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //sec key
+ memmove(this->buffer_send+offset, sec.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(pub.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("secret_key_to_public_key", "pub", pub_x.data, pub.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){
+ lock_device();
+ try {
+ int offset;
+ unsigned char options;
+
+ #ifdef DEBUG_HWDEVICE
+ const crypto::public_key pub_x = pub;
+ const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
+ crypto::key_image image_x;
+ this->controle_device.generate_key_image(pub_x, sec_x, image_x);
+ #endif
+
+ reset_buffer();
+
+ options = 0;
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_GEN_KEY_IMAGE;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = options;
+ offset += 1;
+ //pub
+ memmove(this->buffer_send+offset, pub.data, 32);
+ offset += 32;
+ //sec
+ memmove(this->buffer_send+offset, sec.data, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pub key
+ memmove(image.data, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("generate_key_image", "image", image_x.data, image.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ /* ======================================================================= */
+ /* TRANSACTION */
+ /* ======================================================================= */
+
+ bool device_ledger::open_tx(crypto::secret_key &tx_key) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ lock_tx();
+ reset_buffer();
+ key_map.clear();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_OPEN_TX;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //account
+ this->buffer_send[offset+0] = 0x00;
+ this->buffer_send[offset+1] = 0x00;
+ this->buffer_send[offset+2] = 0x00;
+ this->buffer_send[offset+3] = 0x00;
+ offset += 4;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(tx_key.data, &this->buffer_recv[32], 32);
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::set_signature_mode(unsigned int sig_mode) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_SET_SIGNATURE_MODE;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //account
+ this->buffer_send[offset] = sig_mode;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ 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;
+ this->controle_device.encrypt_payment_id(public_key_x, secret_key_x, payment_id_x);
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_STEALTH;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //pub
+ memmove(&this->buffer_send[offset], public_key.data, 32);
+ offset += 32;
+ //sec
+ memmove(&this->buffer_send[offset], secret_key.data, 32);
+ offset += 32;
+ //id
+ memmove(&this->buffer_send[offset], payment_id.data, 8);
+ offset += 8;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ memmove(payment_id.data, &this->buffer_recv[0], 8);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check8("stealth", "payment_id", payment_id_x.data, payment_id.data);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index,
+ const rct::key &amount_key, const crypto::public_key &out_eph_public_key) {
+ lock_device();
+ try {
+ key_map.add(ABPkeys(rct::pk2rct(Aout),rct::pk2rct(Bout), real_output_index, rct::pk2rct(out_eph_public_key), amount_key));
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key AKout_x = hw::ledger::decrypt(AKout);
+ rct::ecdhTuple unmasked_x = unmasked;
+ this->controle_device.ecdhEncode(AKout_x, unmasked_x);
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_BLIND;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ // AKout
+ memmove(this->buffer_send+offset, AKout.bytes, 32);
+ offset += 32;
+ //mask k
+ memmove(this->buffer_send+offset, unmasked.mask.bytes, 32);
+ offset += 32;
+ //value v
+ memmove(this->buffer_send+offset, unmasked.amount.bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(unmasked.amount.bytes, &this->buffer_recv[0], 32);
+ memmove(unmasked.mask.bytes, &this->buffer_recv[32], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ 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);
+
+ hw::ledger::log_hexbuffer("Blind AKV input", (char*)&this->buffer_recv[64], 3*32);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key AKout_x = hw::ledger::decrypt(AKout);
+ rct::ecdhTuple masked_x = masked;
+ this->controle_device.ecdhDecode(AKout_x, masked_x);
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_UNBLIND;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ // AKout
+ memmove(this->buffer_send+offset, AKout.bytes, 32);
+ offset += 32;
+ //mask k
+ memmove(this->buffer_send+offset, masked.mask.bytes, 32);
+ offset += 32;
+ //value v
+ memmove(this->buffer_send+offset, masked.amount.bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(masked.amount.bytes, &this->buffer_recv[0], 32);
+ memmove(masked.mask.bytes, &this->buffer_recv[32], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ 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
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size,
+ const rct::keyV &hashes, const rct::ctkeyV &outPk,
+ rct::key &prehash) {
+
+ lock_device();
+ try {
+ unsigned char options = 0;
+ unsigned int data_offset, C_offset, kv_offset, i;
+ const char *data;
+
+ #ifdef DEBUG_HWDEVICE
+ const std::string blob_x = blob;
+ size_t inputs_size_x = inputs_size;
+ size_t outputs_size_x = outputs_size;
+ const rct::keyV hashes_x = hashes;
+ const rct::ctkeyV outPk_x = outPk;
+ rct::key prehash_x;
+ this->controle_device.mlsag_prehash(blob_x, inputs_size_x, outputs_size_x, hashes_x, outPk_x, prehash_x);
+ if (inputs_size) {
+ log_message("mlsag_prehash", (std::string("inputs_size not null: ") + std::to_string(inputs_size)).c_str());
+ }
+ this->key_map.log();
+ #endif
+
+ data = blob.data();
+
+ // ====== u8 type, varint txnfee ======
+ int offset;
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VALIDATE;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x01;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80;
+ offset += 1;
+
+ //type
+ this->buffer_send[offset] = data[0];
+ offset += 1;
+
+ //txnfee
+ data_offset = 1;
+ while (data[data_offset]&0x80) {
+ this->buffer_send[offset] = data[data_offset];
+ offset += 1;
+ data_offset += 1;
+ }
+ this->buffer_send[offset] = data[data_offset];
+ offset += 1;
+ data_offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //pseudoOuts
+ for ( i = 0; i < inputs_size; i++) {
+ reset_buffer();
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VALIDATE;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = i+2;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = (i==inputs_size-1)? 0x00:0x80;
+ offset += 1;
+ //pseudoOut
+ memmove(this->buffer_send+offset, data+data_offset,32);
+ offset += 32;
+ data_offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ }
+
+ // ====== Aout, Bout, AKout, C, v, k ======
+ kv_offset = data_offset;
+ C_offset = kv_offset+ (32*2)*outputs_size;
+ for ( i = 0; i < outputs_size; i++) {
+ ABPkeys outKeys;
+ bool found;
+
+ found = this->key_map.find(outPk[i].dest, outKeys);
+ if (!found) {
+ log_hexbuffer("Pout not found", (char*)outPk[i].dest.bytes, 32);
+ CHECK_AND_ASSERT_THROW_MES(found, "Pout not found");
+ }
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VALIDATE;
+ this->buffer_send[2] = 0x02;
+ this->buffer_send[3] = i+1;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
+ offset += 1;
+ if (found) {
+ //Aout
+ memmove(this->buffer_send+offset, outKeys.Aout.bytes, 32);
+ offset+=32;
+ //Bout
+ memmove(this->buffer_send+offset, outKeys.Bout.bytes, 32);
+ offset+=32;
+ //AKout
+ memmove(this->buffer_send+offset, outKeys.AKout.bytes, 32);
+ offset+=32;
+ } else {
+ // dummy: Aout Bout AKout
+ offset += 32*3;
+ }
+ //C
+ memmove(this->buffer_send+offset, data+C_offset,32);
+ offset += 32;
+ C_offset += 32;
+ //k
+ memmove(this->buffer_send+offset, data+kv_offset,32);
+ offset += 32;
+ //v
+ kv_offset += 32;
+ memmove(this->buffer_send+offset, data+kv_offset,32);
+ offset += 32;
+ kv_offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::log_hexbuffer("Prehash AKV input", (char*)&this->buffer_recv[64], 3*32);
+ #endif
+ }
+
+ // ====== C[], message, proof======
+ C_offset = kv_offset;
+ for (i = 0; i < outputs_size; i++) {
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VALIDATE;
+ this->buffer_send[2] = 0x03;
+ this->buffer_send[3] = i+1;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x80 ;
+ offset += 1;
+ //C
+ memmove(this->buffer_send+offset, data+C_offset,32);
+ offset += 32;
+ C_offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ }
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_VALIDATE;
+ this->buffer_send[2] = 0x03;
+ this->buffer_send[3] = i+1;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //message
+ memmove(this->buffer_send+offset, hashes[0].bytes,32);
+ offset += 32;
+ //proof
+ memmove(this->buffer_send+offset, hashes[2].bytes,32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(prehash.bytes, this->buffer_recv, 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("mlsag_prehash", "prehash", (char*)prehash_x.bytes, (char*)prehash.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+
+ bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx,
+ rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key H_x = H;
+ const rct::key xx_x = hw::ledger::decrypt(xx);
+ rct::key a_x;
+ rct::key aG_x;
+ rct::key aHP_x;
+ rct::key II_x;
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_MLSAG;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+ //value H
+ memmove(this->buffer_send+offset, H.bytes, 32);
+ offset += 32;
+ //mask xin
+ memmove(this->buffer_send+offset, xx.bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(a.bytes, &this->buffer_recv[32*0], 32);
+ memmove(aG.bytes, &this->buffer_recv[32*1], 32);
+ memmove(aHP.bytes, &this->buffer_recv[32*2], 32);
+ memmove(II.bytes, &this->buffer_recv[32*3], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ a_x = hw::ledger::decrypt(a);
+
+ rct::scalarmultBase(aG_x, a_x);
+ rct::scalarmultKey(aHP_x, H_x, a_x);
+ rct::scalarmultKey(II_x, H_x, xx_x);
+ hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes);
+ hw::ledger::check32("mlsag_prepare", "aHP", (char*)aHP_x.bytes, (char*)aHP.bytes);
+ hw::ledger::check32("mlsag_prepare", "II", (char*)II_x.bytes, (char*)II.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ #ifdef DEBUG_HWDEVICE
+ rct::key a_x;
+ rct::key aG_x;
+ #endif
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_MLSAG;
+ this->buffer_send[2] = 0x01;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ memmove(a.bytes, &this->buffer_recv[32*0], 32);
+ memmove(aG.bytes, &this->buffer_recv[32*1], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ a_x = hw::ledger::decrypt(a);
+ rct::scalarmultBase(aG_x, a_x);
+ hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+ size_t cnt;
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::keyV long_message_x = long_message;
+ rct::key c_x;
+ this->controle_device.mlsag_hash(long_message_x, c_x);
+ #endif
+
+ cnt = long_message.size();
+ for (size_t i = 0; i<cnt; i++) {
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_MLSAG;
+ this->buffer_send[2] = 0x02;
+ this->buffer_send[3] = i+1;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] =
+ (i==(cnt-1))?0x00:0x80; //last
+ offset += 1;
+ //msg part
+ memmove(this->buffer_send+offset, long_message[i].bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+ }
+
+ memmove(c.bytes, &this->buffer_recv[0], 32);
+
+ #ifdef DEBUG_HWDEVICE
+ hw::ledger::check32("mlsag_hash", "c", (char*)c_x.bytes, (char*)c.bytes);
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+
+ }
+
+ bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows");
+ CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows");
+ CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows");
+ CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows");
+
+ #ifdef DEBUG_HWDEVICE
+ const rct::key c_x = c;
+ const rct::keyV xx_x = hw::ledger::decrypt(xx);
+ const rct::keyV alpha_x = hw::ledger::decrypt(alpha);
+ const int rows_x = rows;
+ const int dsRows_x = dsRows;
+ rct::keyV ss_x(ss.size());
+ this->controle_device.mlsag_sign(c_x, xx_x, alpha_x, rows_x, dsRows_x, ss_x);
+ #endif
+
+ for (size_t j = 0; j < dsRows; j++) {
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_MLSAG;
+ this->buffer_send[2] = 0x03;
+ this->buffer_send[3] = j+1;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ if (j==(dsRows-1)) {
+ this->buffer_send[offset] |= 0x80; //last
+ }
+ offset += 1;
+ //xx
+ memmove(this->buffer_send+offset, xx[j].bytes, 32);
+ offset += 32;
+ //alpa
+ memmove(this->buffer_send+offset, alpha[j].bytes, 32);
+ offset += 32;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ //ss
+ memmove(ss[j].bytes, &this->buffer_recv[0], 32);
+ }
+
+ for (size_t j = dsRows; j < rows; j++) {
+ sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
+ }
+
+ #ifdef DEBUG_HWDEVICE
+ for (size_t j = 0; j < rows; j++) {
+ hw::ledger::check32("mlsag_sign", "ss["+std::to_string(j)+"]", (char*)ss_x[j].bytes, (char*)ss[j].bytes);
+ }
+ #endif
+
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ bool device_ledger::close_tx() {
+ lock_device();
+ try {
+ int offset =0;
+ unsigned char options = 0;
+
+ reset_buffer();
+
+ this->buffer_send[0] = 0x00;
+ this->buffer_send[1] = INS_CLOSE_TX;
+ this->buffer_send[2] = 0x00;
+ this->buffer_send[3] = 0x00;
+ this->buffer_send[4] = 0x00;
+ offset = 5;
+ //options
+ this->buffer_send[offset] = 0x00;
+ offset += 1;
+
+ this->buffer_send[4] = offset-5;
+ this->length_send = offset;
+ this->exchange();
+
+ unlock_tx();
+ unlock_device();
+ }catch (...) {
+ unlock_device();
+ throw;
+ }
+ return true;
+ }
+
+ /* ---------------------------------------------------------- */
+
+ static device_ledger *legder_device = NULL;
+ void register_all(std::map<std::string, std::unique_ptr<device>> &registry) {
+ if (!legder_device) {
+ legder_device = new device_ledger();
+ legder_device->set_name("Ledger");
+ }
+ registry.insert(std::make_pair("Ledger", legder_device));
+ }
+
+ #else //WITH_DEVICE_LEDGER
+
+ void register_all(std::map<std::string, std::unique_ptr<device>> &registry) {
+ }
+
+ #endif //WITH_DEVICE_LEDGER
+
+ }
+}
+
diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp
new file mode 100644
index 000000000..ab8e0c553
--- /dev/null
+++ b/src/device/device_ledger.hpp
@@ -0,0 +1,202 @@
+// Copyright (c) 2017-2018, 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 <cstddef>
+#include <string>
+#include <mutex>
+#include "device.hpp"
+#include <PCSC/winscard.h>
+#include <PCSC/wintypes.h>
+
+
+namespace hw {
+
+ namespace ledger {
+
+ void register_all(std::map<std::string, std::unique_ptr<device>> &registry);
+
+ #ifdef WITH_DEVICE_LEDGER
+
+ namespace {
+ bool apdu_verbose =true;
+ }
+
+ void set_apdu_verbose(bool verbose);
+
+ class ABPkeys {
+ public:
+ rct::key Aout;
+ rct::key Bout;
+ size_t index;
+ rct::key Pout;
+ rct::key AKout;
+ ABPkeys(const rct::key& A, const rct::key& B, size_t index, const rct::key& P,const rct::key& AK);
+ ABPkeys(const ABPkeys& keys) ;
+ ABPkeys() {index=0;}
+ };
+
+ class Keymap {
+ public:
+ std::vector<ABPkeys> ABP;
+
+ bool find(const rct::key& P, ABPkeys& keys) const;
+ void add(const ABPkeys& keys);
+ void clear();
+ void log();
+ };
+
+ #define BUFFER_SEND_SIZE 262
+ #define BUFFER_RECV_SIZE 262
+
+ class device_ledger : public hw::device {
+ private:
+ mutable std::mutex device_locker;
+ mutable std::mutex tx_locker;
+ void lock_device() ;
+ void unlock_device() ;
+ void lock_tx() ;
+ void unlock_tx() ;
+
+ std::string full_name;
+ SCARDCONTEXT hContext;
+ SCARDHANDLE hCard;
+ DWORD length_send;
+ BYTE buffer_send[BUFFER_SEND_SIZE];
+ DWORD length_recv;
+ BYTE buffer_recv[BUFFER_RECV_SIZE];
+ unsigned int id;
+
+ Keymap key_map;
+
+
+ void logCMD(void);
+ void logRESP(void);
+ unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF);
+ void reset_buffer(void);
+
+ #ifdef DEBUGLEDGER
+ Device &controle_device;
+ #endif
+
+ public:
+ device_ledger();
+ ~device_ledger();
+
+ device_ledger(const device_ledger &device) = delete ;
+ device_ledger& operator=(const device_ledger &device) = delete;
+
+ explicit operator bool() const override {return this->hContext != 0;}
+
+ bool reset(void);
+
+ /* ======================================================================= */
+ /* SETUP/TEARDOWN */
+ /* ======================================================================= */
+ bool set_name(const std::string &name) override;
+
+ const std::string get_name() const override;
+ bool init(void) override;
+ bool release() override;
+ bool connect(void) override;
+ bool disconnect() override;
+
+ /* ======================================================================= */
+ /* WALLET & ADDRESS */
+ /* ======================================================================= */
+ bool get_public_address(cryptonote::account_public_address &pubkey) override;
+ bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
+ bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override;
+
+
+ /* ======================================================================= */
+ /* SUB ADDRESS */
+ /* ======================================================================= */
+ bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub) override;
+ bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override;
+ bool get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, std::vector<crypto::public_key> &pkeys) override;
+ bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override;
+ bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override;
+
+ /* ======================================================================= */
+ /* DERIVATION & KEY */
+ /* ======================================================================= */
+ bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override;
+ bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override;
+ bool scalarmultBase(rct::key &aG, const rct::key &a) override;
+ bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override;
+ bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override;
+ bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
+ bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override;
+ bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
+ bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
+ bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override;
+ bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override;
+
+ /* ======================================================================= */
+ /* TRANSACTION */
+ /* ======================================================================= */
+
+ bool open_tx(crypto::secret_key &tx_key) override;
+
+ bool set_signature_mode(unsigned int sig_mode) override;
+
+ bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override;
+
+ bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override;
+ bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override;
+
+ bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index,
+ const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override;
+
+
+ bool mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size, const rct::keyV &hashes, const rct::ctkeyV &outPk, rct::key &prehash) override;
+ bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override;
+ bool mlsag_prepare(rct::key &a, rct::key &aG) override;
+ bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override;
+ bool mlsag_sign( const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) override;
+
+ bool close_tx(void) override;
+
+ };
+
+
+
+ #ifdef DEBUGLEDGER
+ extern crypto::secret_key viewkey;
+ extern crypto::secret_key spendkey;
+ #endif
+
+ #endif //WITH_DEVICE_LEDGER
+ }
+
+}
+
diff --git a/src/device/log.cpp b/src/device/log.cpp
new file mode 100644
index 000000000..103b2b3ba
--- /dev/null
+++ b/src/device/log.cpp
@@ -0,0 +1,164 @@
+// Copyright (c) 2017-2018, 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.
+//
+
+#include "misc_log_ex.h"
+#include "log.hpp"
+
+namespace hw {
+
+ #ifdef WITH_DEVICE_LEDGER
+ namespace ledger {
+
+ #undef MONERO_DEFAULT_LOG_CATEGORY
+ #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger"
+
+ void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) {
+ CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required");
+ for (size_t i=0; i<len; i++) {
+ sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]);
+ }
+ }
+
+ void log_hexbuffer(std::string msg, const char* buff, size_t len) {
+ char logstr[1025];
+ buffer_to_str(logstr, sizeof(logstr), buff, len);
+ MDEBUG(msg<< ": " << logstr);
+ }
+
+ void log_message(std::string msg, std::string info ) {
+ MDEBUG(msg << ": " << info);
+ }
+
+ #ifdef DEBUGLEDGER
+ extern crypto::secret_key viewkey;
+ extern crypto::secret_key spendkey;
+
+
+ void decrypt(char* buf, size_t len) {
+ #ifdef IODUMMYCRYPT
+ int i;
+ if (len == 32) {
+ //view key?
+ for (i = 0; i<32; i++) {
+ if (buf[i] != 0) break;
+ }
+ if (i == 32) {
+ memmove(buf, hw::ledger::viewkey.data, 32);
+ return;
+ }
+ //spend key?
+ for (i = 0; i<32; i++) {
+ if (buf[i] != (char)0xff) break;
+ }
+ if (i == 32) {
+ memmove(buf, hw::ledger::spendkey.data, 32);
+ return;
+ }
+ }
+ //std decrypt: XOR.55h
+ for (i = 0; i<len;i++) {
+ buf[i] ^= 0x55;
+ }
+ #endif
+ }
+
+ crypto::key_derivation decrypt(const crypto::key_derivation &derivation) {
+ crypto::key_derivation x = derivation;
+ decrypt(x.data, 32);
+ return x;
+ }
+
+ cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) {
+ cryptonote::account_keys x = keys;
+ decrypt(x.m_view_secret_key.data, 32);
+ decrypt(x.m_spend_secret_key.data, 32);
+ return x;
+ }
+
+
+ crypto::secret_key decrypt(const crypto::secret_key &sec) {
+ crypto::secret_key x = sec;
+ decrypt(x.data, 32);
+ return x;
+ }
+
+ rct::key decrypt(const rct::key &sec) {
+ rct::key x = sec;
+ decrypt((char*)x.bytes, 32);
+ return x;
+ }
+
+ crypto::ec_scalar decrypt(const crypto::ec_scalar &res) {
+ crypto::ec_scalar x = res;
+ decrypt((char*)x.data, 32);
+ return x;
+ }
+
+ rct::keyV decrypt(const rct::keyV &keys) {
+ rct::keyV x ;
+ for (unsigned int j = 0; j<keys.size(); j++) {
+ x.push_back(decrypt(keys[j]));
+ }
+ return x;
+ }
+
+ static void check(std::string msg, std::string info, const char *h, const char *d, int len, bool crypted) {
+ char dd[32];
+ char logstr[128];
+
+ memmove(dd,d,len);
+ if (crypted) {
+ CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32");
+ decrypt(dd,len);
+ }
+
+ if (memcmp(h,dd,len)) {
+ log_message("ASSERT EQ FAIL", msg + ": "+ info );
+ log_hexbuffer(" host ", h, len);
+ log_hexbuffer(" device", dd, len);
+
+ } else {
+ buffer_to_str(logstr, dd, len);
+ log_message("ASSERT EQ OK", msg + ": "+ info + ": "+ std::string(logstr) );
+ }
+ }
+
+ void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted) {
+ check(msg, info, h, d, 32, crypted);
+ }
+
+ void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted) {
+ check(msg, info, h, d, 8, crypted);
+ }
+ #endif
+
+ }
+ #endif //WITH_DEVICE_LEDGER
+
+} \ No newline at end of file
diff --git a/src/device/log.hpp b/src/device/log.hpp
new file mode 100644
index 000000000..1ab572c2c
--- /dev/null
+++ b/src/device/log.hpp
@@ -0,0 +1,69 @@
+// Copyright (c) 2017-2018, 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 <cstddef>
+#include <string>
+
+#include "ringct/rctOps.h"
+#include "crypto/crypto.h"
+#include "cryptonote_basic/account.h"
+
+#include "device.hpp"
+
+namespace hw {
+
+ #ifdef WITH_DEVICE_LEDGER
+ namespace ledger {
+
+ void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ;
+ void log_hexbuffer(std::string msg, const char* buff, size_t len);
+ void log_message(std::string msg, std::string info );
+ #ifdef DEBUG_HWDEVICE
+ #define TRACK printf("file %s:%d\n",__FILE__, __LINE__)
+ //#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__)
+ //#define TRACK while(0);
+
+ void decrypt(char* buf, size_t len) ;
+ crypto::key_derivation decrypt(const crypto::key_derivation &derivation) ;
+ cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) ;
+ crypto::secret_key decrypt(const crypto::secret_key &sec) ;
+ rct::key decrypt(const rct::key &sec);
+ crypto::ec_scalar decrypt(const crypto::ec_scalar &res);
+ rct::keyV decrypt(const rct::keyV &keys);
+
+ void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted=false);
+ void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted=false);
+
+ void set_check_verbose(bool verbose);
+ #endif
+ }
+ #endif
+}
diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp
index 6c05a38d9..91042d58a 100644
--- a/src/multisig/multisig.cpp
+++ b/src/multisig/multisig.cpp
@@ -33,6 +33,7 @@
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "multisig.h"
+#include "device/device_default.hpp"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "multisig"
@@ -116,7 +117,7 @@ namespace cryptonote
bool generate_multisig_composite_key_image(const account_keys &keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key &tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki)
{
cryptonote::keypair in_ephemeral;
- if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki))
+ if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device()))
return false;
std::unordered_set<crypto::key_image> used;
for (size_t m = 0; m < keys.m_multisig_keys.size(); ++m)
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt
index 9421a1477..83bdffab5 100644
--- a/src/p2p/CMakeLists.txt
+++ b/src/p2p/CMakeLists.txt
@@ -40,6 +40,7 @@ target_link_libraries(p2p
PUBLIC
epee
version
+ cryptonote_core
${UPNP_LIBRARIES}
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp
index 121e72392..170b79984 100644
--- a/src/p2p/net_node.cpp
+++ b/src/p2p/net_node.cpp
@@ -34,15 +34,16 @@
namespace nodetool
{
const command_line::arg_descriptor<std::string> arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"};
- const command_line::arg_descriptor<std::string> arg_p2p_bind_port = {
+ const command_line::arg_descriptor<std::string, false, true> arg_p2p_bind_port = {
"p2p-bind-port"
, "Port for p2p network protocol"
, std::to_string(config::P2P_DEFAULT_PORT)
- };
- const command_line::arg_descriptor<std::string> arg_testnet_p2p_bind_port = {
- "testnet-p2p-bind-port"
- , "Port for testnet p2p network protocol"
- , std::to_string(config::testnet::P2P_DEFAULT_PORT)
+ , cryptonote::arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet && defaulted)
+ return std::to_string(config::testnet::P2P_DEFAULT_PORT);
+ return val;
+ }
};
const command_line::arg_descriptor<uint32_t> arg_p2p_external_port = {"p2p-external-port", "External port for p2p network protocol (if port forwarding used with NAT)", 0};
const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip = {"allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"};
@@ -55,6 +56,7 @@ namespace nodetool
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
const command_line::arg_descriptor<int64_t> arg_out_peers = {"out-peers", "set max number of out peers", -1};
+ const command_line::arg_descriptor<int64_t> arg_in_peers = {"in-peers", "set max number of in peers", -1};
const command_line::arg_descriptor<int> arg_tos_flag = {"tos-flag", "set TOS flag", -1};
const command_line::arg_descriptor<int64_t> arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1};
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 20520f83c..54c474665 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -81,6 +81,7 @@ namespace nodetool
node_server(t_payload_net_handler& payload_handler)
:m_payload_handler(payload_handler),
m_current_number_of_out_peers(0),
+ m_current_number_of_in_peers(0),
m_allow_local_ip(false),
m_hide_my_port(false),
m_no_igd(false),
@@ -117,8 +118,10 @@ namespace nodetool
bool log_connections();
virtual uint64_t get_connections_count();
size_t get_outgoing_connections_count();
+ size_t get_incoming_connections_count();
peerlist_manager& get_peerlist_manager(){return m_peerlist;}
- void delete_connections(size_t count);
+ void delete_out_connections(size_t count);
+ void delete_in_connections(size_t count);
virtual bool block_host(const epee::net_utils::network_address &adress, time_t seconds = P2P_IP_BLOCKTIME);
virtual bool unblock_host(const epee::net_utils::network_address &address);
virtual std::map<std::string, time_t> get_blocked_hosts() { CRITICAL_REGION_LOCAL(m_blocked_hosts_lock); return m_blocked_hosts; }
@@ -214,7 +217,7 @@ namespace nodetool
void add_upnp_port_mapping(uint32_t port);
void delete_upnp_port_mapping(uint32_t port);
template<class t_callback>
- bool try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb);
+ bool try_ping(basic_node_data& node_data, p2p_connection_context& context, const t_callback &cb);
bool try_get_support_flags(const p2p_connection_context& context, std::function<void(p2p_connection_context&, const uint32_t&)> f);
bool make_expected_connections_count(PeerType peer_type, size_t expected_connections);
void cache_connect_fail_info(const epee::net_utils::network_address& addr);
@@ -230,6 +233,7 @@ namespace nodetool
bool parse_peers_and_add_to_container(const boost::program_options::variables_map& vm, const command_line::arg_descriptor<std::vector<std::string> > & arg, Container& container);
bool set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max);
+ bool set_max_in_peers(const boost::program_options::variables_map& vm, int64_t max);
bool set_tos_flag(const boost::program_options::variables_map& vm, int limit);
bool set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit);
@@ -271,6 +275,7 @@ namespace nodetool
public:
config m_config; // TODO was private, add getters?
std::atomic<unsigned int> m_current_number_of_out_peers;
+ std::atomic<unsigned int> m_current_number_of_in_peers;
void set_save_graph(bool save_graph)
{
@@ -332,8 +337,7 @@ namespace nodetool
const int64_t default_limit_up = 2048;
const int64_t default_limit_down = 8192;
extern const command_line::arg_descriptor<std::string> arg_p2p_bind_ip;
- extern const command_line::arg_descriptor<std::string> arg_p2p_bind_port;
- extern const command_line::arg_descriptor<std::string> arg_testnet_p2p_bind_port;
+ extern const command_line::arg_descriptor<std::string, false, true> arg_p2p_bind_port;
extern const command_line::arg_descriptor<uint32_t> arg_p2p_external_port;
extern const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip;
extern const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer;
@@ -345,6 +349,7 @@ namespace nodetool
extern const command_line::arg_descriptor<bool> arg_no_igd;
extern const command_line::arg_descriptor<bool> arg_offline;
extern const command_line::arg_descriptor<int64_t> arg_out_peers;
+ extern const command_line::arg_descriptor<int64_t> arg_in_peers;
extern const command_line::arg_descriptor<int> arg_tos_flag;
extern const command_line::arg_descriptor<int64_t> arg_limit_rate_up;
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 152dba942..59b417d90 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -75,7 +75,6 @@ namespace nodetool
{
command_line::add_arg(desc, arg_p2p_bind_ip);
command_line::add_arg(desc, arg_p2p_bind_port, false);
- command_line::add_arg(desc, arg_testnet_p2p_bind_port, false);
command_line::add_arg(desc, arg_p2p_external_port);
command_line::add_arg(desc, arg_p2p_allow_local_ip);
command_line::add_arg(desc, arg_p2p_add_peer);
@@ -85,6 +84,7 @@ namespace nodetool
command_line::add_arg(desc, arg_p2p_hide_my_port);
command_line::add_arg(desc, arg_no_igd);
command_line::add_arg(desc, arg_out_peers);
+ command_line::add_arg(desc, arg_in_peers);
command_line::add_arg(desc, arg_tos_flag);
command_line::add_arg(desc, arg_limit_rate_up);
command_line::add_arg(desc, arg_limit_rate_down);
@@ -262,15 +262,13 @@ namespace nodetool
const boost::program_options::variables_map& vm
)
{
- auto p2p_bind_arg = m_testnet ? arg_testnet_p2p_bind_port : arg_p2p_bind_port;
-
+ m_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
m_bind_ip = command_line::get_arg(vm, arg_p2p_bind_ip);
- m_port = command_line::get_arg(vm, p2p_bind_arg);
+ m_port = command_line::get_arg(vm, arg_p2p_bind_port);
m_external_port = command_line::get_arg(vm, arg_p2p_external_port);
m_allow_local_ip = command_line::get_arg(vm, arg_p2p_allow_local_ip);
m_no_igd = command_line::get_arg(vm, arg_no_igd);
m_offline = command_line::get_arg(vm, cryptonote::arg_offline);
- m_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
if (command_line::has_arg(vm, arg_p2p_add_peer))
{
@@ -315,6 +313,9 @@ namespace nodetool
if ( !set_max_out_peers(vm, command_line::get_arg(vm, arg_out_peers) ) )
return false;
+ if ( !set_max_in_peers(vm, command_line::get_arg(vm, arg_in_peers) ) )
+ return false;
+
if ( !set_tos_flag(vm, command_line::get_arg(vm, arg_tos_flag) ) )
return false;
@@ -499,8 +500,7 @@ namespace nodetool
}
MDEBUG("Number of seed nodes: " << m_seed_nodes.size());
- auto config_arg = m_testnet ? cryptonote::arg_testnet_data_dir : cryptonote::arg_data_dir;
- m_config_folder = command_line::get_arg(vm, config_arg);
+ m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
if ((!m_testnet && m_port != std::to_string(::config::P2P_DEFAULT_PORT))
|| (m_testnet && m_port != std::to_string(::config::testnet::P2P_DEFAULT_PORT))) {
@@ -565,14 +565,23 @@ namespace nodetool
while (!is_closing && !m_net_server.is_stop_signal_sent())
{ // main loop of thread
//number_of_peers = m_net_server.get_config_object().get_connections_count();
- unsigned int number_of_peers = 0;
+ unsigned int number_of_in_peers = 0;
+ unsigned int number_of_out_peers = 0;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
{
- if (!cntxt.m_is_income) ++number_of_peers;
+ if (cntxt.m_is_income)
+ {
+ ++number_of_in_peers;
+ }
+ else
+ {
+ ++number_of_out_peers;
+ }
return true;
}); // lambda
- m_current_number_of_out_peers = number_of_peers;
+ m_current_number_of_in_peers = number_of_in_peers;
+ m_current_number_of_out_peers = number_of_out_peers;
boost::this_thread::sleep_for(boost::chrono::seconds(1));
} // main loop of thread
@@ -871,11 +880,11 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::try_to_connect_and_handshake_with_new_peer(const epee::net_utils::network_address& na, bool just_take_peerlist, uint64_t last_seen_stamp, PeerType peer_type, uint64_t first_seen_stamp)
{
- if (m_current_number_of_out_peers == m_config.m_net_config.connections_count) // out peers limit
+ if (m_current_number_of_out_peers == m_config.m_net_config.max_out_connection_count) // out peers limit
{
return false;
}
- else if (m_current_number_of_out_peers > m_config.m_net_config.connections_count)
+ else if (m_current_number_of_out_peers > m_config.m_net_config.max_out_connection_count)
{
m_net_server.get_config_object().del_out_connections(1);
m_current_number_of_out_peers --; // atomic variable, update time = 1s
@@ -1151,6 +1160,7 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::connections_maker()
{
+ if (m_offline) return true;
if (!connect_to_peerlist(m_exclusive_peers)) return false;
if (!m_exclusive_peers.empty()) return true;
@@ -1164,10 +1174,10 @@ namespace nodetool
if (!connect_to_peerlist(m_priority_peers)) return false;
- size_t expected_white_connections = (m_config.m_net_config.connections_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
+ size_t expected_white_connections = (m_config.m_net_config.max_out_connection_count*P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT)/100;
size_t conn_count = get_outgoing_connections_count();
- if(conn_count < m_config.m_net_config.connections_count)
+ if(conn_count < m_config.m_net_config.max_out_connection_count)
{
if(conn_count < expected_white_connections)
{
@@ -1178,20 +1188,20 @@ namespace nodetool
if(!make_expected_connections_count(white, expected_white_connections))
return false;
//then do grey list
- if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(gray, m_config.m_net_config.max_out_connection_count))
return false;
}else
{
//start from grey list
- if(!make_expected_connections_count(gray, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(gray, m_config.m_net_config.max_out_connection_count))
return false;
//and then do white list
- if(!make_expected_connections_count(white, m_config.m_net_config.connections_count))
+ if(!make_expected_connections_count(white, m_config.m_net_config.max_out_connection_count))
return false;
}
}
- if (start_conn_count == get_outgoing_connections_count() && start_conn_count < m_config.m_net_config.connections_count)
+ if (start_conn_count == get_outgoing_connections_count() && start_conn_count < m_config.m_net_config.max_out_connection_count)
{
MINFO("Failed to connect to any, trying seeds");
if (!connect_to_seed())
@@ -1253,6 +1263,20 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
+ size_t node_server<t_payload_net_handler>::get_incoming_connections_count()
+ {
+ size_t count = 0;
+ m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
+ {
+ if(cntxt.m_is_income)
+ ++count;
+ return true;
+ });
+
+ return count;
+ }
+ //-----------------------------------------------------------------------------------
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::idle_worker()
{
m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::peer_sync_idle_maker, this));
@@ -1477,7 +1501,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_callback>
- bool node_server<t_payload_net_handler>::try_ping(basic_node_data& node_data, p2p_connection_context& context, t_callback cb)
+ bool node_server<t_payload_net_handler>::try_ping(basic_node_data& node_data, p2p_connection_context& context, const t_callback &cb)
{
if(!node_data.my_port)
return false;
@@ -1618,6 +1642,13 @@ namespace nodetool
return 1;
}
+ if (m_current_number_of_in_peers >= m_config.m_net_config.max_in_connection_count) // in peers limit
+ {
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but already have max incoming connections, so dropping this one.");
+ drop_connection(context);
+ return 1;
+ }
+
if(!m_payload_handler.process_payload_sync_data(arg.payload_data, context, true))
{
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but process_payload_sync_data returned false, dropping connection.");
@@ -1779,20 +1810,37 @@ namespace nodetool
bool node_server<t_payload_net_handler>::set_max_out_peers(const boost::program_options::variables_map& vm, int64_t max)
{
if(max == -1) {
- m_config.m_net_config.connections_count = P2P_DEFAULT_CONNECTIONS_COUNT;
+ m_config.m_net_config.max_out_connection_count = P2P_DEFAULT_CONNECTIONS_COUNT;
return true;
}
- m_config.m_net_config.connections_count = max;
+ m_config.m_net_config.max_out_connection_count = max;
return true;
}
template<class t_payload_net_handler>
- void node_server<t_payload_net_handler>::delete_connections(size_t count)
+ bool node_server<t_payload_net_handler>::set_max_in_peers(const boost::program_options::variables_map& vm, int64_t max)
+ {
+ if(max == -1) {
+ m_config.m_net_config.max_in_connection_count = -1;
+ return true;
+ }
+ m_config.m_net_config.max_in_connection_count = max;
+ return true;
+ }
+
+ template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::delete_out_connections(size_t count)
{
m_net_server.get_config_object().del_out_connections(count);
}
template<class t_payload_net_handler>
+ void node_server<t_payload_net_handler>::delete_in_connections(size_t count)
+ {
+ m_net_server.get_config_object().del_in_connections(count);
+ }
+
+ template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::set_tos_flag(const boost::program_options::variables_map& vm, int flag)
{
if(flag==-1){
@@ -1884,6 +1932,7 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping()
{
+ if (m_offline) return true;
if (!m_exclusive_peers.empty()) return true;
peerlist_entry pe = AUTO_VAL_INIT(pe);
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index 348a8b978..e793e19b6 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -131,13 +131,15 @@ namespace nodetool
struct network_config
{
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(connections_count)
+ KV_SERIALIZE(max_out_connection_count)
+ KV_SERIALIZE(max_in_connection_count)
KV_SERIALIZE(handshake_interval)
KV_SERIALIZE(packet_max_size)
KV_SERIALIZE(config_id)
END_KV_SERIALIZE_MAP()
- uint32_t connections_count;
+ uint32_t max_out_connection_count;
+ uint32_t max_in_connection_count;
uint32_t connection_timeout;
uint32_t ping_connection_timeout;
uint32_t handshake_interval;
diff --git a/src/ringct/CMakeLists.txt b/src/ringct/CMakeLists.txt
index 3a28997dd..2d3ea5cf4 100644
--- a/src/ringct/CMakeLists.txt
+++ b/src/ringct/CMakeLists.txt
@@ -28,6 +28,7 @@
set(ringct_sources
rctOps.cpp
+ rctOps_device.cpp
rctSigs.cpp
rctTypes.cpp
rctCryptoOps.c
@@ -52,6 +53,7 @@ target_link_libraries(ringct
common
cncrypto
cryptonote_basic
+ device
PRIVATE
${OPENSSL_LIBRARIES}
${EXTRA_LIBRARIES})
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index 67e877326..fd15ffbc4 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -297,6 +297,39 @@ static rct::keyV slice(const rct::keyV &a, size_t start, size_t stop)
return res;
}
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1)
+{
+ rct::keyV data;
+ data.reserve(3);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2)
+{
+ rct::keyV data;
+ data.reserve(4);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ data.push_back(mash2);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
+static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3)
+{
+ rct::keyV data;
+ data.reserve(5);
+ data.push_back(hash_cache);
+ data.push_back(mash0);
+ data.push_back(mash1);
+ data.push_back(mash2);
+ data.push_back(mash3);
+ return hash_cache = rct::hash_to_scalar(data);
+}
+
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
{
@@ -329,6 +362,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
}
PERF_TIMER_STOP(PROVE_aLaR);
+ rct::key hash_cache = rct::hash_to_scalar(V);
// DEBUG: Test to ensure this recovers the value
#ifdef DEBUG_BP
@@ -361,11 +395,8 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::addKeys(S, ve, rct::scalarmultBase(rho));
// PAPER LINES 43-45
- rct::keyV hashed;
- hashed.push_back(A);
- hashed.push_back(S);
- rct::key y = rct::hash_to_scalar(hashed);
- rct::key z = rct::hash_to_scalar(y);
+ rct::key y = hash_cache_mash(hash_cache, A, S);
+ rct::key z = hash_cache = rct::hash_to_scalar(y);
// Polynomial construction before PAPER LINE 46
rct::key t0 = rct::zero();
@@ -427,11 +458,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::key T2 = rct::addKeys(rct::scalarmultKey(rct::H, t2), rct::scalarmultBase(tau2));
// PAPER LINES 49-51
- hashed.clear();
- hashed.push_back(z);
- hashed.push_back(T1);
- hashed.push_back(T2);
- rct::key x = rct::hash_to_scalar(hashed);
+ rct::key x = hash_cache_mash(hash_cache, z, T1, T2);
// PAPER LINES 52-53
rct::key taux = rct::zero();
@@ -460,12 +487,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
#endif
// PAPER LINES 32-33
- hashed.clear();
- hashed.push_back(x);
- hashed.push_back(taux);
- hashed.push_back(mu);
- hashed.push_back(t);
- rct::key x_ip = rct::hash_to_scalar(hashed);
+ rct::key x_ip = hash_cache_mash(hash_cache, x, taux, mu, t);
// These are used in the inner product rounds
size_t nprime = N;
@@ -509,20 +531,7 @@ Bulletproof bulletproof_PROVE(const rct::key &sv, const rct::key &gamma)
rct::addKeys(R[round], R[round], rct::scalarmultKey(rct::H, tmp));
// PAPER LINES 21-22
- hashed.clear();
- if (round == 0)
- {
- hashed.push_back(L[0]);
- hashed.push_back(R[0]);
- w[0] = rct::hash_to_scalar(hashed);
- }
- else
- {
- hashed.push_back(w[round - 1]);
- hashed.push_back(L[round]);
- hashed.push_back(R[round]);
- w[round] = rct::hash_to_scalar(hashed);
- }
+ w[round] = hash_cache_mash(hash_cache, L[round], R[round]);
// PAPER LINES 24-25
const rct::key winv = invert(w[round]);
@@ -563,6 +572,7 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
{
init_exponents();
+ CHECK_AND_ASSERT_MES(proof.V.size() == 1, false, "V does not have exactly one element");
CHECK_AND_ASSERT_MES(proof.L.size() == proof.R.size(), false, "Mismatched L and R sizes");
CHECK_AND_ASSERT_MES(proof.L.size() > 0, false, "Empty proof");
CHECK_AND_ASSERT_MES(proof.L.size() == 6, false, "Proof is not for 64 bits");
@@ -573,26 +583,15 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
// Reconstruct the challenges
PERF_TIMER_START_BP(VERIFY);
PERF_TIMER_START_BP(VERIFY_start);
- rct::keyV hashed;
- hashed.push_back(proof.A);
- hashed.push_back(proof.S);
- rct::key y = rct::hash_to_scalar(hashed);
- rct::key z = rct::hash_to_scalar(y);
- hashed.clear();
- hashed.push_back(z);
- hashed.push_back(proof.T1);
- hashed.push_back(proof.T2);
- rct::key x = rct::hash_to_scalar(hashed);
+ rct::key hash_cache = rct::hash_to_scalar(proof.V[0]);
+ rct::key y = hash_cache_mash(hash_cache, proof.A, proof.S);
+ rct::key z = hash_cache = rct::hash_to_scalar(y);
+ rct::key x = hash_cache_mash(hash_cache, z, proof.T1, proof.T2);
PERF_TIMER_STOP(VERIFY_start);
PERF_TIMER_START_BP(VERIFY_line_60);
// Reconstruct the challenges
- hashed.clear();
- hashed.push_back(x);
- hashed.push_back(proof.taux);
- hashed.push_back(proof.mu);
- hashed.push_back(proof.t);
- rct::key x_ip = hash_to_scalar(hashed);
+ rct::key x_ip = hash_cache_mash(hash_cache, x, proof.taux, proof.mu, proof.t);
PERF_TIMER_STOP(VERIFY_line_60);
PERF_TIMER_START_BP(VERIFY_line_61);
@@ -647,17 +646,9 @@ bool bulletproof_VERIFY(const Bulletproof &proof)
// PAPER LINES 21-22
// The inner product challenges are computed per round
rct::keyV w(rounds);
- hashed.clear();
- hashed.push_back(proof.L[0]);
- hashed.push_back(proof.R[0]);
- w[0] = rct::hash_to_scalar(hashed);
- for (size_t i = 1; i < rounds; ++i)
+ for (size_t i = 0; i < rounds; ++i)
{
- hashed.clear();
- hashed.push_back(w[i-1]);
- hashed.push_back(proof.L[i]);
- hashed.push_back(proof.R[i]);
- w[i] = rct::hash_to_scalar(hashed);
+ w[i] = hash_cache_mash(hash_cache, proof.L[i], proof.R[i]);
}
PERF_TIMER_STOP(VERIFY_line_21_22);
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index 3f8f6955c..c9f2e7a43 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -112,10 +112,14 @@ namespace rct {
//does a * G where a is a scalar and G is the curve basepoint
void scalarmultBase(key & aG, const key &a);
+ void scalarmultBase(key & aG, const key &a, hw::device &hwdev);
key scalarmultBase(const key & a);
+ key scalarmultBase(const key & a, hw::device &hwdev);
//does a * P where a is a scalar and P is an arbitrary point
void scalarmultKey(key &aP, const key &P, const key &a);
+ void scalarmultKey(key &aP, const key &P, const key &a, hw::device &hwdev);
key scalarmultKey(const key &P, const key &a);
+ key scalarmultKey(const key &P, const key &a, hw::device &hwdev);
//Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
key scalarmultH(const key & a);
@@ -174,6 +178,8 @@ namespace rct {
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
// where C= aG + bH
void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec);
+ void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev);
void ecdhDecode(ecdhTuple & masked, const key & sharedSec);
+ void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev);
}
#endif /* RCTOPS_H */
diff --git a/src/ringct/rctOps_device.cpp b/src/ringct/rctOps_device.cpp
new file mode 100644
index 000000000..fbfe8e9cf
--- /dev/null
+++ b/src/ringct/rctOps_device.cpp
@@ -0,0 +1,66 @@
+// Copyright (c) 2017-2018, 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.
+//
+
+#include "misc_log_ex.h"
+#include "rctOps.h"
+#include "device/device.hpp"
+using namespace crypto;
+using namespace std;
+
+
+namespace rct
+{
+ void scalarmultKey(key & aP, const key &P, const key &a, hw::device &hwdev) {
+ hwdev.scalarmultKey(aP, P, a);
+ }
+
+ key scalarmultKey(const key & P, const key & a, hw::device &hwdev) {
+ key aP;
+ hwdev.scalarmultKey(aP, P, a);
+ return aP;
+ }
+
+ void scalarmultBase(key &aG, const key &a, hw::device &hwdev) {
+ hwdev.scalarmultBase(aG, a);
+ }
+
+ key scalarmultBase(const key & a, hw::device &hwdev) {
+ key aG;
+ hwdev.scalarmultBase(aG, a);
+ return aG;
+ }
+
+ void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev) {
+ hwdev.ecdhDecode(masked, sharedSec);
+ }
+
+ void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev) {
+ hwdev.ecdhEncode(unmasked, sharedSec);
+ }
+} \ No newline at end of file
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index 3c34a5637..d3437eb36 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -35,6 +35,9 @@
#include "rctSigs.h"
#include "bulletproofs.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "cryptonote_basic/subaddress_index.h"
+#include "device/device.hpp"
using namespace crypto;
using namespace std;
@@ -43,6 +46,30 @@ using namespace std;
#define MONERO_DEFAULT_LOG_CATEGORY "ringct"
namespace rct {
+ bool is_simple(int type)
+ {
+ switch (type)
+ {
+ case RCTTypeSimple:
+ case RCTTypeSimpleBulletproof:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ bool is_bulletproof(int type)
+ {
+ switch (type)
+ {
+ case RCTTypeSimpleBulletproof:
+ case RCTTypeFullBulletproof:
+ return true;
+ default:
+ return false;
+ }
+ }
+
Bulletproof proveRangeBulletproof(key &C, key &mask, uint64_t amount)
{
mask = rct::skGen();
@@ -129,7 +156,7 @@ namespace rct {
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
- mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows) {
+ mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) {
mgSig rv;
size_t cols = pk.size();
CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!");
@@ -167,11 +194,9 @@ namespace rct {
}
else {
Hi = hashToPoint(pk[index][i]);
- skpkGen(alpha[i], aG[i]); //need to save alphas for later..
- aHP[i] = scalarmultKey(Hi, alpha[i]);
+ hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]);
toHash[3 * i + 2] = aG[i];
toHash[3 * i + 3] = aHP[i];
- rv.II[i] = scalarmultKey(Hi, xx[i]);
}
precomp(Ip[i].k, rv.II[i]);
}
@@ -182,7 +207,7 @@ namespace rct {
toHash[ndsRows + 2 * ii + 2] = aG[i];
}
- c_old = hash_to_scalar(toHash);
+ hwdev.mlsag_hash(toHash, c_old);
i = (index + 1) % cols;
@@ -206,7 +231,7 @@ namespace rct {
toHash[ndsRows + 2 * ii + 1] = pk[i][j];
toHash[ndsRows + 2 * ii + 2] = L;
}
- c = hash_to_scalar(toHash);
+ hwdev.mlsag_hash(toHash, c);
copy(c_old, c);
i = (i + 1) % cols;
@@ -214,9 +239,7 @@ namespace rct {
copy(rv.cc, c_old);
}
}
- for (j = 0; j < rows; j++) {
- sc_mulsub(rv.ss[index][j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
- }
+ hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]);
if (mscout)
*mscout = c;
return rv;
@@ -348,7 +371,7 @@ namespace rct {
catch (...) { return false; }
}
- key get_pre_mlsag_hash(const rctSig &rv)
+ key get_pre_mlsag_hash(const rctSig &rv, hw::device &hwdev)
{
keyV hashes;
hashes.reserve(3);
@@ -357,8 +380,10 @@ namespace rct {
std::stringstream ss;
binary_archive<true> ba(ss);
- const size_t inputs = rv.pseudoOuts.size();
+ CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing");
+ const size_t inputs = is_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
const size_t outputs = rv.ecdhInfo.size();
+ key prehash;
CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs),
"Failed to serialize rctSigBase");
cryptonote::get_blob_hash(ss.str(), h);
@@ -402,7 +427,8 @@ namespace rct {
}
}
hashes.push_back(cn_fast_hash(kv));
- return cn_fast_hash(hashes);
+ hwdev.mlsag_prehash(ss.str(), inputs, outputs, hashes, rv.outPk, prehash);
+ return prehash;
}
//Ring-ct MG sigs
@@ -413,7 +439,7 @@ namespace rct {
// this shows that sum inputs = sum outputs
//Ver:
// verifies the above sig is created corretly
- mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey) {
+ mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey, hw::device &hwdev) {
mgSig mg;
//setup vars
size_t cols = pubs.size();
@@ -458,7 +484,7 @@ namespace rct {
for (size_t j = 0; j < outPk.size(); j++) {
sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row..
}
- return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows);
+ return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
}
@@ -469,7 +495,7 @@ namespace rct {
// inSk is x, a_in corresponding to signing index
// a_out, Cout is for the output commitment
// index is the signing index..
- mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index) {
+ mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev) {
mgSig mg;
//setup vars
size_t rows = 1;
@@ -486,7 +512,7 @@ namespace rct {
sk[0] = copy(inSk.dest);
sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes);
}
- return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows);
+ return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev);
}
@@ -620,7 +646,7 @@ namespace rct {
// must know the destination private key to find the correct amount, else will return a random number
// Note: For txn fees, the last index in the amounts vector should contain that
// Thus the amounts vector will be "one" longer than the destinations vectort
- rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof) {
+ rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) {
CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations");
CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations");
CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing");
@@ -660,8 +686,7 @@ namespace rct {
//mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(amounts[i]);
- ecdhEncode(rv.ecdhInfo[i], amount_keys[i]);
-
+ ecdhEncode(rv.ecdhInfo[i], amount_keys[i], hwdev);
}
//set txn fee
@@ -678,21 +703,21 @@ namespace rct {
rv.mixRing = mixRing;
if (msout)
msout->c.resize(1);
- rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey));
+ rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey,hwdev));
return rv;
}
- rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin) {
+ rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev) {
unsigned int index;
ctkeyM mixRing;
ctkeyV outSk;
tie(mixRing, index) = populateFromBlockchain(inPk, mixin);
- return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false);
+ return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev);
}
//RCT simple
//for post-rct only
- rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) {
+ rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) {
CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts");
CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk");
CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations");
@@ -742,7 +767,7 @@ namespace rct {
//mask amount and mask
rv.ecdhInfo[i].mask = copy(outSk[i].mask);
rv.ecdhInfo[i].amount = d2h(outamounts[i]);
- ecdhEncode(rv.ecdhInfo[i], amount_keys[i]);
+ ecdhEncode(rv.ecdhInfo[i], amount_keys[i],hwdev);
}
//set txn fee
@@ -750,30 +775,31 @@ namespace rct {
// TODO: unused ??
// key txnFeeKey = scalarmultH(d2h(rv.txnFee));
rv.mixRing = mixRing;
- rv.pseudoOuts.resize(inamounts.size());
+ keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts;
+ pseudoOuts.resize(inamounts.size());
rv.p.MGs.resize(inamounts.size());
key sumpouts = zero(); //sum pseudoOut masks
keyV a(inamounts.size());
for (i = 0 ; i < inamounts.size() - 1; i++) {
skGen(a[i]);
sc_add(sumpouts.bytes, a[i].bytes, sumpouts.bytes);
- genC(rv.pseudoOuts[i], a[i], inamounts[i]);
+ genC(pseudoOuts[i], a[i], inamounts[i]);
}
rv.mixRing = mixRing;
sc_sub(a[i].bytes, sumout.bytes, sumpouts.bytes);
- genC(rv.pseudoOuts[i], a[i], inamounts[i]);
- DP(rv.pseudoOuts[i]);
+ genC(pseudoOuts[i], a[i], inamounts[i]);
+ DP(pseudoOuts[i]);
- key full_message = get_pre_mlsag_hash(rv);
+ key full_message = get_pre_mlsag_hash(rv,hwdev);
if (msout)
msout->c.resize(inamounts.size());
for (i = 0 ; i < inamounts.size(); i++) {
- rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], rv.pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]);
+ rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev);
}
return rv;
}
- rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin) {
+ rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev) {
std::vector<unsigned int> index;
index.resize(inPk.size());
ctkeyM mixRing;
@@ -783,7 +809,7 @@ namespace rct {
mixRing[i].resize(mixin+1);
index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin);
}
- return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false);
+ return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev);
}
//RingCT protocol
@@ -842,7 +868,7 @@ namespace rct {
if (!semantics) {
//compute txn fee
key txnFeeKey = scalarmultH(d2h(rv.txnFee));
- bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv));
+ bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv, hw::get_device("default")));
DP("mg sig verified?");
DP(mgVerd);
if (!mgVerd) {
@@ -876,16 +902,26 @@ namespace rct {
if (semantics)
{
if (rv.type == RCTTypeSimpleBulletproof)
+ {
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.bulletproofs.size(), false, "Mismatched sizes of outPk and rv.p.bulletproofs");
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs");
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.empty(), false, "rv.pseudoOuts is not empty");
+ }
else
+ {
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.p.rangeSigs.size(), false, "Mismatched sizes of outPk and rv.p.rangeSigs");
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.empty(), false, "rv.p.pseudoOuts is not empty");
+ }
CHECK_AND_ASSERT_MES(rv.outPk.size() == rv.ecdhInfo.size(), false, "Mismatched sizes of outPk and rv.ecdhInfo");
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.pseudoOuts and rv.p.MGs");
}
else
{
// semantics check is early, and mixRing/MGs aren't resolved yet
- CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
+ if (rv.type == RCTTypeSimpleBulletproof)
+ CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.p.pseudoOuts and mixRing");
+ else
+ CHECK_AND_ASSERT_MES(rv.pseudoOuts.size() == rv.mixRing.size(), false, "Mismatched sizes of rv.pseudoOuts and mixRing");
}
const size_t threads = std::max(rv.outPk.size(), rv.mixRing.size());
@@ -894,6 +930,8 @@ namespace rct {
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
+ const keyV &pseudoOuts = is_bulletproof(rv.type) ? rv.p.pseudoOuts : rv.pseudoOuts;
+
if (semantics) {
key sumOutpks = identity();
for (size_t i = 0; i < rv.outPk.size(); i++) {
@@ -904,8 +942,8 @@ namespace rct {
addKeys(sumOutpks, txnFeeKey, sumOutpks);
key sumPseudoOuts = identity();
- for (size_t i = 0 ; i < rv.pseudoOuts.size() ; i++) {
- addKeys(sumPseudoOuts, sumPseudoOuts, rv.pseudoOuts[i]);
+ for (size_t i = 0 ; i < pseudoOuts.size() ; i++) {
+ addKeys(sumPseudoOuts, sumPseudoOuts, pseudoOuts[i]);
}
DP(sumPseudoOuts);
@@ -935,13 +973,13 @@ namespace rct {
}
}
else {
- const key message = get_pre_mlsag_hash(rv);
+ const key message = get_pre_mlsag_hash(rv, hw::get_device("default"));
results.clear();
results.resize(rv.mixRing.size());
for (size_t i = 0 ; i < rv.mixRing.size() ; i++) {
tpool.submit(&waiter, [&, i] {
- results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], rv.pseudoOuts[i]);
+ results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]);
});
}
waiter.wait();
@@ -979,14 +1017,14 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
- xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) {
+ xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) {
CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
//mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i];
- ecdhDecode(ecdh_info, sk);
+ ecdhDecode(ecdh_info, sk, hwdev);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
@@ -1002,19 +1040,19 @@ namespace rct {
return h2d(amount);
}
- xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) {
+ xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) {
key mask;
- return decodeRct(rv, sk, i, mask);
+ return decodeRct(rv, sk, i, mask, hwdev);
}
- xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) {
+ xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig");
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
//mask amount and mask
ecdhTuple ecdh_info = rv.ecdhInfo[i];
- ecdhDecode(ecdh_info, sk);
+ ecdhDecode(ecdh_info, sk, hwdev);
mask = ecdh_info.mask;
key amount = ecdh_info.amount;
key C = rv.outPk[i].mask;
@@ -1030,9 +1068,9 @@ namespace rct {
return h2d(amount);
}
- xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) {
+ xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) {
key mask;
- return decodeRctSimple(rv, sk, i, mask);
+ return decodeRctSimple(rv, sk, i, mask, hwdev);
}
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) {
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index e83083a98..17047fc0f 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -50,6 +50,8 @@ extern "C" {
#include "rctTypes.h"
#include "rctOps.h"
+#include "cryptonote_basic/cryptonote_basic.h"
+#include "device/device_declare.hpp"
//Define this flag when debugging to get additional info on the console
#ifdef DBG
@@ -73,7 +75,7 @@ namespace rct {
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
keyV keyImageV(const keyV &xx);
- mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows);
+ mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev);
bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows);
//mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
@@ -95,8 +97,8 @@ namespace rct {
// this shows that sum inputs = sum outputs
//Ver:
// verifies the above sig is created corretly
- mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message);
- mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index);
+ mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message, hw::device &hwdev);
+ mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev);
bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message);
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C);
@@ -118,18 +120,18 @@ namespace rct {
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
- rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof);
- rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin);
- rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin);
- rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof);
+ rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev);
+ rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev);
+ rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev);
+ rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev);
bool verRct(const rctSig & rv, bool semantics);
static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); }
bool verRctSimple(const rctSig & rv, bool semantics);
static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); }
- xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask);
- xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i);
- xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask);
- xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i);
+ xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev);
+ xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev);
+ xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev);
+ xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev);
bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key);
}
diff --git a/src/ringct/rctTypes.cpp b/src/ringct/rctTypes.cpp
index 1526dcf7c..5650b3ba1 100644
--- a/src/ringct/rctTypes.cpp
+++ b/src/ringct/rctTypes.cpp
@@ -178,6 +178,7 @@ namespace rct {
}
while (i < 8 * (j + 1)) {
amountb2[i] = 0;
+ i++;
}
}
}
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 2df797360..eba1e3d93 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -246,7 +246,7 @@ namespace rct {
// inputs/outputs not saved, only here for serialization help
// FIELD(message) - not serialized, it can be reconstructed
// FIELD(mixRing) - not serialized, it can be reconstructed
- if (type == RCTTypeSimple || type == RCTTypeSimpleBulletproof)
+ if (type == RCTTypeSimple) // moved to prunable with bulletproofs
{
ar.tag("pseudoOuts");
ar.begin_array();
@@ -294,6 +294,7 @@ namespace rct {
std::vector<rangeSig> rangeSigs;
std::vector<Bulletproof> bulletproofs;
std::vector<mgSig> MGs; // simple rct has N, full has 1
+ keyV pseudoOuts; //C - for simple rct
template<bool W, template <bool> class Archive>
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
@@ -381,6 +382,21 @@ namespace rct {
ar.delimit_array();
}
ar.end_array();
+ if (type == RCTTypeSimpleBulletproof)
+ {
+ ar.tag("pseudoOuts");
+ ar.begin_array();
+ PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
+ if (pseudoOuts.size() != inputs)
+ return false;
+ for (size_t i = 0; i < inputs; ++i)
+ {
+ FIELDS(pseudoOuts[i])
+ if (inputs - i > 1)
+ ar.delimit_array();
+ }
+ ar.end_array();
+ }
return true;
}
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 140094faa..a8d801ac7 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -42,6 +42,7 @@ using namespace epee;
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "misc_language.h"
+#include "storages/http_abstract_invoke.h"
#include "crypto/hash.h"
#include "rpc/rpc_args.h"
#include "core_rpc_server_error_codes.h"
@@ -72,9 +73,9 @@ namespace cryptonote
{
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_rpc_restricted_bind_port);
- command_line::add_arg(desc, arg_testnet_rpc_bind_port);
- command_line::add_arg(desc, arg_testnet_rpc_restricted_bind_port);
command_line::add_arg(desc, arg_restricted_rpc);
+ command_line::add_arg(desc, arg_bootstrap_daemon_address);
+ command_line::add_arg(desc, arg_bootstrap_daemon_login);
cryptonote::rpc_args::init_options(desc);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -101,6 +102,30 @@ namespace cryptonote
if (!rpc_config)
return false;
+ m_bootstrap_daemon_address = command_line::get_arg(vm, arg_bootstrap_daemon_address);
+ if (!m_bootstrap_daemon_address.empty())
+ {
+ const std::string &bootstrap_daemon_login = command_line::get_arg(vm, arg_bootstrap_daemon_login);
+ const auto loc = bootstrap_daemon_login.find(':');
+ if (!bootstrap_daemon_login.empty() && loc != std::string::npos)
+ {
+ epee::net_utils::http::login login;
+ login.username = bootstrap_daemon_login.substr(0, loc);
+ login.password = bootstrap_daemon_login.substr(loc + 1);
+ m_http_client.set_server(m_bootstrap_daemon_address, login, false);
+ }
+ else
+ {
+ m_http_client.set_server(m_bootstrap_daemon_address, boost::none, false);
+ }
+ m_should_use_bootstrap_daemon = true;
+ }
+ else
+ {
+ m_should_use_bootstrap_daemon = false;
+ }
+ m_was_bootstrap_ever_used = false;
+
boost::optional<epee::net_utils::http::login> http_login{};
if (rpc_config->login)
@@ -126,6 +151,10 @@ namespace cryptonote
bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res)
{
PERF_TIMER(on_get_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HEIGHT>(invoke_http_mode::JON, "/getheight", req, res, r))
+ return r;
+
res.height = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -134,6 +163,17 @@ namespace cryptonote
bool core_rpc_server::on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res)
{
PERF_TIMER(on_get_info);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON, "/getinfo", req, res, r))
+ {
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
+ ++res.height_without_bootstrap; // turn top block height into blockchain height
+ res.was_bootstrap_ever_used = true;
+ return r;
+ }
+
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
@@ -158,6 +198,12 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ res.height_without_bootstrap = res.height;
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
+ }
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -181,6 +227,10 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res)
{
PERF_TIMER(on_get_blocks);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_FAST>(invoke_http_mode::BIN, "/getblocks.bin", req, res, r))
+ return r;
+
std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > > bs;
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
@@ -240,6 +290,10 @@ namespace cryptonote
bool core_rpc_server::on_get_alt_blocks_hashes(const COMMAND_RPC_GET_ALT_BLOCKS_HASHES::request& req, COMMAND_RPC_GET_ALT_BLOCKS_HASHES::response& res)
{
PERF_TIMER(on_get_alt_blocks_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_ALT_BLOCKS_HASHES>(invoke_http_mode::JON, "/get_alt_blocks_hashes", req, res, r))
+ return r;
+
std::list<block> blks;
if(!m_core.get_alternative_blocks(blks))
@@ -263,6 +317,10 @@ namespace cryptonote
bool core_rpc_server::on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res)
{
PERF_TIMER(on_get_blocks_by_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCKS_BY_HEIGHT>(invoke_http_mode::BIN, "/getblocks_by_height.bin", req, res, r))
+ return r;
+
res.status = "Failed";
res.blocks.clear();
res.blocks.reserve(req.heights.size());
@@ -293,6 +351,10 @@ namespace cryptonote
bool core_rpc_server::on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res)
{
PERF_TIMER(on_get_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
+ return r;
+
NOTIFY_RESPONSE_CHAIN_ENTRY::request resp;
resp.start_height = req.start_height;
@@ -312,6 +374,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)
{
PERF_TIMER(on_get_random_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS>(invoke_http_mode::BIN, "/getrandom_outs.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -351,6 +417,10 @@ namespace cryptonote
bool core_rpc_server::on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res)
{
PERF_TIMER(on_get_outs_bin);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS_BIN>(invoke_http_mode::BIN, "/get_outs.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -374,6 +444,10 @@ namespace cryptonote
bool core_rpc_server::on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res)
{
PERF_TIMER(on_get_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUTS>(invoke_http_mode::JON, "/get_outs", req, res, r))
+ return r;
+
res.status = "Failed";
if (m_restricted)
@@ -412,6 +486,10 @@ namespace cryptonote
bool core_rpc_server::on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res)
{
PERF_TIMER(on_get_random_rct_outs);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS>(invoke_http_mode::BIN, "/getrandom_rctouts.bin", req, res, r))
+ return r;
+
res.status = "Failed";
if(!m_core.get_random_rct_outs(req, res))
{
@@ -436,6 +514,10 @@ namespace cryptonote
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res)
{
PERF_TIMER(on_get_indexes);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES>(invoke_http_mode::BIN, "/get_o_indexes.bin", req, res, ok))
+ return ok;
+
bool r = m_core.get_tx_outputs_gindexs(req.txid, res.o_indexes);
if(!r)
{
@@ -450,6 +532,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res)
{
PERF_TIMER(on_get_transactions);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTIONS>(invoke_http_mode::JON, "/gettransactions", req, res, ok))
+ return ok;
+
std::vector<crypto::hash> vh;
for(const auto& tx_hex_str: req.txs_hashes)
{
@@ -600,6 +686,10 @@ namespace cryptonote
bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_is_key_image_spent);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_IS_KEY_IMAGE_SPENT>(invoke_http_mode::JON, "/is_key_image_spent", req, res, ok))
+ return ok;
+
std::vector<crypto::key_image> key_images;
for(const auto& ki_hex_str: req.key_images)
{
@@ -663,6 +753,10 @@ namespace cryptonote
bool core_rpc_server::on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res)
{
PERF_TIMER(on_send_raw_tx);
+ bool ok;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_SEND_RAW_TX>(invoke_http_mode::JON, "/sendrawtransaction", req, res, ok))
+ return ok;
+
CHECK_CORE_READY();
std::string tx_blob;
@@ -886,6 +980,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL>(invoke_http_mode::JON, "/get_transaction_pool", req, res, r))
+ return r;
+
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -894,6 +992,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_hashes);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r))
+ return r;
+
m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -902,6 +1004,10 @@ namespace cryptonote
bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_stats);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_STATS>(invoke_http_mode::JON, "/get_transaction_pool_stats", req, res, r))
+ return r;
+
m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -920,6 +1026,14 @@ namespace cryptonote
bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res)
{
PERF_TIMER(on_getblockcount);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res.status = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
res.count = m_core.get_current_blockchain_height();
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -928,6 +1042,14 @@ namespace cryptonote
bool core_rpc_server::on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_getblockhash);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
if(req.size() != 1)
{
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
@@ -964,6 +1086,10 @@ namespace cryptonote
bool core_rpc_server::on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_getblocktemplate);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GETBLOCKTEMPLATE>(invoke_http_mode::JON_RPC, "getblocktemplate", req, res, r))
+ return r;
+
if(!check_core_ready())
{
error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY;
@@ -1039,6 +1165,14 @@ namespace cryptonote
bool core_rpc_server::on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_submitblock);
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (m_should_use_bootstrap_daemon)
+ {
+ res.status = "This command is unsupported for bootstrap daemon";
+ return false;
+ }
+ }
CHECK_CORE_READY();
if(req.size()!=1)
{
@@ -1112,9 +1246,80 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ template <typename COMMAND_TYPE>
+ 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;
+ if (m_bootstrap_daemon_address.empty())
+ return false;
+
+ boost::unique_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ if (!m_should_use_bootstrap_daemon)
+ {
+ MINFO("The local daemon is fully synced. Not switching back to the bootstrap daemon");
+ return false;
+ }
+
+ auto current_time = std::chrono::system_clock::now();
+ if (current_time - m_bootstrap_height_check_time > std::chrono::seconds(30)) // update every 30s
+ {
+ m_bootstrap_height_check_time = current_time;
+
+ uint64_t top_height;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(top_height, top_hash);
+ ++top_height; // turn top block height into blockchain height
+
+ // query bootstrap daemon's height
+ cryptonote::COMMAND_RPC_GET_HEIGHT::request getheight_req;
+ cryptonote::COMMAND_RPC_GET_HEIGHT::response getheight_res;
+ bool ok = epee::net_utils::invoke_http_json("/getheight", getheight_req, getheight_res, m_http_client);
+ ok = ok && getheight_res.status == CORE_RPC_STATUS_OK;
+
+ m_should_use_bootstrap_daemon = ok && top_height + 10 < getheight_res.height;
+ MINFO((m_should_use_bootstrap_daemon ? "Using" : "Not using") << " the bootstrap daemon (our height: " << top_height << ", bootstrap daemon's height: " << getheight_res.height << ")");
+ }
+ if (!m_should_use_bootstrap_daemon)
+ return false;
+
+ if (mode == invoke_http_mode::JON)
+ {
+ r = epee::net_utils::invoke_http_json(command_name, req, res, m_http_client);
+ }
+ else if (mode == invoke_http_mode::BIN)
+ {
+ r = epee::net_utils::invoke_http_bin(command_name, req, res, m_http_client);
+ }
+ else if (mode == invoke_http_mode::JON_RPC)
+ {
+ epee::json_rpc::request<typename COMMAND_TYPE::request> json_req = AUTO_VAL_INIT(json_req);
+ epee::json_rpc::response<typename COMMAND_TYPE::response, std::string> json_resp = AUTO_VAL_INIT(json_resp);
+ json_req.jsonrpc = "2.0";
+ json_req.id = epee::serialization::storage_entry(0);
+ json_req.method = command_name;
+ json_req.params = req;
+ r = net_utils::invoke_http_json("/json_rpc", json_req, json_resp, m_http_client);
+ if (r)
+ res = json_resp.result;
+ }
+ else
+ {
+ MERROR("Unknown invoke_http_mode: " << mode);
+ return false;
+ }
+ m_was_bootstrap_ever_used = true;
+ r = r && res.status == CORE_RPC_STATUS_OK;
+ res.untrusted = true;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_last_block_header);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LAST_BLOCK_HEADER>(invoke_http_mode::JON_RPC, "getlastblockheader", req, res, r))
+ return r;
+
CHECK_CORE_READY();
uint64_t last_block_height;
crypto::hash last_block_hash;
@@ -1140,6 +1345,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_header_by_hash);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH>(invoke_http_mode::JON_RPC, "getblockheaderbyhash", req, res, r))
+ return r;
+
crypto::hash block_hash;
bool hash_parsed = parse_hash256(req.hash, block_hash);
if(!hash_parsed)
@@ -1177,6 +1386,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_headers_range(const COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request& req, COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_headers_range);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADERS_RANGE>(invoke_http_mode::JON_RPC, "getblockheadersrange", req, res, r))
+ return r;
+
const uint64_t bc_height = m_core.get_current_blockchain_height();
if (req.start_height >= bc_height || req.end_height >= bc_height || req.start_height > req.end_height)
{
@@ -1223,6 +1436,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block_header_by_height);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT>(invoke_http_mode::JON_RPC, "getblockheaderbyheight", req, res, r))
+ return r;
+
if(m_core.get_current_blockchain_height() <= req.height)
{
error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT;
@@ -1251,6 +1468,10 @@ namespace cryptonote
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_block(const COMMAND_RPC_GET_BLOCK::request& req, COMMAND_RPC_GET_BLOCK::response& res, epee::json_rpc::error& error_resp){
PERF_TIMER(on_get_block);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_BLOCK>(invoke_http_mode::JON_RPC, "getblock", req, res, r))
+ return r;
+
crypto::hash block_hash;
if (!req.hash.empty())
{
@@ -1320,6 +1541,16 @@ namespace cryptonote
bool core_rpc_server::on_get_info_json(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_info_json);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_INFO>(invoke_http_mode::JON_RPC, "get_info", req, res, r))
+ {
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ crypto::hash top_hash;
+ m_core.get_blockchain_top(res.height_without_bootstrap, top_hash);
+ ++res.height_without_bootstrap; // turn top block height into blockchain height
+ res.was_bootstrap_ever_used = true;
+ return r;
+ }
crypto::hash top_hash;
m_core.get_blockchain_top(res.height, top_hash);
@@ -1345,12 +1576,21 @@ namespace cryptonote
res.start_time = (uint64_t)m_core.get_start_time();
res.free_space = m_restricted ? std::numeric_limits<uint64_t>::max() : m_core.get_free_space();
res.offline = m_core.offline();
+ res.bootstrap_daemon_address = m_bootstrap_daemon_address;
+ res.height_without_bootstrap = res.height;
+ {
+ boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex);
+ res.was_bootstrap_ever_used = m_was_bootstrap_ever_used;
+ }
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_hard_fork_info(const COMMAND_RPC_HARD_FORK_INFO::request& req, COMMAND_RPC_HARD_FORK_INFO::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_hard_fork_info);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_HARD_FORK_INFO>(invoke_http_mode::JON_RPC, "hard_fork_info", req, res, r))
+ return r;
const Blockchain &blockchain = m_core.get_blockchain_storage();
uint8_t version = req.version > 0 ? req.version : blockchain.get_next_hard_fork_version();
@@ -1473,6 +1713,9 @@ namespace cryptonote
bool core_rpc_server::on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_output_histogram);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_HISTOGRAM>(invoke_http_mode::JON_RPC, "get_output_histogram", req, res, r))
+ return r;
std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> histogram;
try
@@ -1500,6 +1743,10 @@ namespace cryptonote
bool core_rpc_server::on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_version);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_VERSION>(invoke_http_mode::JON_RPC, "get_version", req, res, r))
+ return r;
+
res.version = CORE_RPC_VERSION;
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1518,6 +1765,10 @@ namespace cryptonote
bool core_rpc_server::on_get_per_kb_fee_estimate(const COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request& req, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_per_kb_fee_estimate);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE>(invoke_http_mode::JON_RPC, "get_fee_estimate", req, res, r))
+ return r;
+
res.fee = m_core.get_blockchain_storage().get_dynamic_per_kb_fee_estimate(req.grace_blocks);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -1545,6 +1796,10 @@ namespace cryptonote
bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res)
{
PERF_TIMER(on_get_limit);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_LIMIT>(invoke_http_mode::JON, "/get_limit", req, res, r))
+ return r;
+
res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit();
res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit();
res.status = CORE_RPC_STATUS_OK;
@@ -1596,9 +1851,21 @@ namespace cryptonote
PERF_TIMER(on_out_peers);
size_t n_connections = m_p2p.get_outgoing_connections_count();
size_t n_delete = (n_connections > req.out_peers) ? n_connections - req.out_peers : 0;
- m_p2p.m_config.m_net_config.connections_count = req.out_peers;
+ m_p2p.m_config.m_net_config.max_out_connection_count = req.out_peers;
+ if (n_delete)
+ m_p2p.delete_out_connections(n_delete);
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res)
+ {
+ PERF_TIMER(on_in_peers);
+ size_t n_connections = m_p2p.get_incoming_connections_count();
+ size_t n_delete = (n_connections > req.in_peers) ? n_connections - req.in_peers : 0;
+ m_p2p.m_config.m_net_config.max_in_connection_count = req.in_peers;
if (n_delete)
- m_p2p.delete_connections(n_delete);
+ m_p2p.delete_in_connections(n_delete);
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -1790,6 +2057,9 @@ namespace cryptonote
bool core_rpc_server::on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp)
{
PERF_TIMER(on_get_txpool_backlog);
+ bool r;
+ if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG>(invoke_http_mode::JON_RPC, "get_txpool_backlog", req, res, r))
+ return r;
if (!m_core.get_txpool_backlog(res.backlog))
{
@@ -1803,10 +2073,16 @@ namespace cryptonote
}
//------------------------------------------------------------------------------------------------------------------------------
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_bind_port = {
+ const command_line::arg_descriptor<std::string, false, true> core_rpc_server::arg_rpc_bind_port = {
"rpc-bind-port"
, "Port for RPC server"
, std::to_string(config::RPC_DEFAULT_PORT)
+ , cryptonote::arg_testnet_on
+ , [](bool testnet, bool defaulted, std::string val) {
+ if (testnet && defaulted)
+ return std::to_string(config::testnet::RPC_DEFAULT_PORT);
+ return val;
+ }
};
const command_line::arg_descriptor<std::string> core_rpc_server::arg_rpc_restricted_bind_port = {
@@ -1815,21 +2091,21 @@ namespace cryptonote
, ""
};
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_testnet_rpc_bind_port = {
- "testnet-rpc-bind-port"
- , "Port for testnet RPC server"
- , std::to_string(config::testnet::RPC_DEFAULT_PORT)
+ const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = {
+ "restricted-rpc"
+ , "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
+ , false
};
- const command_line::arg_descriptor<std::string> core_rpc_server::arg_testnet_rpc_restricted_bind_port = {
- "testnet-rpc-restricted-bind-port"
- , "Port for testnet restricted RPC server"
+ const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_address = {
+ "bootstrap-daemon-address"
+ , "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced"
, ""
};
- const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = {
- "restricted-rpc"
- , "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
- , false
+ const command_line::arg_descriptor<std::string> core_rpc_server::arg_bootstrap_daemon_login = {
+ "bootstrap-daemon-login"
+ , "Specify username:password for the bootstrap daemon login"
+ , ""
};
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 0c7028719..3c57a6016 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -34,6 +34,7 @@
#include <boost/program_options/variables_map.hpp>
#include "net/http_server_impl_base.h"
+#include "net/http_client.h"
#include "core_rpc_server_commands_defs.h"
#include "cryptonote_core/cryptonote_core.h"
#include "p2p/net_node.h"
@@ -52,11 +53,11 @@ namespace cryptonote
{
public:
- static const command_line::arg_descriptor<std::string> arg_rpc_bind_port;
+ static const command_line::arg_descriptor<std::string, false, true> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_rpc_restricted_bind_port;
- static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port;
- static const command_line::arg_descriptor<std::string> arg_testnet_rpc_restricted_bind_port;
static const command_line::arg_descriptor<bool> arg_restricted_rpc;
+ static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_address;
+ static const command_line::arg_descriptor<std::string> arg_bootstrap_daemon_login;
typedef epee::net_utils::connection_context_base connection_context;
@@ -114,6 +115,7 @@ namespace cryptonote
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)
+ MAP_URI_AUTO_JON2_IF("/in_peers", on_in_peers, COMMAND_RPC_IN_PEERS, !m_restricted)
MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2("/get_outs", on_get_outs, COMMAND_RPC_GET_OUTPUTS)
@@ -170,7 +172,7 @@ namespace cryptonote
bool on_get_outs_bin(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res);
bool on_get_outs(const COMMAND_RPC_GET_OUTPUTS::request& req, COMMAND_RPC_GET_OUTPUTS::response& res);
bool on_get_random_rct_outs(const COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::request& req, COMMAND_RPC_GET_RANDOM_RCT_OUTPUTS::response& res);
- bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
+ bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res);
bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res);
bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res);
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res);
@@ -183,6 +185,7 @@ namespace cryptonote
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res);
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res);
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res);
+ bool on_in_peers(const COMMAND_RPC_IN_PEERS::request& req, COMMAND_RPC_IN_PEERS::response& res);
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res);
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
bool on_update(const COMMAND_RPC_UPDATE::request& req, COMMAND_RPC_UPDATE::response& res);
@@ -220,9 +223,18 @@ private:
//utils
uint64_t get_block_reward(const block& blk);
bool fill_block_header_response(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_response& response);
+ enum invoke_http_mode { JON, BIN, JON_RPC };
+ template <typename COMMAND_TYPE>
+ bool 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);
core& m_core;
nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p;
+ std::string m_bootstrap_daemon_address;
+ epee::net_utils::http::http_simple_client m_http_client;
+ boost::shared_mutex m_bootstrap_daemon_mutex;
+ bool m_should_use_bootstrap_daemon;
+ std::chrono::system_clock::time_point m_bootstrap_height_check_time;
+ bool m_was_bootstrap_ever_used;
bool m_testnet;
bool m_restricted;
};
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 9b9a8f949..64a97f8a3 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -65,10 +65,12 @@ namespace cryptonote
{
uint64_t height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -113,6 +115,7 @@ namespace cryptonote
uint64_t current_height;
std::string status;
std::vector<block_output_indices> output_indices;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
@@ -120,6 +123,7 @@ namespace cryptonote
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
KV_SERIALIZE(output_indices)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -138,10 +142,12 @@ namespace cryptonote
{
std::vector<block_complete_entry> blocks;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blocks)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -158,10 +164,12 @@ namespace cryptonote
{
std::vector<std::string> blks_hashes;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(blks_hashes)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -184,12 +192,14 @@ namespace cryptonote
uint64_t start_height;
uint64_t current_height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_block_ids)
KV_SERIALIZE(start_height)
KV_SERIALIZE(current_height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -595,6 +605,7 @@ namespace cryptonote
// new style
std::vector<entry> txs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txs_as_hex)
@@ -602,6 +613,7 @@ namespace cryptonote
KV_SERIALIZE(txs)
KV_SERIALIZE(missed_tx)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -629,10 +641,12 @@ namespace cryptonote
{
std::vector<int> spent_status;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(spent_status)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -653,9 +667,11 @@ namespace cryptonote
{
std::vector<uint64_t> o_indexes;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(o_indexes)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -695,9 +711,11 @@ namespace cryptonote
{
std::vector<outs_for_amount> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -745,10 +763,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -785,10 +805,12 @@ namespace cryptonote
{
std::vector<outkey> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -817,9 +839,11 @@ namespace cryptonote
{
std::list<out_entry> outs;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(outs)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -854,6 +878,7 @@ namespace cryptonote
bool overspend;
bool fee_too_low;
bool not_rct;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -867,6 +892,7 @@ namespace cryptonote
KV_SERIALIZE(overspend)
KV_SERIALIZE(fee_too_low)
KV_SERIALIZE(not_rct)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -930,6 +956,10 @@ namespace cryptonote
uint64_t start_time;
uint64_t free_space;
bool offline;
+ bool untrusted;
+ std::string bootstrap_daemon_address;
+ uint64_t height_without_bootstrap;
+ bool was_bootstrap_ever_used;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
@@ -953,6 +983,10 @@ namespace cryptonote
KV_SERIALIZE(start_time)
KV_SERIALIZE(free_space)
KV_SERIALIZE(offline)
+ KV_SERIALIZE(untrusted)
+ KV_SERIALIZE(bootstrap_daemon_address)
+ KV_SERIALIZE(height_without_bootstrap)
+ KV_SERIALIZE(was_bootstrap_ever_used)
END_KV_SERIALIZE_MAP()
};
};
@@ -1080,6 +1114,7 @@ namespace cryptonote
blobdata blocktemplate_blob;
blobdata blockhashing_blob;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(difficulty)
@@ -1090,6 +1125,7 @@ namespace cryptonote
KV_SERIALIZE(blocktemplate_blob)
KV_SERIALIZE(blockhashing_blob)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1153,10 +1189,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1177,10 +1215,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1201,10 +1241,12 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1231,6 +1273,7 @@ namespace cryptonote
std::vector<std::string> tx_hashes;
std::string blob;
std::string json;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
@@ -1239,6 +1282,7 @@ namespace cryptonote
KV_SERIALIZE(status)
KV_SERIALIZE(blob)
KV_SERIALIZE(json)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
@@ -1415,11 +1459,13 @@ namespace cryptonote
std::string status;
std::vector<tx_info> transactions;
std::vector<spent_key_image_info> spent_key_images;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(transactions)
KV_SERIALIZE(spent_key_images)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1436,10 +1482,12 @@ namespace cryptonote
{
std::string status;
std::vector<crypto::hash> tx_hashes;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(tx_hashes)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1463,10 +1511,12 @@ namespace cryptonote
{
std::string status;
std::vector<tx_backlog_entry> backlog;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(backlog)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1527,10 +1577,12 @@ namespace cryptonote
{
std::string status;
txpool_stats pool_stats;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(pool_stats)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1573,10 +1625,12 @@ namespace cryptonote
{
std::string status;
std::vector<block_header_response> headers;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(headers)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1630,11 +1684,13 @@ namespace cryptonote
std::string status;
uint64_t limit_up;
uint64_t limit_down;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(limit_up)
KV_SERIALIZE(limit_down)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1678,8 +1734,28 @@ namespace cryptonote
struct response
{
- std::string status;
-
+ std::string status;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_IN_PEERS
+ {
+ struct request
+ {
+ uint64_t in_peers;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(in_peers)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()
@@ -1744,6 +1820,7 @@ namespace cryptonote
uint32_t state;
uint64_t earliest_height;
std::string status;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(version)
@@ -1755,6 +1832,7 @@ namespace cryptonote
KV_SERIALIZE(state)
KV_SERIALIZE(earliest_height)
KV_SERIALIZE(status)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1891,10 +1969,12 @@ namespace cryptonote
{
std::string status;
std::vector<entry> histogram;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(histogram)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1911,10 +1991,12 @@ namespace cryptonote
{
std::string status;
uint32_t version;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(version)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
@@ -1961,10 +2043,12 @@ namespace cryptonote
{
std::string status;
uint64_t fee;
+ bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(fee)
+ KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index 6559db9b2..d4a6138ba 100644
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -37,7 +37,7 @@
namespace cryptonote
{
rpc_args::descriptors::descriptors()
- : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify ip to bind rpc server"), "127.0.0.1"})
+ : rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify IP to bind RPC server"), "127.0.0.1"})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
, rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h
index 79c6c753c..f47a4494d 100644
--- a/src/serialization/binary_archive.h
+++ b/src/serialization/binary_archive.h
@@ -82,7 +82,7 @@ protected:
/* \struct binary_archive
*
- * \brief the actualy binary archive type
+ * \brief the actually binary archive type
*
* \detailed The boolean template argument /a W is the is_saving
* parameter for binary_archive_base.
diff --git a/src/serialization/variant.h b/src/serialization/variant.h
index 31d903d55..1d00ab461 100644
--- a/src/serialization/variant.h
+++ b/src/serialization/variant.h
@@ -87,7 +87,7 @@ struct variant_reader
};
// This one just fails when you call it.... okay
-// So the TEnd parameter must be specified/differnt from TBegin
+// So the TEnd parameter must be specified/different from TBegin
template <class Archive, class Variant, class TBegin>
struct variant_reader<Archive, Variant, TBegin, TBegin>
{
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a6cef1bb9..3c940bfef 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -62,6 +62,7 @@
#include "ringct/rctSigs.h"
#include "multisig/multisig.h"
#include "wallet/wallet_args.h"
+#include "device/device.hpp"
#include <stdexcept>
#ifdef HAVE_READLINE
@@ -113,6 +114,7 @@ namespace
const std::array<const char* const, 5> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}};
const auto arg_wallet_file = wallet_args::arg_wallet_file();
const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""};
+ const command_line::arg_descriptor<std::string> arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to <arg>"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""};
const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""};
@@ -158,7 +160,7 @@ namespace
boost::optional<tools::password_container> default_password_prompter(bool verify)
{
- return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify);
+ return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify);
}
inline std::string interpret_rpc_response(bool ok, const std::string& status)
@@ -397,6 +399,7 @@ namespace
{
writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second;
}
+ writer << tr("Please use sweep_unmixable.");
}
catch (const tools::error::tx_not_constructed&)
{
@@ -508,7 +511,11 @@ bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector
{
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
// don't log
- std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl;
+ if (m_wallet->key_on_device()) {
+ std::cout << "secret: On device. Not available" << std::endl;
+ } else {
+ std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl;
+ }
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl;
return true;
@@ -523,7 +530,11 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
}
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
// don't log
- std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl;
+ if (m_wallet->key_on_device()) {
+ std::cout << "secret: On device. Not available" << std::endl;
+ } else {
+ std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl;
+ }
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl;
return true;
@@ -535,6 +546,11 @@ bool simple_wallet::print_seed(bool encrypted)
std::string seed;
bool ready, multisig;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (m_wallet->watch_only())
{
fail_msg_writer() << tr("wallet is watch-only and has no seed");
@@ -597,6 +613,11 @@ bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std:
bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (m_wallet->multisig())
{
fail_msg_writer() << tr("wallet is multisig and has no seed");
@@ -638,6 +659,8 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
// prompts for a new password, pass true to verify the password
const auto pwd_container = default_password_prompter(true);
+ if(!pwd_container)
+ return true;
try
{
@@ -723,6 +746,11 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std:
bool simple_wallet::prepare_multisig(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (m_wallet->multisig())
{
fail_msg_writer() << tr("This wallet is already multisig");
@@ -756,6 +784,11 @@ bool simple_wallet::prepare_multisig(const std::vector<std::string> &args)
bool simple_wallet::make_multisig(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (m_wallet->multisig())
{
fail_msg_writer() << tr("This wallet is already multisig");
@@ -816,7 +849,11 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
}
uint32_t total;
- m_wallet->multisig(NULL, &threshold, &total);
+ if (!m_wallet->multisig(NULL, &threshold, &total))
+ {
+ fail_msg_writer() << tr("Error creating multisig: new wallet is not multisig");
+ return true;
+ }
success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ")
<< m_wallet->get_account().get_public_address_str(m_wallet->testnet());
@@ -826,6 +863,11 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args)
bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
{
bool ready;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_wallet->multisig(&ready))
{
fail_msg_writer() << tr("This wallet is not multisig");
@@ -870,6 +912,11 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args)
bool simple_wallet::export_multisig(const std::vector<std::string> &args)
{
bool ready;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_wallet->multisig(&ready))
{
fail_msg_writer() << tr("This wallet is not multisig");
@@ -917,6 +964,11 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
{
bool ready;
uint32_t threshold, total;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_wallet->multisig(&ready, &threshold, &total))
{
fail_msg_writer() << tr("This wallet is not multisig");
@@ -991,6 +1043,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs)
bool simple_wallet::sign_multisig(const std::vector<std::string> &args)
{
bool ready;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if(!m_wallet->multisig(&ready))
{
fail_msg_writer() << tr("This is not a multisig wallet");
@@ -1059,6 +1116,11 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
{
bool ready;
uint32_t threshold;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_wallet->multisig(&ready, &threshold))
{
fail_msg_writer() << tr("This is not a multisig wallet");
@@ -1121,6 +1183,11 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args)
{
bool ready;
uint32_t threshold;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_wallet->multisig(&ready, &threshold))
{
fail_msg_writer() << tr("This is not a multisig wallet");
@@ -1293,7 +1360,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
priority = boost::lexical_cast<int>(args[1]);
if (priority < 1 || priority > 4)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3,or 4");
+ fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
return true;
}
}
@@ -1308,7 +1375,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
catch(const boost::bad_lexical_cast &)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2 3,or 4");
+ fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
return true;
}
catch(...)
@@ -1589,14 +1656,14 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("transfer_original",
boost::bind(&simple_wallet::transfer, this, _1),
tr("transfer_original [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1),
tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::locked_transfer, this, _1),
tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]"),
- tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));
@@ -2058,12 +2125,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (!handle_command_line(vm))
return false;
- if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1)
+ if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1)
{
- fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\" and --generate-from-json=\"jsonfilename\"");
+ fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\"");
return false;
}
- else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty())
+ else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty())
{
if(!ask_wallet_create_if_needed()) return false;
}
@@ -2400,7 +2467,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
// get N secret spend keys from user
for(unsigned int i=0; i<multisig_n; ++i)
{
- spendkey_string = input_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+i) % multisig_m).str().c_str()));
+ spendkey_string = input_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+1) % multisig_m).str().c_str()));
if (std::cin.eof())
return false;
if (spendkey_string.empty())
@@ -2460,6 +2527,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (!m_wallet)
return false;
}
+ else if (!m_generate_from_device.empty())
+ {
+ m_wallet_file = m_generate_from_device;
+ // create wallet
+ bool r = new_wallet(vm, "Ledger");
+ CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
+ }
else
{
if (m_generate_new.empty()) {
@@ -2474,7 +2548,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
- if (!m_restore_height && m_restoring)
+ if (!m_wallet->explicit_refresh_from_block_height() && m_restoring)
{
uint32_t version;
bool connected = try_connect_to_daemon(false, &version);
@@ -2515,7 +2589,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
try
{
year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
- // lexical_cast<uint8_t> won't work becasue uint8_t is treated as character type
+ // lexical_cast<uint8_t> won't work because uint8_t is treated as character type
month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
@@ -2594,6 +2668,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
{
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet);
+ m_generate_from_device = command_line::get_arg(vm, arg_generate_from_device);
m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key);
m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key);
m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys);
@@ -2613,6 +2688,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
!m_generate_from_keys.empty() ||
!m_generate_from_multisig_keys.empty() ||
!m_generate_from_json.empty() ||
+ !m_generate_from_device.empty() ||
m_restore_deterministic_wallet ||
m_restore_multisig_wallet;
@@ -2672,12 +2748,12 @@ std::string simple_wallet::get_mnemonic_language()
if (!((language_number >= 0) && (static_cast<unsigned int>(language_number) < language_list.size())))
{
language_number = -1;
- fail_msg_writer() << tr("invalid language choice passed. Please try again.\n");
+ fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
}
}
catch (const std::exception &e)
{
- fail_msg_writer() << tr("invalid language choice passed. Please try again.\n");
+ fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
}
}
return language_list[language_number];
@@ -2813,6 +2889,33 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
return true;
}
+
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const std::string &device_name) {
+ auto rc = tools::wallet2::make_new(vm, password_prompter);
+ m_wallet = std::move(rc.first);
+ if (!m_wallet)
+ {
+ return false;
+ }
+ if (m_restore_height)
+ m_wallet->set_refresh_from_block_height(m_restore_height);
+
+ try
+ {
+ m_wallet->restore(m_wallet_file, std::move(rc.second).password(), device_name);
+ message_writer(console_color_white, true) << tr("Generated new on device wallet: ")
+ << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
+ return false;
+ }
+
+ return true;
+}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const std::string &multisig_keys, const std::string &old_language)
@@ -2886,6 +2989,9 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
prefix = tr("Opened wallet");
message_writer(console_color_white, true) <<
prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ if (m_wallet->get_account().get_device()) {
+ message_writer(console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name();
+ }
// If the wallet file is deprecated, we should ask for mnemonic language again and store
// everything in the new format.
// NOTE: this is_deprecated() refers to the wallet file format before becoming JSON. It does not refer to the "old english" seed words form of "deprecated" used elsewhere.
@@ -3080,6 +3186,7 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args)
fail_msg_writer() << tr("wallet is null");
return true;
}
+
COMMAND_RPC_STOP_MINING::request req;
COMMAND_RPC_STOP_MINING::response res;
bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client);
@@ -3187,14 +3294,6 @@ void simple_wallet::on_money_spent(uint64_t height, const crypto::hash &txid, co
//----------------------------------------------------------------------------------------------------
void simple_wallet::on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
{
- message_writer(console_color_red, true) << "\r" <<
- tr("Height ") << height << ", " <<
- tr("transaction ") << txid << ", " <<
- tr("unsupported transaction format");
- if (m_auto_refresh_refreshing)
- m_cmd_binder.print_prompt();
- else
- m_refresh_progress_reporter.update(height, true);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::refresh_main(uint64_t start_height, bool reset, bool is_init)
@@ -3434,7 +3533,7 @@ bool simple_wallet::show_payments(const std::vector<std::string> &args)
{
if(args.empty())
{
- fail_msg_writer() << tr("expected at least one payment_id");
+ fail_msg_writer() << tr("expected at least one payment ID");
return true;
}
@@ -4578,7 +4677,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
uint64_t below = 0;
if (args_.size() < 1)
{
- fail_msg_writer() << tr("missing amount threshold");
+ fail_msg_writer() << tr("missing threshold amount");
return true;
}
if (!cryptonote::parse_amount(below, args_[0]))
@@ -4622,7 +4721,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
local_args.push_back(amount_str);
if (!payment_id_str.empty())
local_args.push_back(payment_id_str);
- message_writer() << tr("Donating ") << amount_str << " to The Monero Project (donate.getmonero.org/"<< MONERO_DONATION_ADDR <<").";
+ message_writer() << tr("Donating ") << amount_str << " to The Monero Project (donate.getmonero.org or "<< MONERO_DONATION_ADDR <<").";
transfer_new(local_args);
return true;
}
@@ -4777,6 +4876,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::signed_tx_set &txs)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if(m_wallet->multisig())
{
fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig");
@@ -4835,6 +4939,11 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!try_connect_to_daemon())
return true;
@@ -4867,6 +4976,11 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_)
{
std::vector<std::string> local_args = args_;
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if(local_args.size() != 1) {
fail_msg_writer() << tr("usage: get_tx_key <txid>");
return true;
@@ -4902,6 +5016,11 @@ bool simple_wallet::get_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())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (args.size() != 2 && args.size() != 3)
{
fail_msg_writer() << tr("usage: get_tx_proof <txid> <address> [<message>]");
@@ -5108,6 +5227,11 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_spend_proof(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if(args.size() != 1 && args.size() != 2) {
fail_msg_writer() << tr("usage: get_spend_proof <txid> [<message>]");
return true;
@@ -5193,6 +5317,11 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if(args.size() != 1 && args.size() != 2) {
fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]");
return true;
@@ -6294,6 +6423,11 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sign(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: sign <filename>");
@@ -6363,6 +6497,11 @@ bool simple_wallet::verify(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::export_key_images(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: export_key_images <filename>");
@@ -6400,6 +6539,11 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::import_key_images(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (!m_trusted_daemon)
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
@@ -6437,6 +6581,11 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::export_outputs(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: export_outputs <filename>");
@@ -6482,6 +6631,11 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::import_outputs(const std::vector<std::string> &args)
{
+ if (m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command not supported by HW wallet");
+ return true;
+ }
if (args.size() != 1)
{
fail_msg_writer() << tr("usage: import_outputs <filename>");
@@ -6756,6 +6910,7 @@ int main(int argc, char* argv[])
tools::wallet2::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_generate_new_wallet);
+ command_line::add_arg(desc_params, arg_generate_from_device);
command_line::add_arg(desc_params, arg_generate_from_view_key);
command_line::add_arg(desc_params, arg_generate_from_spend_key);
command_line::add_arg(desc_params, arg_generate_from_keys);
@@ -6806,6 +6961,11 @@ int main(int argc, char* argv[])
else
{
tools::signal_handler::install([&w](int type) {
+ if (tools::password_container::is_prompting.load())
+ {
+ // must be prompting for password so return and let the signal stop prompt
+ return;
+ }
#ifdef WIN32
if (type == CTRL_C_EVENT)
#else
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index af2f940c3..4c7818bf1 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -97,6 +97,7 @@ namespace cryptonote
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
bool new_wallet(const boost::program_options::variables_map& vm,
const std::string &multisig_keys, const std::string &old_language);
+ bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name);
bool open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
@@ -303,6 +304,7 @@ namespace cryptonote
private:
std::string m_wallet_file;
std::string m_generate_new;
+ std::string m_generate_from_device;
std::string m_generate_from_view_key;
std::string m_generate_from_spend_key;
std::string m_generate_from_keys;
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index 8089a6a05..38c34a912 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -74,7 +74,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
// integrated + long payment id provided
if(has_long_pid && info.has_payment_id) {
- m_errorString = tr("Integrated address and long payment id can't be used at the same time");
+ m_errorString = tr("Integrated address and long payment ID can't be used at the same time");
m_errorCode = Invalid_Payment_Id;
return false;
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 82948081e..7f8144129 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -626,7 +626,7 @@ bool WalletImpl::close(bool store)
if (status() != Status_Critical)
m_wallet->store();
else
- LOG_ERROR("Status_Critical - not storing wallet");
+ LOG_ERROR("Status_Critical - not saving wallet");
LOG_PRINT_L1("wallet::store done");
}
LOG_PRINT_L1("Calling wallet::stop...");
@@ -732,7 +732,7 @@ bool WalletImpl::store(const std::string &path)
m_wallet->store_to(path, m_password);
}
} catch (const std::exception &e) {
- LOG_ERROR("Error storing wallet: " << e.what());
+ LOG_ERROR("Error saving wallet: " << e.what());
m_status = Status_Error;
m_errorString = e.what();
}
@@ -1198,6 +1198,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
for (const std::pair<uint64_t, uint64_t> outs_for_amount : e.scanty_outs()) {
writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second;
}
+ writer << "\n" << tr("Please sweep unmixable outputs.");
m_errorString = writer.str();
m_status = Status_Error;
} catch (const tools::error::tx_not_constructed&) {
@@ -1745,7 +1746,7 @@ void WalletImpl::doRefresh()
m_synchronized = true;
}
// assuming if we have empty history, it wasn't initialized yet
- // for futher history changes client need to update history in
+ // for further history changes client need to update history in
// "on_money_received" and "on_money_sent" callbacks
if (m_history->count() == 0) {
m_history->refresh();
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index a22788399..1c4545a25 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -685,7 +685,7 @@ struct Wallet
* \brief setUserNote - attach an arbitrary string note to a txid
* \param txid - the transaction id to attach the note to
* \param note - the note
- * \return true if succesful, false otherwise
+ * \return true if successful, false otherwise
*/
virtual bool setUserNote(const std::string &txid, const std::string &note) = 0;
/*!
@@ -827,7 +827,7 @@ struct WalletManager
const std::string &spendKeyString = "") = 0;
/*!
- * \brief Closes wallet. In case operation succeded, wallet object deleted. in case operation failed, wallet object not deleted
+ * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
* \param wallet previously opened / created wallet instance
* \return None
*/
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index bb144227e..22bc343fb 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -37,7 +37,7 @@
#include "common/updates.h"
#include "version.h"
#include "net/http_client.h"
-
+#include "deviuce/device.hpp"
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>
@@ -151,7 +151,7 @@ bool WalletManagerImpl::walletExists(const std::string &path)
bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const
{
- return tools::wallet2::verify_password(keys_file_name, password, no_spend_key);
+ return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default"));
}
std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path)
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 7dc8a1e47..e688086fc 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -66,6 +66,7 @@ using namespace epee;
#include "memwipe.h"
#include "common/base58.h"
#include "ringct/rctSigs.h"
+#include "device/device.hpp"
extern "C"
{
@@ -223,7 +224,7 @@ boost::optional<tools::password_container> get_password(const boost::program_opt
THROW_WALLET_EXCEPTION_IF(!password_prompter, tools::error::wallet_internal_error, tools::wallet2::tr("no password specified; use --prompt-for-password to prompt for a password"));
- return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify);
+ return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify);
}
std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -361,6 +362,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
wallet.reset(make_basic(vm, opts, password_prompter).release());
wallet->set_refresh_from_block_height(field_scan_from_height);
+ wallet->explicit_refresh_from_block_height(field_scan_from_height_found);
try
{
@@ -381,7 +383,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
if (field_spendkey.empty())
{
- // if we have an addres but no spend key, we can deduce the spend public key
+ // if we have an address but no spend key, we can deduce the spend public key
// from the address
if (field_address_found)
{
@@ -532,15 +534,12 @@ size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, si
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
}
-uint8_t get_bulletproof_fork(bool testnet)
+uint8_t get_bulletproof_fork()
{
- if (testnet)
- return 7;
- else
- return 255; // TODO
+ return 8;
}
-crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
+crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
{
crypto::hash8 payment_id8 = null_hash8;
std::vector<tx_extra_field> tx_extra_fields;
@@ -555,16 +554,16 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx)
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
return crypto::null_hash8;
}
- decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key);
+ decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, hwdev);
}
}
return payment_id8;
}
-tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx)
+tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
{
tools::wallet2::tx_construction_data construction_data = ptx.construction_data;
- crypto::hash8 payment_id = get_short_payment_id(ptx);
+ crypto::hash8 payment_id = get_short_payment_id(ptx,hwdev);
if (payment_id != null_hash8)
{
// Remove encrypted
@@ -604,6 +603,7 @@ wallet2::wallet2(bool testnet, bool restricted):
m_refresh_type(RefreshOptimizeCoinbase),
m_auto_refresh(true),
m_refresh_from_block_height(0),
+ m_explicit_refresh_from_block_height(true),
m_confirm_missing_payment_id(true),
m_ask_password(true),
m_min_output_count(0),
@@ -624,7 +624,8 @@ wallet2::wallet2(bool testnet, bool restricted):
m_light_wallet_blockchain_height(0),
m_light_wallet_connected(false),
m_light_wallet_balance(0),
- m_light_wallet_unlocked_balance(0)
+ m_light_wallet_unlocked_balance(0),
+ m_key_on_device(false)
{
}
@@ -818,40 +819,17 @@ void wallet2::set_seed_language(const std::string &language)
//----------------------------------------------------------------------------------------------------
cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::subaddress_index& index) const
{
- const cryptonote::account_keys& keys = m_account.get_keys();
- if (index.is_zero())
- return keys.m_account_address;
-
- crypto::public_key D = get_subaddress_spend_public_key(index);
-
- // C = a*D
- crypto::public_key C = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(D), rct::sk2rct(keys.m_view_secret_key))); // could have defined secret_key_mult_public_key() under src/crypto
-
- // result: (C, D)
cryptonote::account_public_address address;
- address.m_view_public_key = C;
- address.m_spend_public_key = D;
+ hw::device &hwdev = m_account.get_device();
+ hwdev.get_subaddress(m_account.get_keys(), index,address);
return address;
}
//----------------------------------------------------------------------------------------------------
crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const
{
- const cryptonote::account_keys& keys = m_account.get_keys();
- if (index.is_zero())
- return keys.m_account_address.m_spend_public_key;
-
- // m = Hs(a || index_major || index_minor)
- crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index);
-
- // M = m*G
- crypto::public_key M;
- crypto::secret_key_to_public_key(m, M);
-
- // D = B + M
- rct::key D_rct;
- rct::addKeys(D_rct, rct::pk2rct(keys.m_account_address.m_spend_public_key), rct::pk2rct(M)); // could have defined add_public_key() under src/crypto
- crypto::public_key D = rct::rct2pk(D_rct);
-
+ crypto::public_key D ;
+ hw::device &hwdev = m_account.get_device();
+ hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index, D);
return D;
}
//----------------------------------------------------------------------------------------------------
@@ -883,20 +861,19 @@ void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
//----------------------------------------------------------------------------------------------------
void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
{
+ hw::device &hwdev = m_account.get_device();
if (m_subaddress_labels.size() <= index.major)
{
// add new accounts
cryptonote::subaddress_index index2;
for (index2.major = m_subaddress_labels.size(); index2.major < index.major + m_subaddress_lookahead_major; ++index2.major)
{
- for (index2.minor = 0; index2.minor < (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor; ++index2.minor)
+ const uint32_t end = (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor;
+ const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end, hwdev);
+ for (index2.minor = 0; index2.minor < end; ++index2.minor)
{
- if (m_subaddresses_inv.count(index2) == 0)
- {
- crypto::public_key D = get_subaddress_spend_public_key(index2);
- m_subaddresses[D] = index2;
- m_subaddresses_inv[index2] = D;
- }
+ const crypto::public_key &D = pkeys[index2.minor];
+ m_subaddresses[D] = index2;
}
}
m_subaddress_labels.resize(index.major + 1, {"Untitled account"});
@@ -905,15 +882,14 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index)
else if (m_subaddress_labels[index.major].size() <= index.minor)
{
// add new subaddresses
- cryptonote::subaddress_index index2 = index;
- for (index2.minor = m_subaddress_labels[index.major].size(); index2.minor < index.minor + m_subaddress_lookahead_minor; ++index2.minor)
+ const uint32_t end = index.minor + m_subaddress_lookahead_minor;
+ const uint32_t begin = m_subaddress_labels[index.major].size();
+ cryptonote::subaddress_index index2 = {index.major, begin};
+ const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end, hwdev);
+ for (; index2.minor < end; ++index2.minor)
{
- if (m_subaddresses_inv.count(index2) == 0)
- {
- crypto::public_key D = get_subaddress_spend_public_key(index2);
- m_subaddresses[D] = index2;
- m_subaddresses_inv[index2] = D;
- }
+ const crypto::public_key &D = pkeys[index2.minor - begin];
+ m_subaddresses[D] = index2;
}
m_subaddress_labels[index.major].resize(index.minor + 1);
}
@@ -974,7 +950,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
LOG_ERROR("wrong type id in transaction out");
return;
}
- tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i);
+ tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i, m_account.get_device());
if(tx_scan_info.received)
{
tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs
@@ -986,20 +962,20 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
tx_scan_info.error = false;
}
//----------------------------------------------------------------------------------------------------
-static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask)
+static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev)
{
crypto::secret_key scalar1;
- crypto::derivation_to_scalar(derivation, i, scalar1);
+ crypto::derivation_to_scalar(derivation, i, scalar1, hwdev);
try
{
switch (rv.type)
{
case rct::RCTTypeSimple:
case rct::RCTTypeSimpleBulletproof:
- return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask);
+ return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
case rct::RCTTypeFull:
case rct::RCTTypeFullBulletproof:
- return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask);
+ return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
default:
LOG_ERROR("Unsupported rct type: " << rv.type);
return 0;
@@ -1023,7 +999,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi
}
else
{
- bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki);
+ bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
@@ -1032,7 +1008,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi
outs.push_back(i);
if (tx_scan_info.money_transfered == 0)
{
- tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask);
+ tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask, m_account.get_device());
}
tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered;
tx_scan_info.amount = tx_scan_info.money_transfered;
@@ -1080,8 +1056,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
const cryptonote::account_keys& keys = m_account.get_keys();
+ hw::device &hwdev = m_account.get_device();
crypto::key_derivation derivation;
- if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
+ if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev))
{
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
@@ -1094,7 +1071,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
additional_derivations.push_back({});
- if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
+ if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(),hwdev))
{
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
additional_derivations.pop_back();
@@ -1219,7 +1196,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_rct = false;
}
set_unspent(m_transfers.size()-1);
- if (!m_multisig)
+ if (!m_multisig && !m_watch_only)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
if (m_multisig)
@@ -1313,11 +1290,21 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
if (amount > 0)
{
- THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error,
- std::string("Inconsistent amount in tx input: got ") + print_money(amount) +
- std::string(", expected ") + print_money(td.amount()));
+ if(amount != td.amount())
+ {
+ MERROR("Inconsistent amount in tx input: got " << print_money(amount) <<
+ ", expected " << print_money(td.amount()));
+ // this means:
+ // 1) the same output pub key was used as destination multiple times,
+ // 2) the wallet set the highest amount among them to transfer_details::m_amount, and
+ // 3) the wallet somehow spent that output with an amount smaller than the above amount, causing inconsistency
+ td.m_amount = amount;
+ }
+ }
+ else
+ {
+ amount = td.amount();
}
- amount = td.amount();
tx_money_spent_in_ins += amount;
if (subaddr_account && *subaddr_account != td.m_subaddr_index.major)
LOG_ERROR("spent funds are from different subaddress accounts; count of incoming/outgoing payments will be incorrect");
@@ -1376,7 +1363,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8);
if (tx_pub_key != null_pkey)
{
- if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key))
+ if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key, m_account.get_device()))
{
LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id8);
}
@@ -2343,7 +2330,6 @@ bool wallet2::clear()
m_address_book.clear();
m_local_bc_height = 1;
m_subaddresses.clear();
- m_subaddresses_inv.clear();
m_subaddress_labels.clear();
return true;
}
@@ -2380,6 +2366,10 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
}
rapidjson::Value value2(rapidjson::kNumberType);
+
+ value2.SetInt(m_key_on_device?1:0);
+ json.AddMember("key_on_device", value2, json.GetAllocator());
+
value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ??
json.AddMember("watch_only", value2, json.GetAllocator());
@@ -2477,16 +2467,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
return true;
}
//----------------------------------------------------------------------------------------------------
-namespace
-{
- bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub)
- {
- crypto::public_key pub;
- bool r = crypto::secret_key_to_public_key(sec, pub);
- return r && expected_pub == pub;
- }
-}
-
/*!
* \brief Load wallet information from wallet file.
* \param keys_file_name Name of wallet file
@@ -2534,6 +2514,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_confirm_backlog_threshold = 0;
m_confirm_export_overwrite = true;
m_auto_low_priority = true;
+ m_key_on_device = false;
}
else if(json.IsObject())
{
@@ -2550,6 +2531,12 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
const char *field_key_data = json["key_data"].GetString();
account_data = std::string(field_key_data, field_key_data + json["key_data"].GetStringLength());
+ if (json.HasMember("key_on_device"))
+ {
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, key_on_device, int, Int, false, false);
+ m_key_on_device = field_key_on_device;
+ }
+
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed_language, std::string, String, false, std::string());
if (field_seed_language_found)
{
@@ -2635,8 +2622,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_confirm_backlog_threshold = field_confirm_backlog_threshold;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_export_overwrite, int, Int, false, true);
m_confirm_export_overwrite = field_confirm_export_overwrite;
- GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, m_auto_low_priority, int, Int, false, true);
- m_auto_low_priority = field_m_auto_low_priority;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_low_priority, int, Int, false, true);
+ m_auto_low_priority = field_auto_low_priority;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet);
// Wallet is being opened with testnet flag, but is saved as a mainnet wallet
THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet");
@@ -2649,11 +2636,20 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
return false;
}
- const cryptonote::account_keys& keys = m_account.get_keys();
r = epee::serialization::load_t_from_binary(m_account, account_data);
- r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
+ if (r && m_key_on_device) {
+ LOG_PRINT_L0("Account on device. Initing device...");
+ hw::device &hwdev = hw::get_device("Ledger");
+ hwdev.init();
+ hwdev.connect();
+ m_account.set_device(hwdev);
+ LOG_PRINT_L0("Device inited...");
+ }
+ const cryptonote::account_keys& keys = m_account.get_keys();
+ hw::device &hwdev = m_account.get_device();
+ r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
if(!m_watch_only && !m_multisig)
- r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
+ r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password);
return true;
}
@@ -2670,7 +2666,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
*/
bool wallet2::verify_password(const epee::wipeable_string& password) const
{
- return verify_password(m_keys_file, password, m_watch_only || m_multisig);
+ return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device());
}
/*!
@@ -2685,7 +2681,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const
* can be used prior to rewriting wallet keys file, to ensure user has entered the correct password
*
*/
-bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key)
+bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev)
{
rapidjson::Document json;
wallet2::keys_file_data keys_file_data;
@@ -2720,9 +2716,9 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
r = epee::serialization::load_t_from_binary(account_data_check, account_data);
const cryptonote::account_keys& keys = account_data_check.get_keys();
- r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
+ r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key);
if(!no_spend_key)
- r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
+ r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
return r;
}
@@ -2798,6 +2794,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = true;
m_multisig_threshold = threshold;
m_multisig_signers = multisig_signers;
+ m_key_on_device = false;
if (!wallet_.empty())
{
@@ -2846,6 +2843,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_key_on_device = false;
// -1 month for fluctuations in block time and machine date/time setup.
// avg seconds per block
@@ -2937,6 +2935,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_key_on_device = false;
if (!wallet_.empty())
{
@@ -2983,6 +2982,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_multisig = false;
m_multisig_threshold = 0;
m_multisig_signers.clear();
+ m_key_on_device = false;
if (!wallet_.empty())
{
@@ -3002,6 +3002,46 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
store();
}
+/*!
+* \brief Creates a wallet from a device
+* \param wallet_ Name of wallet file
+* \param password Password of wallet file
+* \param device_name device string address
+*/
+void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name)
+{
+ clear();
+ prepare_file_names(wallet_);
+
+ boost::system::error_code ignored_ec;
+ if (!wallet_.empty()) {
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
+ }
+ m_key_on_device = true;
+ m_account.create_from_device(device_name);
+ m_account_public_address = m_account.get_keys().m_account_address;
+ m_watch_only = false;
+ m_multisig = false;
+ m_multisig_threshold = 0;
+ m_multisig_signers.clear();
+
+ if (!wallet_.empty()) {
+ bool r = store_keys(m_keys_file, password, false);
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+
+ r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet));
+ if(!r) MERROR("String with address text not saved");
+ }
+ cryptonote::block b;
+ generate_genesis(b);
+ m_blockchain.push_back(get_block_hash(b));
+ add_subaddress_account(tr("Primary account"));
+ if (!wallet_.empty()) {
+ store();
+ }
+}
+
std::string wallet2::make_multisig(const epee::wipeable_string &password,
const std::vector<crypto::secret_key> &view_keys,
const std::vector<crypto::public_key> &spend_keys,
@@ -3065,6 +3105,8 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
m_watch_only = false;
m_multisig = true;
m_multisig_threshold = threshold;
+ m_key_on_device = false;
+
if (threshold == spend_keys.size() + 1)
{
m_multisig_signers = spend_keys;
@@ -3185,7 +3227,6 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unor
}
m_subaddresses.clear();
- m_subaddresses_inv.clear();
m_subaddress_labels.clear();
add_subaddress_account(tr("Primary account"));
@@ -3474,15 +3515,8 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
//----------------------------------------------------------------------------------------------------
bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const
{
- const account_keys &keys = m_account.get_keys();
- const crypto::secret_key &view_key = keys.m_view_secret_key;
- const crypto::secret_key &spend_key = keys.m_spend_secret_key;
- tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data;
- memcpy(data.data(), &view_key, sizeof(view_key));
- memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key));
- data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
- crypto::generate_chacha_key(data.data(), sizeof(data), key);
- return true;
+ hw::device &hwdev = m_account.get_device();
+ return hwdev.generate_chacha_key(m_account.get_keys(), key);
}
//----------------------------------------------------------------------------------------------------
void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password)
@@ -4256,7 +4290,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt");
return crypto::null_hash;
}
- if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key))
+ if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, m_account.get_device()))
{
memcpy(payment_id.data, payment_id8.data, 8);
}
@@ -4365,7 +4399,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri
// Short payment id is encrypted with tx_key.
// Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID
// Save tx construction_data to unsigned_tx_set
- txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx));
+ txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
}
txs.transfers = m_transfers;
@@ -4692,7 +4726,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
for (auto &ptx: txs.m_ptx)
{
// Get decrypted payment id from pending_tx
- ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx);
+ ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx, m_account.get_device());
}
// save as binary
@@ -5271,7 +5305,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
- THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs recieved from light wallet node. Error: " + ores.Error);
+ THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
// Check if we got enough outputs for each amount
for(auto& out: ores.amount_outs) {
@@ -5495,7 +5529,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
}
- // sort the subsection, to ensure the daemon doesn't know wich output is ours
+ // sort the subsection, to ensure the daemon doesn't know which output is ours
std::sort(req.outputs.begin() + start, req.outputs.end(),
[](const get_outputs_out &a, const get_outputs_out &b) { return a.index < b.index; });
}
@@ -6122,7 +6156,7 @@ bool wallet2::light_wallet_login(bool &new_address)
cryptonote::COMMAND_RPC_LOGIN::response response;
request.address = get_account().get_public_address_str(m_testnet);
request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
- // Always create account if it doesnt exist.
+ // Always create account if it doesn't exist.
request.create_account = true;
m_daemon_rpc_mutex.lock();
bool connected = epee::net_utils::invoke_http_json("/login", request, response, m_http_client, rpc_timeout, "POST");
@@ -6135,7 +6169,7 @@ bool wallet2::light_wallet_login(bool &new_address)
MDEBUG("New wallet: " << response.new_address);
if(m_light_wallet_connected)
{
- // Clear old data on successfull login.
+ // Clear old data on successful login.
// m_transfers.clear();
// m_payments.clear();
// m_unconfirmed_payments.clear();
@@ -6507,7 +6541,7 @@ void wallet2::light_wallet_get_address_txs()
// Calculate wallet balance
m_light_wallet_balance = ires.total_received-wallet_total_sent;
- // MyMonero doesnt send unlocked balance
+ // MyMonero doesn't send unlocked balance
if(ires.total_received_unlocked > 0)
m_light_wallet_unlocked_balance = ires.total_received_unlocked-wallet_total_sent;
else
@@ -6642,7 +6676,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
uint64_t needed_fee, available_for_fee = 0;
uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
const bool use_rct = use_fork_rules(4, 0);
- const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const uint64_t fee_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
@@ -6784,7 +6818,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
{
string s;
for (auto i: preferred_inputs) s += boost::lexical_cast<std::string>(i) + " (" + print_money(m_transfers[i].amount()) + ") ";
- LOG_PRINT_L1("Found prefered rct inputs for rct tx: " << s);
+ LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s);
// bring the list of available outputs stored by the same subaddress index to the front of the list
uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor;
@@ -6815,6 +6849,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
unsigned int original_output_index = 0;
std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
+ hw::device &hwdev = m_account.get_device();
+ hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE);
while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) {
TX &tx = txes.back();
@@ -7000,6 +7036,37 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
+ if ((!dsts.empty()) ||
+ (dsts.empty() && !(adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) )
+ ) {
+ hwdev.set_signature_mode(hw::device::SIGNATURE_REAL);
+ if (use_rct) {
+ transfer_selected_rct(tx.dsts, /* NOMOD std::vector<cryptonote::tx_destination_entry> dsts,*/
+ tx.selected_transfers, /* const std::list<size_t> selected_transfers */
+ fake_outs_count, /* CONST size_t fake_outputs_count, */
+ outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
+ unlock_time, /* CONST uint64_t unlock_time, */
+ needed_fee, /* CONST uint64_t fee, */
+ extra, /* const std::vector<uint8_t>& extra, */
+ test_tx, /* OUT cryptonote::transaction& tx, */
+ test_ptx, /* OUT cryptonote::transaction& tx, */
+ bulletproof);
+ } else {
+ transfer_selected(tx.dsts,
+ tx.selected_transfers,
+ fake_outs_count,
+ outs,
+ unlock_time,
+ needed_fee,
+ extra,
+ detail::digit_split_strategy,
+ tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD),
+ test_tx,
+ test_ptx);
+ }
+ hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE);
+ }
+
tx.tx = test_tx;
tx.ptx = test_ptx;
tx.bytes = txBlob.size();
@@ -7151,7 +7218,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std::vector<std::vector<get_outs_entry>> outs;
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
- const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0);
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
const uint64_t fee_per_kb = get_per_kb_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
@@ -7168,6 +7235,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
needed_fee = 0;
// while we have something to send
+ hw::device &hwdev = m_account.get_device();
+ hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE);
while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) {
TX &tx = txes.back();
@@ -7233,6 +7302,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
} while (needed_fee > test_ptx.fee);
+ if (!unused_transfers_indices.empty() || !unused_dust_indices.empty()) {
+ hwdev.set_signature_mode(hw::device::SIGNATURE_REAL);
+ if (use_rct) {
+ transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
+ test_tx, test_ptx, bulletproof);
+ } else {
+ transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
+ detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
+ }
+ hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE);
+ }
+
LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
@@ -7522,7 +7603,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx);
keypair in_ephemeral;
crypto::key_image in_img;
- THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img),
+ THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device()),
error::wallet_internal_error, "failed to generate key image");
THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch");
@@ -7697,13 +7778,13 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
void wallet2::check_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations)
{
crypto::key_derivation derivation;
- THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation), error::wallet_internal_error,
+ THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation, m_account.get_device()), error::wallet_internal_error,
"Failed to generate key derivation from supplied parameters");
std::vector<crypto::key_derivation> additional_derivations;
additional_derivations.resize(additional_tx_keys.size());
for (size_t i = 0; i < additional_tx_keys.size(); ++i)
- THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i]), error::wallet_internal_error,
+ THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i], m_account.get_device()), error::wallet_internal_error,
"Failed to generate key derivation from supplied parameters");
check_tx_key_helper(txid, derivation, additional_derivations, address, received, in_pool, confirmations);
@@ -7737,6 +7818,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
"The size of additional derivations is wrong");
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));
@@ -7744,13 +7826,13 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
continue;
crypto::public_key derived_out_key;
- bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key);
+ bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key, hwdev);
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 = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key);
+ r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key,hwdev);
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];
@@ -7766,9 +7848,9 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
else
{
crypto::secret_key scalar1;
- crypto::derivation_to_scalar(found_derivation, n, scalar1);
+ crypto::derivation_to_scalar(found_derivation, n, scalar1, hwdev);
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n];
- rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1));
+ rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), hwdev);
const rct::key C = tx.rct_signatures.outPk[n].mask;
rct::key Ctmp;
rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H);
@@ -8122,7 +8204,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
// derive ephemeral secret key
crypto::key_image ki;
cryptonote::keypair ephemeral;
- const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki);
+ const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
@@ -8354,8 +8436,9 @@ uint64_t wallet2::get_approximate_blockchain_height() const
// Calculated blockchain height
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
// testnet got some huge rollbacks, so the estimation is way off
- if (m_testnet && approx_blockchain_height > 105000)
- approx_blockchain_height -= 105000;
+ static const uint64_t approximate_testnet_rolled_back_blocks = 148540;
+ if (m_testnet && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
+ approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
return approx_blockchain_height;
}
@@ -8495,20 +8578,21 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
// more than one, loop and search
const cryptonote::account_keys& keys = m_account.get_keys();
size_t pk_index = 0;
+ hw::device &hwdev = m_account.get_device();
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
std::vector<crypto::key_derivation> additional_derivations;
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
additional_derivations.push_back({});
- bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back());
+ bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
}
while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) {
const crypto::public_key tx_pub_key = pub_key_field.pub_key;
crypto::key_derivation derivation;
- bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
+ bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
for (size_t i = 0; i < td.m_tx.vout.size(); ++i)
@@ -8579,7 +8663,7 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key
// generate ephemeral secret key
crypto::key_image ki;
cryptonote::keypair in_ephemeral;
- bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki);
+ bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image,
@@ -8779,6 +8863,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
// process each outgoing tx
auto spent_txid = spent_txids.begin();
+ hw::device &hwdev = m_account.get_device();
for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs)
{
THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool");
@@ -8796,14 +8881,14 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
const cryptonote::account_keys& keys = m_account.get_keys();
const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx);
crypto::key_derivation derivation;
- bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
+ bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx);
std::vector<crypto::key_derivation> additional_derivations;
for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
{
additional_derivations.push_back({});
- r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back());
+ r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation");
}
size_t output_index = 0;
@@ -8817,7 +8902,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
if (tx_scan_info.money_transfered == 0)
{
rct::key mask;
- tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask);
+ tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask, hwdev);
}
tx_money_got_in_outs += tx_scan_info.money_transfered;
}
@@ -8977,7 +9062,7 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
- bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image);
+ bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index f768581b2..127e70a26 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -162,7 +162,7 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter);
- static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key);
+ static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev);
wallet2(bool testnet = false, bool restricted = false);
@@ -487,6 +487,14 @@ namespace tools
const cryptonote::account_public_address &account_public_address,
const crypto::secret_key& viewkey = crypto::secret_key());
/*!
+ * \brief Restore a wallet hold by an HW.
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param device_name name of HW to use
+ */
+ void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name);
+
+ /*!
* \brief Creates a multisig wallet
* \return empty if done, non empty if we need to send another string
* to other participants
@@ -561,6 +569,9 @@ namespace tools
void set_refresh_from_block_height(uint64_t height) {m_refresh_from_block_height = height;}
uint64_t get_refresh_from_block_height() const {return m_refresh_from_block_height;}
+ void explicit_refresh_from_block_height(bool expl) {m_explicit_refresh_from_block_height = expl;}
+ bool explicit_refresh_from_block_height() const {return m_explicit_refresh_from_block_height;}
+
// upper_transaction_size_limit as defined below is set to
// approximately 125% of the fixed minimum allowable penalty
// free block size. TODO: fix this so that it actually takes
@@ -602,6 +613,7 @@ namespace tools
cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index& index) const;
cryptonote::account_public_address get_address() const { return get_subaddress({0,0}); }
crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const;
+ std::vector<crypto::public_key> get_subaddress_spend_public_keys(uint32_t account, uint32_t begin, uint32_t end) const;
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
std::string get_address_as_str() const { return get_subaddress_as_str({0, 0}); }
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
@@ -631,6 +643,7 @@ namespace tools
bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const;
bool has_multisig_partial_key_images() const;
bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const;
+ bool key_on_device() const { return m_key_on_device; }
// locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major) const;
@@ -779,7 +792,8 @@ namespace tools
if (ver < 20)
return;
a & m_subaddresses;
- a & m_subaddresses_inv;
+ std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv;
+ a & dummy_subaddresses_inv;
a & m_subaddress_labels;
a & m_additional_tx_keys;
if(ver < 21)
@@ -1086,7 +1100,6 @@ namespace tools
std::unordered_map<crypto::public_key, size_t> m_pub_keys;
cryptonote::account_public_address m_account_public_address;
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses;
- std::unordered_map<cryptonote::subaddress_index, crypto::public_key> m_subaddresses_inv;
std::vector<std::vector<std::string>> m_subaddress_labels;
std::unordered_map<crypto::hash, std::string> m_tx_notes;
std::unordered_map<std::string, std::string> m_attributes;
@@ -1101,6 +1114,7 @@ namespace tools
boost::mutex m_daemon_rpc_mutex;
i_wallet2_callback* m_callback;
+ bool m_key_on_device;
bool m_testnet;
bool m_restricted;
std::string seed_language; /*!< Language of the mnemonics (seed). */
@@ -1117,6 +1131,9 @@ namespace tools
RefreshType m_refresh_type;
bool m_auto_refresh;
uint64_t m_refresh_from_block_height;
+ // If m_refresh_from_block_height is explicitly set to zero we need this to differentiate it from the case that
+ // m_refresh_from_block_height was defaulted to zero.*/
+ bool m_explicit_refresh_from_block_height;
bool m_confirm_missing_payment_id;
bool m_ask_password;
uint32_t m_min_output_count;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 97faf0b56..6d5419521 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -39,6 +39,7 @@ using namespace epee;
#include "wallet/wallet_args.h"
#include "common/command_line.h"
#include "common/i18n.h"
+#include "cryptonote_config.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
#include "multisig/multisig.h"
@@ -1803,11 +1804,11 @@ namespace tools
return false;
}
- uint64_t min_height = 0, max_height = (uint64_t)-1;
+ uint64_t min_height = 0, max_height = CRYPTONOTE_MAX_BLOCK_NUMBER;
if (req.filter_by_height)
{
min_height = req.min_height;
- max_height = req.max_height;
+ max_height = req.max_height <= max_height ? req.max_height : max_height;
}
if (req.in)
@@ -1889,8 +1890,15 @@ namespace tools
return false;
}
+ if (req.account_index >= m_wallet->get_num_subaddress_accounts())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS;
+ er.message = "Account index is out of bound";
+ return false;
+ }
+
std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments;
- m_wallet->get_payments(payments, 0);
+ m_wallet->get_payments(payments, 0, (uint64_t)-1, req.account_index);
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
if (i->second.m_tx_hash == txid)
{
@@ -1900,7 +1908,7 @@ namespace tools
}
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments_out;
- m_wallet->get_payments_out(payments_out, 0);
+ m_wallet->get_payments_out(payments_out, 0, (uint64_t)-1, req.account_index);
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) {
if (i->first == txid)
{
@@ -1910,7 +1918,7 @@ namespace tools
}
std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments;
- m_wallet->get_unconfirmed_payments_out(upayments);
+ m_wallet->get_unconfirmed_payments_out(upayments, req.account_index);
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
if (i->first == txid)
{
@@ -1922,7 +1930,7 @@ namespace tools
m_wallet->update_pool_state();
std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> pool_payments;
- m_wallet->get_unconfirmed_payments(pool_payments);
+ m_wallet->get_unconfirmed_payments(pool_payments, req.account_index);
for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
if (i->second.m_pd.m_tx_hash == txid)
{
@@ -2397,6 +2405,11 @@ namespace tools
{
std::rethrow_exception(e);
}
+ catch (const tools::error::no_connection_to_daemon& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
+ er.message = e.what();
+ }
catch (const tools::error::daemon_busy& e)
{
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
@@ -2412,6 +2425,11 @@ namespace tools
er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY;
er.message = e.what();
}
+ catch (const tools::error::not_enough_unlocked_money& e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY;
+ er.message = e.what();
+ }
catch (const tools::error::tx_not_possible& e)
{
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
@@ -2425,7 +2443,7 @@ namespace tools
catch (const tools::error::not_enough_outs_to_mix& e)
{
er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX;
- er.message = e.what();
+ er.message = e.what() + std::string(" Please use sweep_dust.");
}
catch (const error::file_exists& e)
{
@@ -2439,12 +2457,12 @@ namespace tools
}
catch (const error::account_index_outofbound& e)
{
- er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUTOFBOUND;
+ er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS;
er.message = e.what();
}
catch (const error::address_index_outofbound& e)
{
- er.code = WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUTOFBOUND;
+ er.code = WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS;
er.message = e.what();
}
catch (const std::exception& e)
@@ -2922,12 +2940,12 @@ int main(int argc, char** argv) {
// if we ^C during potentially length load/refresh, there's no server loop yet
if (quit)
{
- MINFO(tools::wallet_rpc_server::tr("Storing wallet..."));
+ MINFO(tools::wallet_rpc_server::tr("Saving wallet..."));
wal->store();
- MINFO(tools::wallet_rpc_server::tr("Stored ok"));
+ MINFO(tools::wallet_rpc_server::tr("Successfully saved"));
return 1;
}
- MINFO(tools::wallet_rpc_server::tr("Loaded ok"));
+ MINFO(tools::wallet_rpc_server::tr("Successfully loaded"));
}
catch (const std::exception& e)
{
@@ -2938,11 +2956,11 @@ just_dir:
tools::wallet_rpc_server wrpc;
if (wal) wrpc.set_wallet(wal.release());
bool r = wrpc.init(&(vm.get()));
- CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet rpc server"));
+ CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet RPC server"));
tools::signal_handler::install([&wrpc](int) {
wrpc.send_stop_signal();
});
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet rpc server"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet RPC server"));
try
{
wrpc.run();
@@ -2952,16 +2970,16 @@ just_dir:
LOG_ERROR(tools::wallet_rpc_server::tr("Failed to run wallet: ") << e.what());
return 1;
}
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet rpc server"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet RPC server"));
try
{
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Storing wallet..."));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Saving wallet..."));
wrpc.stop();
- LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stored ok"));
+ LOG_PRINT_L0(tools::wallet_rpc_server::tr("Successfully saved"));
}
catch (const std::exception& e)
{
- LOG_ERROR(tools::wallet_rpc_server::tr("Failed to store wallet: ") << e.what());
+ LOG_ERROR(tools::wallet_rpc_server::tr("Failed to save wallet: ") << e.what());
return 1;
}
return 0;
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index e9f112b63..e38cba5a5 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
+#include "cryptonote_config.h"
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/subaddress_index.h"
@@ -1262,7 +1263,7 @@ namespace wallet_rpc
KV_SERIALIZE(pool);
KV_SERIALIZE(filter_by_height);
KV_SERIALIZE(min_height);
- KV_SERIALIZE(max_height);
+ KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER);
KV_SERIALIZE(account_index);
KV_SERIALIZE(subaddr_indices);
END_KV_SERIALIZE_MAP()
@@ -1291,9 +1292,11 @@ namespace wallet_rpc
struct request
{
std::string txid;
+ uint32_t account_index;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(txid);
+ KV_SERIALIZE_OPT(account_index, (uint32_t)0)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h
index 311556657..d47467940 100644
--- a/src/wallet/wallet_rpc_server_error_codes.h
+++ b/src/wallet/wallet_rpc_server_error_codes.h
@@ -44,8 +44,8 @@
#define WALLET_RPC_ERROR_CODE_WRONG_URI -11
#define WALLET_RPC_ERROR_CODE_WRONG_INDEX -12
#define WALLET_RPC_ERROR_CODE_NOT_OPEN -13
-#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUTOFBOUND -14
-#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUTOFBOUND -15
+#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS -14
+#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS -15
#define WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE -16
#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -17
#define WALLET_RPC_ERROR_CODE_TX_TOO_LARGE -18
@@ -67,3 +67,5 @@
#define WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA -34
#define WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE -35
#define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION -36
+#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY -37
+#define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION -38