aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorDusan Klinec <dusan.klinec@gmail.com>2018-08-23 23:50:53 +0200
committerDusan Klinec <dusan.klinec@gmail.com>2018-11-02 21:36:39 +0100
commit29ffb6bba8867586986345b4f0c560e5ea5fce85 (patch)
tree544386c5c4158ab4d8edfb50ab3792e25a97439d /src/wallet
parentMerge pull request #4676 (diff)
downloadmonero-29ffb6bba8867586986345b4f0c560e5ea5fce85.tar.xz
device/trezor: trezor support added
Diffstat (limited to '')
-rw-r--r--src/wallet/CMakeLists.txt1
-rw-r--r--src/wallet/wallet2.cpp158
-rw-r--r--src/wallet/wallet2.h22
3 files changed, 154 insertions, 27 deletions
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index be10b9f62..4932dd4b6 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -57,6 +57,7 @@ target_link_libraries(wallet
common
cryptonote_core
mnemonics
+ device_trezor
${LMDB_LIBRARY}
${Boost_CHRONO_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 37b60c5d7..f2e54cf09 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -71,6 +71,8 @@ using namespace epee;
#include "common/notify.h"
#include "ringct/rctSigs.h"
#include "ringdb.h"
+#include "device/device_cold.hpp"
+#include "device_trezor/device_trezor.hpp"
extern "C"
{
@@ -768,6 +770,11 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra)
return idx + extra;
}
+static void setup_shim(hw::wallet_shim * shim, tools::wallet2 * wallet)
+{
+ shim->get_tx_pub_key_from_received_outs = boost::bind(&tools::wallet2::get_tx_pub_key_from_received_outs, wallet, _1);
+}
+
//-----------------------------------------------------------------
} //namespace
@@ -1060,8 +1067,9 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl
bool wallet2::reconnect_device()
{
bool r = true;
- hw::device &hwdev = hw::get_device(m_device_name);
+ hw::device &hwdev = lookup_device(m_device_name);
hwdev.set_name(m_device_name);
+ hwdev.set_network_type(m_nettype);
r = hwdev.init();
if (!r){
LOG_PRINT_L2("Could not init device");
@@ -2944,6 +2952,7 @@ bool wallet2::deinit()
{
m_is_initialized=false;
unlock_keys_file();
+ m_account.deinit();
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -3413,13 +3422,20 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
r = epee::serialization::load_t_from_binary(m_account, account_data);
THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password);
- if (m_key_device_type == hw::device::device_type::LEDGER) {
+ if (m_key_device_type == hw::device::device_type::LEDGER || m_key_device_type == hw::device::device_type::TREZOR) {
LOG_PRINT_L0("Account on device. Initing device...");
- hw::device &hwdev = hw::get_device(m_device_name);
- hwdev.set_name(m_device_name);
- hwdev.init();
- hwdev.connect();
+ hw::device &hwdev = lookup_device(m_device_name);
+ THROW_WALLET_EXCEPTION_IF(!hwdev.set_name(m_device_name), error::wallet_internal_error, "Could not set device name " + m_device_name);
+ hwdev.set_network_type(m_nettype);
+ THROW_WALLET_EXCEPTION_IF(!hwdev.init(), error::wallet_internal_error, "Could not initialize the device " + m_device_name);
+ THROW_WALLET_EXCEPTION_IF(!hwdev.connect(), error::wallet_internal_error, "Could not connect to the device " + m_device_name);
m_account.set_device(hwdev);
+
+ account_public_address device_account_public_address;
+ THROW_WALLET_EXCEPTION_IF(!hwdev.get_public_address(device_account_public_address), error::wallet_internal_error, "Cannot get a device address");
+ THROW_WALLET_EXCEPTION_IF(device_account_public_address != m_account.get_keys().m_account_address, error::wallet_internal_error, "Device wallet does not match wallet address. "
+ "Device address: " + cryptonote::get_account_address_as_str(m_nettype, false, device_account_public_address) +
+ ", wallet address: " + m_account.get_public_address_str(m_nettype));
LOG_PRINT_L0("Device inited...");
} else if (key_on_device()) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "hardware device not supported");
@@ -3450,7 +3466,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
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)
+ if(!m_watch_only && !m_multisig && hwdev.device_protocol() != hw::device::PROTOCOL_COLD)
r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key);
THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password);
@@ -3474,7 +3490,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password)
{
// this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded).
unlock_keys_file();
- bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds);
+ bool r = verify_password(m_keys_file, password, m_account.get_device().device_protocol() == hw::device::PROTOCOL_COLD || m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds);
lock_keys_file();
return r;
}
@@ -3914,8 +3930,9 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
}
- auto &hwdev = hw::get_device(device_name);
+ auto &hwdev = lookup_device(device_name);
hwdev.set_name(device_name);
+ hwdev.set_network_type(m_nettype);
m_account.create_from_device(hwdev);
m_key_device_type = m_account.get_device().get_type();
@@ -5781,22 +5798,8 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too
}
// import key images
- if (signed_txs.key_images.size() > m_transfers.size())
- {
- LOG_PRINT_L1("More key images returned that we know outputs for");
- return false;
- }
- for (size_t i = 0; i < signed_txs.key_images.size(); ++i)
- {
- transfer_details &td = m_transfers[i];
- if (td.m_key_image_known && !td.m_key_image_partial && td.m_key_image != signed_txs.key_images[i])
- LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << i << ": trusting imported one");
- td.m_key_image = signed_txs.key_images[i];
- m_key_images[m_transfers[i].m_key_image] = i;
- td.m_key_image_known = true;
- td.m_key_image_partial = false;
- m_pub_keys[m_transfers[i].get_public_key()] = i;
- }
+ bool r = import_key_images(signed_txs.key_images);
+ if (!r) return false;
ptx = signed_txs.ptx;
@@ -6346,6 +6349,19 @@ crypto::chacha_key wallet2::get_ringdb_key()
return *m_ringdb_key;
}
+void wallet2::register_devices(){
+ hw::trezor::register_all();
+}
+
+hw::device& wallet2::lookup_device(const std::string & device_descriptor){
+ if (!m_devices_registered){
+ m_devices_registered = true;
+ register_devices();
+ }
+
+ return hw::get_device(device_descriptor);
+}
+
bool wallet2::add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx)
{
if (!m_ringdb)
@@ -9084,6 +9100,62 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
return ptx_vector;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::cold_tx_aux_import(const std::vector<pending_tx> & ptx, const std::vector<std::string> & tx_device_aux)
+{
+ CHECK_AND_ASSERT_THROW_MES(ptx.size() == tx_device_aux.size(), "TX aux has invalid size");
+ for (size_t i = 0; i < ptx.size(); ++i){
+ crypto::hash txid;
+ txid = get_transaction_hash(ptx[i].tx);
+ set_tx_device_aux(txid, tx_device_aux[i]);
+ }
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux)
+{
+ auto & hwdev = get_account().get_device();
+ if (!hwdev.has_tx_cold_sign()){
+ throw std::invalid_argument("Device does not support cold sign protocol");
+ }
+
+ unsigned_tx_set txs;
+ for (auto &tx: ptx_vector)
+ {
+ txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device()));
+ }
+ txs.transfers = m_transfers;
+
+ auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
+ CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
+
+ hw::tx_aux_data aux_data;
+ hw::wallet_shim wallet_shim;
+ setup_shim(&wallet_shim, this);
+ aux_data.tx_recipients = dsts_info;
+ dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data);
+ tx_device_aux = aux_data.tx_device_aux;
+
+ MDEBUG("Signed tx data from hw: " << exported_txs.ptx.size() << " transactions");
+ for (auto &c_ptx: exported_txs.ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(c_ptx.tx));
+}
+//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) {
+ auto & hwdev = get_account().get_device();
+ if (!hwdev.has_ki_cold_sync()){
+ throw std::invalid_argument("Device does not support cold ki sync protocol");
+ }
+
+ auto dev_cold = dynamic_cast<::hw::device_cold*>(&hwdev);
+ CHECK_AND_ASSERT_THROW_MES(dev_cold, "Device does not implement cold signing interface");
+
+ std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
+ hw::wallet_shim wallet_shim;
+ setup_shim(&wallet_shim, this);
+
+ dev_cold->ki_sync(&wallet_shim, m_transfers, ski);
+
+ return import_key_images(ski, spent, unspent);
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const
{
boost::optional<std::string> result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
@@ -10240,6 +10312,19 @@ std::string wallet2::get_tx_note(const crypto::hash &txid) const
return i->second;
}
+void wallet2::set_tx_device_aux(const crypto::hash &txid, const std::string &aux)
+{
+ m_tx_device[txid] = aux;
+}
+
+std::string wallet2::get_tx_device_aux(const crypto::hash &txid) const
+{
+ std::unordered_map<crypto::hash, std::string>::const_iterator i = m_tx_device.find(txid);
+ if (i == m_tx_device.end())
+ return std::string();
+ return i->second;
+}
+
void wallet2::set_attribute(const std::string &key, const std::string &value)
{
m_attributes[key] = value;
@@ -10785,6 +10870,29 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
return m_transfers[signed_key_images.size() - 1].m_block_height;
}
+
+bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
+{
+ if (key_images.size() > m_transfers.size())
+ {
+ LOG_PRINT_L1("More key images returned that we know outputs for");
+ return false;
+ }
+ for (size_t i = 0; i < key_images.size(); ++i)
+ {
+ transfer_details &td = m_transfers[i];
+ if (td.m_key_image_known && !td.m_key_image_partial && td.m_key_image != key_images[i])
+ LOG_PRINT_L0("WARNING: imported key image differs from previously known key image at index " << i << ": trusting imported one");
+ td.m_key_image = key_images[i];
+ m_key_images[m_transfers[i].m_key_image] = i;
+ td.m_key_image_known = true;
+ td.m_key_image_partial = false;
+ m_pub_keys[m_transfers[i].get_public_key()] = i;
+ }
+
+ return true;
+}
+
wallet2::payment_container wallet2::export_payments() const
{
payment_container payments;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 680196f01..7d78a3fee 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -54,6 +54,7 @@
#include "ringct/rctTypes.h"
#include "ringct/rctOps.h"
#include "checkpoints/checkpoints.h"
+#include "serialization/pair.h"
#include "wallet_errors.h"
#include "common/password.h"
@@ -764,6 +765,9 @@ namespace tools
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
+ void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux);
+ void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux);
+ uint64_t cold_key_image_sync(uint64_t &spent, uint64_t &unspent);
bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
bool sign_multisig_tx_from_file(const std::string &filename, std::vector<crypto::hash> &txids, std::function<bool(const multisig_tx_set&)> accept_func);
@@ -892,6 +896,9 @@ namespace tools
if(ver < 25)
return;
a & m_last_block_reward;
+ if(ver < 26)
+ return;
+ a & m_tx_device;
}
/*!
@@ -1020,6 +1027,9 @@ namespace tools
void set_tx_note(const crypto::hash &txid, const std::string &note);
std::string get_tx_note(const crypto::hash &txid) const;
+ void set_tx_device_aux(const crypto::hash &txid, const std::string &aux);
+ std::string get_tx_device_aux(const crypto::hash &txid) const;
+
void set_description(const std::string &description);
std::string get_description() const;
@@ -1074,6 +1084,8 @@ namespace tools
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
+ bool import_key_images(std::vector<crypto::key_image> key_images);
+ crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
void update_pool_state(bool refreshed = false);
void remove_obsolete_pool_txs(const std::vector<crypto::hash> &tx_hashes);
@@ -1236,7 +1248,6 @@ namespace tools
void set_unspent(size_t idx);
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count);
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
- crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
void scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map<cryptonote::subaddress_index, uint64_t> &tx_money_got_in_outs, std::vector<size_t> &outs);
@@ -1253,6 +1264,9 @@ namespace tools
crypto::chacha_key get_ringdb_key();
void setup_keys(const epee::wipeable_string &password);
+ void register_devices();
+ hw::device& lookup_device(const std::string & device_descriptor);
+
bool get_rct_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution);
uint64_t get_segregation_fork_height() const;
@@ -1347,6 +1361,9 @@ namespace tools
size_t m_subaddress_lookahead_major, m_subaddress_lookahead_minor;
std::string m_device_name;
+ // Aux transaction data from device
+ std::unordered_map<crypto::hash, std::string> m_tx_device;
+
// Light wallet
bool m_light_wallet; /* sends view key to daemon for scanning */
uint64_t m_light_wallet_scanned_block_height;
@@ -1373,11 +1390,12 @@ namespace tools
boost::optional<epee::wipeable_string> m_encrypt_keys_after_refresh;
bool m_unattended;
+ bool m_devices_registered;
std::shared_ptr<tools::Notify> m_tx_notify;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 25)
+BOOST_CLASS_VERSION(tools::wallet2, 26)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 9)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)