mirror of https://github.com/oxen-io/oxen-core.git
Overhaul tx prefix comms; rename some overloaded methods
Tx prefix communication was missing some needed information on the tx type, and was a little inefficient. This redoes the protocol to send the tx type info and then the entire prefix (rather than starting from a few bytes in). It also changes how we number requests and signal the final piece of a multi-piece transmission.
This commit is contained in:
parent
d044ecd391
commit
ad7e63a04f
|
@ -35,6 +35,7 @@
|
|||
#include "cryptonote_basic/subaddress_index.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "common/lock.h"
|
||||
#include "common/varint.h"
|
||||
|
||||
namespace hw {
|
||||
|
||||
|
@ -1443,13 +1444,26 @@ namespace hw {
|
|||
void device_ledger::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
|
||||
auto locks = tools::unique_locks(device_locker, command_locker);
|
||||
|
||||
int pref_length = 0, pref_offset = 0, offset = 0;
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
crypto::hash h_x;
|
||||
this->controle_device->get_transaction_prefix_hash(tx,h_x);
|
||||
MDEBUG("get_transaction_prefix_hash [[IN]] h_x/1 "<<h_x);
|
||||
#endif
|
||||
|
||||
// As of protocol version 4, we send:
|
||||
// - tx version
|
||||
// - tx type (transfer, registration, stake, lns)
|
||||
// - tx lock time (if the tx has multiple lock times this will be the largest one)
|
||||
// We then wait for confirmation from the device, and if we get it we continue by sending the
|
||||
// data in chunks of 256 bytes at a time. The last chunk will have a p2 subparameter of ff;
|
||||
// otherwise the p2 subparameters are in order.
|
||||
//
|
||||
// In terms of subcommand parameters, then, this goes:
|
||||
// (1) -- send version, type, locktime
|
||||
// (2,0) -- 256 bytes and more to come
|
||||
// (2,1) -- another 256 bytes and more to come
|
||||
// ...
|
||||
// (2,ff) -- last 256 bytes. (Note that this could happen instead of (2,0), above).
|
||||
|
||||
std::string tx_prefix;
|
||||
try {
|
||||
|
@ -1458,55 +1472,45 @@ namespace hw {
|
|||
ASSERT_MES_AND_THROW("unable to serialize transaction prefix: " << e.what());
|
||||
}
|
||||
|
||||
pref_length = tx_prefix.size();
|
||||
const unsigned char* pref = reinterpret_cast<const unsigned char*>(tx_prefix.c_str());
|
||||
// Safety check because this is the biggest the protocol can support (it's also an insanely
|
||||
// large tx prefix).
|
||||
CHECK_AND_ASSERT_THROW_MES(tx_prefix.size() <= 256*256, "Transaction prefix too big.");
|
||||
|
||||
offset = set_command_header_noopt(INS_PREFIX_HASH,1);
|
||||
pref_offset = 0;
|
||||
unsigned char v;
|
||||
unsigned char* send = this->buffer_send + set_command_header_noopt(INS_PREFIX_HASH, 1);
|
||||
|
||||
//version as varint
|
||||
do {
|
||||
v = pref[pref_offset];
|
||||
this->buffer_send[offset] = v;
|
||||
offset += 1;
|
||||
pref_offset += 1;
|
||||
} while (v&0x80);
|
||||
// version as varint
|
||||
tools::write_varint(send, static_cast<std::underlying_type_t<cryptonote::txversion>>(tx.version));
|
||||
|
||||
//locktime as var int
|
||||
do {
|
||||
v = pref[pref_offset];
|
||||
this->buffer_send[offset] = v;
|
||||
offset += 1;
|
||||
pref_offset += 1;
|
||||
} while (v&0x80);
|
||||
// transaction type as varint
|
||||
tools::write_varint(send, static_cast<std::underlying_type_t<cryptonote::txtype>>(tx.type));
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
// Transactions can have multiple unlock times; find the longest one and send that
|
||||
uint64_t max_unlock = 0;
|
||||
for (size_t i = 0; i < tx.vout.size(); i++)
|
||||
max_unlock = std::max(max_unlock, tx.get_unlock_time(i));
|
||||
tools::write_varint(send, max_unlock);
|
||||
|
||||
|
||||
this->length_send = send - this->buffer_send;
|
||||
this->buffer_send[4] = length_send - 5;
|
||||
this->exchange_wait_on_input();
|
||||
|
||||
//hash remains
|
||||
int cnt = 0;
|
||||
while (pref_offset < pref_length) {
|
||||
int len;
|
||||
cnt++;
|
||||
offset = set_command_header(INS_PREFIX_HASH,2,cnt);
|
||||
len = pref_length - pref_offset;
|
||||
//options
|
||||
if (len > (BUFFER_SEND_SIZE-7)) {
|
||||
len = BUFFER_SEND_SIZE-7;
|
||||
this->buffer_send[offset] = 0x80;
|
||||
} else {
|
||||
this->buffer_send[offset] = 0x00;
|
||||
}
|
||||
offset += 1;
|
||||
//send chunk
|
||||
memmove(&this->buffer_send[offset], pref+pref_offset, len);
|
||||
offset += len;
|
||||
pref_offset += len;
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
// hash the full prefix
|
||||
uint8_t cnt = 0;
|
||||
for (size_t pos = 0; pos < tx_prefix.size(); pos += 256, ++cnt) {
|
||||
size_t size = tx_prefix.size() - pos;
|
||||
if (size > 256)
|
||||
size = 256;
|
||||
else
|
||||
cnt = 0xff;
|
||||
|
||||
size_t header_size = set_command_header_noopt(INS_PREFIX_HASH, 2, cnt);
|
||||
assert(header_size + 256 <= BUFFER_SEND_SIZE);
|
||||
|
||||
std::memcpy(this->buffer_send + header_size, &tx_prefix[pos], size);
|
||||
this->buffer_send[4] = size;
|
||||
this->length_send = header_size + size;
|
||||
exchange();
|
||||
}
|
||||
memmove(h.data, &this->buffer_recv[0], 32);
|
||||
|
||||
|
|
|
@ -4400,9 +4400,10 @@ std::optional<epee::wipeable_string> simple_wallet::new_device_wallet(const boos
|
|||
message_writer() << tr("Your hardware device will ask for permission to export your wallet view key.\n"
|
||||
"This is optional, but will significantly improve wallet syncing speed. Your\n"
|
||||
"spend key (needed to spend funds) does not leave the device.");
|
||||
m_wallet->restore(m_wallet_file, std::move(rc.second).password(), device_desc.empty() ? "Ledger" : device_desc, create_address_file);
|
||||
message_writer(epee::console_color_white, true) << tr("Generated new wallet on hw device: ")
|
||||
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
m_wallet->restore_from_device(
|
||||
m_wallet_file, std::move(rc.second).password(), device_desc.empty() ? "Ledger" : device_desc, create_address_file,
|
||||
[](const std::string& msg) { message_writer(epee::console_color_green, true) << msg; });
|
||||
message_writer(epee::console_color_white, true) << tr("Finished setting up wallet from hw device");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -4508,7 +4509,7 @@ std::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::pro
|
|||
prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str();
|
||||
else
|
||||
prefix = tr("Opened wallet");
|
||||
message_writer(epee::console_color_white, true) <<
|
||||
message_writer(epee::console_color_green, true) <<
|
||||
prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
if (m_wallet->get_account().get_device()) {
|
||||
message_writer(epee::console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name();
|
||||
|
|
|
@ -4937,13 +4937,8 @@ void wallet2::generate(const fs::path& wallet_, const epee::wipeable_string& pas
|
|||
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 fs::path& wallet_, const epee::wipeable_string& password, const std::string &device_name, bool create_address_file)
|
||||
void wallet2::restore_from_device(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name,
|
||||
bool create_address_file, std::function<void(std::string msg)> progress_callback)
|
||||
{
|
||||
clear();
|
||||
prepare_file_names(wallet_);
|
||||
|
@ -4963,6 +4958,8 @@ void wallet2::restore(const fs::path& wallet_, const epee::wipeable_string& pass
|
|||
m_account.create_from_device(hwdev);
|
||||
init_type(m_account.get_device().get_type());
|
||||
setup_keys(password);
|
||||
if (progress_callback)
|
||||
progress_callback(tr("Retrieved wallet address from device: ") + m_account.get_public_address_str(m_nettype));
|
||||
m_device_name = device_name;
|
||||
|
||||
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
|
||||
|
@ -4972,6 +4969,7 @@ void wallet2::restore(const fs::path& wallet_, const epee::wipeable_string& pass
|
|||
m_subaddress_lookahead_major = 5;
|
||||
m_subaddress_lookahead_minor = 20;
|
||||
}
|
||||
progress_callback(tr("Setting up account and subaddresses"));
|
||||
setup_new_blockchain();
|
||||
if (!wallet_.empty()) {
|
||||
store();
|
||||
|
|
|
@ -519,13 +519,15 @@ private:
|
|||
const cryptonote::account_public_address &account_public_address,
|
||||
const crypto::secret_key& viewkey = crypto::secret_key(), bool create_address_file = true);
|
||||
/*!
|
||||
* \brief Restore a wallet hold by an HW.
|
||||
* \brief Restore a wallet from a hardware device
|
||||
* \param wallet_ Name of wallet file
|
||||
* \param password Password of wallet file
|
||||
* \param device_name name of HW to use
|
||||
* \param create_address_file Whether to create an address file
|
||||
* \param status_callback callback to invoke with progress messages to display to the user
|
||||
*/
|
||||
void restore(const fs::path& wallet_, const epee::wipeable_string& password, const std::string &device_name, bool create_address_file = true);
|
||||
void restore_from_device(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name,
|
||||
bool create_address_file = false, std::function<void(std::string msg)> status_callback = {});
|
||||
|
||||
/*!
|
||||
* \brief Creates a multisig wallet
|
||||
|
|
Loading…
Reference in New Issue