This is a big update towards working protocol transactions.

1. The CONVERT TX is creating the necessary information.
2. The PROTOCOL TX is creating the necessary information.
3. The wallet recognises the subaddress (kind of) on incoming amounts.

At present, the PROTOCOL TX outputs are NOT spendable or included in balances.
This commit is contained in:
Some Random Crypto Guy
2023-12-13 14:41:59 +00:00
parent 4955910886
commit 6787d1d018
19 changed files with 487 additions and 142 deletions
+6 -3
View File
@@ -157,7 +157,9 @@ struct txpool_tx_meta_t
{
crypto::hash max_used_block_id;
crypto::hash last_failed_id;
crypto::public_key destination_address;
crypto::key_image input_k_image;
crypto::public_key return_address;
crypto::public_key one_time_public_key;
uint64_t weight;
uint64_t fee;
uint64_t amount_burnt;
@@ -168,7 +170,8 @@ struct txpool_tx_meta_t
uint64_t last_relayed_time; //!< If received over i2p/tor, randomized forward time. If Dandelion++stem, randomized embargo time. Otherwise, last relayed timestamp
uint32_t source_asset_id;
uint32_t destination_asset_id;
// 168 bytes
// 232 bytes
uint8_t tx_type;
uint8_t kept_by_block;
uint8_t relayed;
uint8_t do_not_relay;
@@ -179,7 +182,7 @@ struct txpool_tx_meta_t
uint8_t is_forwarding: 1;
uint8_t bf_padding: 3;
uint8_t padding[20]; // till 192 bytes
uint8_t padding[19]; // till 256 bytes
void set_relay_method(relay_method method) noexcept;
relay_method get_relay_method() const noexcept;
+2 -2
View File
@@ -382,7 +382,7 @@ typedef struct circ_supply_tally {
typedef struct yield_tx_data {
crypto::hash tx_hash;
crypto::public_key destination_address;
crypto::public_key return_address;
uint64_t amount;
} yield_tx_data;
@@ -1156,7 +1156,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
// Create the object we are going to write to the database
yield_tx_data yield_data;
yield_data.tx_hash = tx_hash;
yield_data.destination_address = tx.destination_address;
yield_data.return_address = tx.return_address;
yield_data.amount = tx.amount_burnt; // SRCG - this feels as though we are bastardising the variable for an invalid purpose
MDB_val_set(val_height, m_height);
MDB_val_set(val_yield_tx_data, yield_data);
-1
View File
@@ -212,7 +212,6 @@ namespace crypto {
tools::write_varint(end, output_index);
assert(end <= buf.output_index + sizeof buf.output_index);
hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
assert(false);
}
bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
+8
View File
@@ -49,6 +49,14 @@ namespace crypto {
derivation_to_scalar(d, uniqueness, scalar);
return monero_crypto_generate_subaddress_public_key(out.data, output_pub.data, scalar.data) == 0;
}
inline
bool derive_subaddress_public_key(const public_key &output_pub, const key_derivation &d, std::size_t output_index, public_key &out)
{
ec_scalar scalar;
derivation_to_scalar(d, output_index, scalar);
return monero_crypto_generate_subaddress_public_key(out.data, output_pub.data, scalar.data) == 0;
}
#else
using ::crypto::generate_key_derivation;
using ::crypto::derive_subaddress_public_key;
+4 -4
View File
@@ -199,8 +199,8 @@ namespace cryptonote
std::vector<uint8_t> extra;
// TX type
cryptonote::transaction_type type;
// Destination address (encrypted)
crypto::public_key destination_address;
// Return address (encrypted)
crypto::public_key return_address;
// Source asset type
std::string source_asset_type;
// Destination asset type (this is only necessary for CONVERT transactions)
@@ -218,7 +218,7 @@ namespace cryptonote
FIELD(vout)
FIELD(extra)
VARINT_FIELD(type)
FIELD(destination_address)
FIELD(return_address)
FIELD(source_asset_type)
FIELD(destination_asset_type)
VARINT_FIELD(amount_burnt)
@@ -235,7 +235,7 @@ namespace cryptonote
vout.clear();
extra.clear();
type = cryptonote::transaction_type::UNSET;
destination_address = crypto::null_pkey;
return_address = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
amount_burnt = 0;
@@ -167,7 +167,7 @@ namespace boost
a & x.vout;
a & x.extra;
a & x.type;
a & x.destination_address;
a & x.return_address;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_burnt;
@@ -183,7 +183,7 @@ namespace boost
a & x.vout;
a & x.extra;
a & x.type;
a & x.destination_address;
a & x.return_address;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_burnt;
@@ -358,6 +358,7 @@ namespace cryptonote
// computes Hs(a*R || uniqueness) + b
//crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&real_output_index), sizeof(size_t));
hwdev.derive_secret_key(recv_derivation, uniqueness, spend_skey, scalar_step1);
//hwdev.derive_secret_key(recv_derivation, real_output_index, spend_skey, scalar_step1);
// step 2: add Hs(a || index_major || index_minor)
crypto::secret_key subaddr_sk;
@@ -1278,6 +1279,7 @@ namespace cryptonote
//---------------------------------------------------------------
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, const boost::optional<crypto::view_tag>& view_tag_opt)
{
LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__);
// Calculate the uniqueness
crypto::hash uniqueness = cn_fast_hash(reinterpret_cast<void*>(&output_index), sizeof(size_t));
@@ -1297,7 +1299,18 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev))
{
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], uniqueness, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
LOG_ERROR("*****************************************************************************");
LOG_ERROR("derivation: " << additional_derivations[output_index]);
LOG_ERROR("output_ind: " << output_index);
LOG_ERROR("uniqueness: " << uniqueness);
LOG_ERROR("output_key: " << out_key);
LOG_ERROR("subaddr_sp: " << subaddress_spendkey);
LOG_ERROR("*****************************************************************************");
auto found = subaddresses.find(subaddress_spendkey);
if (found != subaddresses.end())
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
+8 -5
View File
@@ -1528,9 +1528,9 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
// Only conversion (and failed conversion, aka refund) TXs need to be verified - skip this TX
continue;
}
/*
// Verify that the TX has an output in the protocol_tx to verify
if (outputs.count(tx->destination_address) != 1) {
if (outputs.count(tx->return_address) != 1) {
LOG_ERROR("Failed to locate output for conversion TX id " << tx->hash << " - rejecting block");
return false;
}
@@ -1539,7 +1539,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
std::string output_asset_type;
uint64_t output_amount;
uint64_t output_unlock_time;
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->destination_address];
std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->return_address];
// Verify the asset_type
if (tx->source_asset_type == output_asset_type) {
@@ -1566,6 +1566,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
LOG_ERROR("Output asset type incorrect: source " << tx->source_asset_type << ", dest " << tx->destination_asset_type << ", got " << output_asset_type << " - rejecting block");
return false;
}
*/
}
return true;
@@ -1817,7 +1818,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
* Here is where the magic happens - determination of the payments for the protocol_tx
*
* We need to know the following:
* - address to send the funds to ("destination_address")
* - address to send the funds to ("return_address")
* - asset_type being burnt
* - amount being burnt
* - asset_type being minted
@@ -1842,7 +1843,9 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.amount_slippage_limit = meta.amount_slippage_limit;
entry.source_asset = asset_type_from_id(meta.source_asset_id);
entry.destination_asset = asset_type_from_id(meta.destination_asset_id);
entry.destination_address = meta.destination_address;
entry.return_address = meta.return_address;
entry.P_change = meta.one_time_public_key;
entry.input_k_image = meta.input_k_image;
protocol_entries.push_back(entry);
}
+190 -28
View File
@@ -49,6 +49,68 @@ using namespace crypto;
namespace cryptonote
{
rct::key sm(rct::key y, int n, const rct::key &x)
{
while (n--)
sc_mul(y.bytes, y.bytes, y.bytes);
sc_mul(y.bytes, y.bytes, x.bytes);
return y;
}
// Compute the inverse of a scalar, the clever way
rct::key invert(const rct::key &x)
{
rct::key _1, _10, _100, _11, _101, _111, _1001, _1011, _1111;
_1 = x;
sc_mul(_10.bytes, _1.bytes, _1.bytes);
sc_mul(_100.bytes, _10.bytes, _10.bytes);
sc_mul(_11.bytes, _10.bytes, _1.bytes);
sc_mul(_101.bytes, _10.bytes, _11.bytes);
sc_mul(_111.bytes, _10.bytes, _101.bytes);
sc_mul(_1001.bytes, _10.bytes, _111.bytes);
sc_mul(_1011.bytes, _10.bytes, _1001.bytes);
sc_mul(_1111.bytes, _100.bytes, _1011.bytes);
rct::key inv;
sc_mul(inv.bytes, _1111.bytes, _1.bytes);
inv = sm(inv, 123 + 3, _101);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 4, _1001);
inv = sm(inv, 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 3, _101);
inv = sm(inv, 3 + 3, _101);
inv = sm(inv, 3, _111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 2 + 3, _111);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 2 + 4, _1011);
inv = sm(inv, 6 + 4, _1001);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 1 + 4, _1001);
inv = sm(inv, 1 + 3, _111);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 3, _101);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 3, _101);
inv = sm(inv, 1 + 2, _11);
// Sanity check for successful inversion
rct::key tmp;
sc_mul(tmp.bytes, inv.bytes, x.bytes);
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
return inv;
}
//---------------------------------------------------------------
void classify_addresses(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
{
@@ -173,6 +235,9 @@ namespace cryptonote
const oracle::pricing_record& pr,
const uint8_t hf_version) {
// A vector to contain all of the additional _tx_secret_keys_
//std::vector<crypto::secret_key>& additional_tx_keys;
// Clear the TX contents
tx.set_null();
tx.type = cryptonote::transaction_type::PROTOCOL;
@@ -202,12 +267,63 @@ namespace cryptonote
// Calculate the slippage for the output amounts
LOG_PRINT_L2("Creating protocol_tx...");
std::vector<crypto::public_key> additional_tx_public_keys;
for (auto const& entry: protocol_data) {
if (entry.destination_asset == "BURN") {
// BURN TX - no slippage, no money minted - skip
continue;
}
// CONVERT TX - calculate the slippage, and decide if it is going to be converted or refunded
// CONVERT TX
// Create a secret TX key (= s)
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
//additional_tx_keys.push_back(s);
// Now add the correct TX public key (= sP_change)
crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s)));
additional_tx_public_keys.push_back(txkey_pub);
// Calculate the actual return address, because the field we already have is actually the TX pubkey to use
// return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change
// Generate the uniqueness for the input
size_t output_index = tx.vout.size();
crypto::hash uniqueness = cn_fast_hash(&entry.input_k_image.data[0], 32);
// y = Hs(uniqueness)
ec_scalar y;
crypto::hash_to_scalar(&uniqueness, sizeof(crypto::hash), y);
rct::key key_y = (rct::key&)(y);
rct::key key_F = (rct::key&)(entry.return_address);
crypto::public_key yF = rct::rct2pk(rct::scalarmultKey(key_F, key_y));
crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s)));
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation));
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << uniqueness << ", "<< entry.P_change << ")");
// Sanity checks
crypto::public_key P_change_verify = crypto::null_pkey;
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << output_index << ", " << P_change_verify << ")");
LOG_ERROR("*****************************************************************************");
LOG_ERROR("output_index : " << output_index);
LOG_ERROR("P_change : " << entry.P_change);
LOG_ERROR("key_y : " << key_y);
LOG_ERROR("key_F : " << key_F);
LOG_ERROR("s : " << s);
LOG_ERROR("yF : " << yF);
LOG_ERROR("der. (syF) : " << derivation_syF);
LOG_ERROR("uniqueness : " << uniqueness);
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)");
LOG_ERROR("P_change_ver : " << P_change_verify);
LOG_ERROR("*****************************************************************************");
// Now calculate the slippage, and decide if it is going to be converted or refunded
uint64_t amount_slippage = 0, amount_minted = 0;
bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version);
if (!ok) {
@@ -222,7 +338,7 @@ namespace cryptonote
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, entry.destination_address, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
tx.vout.push_back(out);
} else {
@@ -232,12 +348,14 @@ namespace cryptonote
// Create the TX output for this conversion
tx_out out;
cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, entry.destination_address, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
tx.vout.push_back(out);
}
}
// Add in all of the additional TX pubkeys we need to process the payments
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
// TODO: create the YIELD outputs
// Create the txin_gen now
@@ -291,13 +409,6 @@ namespace cryptonote
r = crypto::derive_public_key(derivation, /*output_index*/uniqueness, miner_address.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
LOG_ERROR("*****************************************************************************");
LOG_ERROR("derivation: " << derivation);
LOG_ERROR("uniqueness: " << uniqueness);
LOG_ERROR("txkey_pub : " << txkey.pub);
LOG_ERROR("output_key: " << out_eph_public_key);
LOG_ERROR("*****************************************************************************");
uint64_t amount = block_reward;
summary_amounts += amount;
@@ -348,23 +459,71 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
bool get_protocol_destination_address(const size_t tx_version, const crypto::key_image& ki, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, crypto::public_key& tx_destination_address, hw::device& hwdev) {
bool get_return_address(const size_t tx_version, // needed in case we change implementation down the line
const cryptonote::transaction_type& type, // needed to determine between TRANSFER, CONVERT, YIELD
const crypto::key_image& ki, // needed for uniqueness
const cryptonote::account_keys &sender_account_keys, // needed to calculate pretty much anything
const crypto::public_key &P_change, // one-time public key from CONVERT/YIELD change
const crypto::public_key &txkey_pub, // public TX key from CONVERT/YIELD TX
crypto::public_key& F, // OUTPUT
hw::device& hwdev // hardware device to use (usually a software dev)
) {
// With a protocol destination address, you are always sending the payment to yourself; derivation = a*R
// Derivation ( = shared secret = z_i)
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
bool r = hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "at get_protocol_destination_address: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
CHECK_AND_ASSERT_MES(r, false, "at get_return_address: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
// Generate the uniqueness for the input
crypto::hash uniqueness = cn_fast_hash(&ki.data[0], 32);
r = hwdev.derive_public_key(derivation, uniqueness, sender_account_keys.m_account_address.m_spend_public_key, tx_destination_address);
CHECK_AND_ASSERT_MES(r, false, "at get_protocol_destination_address: failed to derive_public_key()");
ec_scalar y;
if (type == cryptonote::TRANSFER) {
// TRANSFER relies on a shared secret (the key_derivation Z_i) between sender and recipient
// y = Hs(uniqueness || z_i)
r = hwdev.derivation_to_scalar(derivation, uniqueness, y);
CHECK_AND_ASSERT_MES(r, false, "at get_return_address: failed to derivation_to_scalar(" << derivation << ", " << uniqueness << ")");
} else if (type == cryptonote::CONVERT || type == cryptonote::YIELD) {
// CONVERT & YIELD do not use the shared secret, because protocol_tx cannot have a wallet address or keys
// Instead, we just use the uniqueness value from tx.vin[0].k_image
crypto::hash_to_scalar(&uniqueness, sizeof(crypto::hash), y);
} else {
LOG_ERROR("Invalid TX type - return_address is not applicable");
return false;
}
// Now generate the return address
// F = (y^-1).a.P_change
// First, we need to produce the multiplicative inverse of the scalar "y" (aka "y^-1")
rct::key key_y = (rct::key&)(y);
rct::key key_inv_y = invert(key_y);
// Now convert this value back into a secret key that we can use
crypto::secret_key sk_y = rct::rct2sk(key_y);
crypto::secret_key sk_inv_y = rct::rct2sk(key_inv_y);
crypto::key_derivation derivation_aP_change = AUTO_VAL_INIT(derivation_aP_change);
r = hwdev.generate_key_derivation(P_change, sender_account_keys.m_view_secret_key, derivation_aP_change);
CHECK_AND_ASSERT_MES(r, false, "while calculating get_return_address: failed to generate_key_derivation(" << P_change << ", " << sender_account_keys.m_view_secret_key << ")");
crypto::public_key pk_aP_change = crypto::null_pkey;
memcpy(pk_aP_change.data, derivation_aP_change.data, sizeof(crypto::public_key));
// Sanity check that we can reverse the invert safely
rct::key key_aP_change = rct::pk2rct(pk_aP_change);
rct::key key_test = rct::scalarmultKey(key_aP_change, key_inv_y);
rct::key key_verify = rct::scalarmultKey(key_test, key_y);
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
F = rct::rct2pk(key_test);
LOG_ERROR("*****************************************************************************");
LOG_ERROR("derivation: " << derivation);
LOG_ERROR("key_image : " << ki);
LOG_ERROR("uniqueness: " << uniqueness);
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("tx_address: " << tx_destination_address);
LOG_ERROR("a : " << sender_account_keys.m_view_secret_key);
LOG_ERROR("y : " << key_y);
LOG_ERROR("P_change : " << P_change);
LOG_ERROR("aP_change : " << pk_aP_change);
LOG_ERROR("F : " << F);
LOG_ERROR("*****************************************************************************");
return true;
@@ -630,16 +789,6 @@ namespace cryptonote
if (need_additional_txkeys)
CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys");
// Is this a CONVERT tx?
if (tx_type == cryptonote::transaction_type::CONVERT) {
// Set the destination address to be something only our wallet can identify
// This is where Fulmo gets interesting... we need to include the input key images
// so that we get uniqueness and prevent either Monero burning bug or key leakage.
// tx.d_a = Hs("convert" || input_key_images || 8rAG) + B
const txin_to_key &in = boost::get<txin_to_key>(tx.vin[0]);
CHECK_AND_ASSERT_MES(get_protocol_destination_address(tx.version, in.k_image, sender_account_keys, txkey_pub, tx_key, tx.destination_address, hwdev), false, "Failed to get protocol destination address");
}
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
@@ -678,6 +827,19 @@ namespace cryptonote
}
CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys");
// Is this a CONVERT tx?
if (tx_type == cryptonote::transaction_type::CONVERT) {
// Set the destination address to be something our wallet can prove ownership of.
// This is where Fulmo gets interesting... we need to include the input key images
// so that we get uniqueness and prevent either Monero burning bug or key leakage.
// tx.d_a = Hs("convert" || input_key_image[0] || 8rAG) + B
const txin_to_key &in = boost::get<txin_to_key>(tx.vin[0]);
crypto::public_key P_change;
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - too many outputs for CONVERT tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[0], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, in.k_image, sender_account_keys, P_change, txkey_pub, tx.return_address, hwdev), false, "Failed to get protocol destination address");
}
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
LOG_PRINT_L2("tx pubkey: " << txkey_pub);
+4 -1
View File
@@ -54,12 +54,15 @@ namespace cryptonote
*/
struct protocol_data_entry
{
crypto::public_key destination_address;
crypto::public_key return_address;
uint64_t amount_burnt;
uint64_t amount_minted;
uint64_t amount_slippage_limit;
std::string source_asset;
std::string destination_asset;
cryptonote::transaction_type type;
crypto::public_key P_change;
crypto::key_image input_k_image;
};
bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector<protocol_data_entry>& protocol_data, std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
//---------------------------------------------------------------
+9 -2
View File
@@ -284,7 +284,7 @@ namespace cryptonote
memset(meta.padding, 0, sizeof(meta.padding));
//SRCG - need to work out how to populate this
meta.destination_address = tx.destination_address;
meta.return_address = tx.return_address;
meta.amount_burnt = tx.amount_burnt;
meta.amount_slippage_limit = tx.amount_slippage_limit;
meta.source_asset_id = cryptonote::asset_id_from_type(tx.source_asset_type);
@@ -367,11 +367,18 @@ namespace cryptonote
memset(meta.padding, 0, sizeof(meta.padding));
//SRCG - need to work out how to populate this
meta.destination_address = tx.destination_address;
meta.return_address = tx.return_address;
meta.amount_burnt = tx.amount_burnt;
meta.amount_slippage_limit = tx.amount_slippage_limit;
meta.source_asset_id = cryptonote::asset_id_from_type(tx.source_asset_type);
meta.destination_asset_id = cryptonote::asset_id_from_type(tx.destination_asset_type);
meta.tx_type = tx.type;
crypto::public_key change_output_public_key;
bool ok = cryptonote::get_output_public_key(tx.vout[0], change_output_public_key);
if (!ok)
return false;
meta.one_time_public_key = change_output_public_key;
meta.input_k_image = boost::get<cryptonote::txin_to_key>(tx.vin[0]).k_image;
if (!insert_key_images(tx, id, tx_relay))
return false;
+4
View File
@@ -157,6 +157,7 @@ namespace hw {
/* SUB ADDRESS */
/* ======================================================================= */
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) = 0;
virtual bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_pub) = 0;
virtual crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) = 0;
virtual std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) = 0;
virtual cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) = 0;
@@ -172,6 +173,9 @@ namespace hw {
virtual crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) = 0;
virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0;
virtual bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) = 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 derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) = 0;
virtual bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0;
virtual bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0;
+18
View File
@@ -124,6 +124,10 @@ namespace hw {
return crypto::wallet::derive_subaddress_public_key(out_key, derivation, uniqueness, derived_key);
}
bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_key) {
return crypto::wallet::derive_subaddress_public_key(out_key, derivation, output_index, derived_key);
}
crypto::public_key device_default::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;
@@ -240,6 +244,20 @@ namespace hw {
return crypto::wallet::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::derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res){
crypto::derivation_to_scalar(derivation, uniqueness, res);
return true;
+4
View File
@@ -81,6 +81,7 @@ namespace hw {
/* SUB ADDRESS */
/* ======================================================================= */
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) override;
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, std::size_t output_index, crypto::public_key &derived_pub) override;
crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) override;
std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) override;
cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) override;
@@ -96,6 +97,9 @@ namespace hw {
crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override;
bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) 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 derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) override;
bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
+180
View File
@@ -735,6 +735,60 @@ namespace hw {
return true;
}
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){
#ifdef DEBUG_HWDEVICE
const crypto::public_key pub_x = pub;
crypto::key_derivation derivation_x;
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
derivation_x = derivation;
} else {
derivation_x = hw::ledger::decrypt(derivation);
}
const std::size_t output_index_x = output_index;
crypto::public_key derived_pub_x;
log_hexbuffer("derive_subaddress_public_key: [[IN]] pub ", pub_x.data, 32);
log_hexbuffer("derive_subaddress_public_key: [[IN]] derivation", derivation_x.data, 32);
log_message ("derive_subaddress_public_key: [[IN]] index ", std::to_string((int)output_index_x));
if (!this->controle_device->derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x))
return false;
log_hexbuffer("derive_subaddress_public_key: [[OUT]] derived_pub", derived_pub_x.data, 32);
#endif
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
//If we are in TRANSACTION_PARSE, the given derivation has been retrieved uncrypted (wihtout the help
//of the device), so continue that way.
MDEBUG( "derive_subaddress_public_key : PARSE mode with known viewkey");
if (!crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub))
return false;
} else {
AUTO_LOCK_CMD();
int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY);
//pub
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
//derivation
this->send_secret((unsigned char*)derivation.data, offset);
//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
return true;
}
crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
if (has_view_key) {
cryptonote::account_keys keys_{keys};
@@ -1117,6 +1171,132 @@ namespace hw {
return this->generate_key_derivation(*pkey, crypto::null_skey, derivation);
}
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) {
AUTO_LOCK_CMD();
#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;
log_hexbuffer("derivation_to_scalar: [[IN]] derivation ", derivation_x.data, 32);
log_message ("derivation_to_scalar: [[IN]] output_index ", std::to_string(output_index_x));
this->controle_device->derivation_to_scalar(derivation_x, output_index_x, res_x);
log_hexbuffer("derivation_to_scalar: [[OUT]] res ", res_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR);
//derivation
this->send_secret((unsigned char*)derivation.data, offset);
//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();
//derivation data
offset = 0;
this->receive_secret((unsigned char*)res.data, offset);
#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
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) {
AUTO_LOCK_CMD();
#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;
log_hexbuffer("derive_secret_key: [[IN]] derivation ", derivation_x.data, 32);
log_message ("derive_secret_key: [[IN]] index ", std::to_string(output_index_x));
log_hexbuffer("derive_secret_key: [[IN]] sec ", sec_x.data, 32);
this->controle_device->derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x);
log_hexbuffer("derive_secret_key: [[OUT]] derived_sec", derived_sec_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY);
//derivation
this->send_secret((unsigned char*)derivation.data, offset);
//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
this->send_secret((unsigned char*)sec.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
this->exchange();
offset = 0;
//sec key
this->receive_secret((unsigned char*)derived_sec.data, offset);
#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
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){
AUTO_LOCK_CMD();
#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;
log_hexbuffer("derive_public_key: [[IN]] derivation ", derivation_x.data, 32);
log_message ("derive_public_key: [[IN]] output_index", std::to_string(output_index_x));
log_hexbuffer("derive_public_key: [[IN]] pub ", pub_x.data, 32);
if (!this->controle_device->derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x))
return false;
log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY);
//derivation
this->send_secret((unsigned char*)derivation.data, offset);
//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
return true;
}
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) {
AUTO_LOCK_CMD();
+4
View File
@@ -229,6 +229,7 @@ namespace hw {
/* SUB ADDRESS */
/* ======================================================================= */
bool derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::public_key &derived_pub) override;
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;
crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) override;
std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) override;
cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) override;
@@ -244,6 +245,9 @@ namespace hw {
crypto::secret_key generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false) override;
bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override;
bool conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) 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 derivation_to_scalar(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, crypto::ec_scalar &res) override;
bool derive_secret_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override;
bool derive_public_key(const crypto::key_derivation &derivation, const crypto::hash& uniqueness, const crypto::public_key &pub, crypto::public_key &derived_pub) override;
+1
View File
@@ -120,6 +120,7 @@ namespace
}
namespace rct {
Bulletproof proveRangeBulletproof(keyV &C, keyV &masks, const std::vector<uint64_t> &amounts, epee::span<const key> sk, hw::device &hwdev)
{
CHECK_AND_ASSERT_THROW_MES(amounts.size() == sk.size(), "Invalid amounts/sk sizes");
+2 -2
View File
@@ -275,7 +275,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
INSERT_INTO_JSON_OBJECT(dest, outputs, tx.vout);
INSERT_INTO_JSON_OBJECT(dest, extra, tx.extra);
INSERT_INTO_JSON_OBJECT(dest, type, static_cast<uint8_t>(tx.type));
INSERT_INTO_JSON_OBJECT(dest, destination_address, tx.destination_address);
INSERT_INTO_JSON_OBJECT(dest, return_address, tx.return_address);
INSERT_INTO_JSON_OBJECT(dest, source_asset_type, tx.source_asset_type);
INSERT_INTO_JSON_OBJECT(dest, destination_asset_type, tx.destination_asset_type);
INSERT_INTO_JSON_OBJECT(dest, amount_burnt, tx.amount_burnt);
@@ -303,7 +303,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
GET_FROM_JSON_OBJECT(val, tx.vout, outputs);
GET_FROM_JSON_OBJECT(val, tx.extra, extra);
GET_FROM_JSON_OBJECT(val, tx.type, type);
GET_FROM_JSON_OBJECT(val, tx.destination_address, destination_address);
GET_FROM_JSON_OBJECT(val, tx.return_address, return_address);
GET_FROM_JSON_OBJECT(val, tx.source_asset_type, source_asset_type);
GET_FROM_JSON_OBJECT(val, tx.destination_asset_type, destination_asset_type);
GET_FROM_JSON_OBJECT(val, tx.amount_burnt, amount_burnt);
+27 -91
View File
@@ -1788,13 +1788,13 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
LOG_ERROR("wrong type id in transaction out");
return;
}
/*
// Check for presence in the map of protocol_tx entries we are expecting
if (auto search = m_protocol_txs.find(output_public_key); search != m_protocol_txs.end())
{
LOG_ERROR("********************** FOUND A PROTOCOL_TX - WHAT TO DO NEXT??? **********************");
}
*/
tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, output_public_key, derivation, additional_derivations, i, hwdev, get_output_view_tag(o));
if(tx_scan_info.received)
{
@@ -1820,7 +1820,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
LOG_ERROR("wrong type id in transaction out");
return;
}
/*
// Check for presence in the map of protocol_tx entries we are expecting
if (auto search = m_protocol_txs.find(output_public_key); search != m_protocol_txs.end())
{
@@ -1903,7 +1903,10 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
tx_scan_info.error = true;
return;
}
} else {
}
else
*/
{
tx_scan_info.received = is_out_data->received[i];
tx_scan_info.uniqueness = cn_fast_hash(reinterpret_cast<void*>(&i), sizeof(size_t));
}
@@ -2011,85 +2014,6 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons
++num_vouts_received;
}
//----------------------------------------------------------------------------------------------------
void wallet2::scan_protocol_tx_output(const cryptonote::transaction &tx, bool miner_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, std::map<std::string, uint64_t>> &tx_money_got_in_outs, std::vector<size_t> &outs, bool pool)
{
THROW_WALLET_EXCEPTION_IF(tx.type != cryptonote::transaction_type::PROTOCOL, error::wallet_internal_error, "Only PROTOCOL transactions may use the scan_protocol_tx_output() method");
THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index");
// if keys are encrypted, ask for password
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only && !m_multisig_rescan_k)
{
static critical_section password_lock;
CRITICAL_REGION_LOCAL(password_lock);
if (!m_encrypt_keys_after_refresh)
{
boost::optional<epee::wipeable_string> pwd = m_callback->on_get_password(pool ? "output found in pool" : "output received");
THROW_WALLET_EXCEPTION_IF(!pwd, error::password_needed, tr("Password is needed to compute key image for incoming monero"));
THROW_WALLET_EXCEPTION_IF(!verify_password(*pwd), error::password_needed, tr("Invalid password: password is needed to compute key image for incoming monero"));
m_encrypt_keys_after_refresh.reset(new wallet_keys_unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, *pwd));
}
}
// Scan our map of protocol_tx entries for the appropriate progenitor for this TX
crypto::public_key output_public_key;
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(tx.vout[i], output_public_key), error::wallet_internal_error, "Failed to get output public key");
// Check for presence in the map of protocol_tx entries we are expecting
auto search = m_protocol_txs.find(output_public_key);
if (search == m_protocol_txs.end())
{
tx_scan_info.error = true;
MERROR("failed to locate progenitor for specified output_public_key" << output_public_key);
return;
}
size_t idx = search->second;
if (idx >= get_num_transfer_details()) {
MERROR("cannot locate protocol_txs index in m_transfers - idx = " << idx);
tx_scan_info.error = true;
return;
}
const transfer_details& td = get_transfer_details(idx);
if (td.m_tx.type != cryptonote::transaction_type::CONVERT && td.m_tx.type != cryptonote::transaction_type::YIELD) {
// We can only accept CONVERT & YIELD payments
MERROR("incorrect TX type for protocol_tx origin in m_transfers - idx = " << idx);
tx_scan_info.error = true;
return;
}
if (m_multisig)
{
tx_scan_info.in_ephemeral.pub = output_public_key;
tx_scan_info.in_ephemeral.sec = crypto::null_skey;
tx_scan_info.ki = rct::rct2ki(rct::zero());
}
else
{
bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.uniqueness, 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 != output_public_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
}
THROW_WALLET_EXCEPTION_IF(std::find(outs.begin(), outs.end(), i) != outs.end(), error::wallet_internal_error, "Same output cannot be added twice");
if (tx_scan_info.money_transfered == 0 && !miner_tx)
{
tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.uniqueness, tx_scan_info.mask, m_account.get_device());
}
if (tx_scan_info.money_transfered == 0)
{
MERROR("Invalid output amount, skipping");
tx_scan_info.error = true;
return;
}
outs.push_back(i);
THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info.received->index][tx_scan_info.asset_type] >= std::numeric_limits<uint64_t>::max() - tx_scan_info.money_transfered,
error::wallet_internal_error, "Overflow in received amounts");
tx_money_got_in_outs[tx_scan_info.received->index][tx_scan_info.asset_type] += tx_scan_info.money_transfered;
tx_scan_info.amount = tx_scan_info.money_transfered;
++num_vouts_received;
}
//----------------------------------------------------------------------------------------------------
void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const
{
if(!parse_tx_extra(tx.extra, tx_cache_data.tx_extra_fields))
@@ -2280,7 +2204,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
std::vector<crypto::key_derivation> additional_derivations;
tx_extra_additional_pub_keys additional_tx_pub_keys;
const wallet2::is_out_data *is_out_data_ptr = NULL;
if (tx_cache_data.primary.empty())
if (tx_cache_data.primary.empty() || tx.type == cryptonote::PROTOCOL)
{
hw::device &hwdev = m_account.get_device();
boost::unique_lock<hw::device> hwdev_lock (hwdev);
@@ -2301,6 +2225,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for (size_t i = 0; i < additional_tx_pub_keys.data.size(); ++i)
{
crypto::public_key aR = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(additional_tx_pub_keys.data[i]), rct::sk2rct(keys.m_view_secret_key)));
additional_derivations.push_back({});
if (!hwdev.generate_key_derivation(additional_tx_pub_keys.data[i], keys.m_view_secret_key, additional_derivations.back()))
{
@@ -2378,11 +2303,11 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
boost::unique_lock<hw::device> hwdev_lock (hwdev);
hwdev.set_mode(hw::device::NONE);
hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations);
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
scan_protocol_tx_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
} else {
//if (tx.type == cryptonote::transaction_type::PROTOCOL) {
// scan_protocol_tx_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
//} else {
scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool);
}
//}
if (!tx_scan_info[i].error)
{
tx_amounts_individual_outs[tx_scan_info[i].received->index].push_back(tx_scan_info[i].money_transfered);
@@ -2663,8 +2588,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
// The CONVERT/YIELD TX was created by us - therefore we need to expect an output in the PROTOCOL_TX
// It could be a refund or a conversion
m_protocol_txs.insert({tx.destination_address, m_transfers.size()-1});
}
//m_protocol_txs.insert({tx.return_address, m_transfers.size()-1});
// Add the change output_public_key to the list of subaddresses to check
crypto::public_key P_change = crypto::null_pkey;
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[0], P_change), error::wallet_internal_error, "Failed to get change output public key");
m_subaddresses[P_change] = {0,0};
m_protocol_txs.insert({P_change, m_transfers.size()-1});
}
if (tx_money_spent_in_ins > 0 && !pool)
{
@@ -3109,8 +3040,13 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
auto &slot = tx_cache_data[i];
for (auto &iod: slot.primary)
gender(iod);
for (auto &iod: slot.additional)
for (auto &iod: slot.additional) {
gender(iod);
LOG_ERROR("*****************************************************************************");
LOG_ERROR("public_key : " << iod.pkey);
LOG_ERROR("der. (aR) : " << iod.derivation);
LOG_ERROR("*****************************************************************************");
}
}, true);
}
THROW_WALLET_EXCEPTION_IF(!waiter.wait(), error::wallet_internal_error, "Exception in thread pool");