device: show address on device display

- Trezor: support for device address display (subaddress, integrated address)
- Wallet::API support added
- Simplewallet:
  - address device [<index>]
  - address new <label>  // shows address on device also
  - integrated_address [device] <payment_id|address>  // new optional "device" arg to display also on the device
This commit is contained in:
Dusan Klinec 2019-05-31 10:41:52 +02:00
parent 5fbfa8a656
commit f074b6b571
No known key found for this signature in database
GPG key ID: 6337E118CCBCE103
12 changed files with 128 additions and 7 deletions

@ -1 +1 @@
Subproject commit cb238cb1f134accc4200217d9511115a8f61c6cb
Subproject commit 31a0073c62738827b48d725facd3766879429124

View file

@ -236,6 +236,7 @@ namespace hw {
virtual bool compute_key_image(const cryptonote::account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const cryptonote::subaddress_index& received_index, cryptonote::keypair& in_ephemeral, crypto::key_image& ki) { return false; }
virtual void computing_key_images(bool started) {};
virtual void set_network_type(cryptonote::network_type network_type) { }
virtual void display_address(const cryptonote::subaddress_index& index, const boost::optional<crypto::hash8> &payment_id) {}
protected:
device_mode mode;

View file

@ -47,6 +47,7 @@ namespace hw {
std::vector<cryptonote::address_parse_info> tx_recipients; // as entered by user
boost::optional<int> bp_version; // BP version to use
boost::optional<unsigned> client_version; // Signing client version to use (testing)
boost::optional<uint8_t> hard_fork; // hard fork being used for the transaction
};
class device_cold {

View file

@ -200,6 +200,10 @@ namespace trezor {
}
}
void device_trezor::display_address(const cryptonote::subaddress_index& index, const boost::optional<crypto::hash8> &payment_id) {
get_address(index, payment_id, true);
}
/* ======================================================================= */
/* Helpers */
/* ======================================================================= */
@ -209,8 +213,12 @@ namespace trezor {
/* ======================================================================= */
std::shared_ptr<messages::monero::MoneroAddress> device_trezor::get_address(
const boost::optional<cryptonote::subaddress_index> & subaddress,
const boost::optional<crypto::hash8> & payment_id,
bool show_address,
const boost::optional<std::vector<uint32_t>> & path,
const boost::optional<cryptonote::network_type> & network_type){
CHECK_AND_ASSERT_THROW_MES(!payment_id || !subaddress || subaddress->is_zero(), "Subaddress cannot be integrated");
TREZOR_AUTO_LOCK_CMD();
require_connected();
device_state_reset_unsafe();
@ -218,6 +226,14 @@ namespace trezor {
auto req = std::make_shared<messages::monero::MoneroGetAddress>();
this->set_msg_addr<messages::monero::MoneroGetAddress>(req.get(), path, network_type);
req->set_show_display(show_address);
if (subaddress){
req->set_account(subaddress->major);
req->set_minor(subaddress->minor);
}
if (payment_id){
req->set_payment_id(std::string(payment_id->data, 8));
}
auto response = this->client_exchange<messages::monero::MoneroAddress>(req);
MTRACE("Get address response received");

View file

@ -110,6 +110,7 @@ namespace trezor {
/* ======================================================================= */
bool get_public_address(cryptonote::account_public_address &pubkey) override;
bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
void display_address(const cryptonote::subaddress_index& index, const boost::optional<crypto::hash8> &payment_id) override;
/* ======================================================================= */
/* TREZOR PROTOCOL */
@ -119,6 +120,9 @@ namespace trezor {
* Get address. Throws.
*/
std::shared_ptr<messages::monero::MoneroAddress> get_address(
const boost::optional<cryptonote::subaddress_index> & subaddress = boost::none,
const boost::optional<crypto::hash8> & payment_id = boost::none,
bool show_address = false,
const boost::optional<std::vector<uint32_t>> & path = boost::none,
const boost::optional<cryptonote::network_type> & network_type = boost::none);

View file

@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "version.h"
#include "protocol.hpp"
#include <unordered_map>
#include <set>
@ -502,6 +503,8 @@ namespace tx {
tsx_data.set_num_inputs(static_cast<google::protobuf::uint32>(tx.sources.size()));
tsx_data.set_mixin(static_cast<google::protobuf::uint32>(tx.sources[0].outputs.size() - 1));
tsx_data.set_account(tx.subaddr_account);
tsx_data.set_monero_version(std::string(MONERO_VERSION) + "|" + MONERO_VERSION_TAG);
tsx_data.set_hard_fork(m_aux_data->hard_fork ? m_aux_data->hard_fork.get() : 0);
assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end());
// Rsig decision

View file

@ -177,8 +177,8 @@ namespace
" account tag <tag_name> <account_index_1> [<account_index_2> ...]\n"
" account untag <account_index_1> [<account_index_2> ...]\n"
" account tag_description <tag_name> <description>");
const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]");
const char* USAGE_INTEGRATED_ADDRESS("integrated_address [<payment_id> | <address>]");
const char* USAGE_ADDRESS("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed> | device [<index>]]");
const char* USAGE_INTEGRATED_ADDRESS("integrated_address [device] [<payment_id> | <address>]");
const char* USAGE_ADDRESS_BOOK("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]");
const char* USAGE_SET_VARIABLE("set <option> [<value>]");
const char* USAGE_GET_TX_KEY("get_tx_key <txid>");
@ -8501,6 +8501,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
// address all
// address <index_min> [<index_max>]
// address label <index> <label text with white spaces allowed>
// address device [<index>]
std::vector<std::string> local_args = args;
tools::wallet2::transfer_container transfers;
@ -8537,6 +8538,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
label = tr("(Untitled address)");
m_wallet->add_subaddress(m_current_subaddress_account, label);
print_address_sub(m_wallet->get_num_subaddresses(m_current_subaddress_account) - 1);
m_wallet->device_show_address(m_current_subaddress_account, m_wallet->get_num_subaddresses(m_current_subaddress_account) - 1, boost::none);
}
else if (local_args.size() >= 2 && local_args[0] == "label")
{
@ -8585,6 +8587,27 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
for (index = index_min; index <= index_max; ++index)
print_address_sub(index);
}
else if (local_args[0] == "device")
{
index = 0;
local_args.erase(local_args.begin());
if (local_args.size() > 0)
{
if (!epee::string_tools::get_xtype_from_string(index, local_args[0]))
{
fail_msg_writer() << tr("failed to parse index: ") << local_args[0];
return true;
}
if (index >= m_wallet->get_num_subaddresses(m_current_subaddress_account))
{
fail_msg_writer() << tr("<index> is out of bounds");
return true;
}
}
print_address_sub(index);
m_wallet->device_show_address(m_current_subaddress_account, index, boost::none);
}
else
{
PRINT_USAGE(USAGE_ADDRESS);
@ -8596,12 +8619,29 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
bool simple_wallet::print_integrated_address(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
crypto::hash8 payment_id;
if (args.size() > 1)
bool display_on_device = false;
std::vector<std::string> local_args = args;
if (local_args.size() > 0 && local_args[0] == "device")
{
local_args.erase(local_args.begin());
display_on_device = true;
}
auto device_show_integrated = [this, display_on_device](crypto::hash8 payment_id)
{
if (display_on_device)
{
m_wallet->device_show_address(m_current_subaddress_account, 0, payment_id);
}
};
if (local_args.size() > 1)
{
PRINT_USAGE(USAGE_INTEGRATED_ADDRESS);
return true;
}
if (args.size() == 0)
if (local_args.size() == 0)
{
if (m_current_subaddress_account != 0)
{
@ -8611,9 +8651,10 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
payment_id = crypto::rand<crypto::hash8>();
success_msg_writer() << tr("Random payment ID: ") << payment_id;
success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype());
device_show_integrated(payment_id);
return true;
}
if(tools::wallet2::parse_short_payment_id(args.back(), payment_id))
if(tools::wallet2::parse_short_payment_id(local_args.back(), payment_id))
{
if (m_current_subaddress_account != 0)
{
@ -8621,16 +8662,18 @@ bool simple_wallet::print_integrated_address(const std::vector<std::string> &arg
return true;
}
success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype());
device_show_integrated(payment_id);
return true;
}
else {
address_parse_info info;
if(get_account_address_from_str(info, m_wallet->nettype(), args.back()))
if(get_account_address_from_str(info, m_wallet->nettype(), local_args.back()))
{
if (info.has_payment_id)
{
success_msg_writer() << boost::format(tr("Integrated address: %s, payment ID: %s")) %
get_account_address_as_str(m_wallet->nettype(), false, info.address) % epee::string_tools::pod_to_hex(info.payment_id);
device_show_integrated(info.payment_id);
}
else
{

View file

@ -2419,6 +2419,23 @@ uint64_t WalletImpl::coldKeyImageSync(uint64_t &spent, uint64_t &unspent)
{
return m_wallet->cold_key_image_sync(spent, unspent);
}
void WalletImpl::deviceShowAddress(uint32_t accountIndex, uint32_t addressIndex, const std::string &paymentId)
{
boost::optional<crypto::hash8> payment_id_param = boost::none;
if (!paymentId.empty())
{
crypto::hash8 payment_id;
bool res = tools::wallet2::parse_short_payment_id(paymentId, payment_id);
if (!res)
{
throw runtime_error("Invalid payment ID");
}
payment_id_param = payment_id;
}
m_wallet->device_show_address(accountIndex, addressIndex, payment_id_param);
}
} // namespace
namespace Bitmonero = Monero;

View file

@ -201,6 +201,7 @@ public:
virtual bool unlockKeysFile() override;
virtual bool isKeysFileLocked() override;
virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) override;
virtual void deviceShowAddress(uint32_t accountIndex, uint32_t addressIndex, const std::string &paymentId) override;
private:
void clearStatus() const;

View file

@ -1003,6 +1003,9 @@ struct Wallet
//! cold-device protocol key image sync
virtual uint64_t coldKeyImageSync(uint64_t &spent, uint64_t &unspent) = 0;
//! shows address on device display
virtual void deviceShowAddress(uint32_t accountIndex, uint32_t addressIndex, const std::string &paymentId) = 0;
};
/**

View file

@ -10048,6 +10048,7 @@ void wallet2::cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_
setup_shim(&wallet_shim, this);
aux_data.tx_recipients = dsts_info;
aux_data.bp_version = use_fork_rules(HF_VERSION_SMALLER_BP, -10) ? 2 : 1;
aux_data.hard_fork = get_current_hard_fork();
dev_cold->tx_sign(&wallet_shim, txs, exported_txs, aux_data);
tx_device_aux = aux_data.tx_device_aux;
@ -10075,6 +10076,35 @@ uint64_t wallet2::cold_key_image_sync(uint64_t &spent, uint64_t &unspent) {
return import_res;
}
//----------------------------------------------------------------------------------------------------
void wallet2::device_show_address(uint32_t account_index, uint32_t address_index, const boost::optional<crypto::hash8> &payment_id)
{
if (!key_on_device())
{
return;
}
auto & hwdev = get_account().get_device();
hwdev.display_address(subaddress_index{account_index, address_index}, payment_id);
}
//----------------------------------------------------------------------------------------------------
uint8_t wallet2::get_current_hard_fork()
{
if (m_offline)
return 0;
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_HARD_FORK_INFO::response resp_t = AUTO_VAL_INIT(resp_t);
m_daemon_rpc_mutex.lock();
req_t.version = 0;
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, tools::error::no_connection_to_daemon, "hard_fork_info");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "hard_fork_info");
THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, "hard_fork_info", m_trusted_daemon ? resp_t.status : "daemon error");
return resp_t.version;
}
//----------------------------------------------------------------------------------------------------
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);

View file

@ -843,6 +843,7 @@ private:
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);
void device_show_address(uint32_t account_index, uint32_t address_index, const boost::optional<crypto::hash8> &payment_id);
bool parse_multisig_tx_from_str(std::string multisig_tx_st, multisig_tx_set &exported_txs) const;
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);
@ -1094,6 +1095,7 @@ private:
size_t get_num_transfer_details() const { return m_transfers.size(); }
const transfer_details &get_transfer_details(size_t idx) const;
uint8_t get_current_hard_fork();
void get_hard_fork_info(uint8_t version, uint64_t &earliest_height) const;
bool use_fork_rules(uint8_t version, int64_t early_blocks = 0) const;
int get_fee_algorithm() const;