1
0
Fork 0
forked from lthn/blockchain

ca: global refactoring: tx balance validation, asset operation validation, transaction creation. Also, main tx structure improved with @cryptozoidberg to reflect needs in versatile prunable proofs storage!

This commit is contained in:
sowle 2023-02-21 01:51:55 +01:00
parent f9b54f305a
commit f3eb63d25c
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
6 changed files with 292 additions and 256 deletions

View file

@ -1359,7 +1359,8 @@ bool blockchain_storage::validate_miner_transaction(const block& b,
return false;
}
if (!check_tx_balance(b.miner_tx, base_reward + fee))
crypto::hash tx_id_for_balance_check = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash;
if (!check_tx_balance(b.miner_tx, tx_id_for_balance_check, base_reward + fee))
{
LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee)
<< ", blocks_size_median = " << blocks_size_median
@ -3551,8 +3552,7 @@ bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx)
}
else
{
CHECK_AND_ASSERT_MES(ei.m_asset_operation.asset_id.size() == 1, false, "Unexpected asset_id in operation");
asset_id = ei.m_asset_operation.asset_id.back();
CHECK_AND_NO_ASSERT_MES(false, false, "asset operation not implemented");
}
r = pop_asset_info(asset_id);
CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info");
@ -3802,15 +3802,16 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id)
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::put_asset_info(const transaction & tx, asset_descriptor_operation & ado)
bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado)
{
CRITICAL_REGION_LOCAL(m_read_lock);
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::public_key asset_id{};
calculate_asset_id(ado.descriptor.owner, nullptr, &asset_id);
CHECK_AND_ASSERT_MES(validate_asset_operation(tx, tx_id, ado, asset_id), false, "asset operation validation failed!");
auto asset_history_ptr = m_db_assets.find(asset_id);
CHECK_AND_ASSERT_MES(!asset_history_ptr, false, "Asset id already existing");
CHECK_AND_ASSERT_MES(!asset_history_ptr, false, "asset with id " << asset_id << " has already been registered");
assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history);
local_asset_history.push_back(ado);
m_db_assets.set(asset_id, local_asset_history);
@ -3821,7 +3822,7 @@ bool blockchain_storage::put_asset_info(const transaction & tx, asset_descriptor
else
{
//TODO: implement other operations
CHECK_AND_ASSERT_THROW(false, "not implemented yet");
CHECK_AND_ASSERT_THROW(false, "asset operation not implemented yet");
}
return true;
@ -3902,7 +3903,7 @@ bool blockchain_storage::prevalidate_alias_info(const transaction& tx, const ext
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx)
bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id)
{
//check transaction extra
tx_extra_info ei = AUTO_VAL_INIT(ei);
@ -3918,7 +3919,7 @@ bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx)
}
if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED)
{
r = put_asset_info(tx, ei.m_asset_operation);
r = put_asset_info(tx, tx_id, ei.m_asset_operation);
CHECK_AND_ASSERT_MES(r, false, "failed to put_asset_info");
}
@ -4096,7 +4097,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(tx, tx_id, bl_height), false, "tx " << tx_id << ": hardfork-specific validation failed");
TIME_MEASURE_START_PD(tx_process_extra);
bool r = process_blockchain_tx_extra(tx);
bool r = process_blockchain_tx_extra(tx, tx_id);
CHECK_AND_ASSERT_MES(r, false, "failed to process_blockchain_tx_extra");
TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_extra);
@ -5351,6 +5352,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
return false;
}
// TODO @#@# consider: 1) tx.proofs, 2) new proof data structures
if (var_is_after_hardfork_4_zone)
{
@ -5714,7 +5716,7 @@ bool blockchain_storage::collect_rangeproofs_data_from_tx(std::vector<zc_outs_ra
// TODO @#@# Verify somewhere(maybe here) that all outputs are covered with associated rangeproofs
size_t proofs_count = 0;
size_t current_output_start = 0; //for Consolidated Transactions we'll have multiple zc_outs_range_proof entries
for (const auto& a : tx.attachment)
for (const auto& a : tx.proofs)
{
if (a.type() == typeid(zc_outs_range_proof))
{
@ -5886,24 +5888,24 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
append_per_block_increments_for_tx(tx, gindices);
//If we under checkpoints, ring signatures should be pruned
//If we under checkpoints, attachments, ring signatures and proofs should be pruned
if(m_is_in_checkpoint_zone)
{
tx.signatures.clear();
tx.attachment.clear();
tx.signatures.clear();
tx.proofs.clear();
}
//std::vector<crypto::point_t&> tx_outs_commitments;
if (!m_is_in_checkpoint_zone)
{
if (!collect_rangeproofs_data_from_tx(range_proofs_agregated, tx/*, tx_outs_commitments*/))
{
LOG_PRINT_L0("Block with id: " << id << " has at least one transaction with wrong proofs, tx_id: " << tx_id << ", collect_rangeproofs_data_from_tx failed");
purge_block_data_from_blockchain(bl, tx_processed_count);
//add_block_as_invalid(bl, id);
bvc.m_verification_failed = true;
return false;
}
auto cleanup = [&](){ purge_block_data_from_blockchain(bl, tx_processed_count); bvc.m_verification_failed = true; };
CHECK_AND_ASSERT_MES_CUSTOM(collect_rangeproofs_data_from_tx(range_proofs_agregated, tx/*, tx_outs_commitments*/), false, cleanup(),
"block " << id << ", tx " << tx_id << ": collect_rangeproofs_data_from_tx failed");
CHECK_AND_ASSERT_MES_CUSTOM(check_tx_balance(tx, tx_id), false, cleanup(),
"block " << id << ", tx " << tx_id << ": check_tx_balance failed");
}
TIME_MEASURE_START_PD(tx_add_one_tx_time);
@ -5970,8 +5972,20 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
return false;
}
boost::multiprecision::uint128_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins:0;
uint64_t base_reward = get_base_block_reward(is_pos_bl, already_generated_coins, height);
if (!m_is_in_checkpoint_zone)
{
if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) // TODO @#@# base_reward will be calculated once again, consider refactoring
{
LOG_PRINT_L0("Block with id: " << id
<< " have wrong miner transaction");
purge_block_data_from_blockchain(bl, tx_processed_count);
bvc.m_verification_failed = true;
return false;
}
if (!collect_rangeproofs_data_from_tx(range_proofs_agregated, bl.miner_tx))
{
LOG_PRINT_L0("Block with id: " << id
@ -5980,28 +5994,16 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
bvc.m_verification_failed = true;
return false;
}
}
uint64_t base_reward = 0;
boost::multiprecision::uint128_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins:0;
if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins))
{
LOG_PRINT_L0("Block with id: " << id
<< " have wrong miner transaction");
purge_block_data_from_blockchain(bl, tx_processed_count);
bvc.m_verification_failed = true;
return false;
}
//validate range proofs
if (!verify_multiple_zc_outs_range_proofs(range_proofs_agregated))
{
LOG_PRINT_L0("Block with id: " << id
<< " have failed to verify multiple rangeproofs");
purge_block_data_from_blockchain(bl, tx_processed_count);
bvc.m_verification_failed = true;
return false;
//validate range proofs
if (!verify_multiple_zc_outs_range_proofs(range_proofs_agregated))
{
LOG_PRINT_L0("Block with id: " << id
<< " have failed to verify multiple rangeproofs");
purge_block_data_from_blockchain(bl, tx_processed_count);
bvc.m_verification_failed = true;
return false;
}
}

View file

@ -492,7 +492,7 @@ namespace currency
typedef tools::db::cached_key_value_accessor<uint64_t, uint64_t, false, true> solo_options_container;
typedef tools::db::basic_key_value_accessor<uint32_t, block_gindex_increments, true> per_block_gindex_increments_container; // height => [(amount, gindex_increment), ...]
typedef tools::db::cached_key_value_accessor<crypto::public_key, std::list<asset_descriptor_operation>, true, false> assets_container;
typedef tools::db::cached_key_value_accessor<crypto::public_key, std::list<asset_descriptor_operation>, true, false> assets_container; // TODO @#@# consider storing tx_id as well for reference -- sowle
//-----------------------------------------
@ -648,14 +648,14 @@ namespace currency
uint64_t get_adjusted_time()const;
bool complete_timestamps_vector(uint64_t start_height, std::vector<uint64_t>& timestamps);
bool update_next_comulative_size_limit();
bool process_blockchain_tx_extra(const transaction& tx);
bool process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id);
bool unprocess_blockchain_tx_extra(const transaction& tx);
bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp);
bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp);
bool pop_alias_info(const extra_alias_entry& ai);
bool put_alias_info(const transaction& tx, extra_alias_entry& ai);
bool pop_asset_info(const crypto::public_key& asset_id);
bool put_asset_info(const transaction & tx, asset_descriptor_operation & ado);
bool put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado);
void fill_addr_to_alias_dict();
//bool resync_spent_tx_flags();
bool prune_ring_signatures_and_attachments_if_need();

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@ -26,4 +26,5 @@
#define CRYPTO_HDS_ZARCANUM_PROOF_HASH "ZANO_HDS_ZARCANUM_PROOF_HASH___"
#define CRYPTO_HDS_ASSET_CONTROL_KEY "ZANO_HDS_ASSET_CONTROL_KEY_____"
#define CRYPTO_HDS_ASSET_CONTROL_ABM "ZANO_HDS_ASSET_CONTROL_ABM_____"
#define CRYPTO_HDS_ASSET_ID "ZANO_HDS_ASSET_ID______________"

View file

@ -765,7 +765,8 @@ namespace currency
std::string ticker;
std::string full_name;
std::string meta_info;
crypto::public_key owner = currency::null_pkey;
crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8
bool hidden_supply = false;
BEGIN_VERSIONED_SERIALIZE()
FIELD(total_max_supply)
@ -775,6 +776,7 @@ namespace currency
FIELD(full_name)
FIELD(meta_info)
FIELD(owner)
FIELD(hidden_supply)
END_SERIALIZE()
@ -828,23 +830,36 @@ namespace currency
struct asset_descriptor_operation
{
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
std::vector<crypto::signature> proof;
asset_descriptor_base descriptor;
std::vector<crypto::public_key> asset_id; //questionable regarding form of optional fields // premultiplied by 1/8
boost::optional<crypto::public_key> opt_amount_commitment; // premultiplied by 1/8
BEGIN_VERSIONED_SERIALIZE()
FIELD(operation_type)
FIELD(proof)
FIELD(descriptor)
FIELD(asset_id)
//FIELD(opt_amount_commitment)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(proof)
BOOST_SERIALIZE(descriptor)
//BOOST_SERIALIZE(opt_amount_commitment)
END_BOOST_SERIALIZATION()
};
struct asset_operation_proof
{
// linear composition proof for the fact amount_commitment = lin(asset_id, G)
boost::optional<crypto::linear_composition_proof_s> opt_amount_commitment_composition_proof; // for hidden supply
boost::optional<crypto::signature> opt_amount_commitment_g_proof; // for non-hidden supply, proofs that amount_commitment - supply * asset_id = lin(G)
BEGIN_VERSIONED_SERIALIZE()
//FIELD(opt_amount_commitment_composition_proof)
//FIELD(opt_amount_commitment_g_proof)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
//BOOST_SERIALIZE(opt_amount_commitment_composition_proof)
//BOOST_SERIALIZE(opt_amount_commitment_g_proof)
END_BOOST_SERIALIZATION()
};
@ -915,10 +930,10 @@ namespace currency
END_SERIALIZE()
};
typedef boost::mpl::vector26<
typedef boost::mpl::vector23<
tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time,
etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry_old, extra_user_data, extra_padding, etc_tx_flags16_t, etc_tx_details_unlock_time2,
tx_payer, tx_receiver, extra_alias_entry, zarcanum_tx_data_v1, zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_descriptor_operation
tx_payer, tx_receiver, extra_alias_entry, zarcanum_tx_data_v1, asset_descriptor_operation
> all_payload_types;
typedef boost::make_variant_over<all_payload_types>::type payload_items_v;
@ -969,7 +984,7 @@ namespace currency
typedef boost::variant<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v;
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof> proof_v;
//include backward compatibility defintions
@ -978,11 +993,9 @@ namespace currency
class transaction_prefix
{
public:
// tx version information
uint64_t version{};
//extra
std::vector<extra_v> extra;
uint64_t version = 0;
std::vector<txin_v> vin;
std::vector<extra_v> extra;
std::vector<tx_out_v> vout;
BEGIN_SERIALIZE()
@ -991,12 +1004,9 @@ namespace currency
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_prefix_v1)
if(CURRENT_TRANSACTION_VERSION < version) return false;
FIELD(vin)
FIELD(vout)
FIELD(extra)
FIELD(vout)
END_SERIALIZE()
protected:
transaction_prefix(){}
};
/*
@ -1012,55 +1022,23 @@ namespace currency
class transaction: public transaction_prefix
{
public:
std::vector<signature_v> signatures;
std::vector<attachment_v> attachment;
transaction();
std::vector<signature_v> signatures;
std::vector<proof_v> proofs;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<transaction_prefix *>(this))
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_v1)
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_v1)
FIELD(signatures)
FIELD(attachment)
FIELD(signatures)
FIELD(proofs)
END_SERIALIZE()
};
inline
transaction::transaction()
{
version = 0;
vin.clear();
vout.clear();
extra.clear();
signatures.clear();
attachment.clear();
}
/*
inline
transaction::~transaction()
{
//set_null();
}
inline
void transaction::set_null()
{
version = 0;
unlock_time = 0;
vin.clear();
vout.clear();
extra.clear();
signatures.clear();
}
*/
/************************************************************************/
/* */
@ -1122,8 +1100,6 @@ namespace currency
*/
//-------------------------------------------------------------------------------------------------------------------
#pragma pack(push, 1)
struct stake_modifier_type
{
@ -1133,7 +1109,6 @@ namespace currency
struct stake_kernel
{
stake_modifier_type stake_modifier;
uint64_t block_timestamp; //this block timestamp
crypto::key_image kimage;
@ -1246,6 +1221,7 @@ SET_VARIANT_TAGS(currency::zc_outs_range_proof, 47, "zc_outs_range_proof");
SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof");
SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base");
SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof");

View file

@ -103,15 +103,21 @@ namespace currency
crypto::scalar_t local_asset_id_blinding_masks_sum = 0;
crypto::scalar_t amount_blinding_masks_sum = 0;
crypto::scalar_t local_amount_blinding_masks_sum = 0;
// data for ongoing asset operation in tx (if applicable, tx extra should contain asset_descriptor_operation)
crypto::public_key ao_asset_id{};
crypto::point_t ao_asset_id_pt = crypto::c_point_0;
crypto::point_t ao_amount_commitment = crypto::c_point_0;
crypto::scalar_t ao_amount_blinding_mask{};
};
//--------------------------------------------------------------------------------
bool generate_asset_surjection_proof(zc_asset_surjection_proof& result)
bool generate_asset_surjection_proof(const crypto::hash& context_hash, zc_asset_surjection_proof& result)
{
// TODO: membership proof here
return false;
}
//--------------------------------------------------------------------------------
bool generate_zc_outs_range_proof(size_t out_index_start, size_t outs_count, const outputs_generation_context& outs_gen_context,
bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, size_t outs_count, const outputs_generation_context& outs_gen_context,
const std::vector<tx_out_v>& vouts, zc_outs_range_proof& result)
{
CHECK_AND_ASSERT_MES(outs_gen_context.check_sizes(outs_count), false, "");
@ -130,9 +136,8 @@ namespace currency
}
// aggregation proof
// TODO: @#@# use appropriate hash for context binding
uint8_t err = 0;
bool r = crypto::generate_vector_UG_aggregation_proof(null_hash, outs_gen_context.amounts, g_secrets,
bool r = crypto::generate_vector_UG_aggregation_proof(context_hash, outs_gen_context.amounts, g_secrets,
outs_gen_context.amount_commitments,
amount_commitments_for_rp_aggregation,
outs_gen_context.blinded_asset_ids, result.aggregation_proof, &err);
@ -162,7 +167,7 @@ namespace currency
}
//------------------------------------------------------------------
// for txs with no zc inputs (and thus no zc signatures) but with zc outputs
bool generate_tx_balance_proof(transaction &tx, const outputs_generation_context& outs_gen_context, uint64_t block_reward_for_miner_tx = 0)
bool generate_tx_balance_proof(transaction &tx, const crypto::hash& tx_id, const outputs_generation_context& outs_gen_context, uint64_t block_reward_for_miner_tx = 0)
{
CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "unsupported tx.version: " << tx.version);
CHECK_AND_ASSERT_MES(count_type_in_variant_container<ZC_sig>(tx.signatures) == 0, false, "ZC_sig is unexpected");
@ -200,15 +205,14 @@ namespace currency
// (fee - sum(bare inputs' amounts)) * H - sum(pseudo outs commitments for ZC inputs) + sum(outputs' commitments) = residual * G
// tx doesn't have any zc inputs --> add Schnorr proof for commitment to zero
CHECK_AND_ASSERT_MES(count_type_in_variant_container<zc_balance_proof>(tx.attachment) == 0, false, "");
CHECK_AND_ASSERT_MES(count_type_in_variant_container<zc_balance_proof>(tx.proofs) == 0, false, "");
zc_balance_proof balance_proof = AUTO_VAL_INIT(balance_proof);
crypto::point_t commitment_to_zero = outs_commitments_sum + (crypto::scalar_t(fee) - crypto::scalar_t(bare_inputs_sum)) * crypto::c_point_H;
//crypto::scalar_t witness = outputs_blinding_masks_sum;
// TODO: consider adding more data to message
crypto::generate_signature(null_hash, commitment_to_zero.to_public_key(), outs_gen_context.amount_blinding_masks_sum.as_secret_key(), balance_proof.s);
tx.attachment.push_back(balance_proof);
crypto::generate_signature(tx_id, commitment_to_zero.to_public_key(), outs_gen_context.amount_blinding_masks_sum.as_secret_key(), balance_proof.s);
tx.proofs.emplace_back(std::move(balance_proof));
return true;
}
@ -364,21 +368,6 @@ namespace currency
++output_index;
}
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
//add range proofs
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
bool r = generate_zc_outs_range_proof(0, destinations.size(), outs_gen_context, tx.vout, range_proofs);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
tx.attachment.push_back(range_proofs);
if (!pos)
{
r = generate_tx_balance_proof(tx, outs_gen_context, block_reward);
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
}
}
if (tx.attachment.size())
add_attachments_info_to_extra(tx.extra, tx.attachment);
@ -388,13 +377,87 @@ namespace currency
set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
}
//
// The tx prefix should be sealed by now, and the tx hash should be defined.
// Any changes made below should only affect the signatures/proofs and should not impact the prefix hash calculation.
//
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
crypto::hash tx_id = get_transaction_hash(tx);
//add range proofs
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
bool r = generate_zc_outs_range_proof(tx_id, 0, destinations.size(), outs_gen_context, tx.vout, range_proofs);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
tx.proofs.emplace_back(std::move(range_proofs));
if (!pos)
{
r = generate_tx_balance_proof(tx, tx_id, outs_gen_context, block_reward);
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
}
}
if (blinding_masks_sum_ptr)
*blinding_masks_sum_ptr = outs_gen_context.amount_blinding_masks_sum; // TODO @#@#
return true;
}
//------------------------------------------------------------------
bool check_tx_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx /* = 0 */)
bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx /* = 0 */)
{
// legacy checks for old fashioned tx with non-hidden amounts
CHECK_AND_ASSERT_MES(tx.version <= TRANSACTION_VERSION_PRE_HF4, false, "check_tx_bare_balance can't check post-HF4 txs");
uint64_t bare_outputs_sum = get_outs_money_amount(tx);
uint64_t bare_inputs_sum = get_inputs_money_amount(tx);
if (additional_inputs_amount_and_fees_for_mining_tx == 0)
{
// normal tx
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum)
<< ") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
}
else
{
// miner tx
CHECK_AND_ASSERT_MES(bare_inputs_sum + additional_inputs_amount_and_fees_for_mining_tx == bare_outputs_sum, false,
"tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum) <<
") + additional inputs and fees (" << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx) <<
") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
}
return true;
}
//-----------------------------------------------------------------------------------------------
bool validate_asset_operation(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, crypto::public_key& asset_id)
{
crypto::point_t asset_id_pt = crypto::c_point_0;
calculate_asset_id(ado.descriptor.owner, &asset_id_pt, &asset_id);
CHECK_AND_ASSERT_MES(count_type_in_variant_container<asset_operation_proof>(tx.proofs) == 1, false, "asset_operation_proof not present or present more than once");
const asset_operation_proof& aop = get_type_in_variant_container_by_ref<const asset_operation_proof>(tx.proofs);
if (ado.descriptor.hidden_supply)
{
CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_composition_proof.has_value(), false, "opt_amount_commitment_composition_proof is absent");
// TODO @#@# if asset is hidden -- theck composition proof
return false;
}
else
{
// make sure that amount commitment corresponds to opt_amount_commitment_g_proof
CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is absent");
CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_g_proof.has_value(), false, "opt_amount_commitment_g_proof is absent");
crypto::point_t A = crypto::point_t(ado.opt_amount_commitment.get()).modify_mul8() - ado.descriptor.current_supply * asset_id_pt;
bool r = crypto::check_signature(tx_id, A.to_public_key(), aop.opt_amount_commitment_g_proof.get());
CHECK_AND_ASSERT_MES(r, false, "opt_amount_commitment_g_proof check failed");
}
return true;
}
//------------------------------------------------------------------
bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx /* = 0 */)
{
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
@ -434,8 +497,9 @@ namespace currency
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
if (get_type_in_variant_container(tx.extra, ado) && ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) // @#@ TODO: Support other asset operations
{
CHECK_AND_ASSERT_MES(ado.asset_id.size() == 1, false, "invalid size of ado.asset_id: " << ado.asset_id.size());
sum_of_pseudo_out_amount_commitments += crypto::scalar_t(ado.descriptor.current_supply) * crypto::point_t(ado.asset_id.back()).modify_mul8();
// opt_amount_commitment supposed to be validated earlier in validate_asset_operation()
CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is not set");
sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.opt_amount_commitment.get()); // *1/8
}
size_t zc_sigs_count = 0;
for(auto& sig_v : tx.signatures)
@ -465,34 +529,16 @@ namespace currency
// no zc inputs -- there should be an explicit proof structure (Schnorr proof), proving that:
// (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = residual_g * G
zc_balance_proof balance_proof = AUTO_VAL_INIT(balance_proof);
bool r = get_type_in_variant_container<zc_balance_proof>(tx.attachment, balance_proof);
bool r = get_type_in_variant_container<zc_balance_proof>(tx.proofs, balance_proof);
CHECK_AND_ASSERT_MES(r, false, "no zc inputs are present, but at the same time there's no zc_balance_proof in attachment");
r = crypto::check_signature(null_hash, commitment_to_zero.to_public_key(), balance_proof.s);
r = crypto::check_signature(tx_id, commitment_to_zero.to_public_key(), balance_proof.s);
CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof is invalid");
}
return true;
}
else
{
// old fashioned tx with non-hidden amounts
uint64_t bare_outputs_sum = get_outs_money_amount(tx);
uint64_t bare_inputs_sum = get_inputs_money_amount(tx);
if (additional_inputs_amount_and_fees_for_mining_tx == 0)
{
// normal tx
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum)
<< ") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
}
else
{
// miner tx
CHECK_AND_ASSERT_MES(bare_inputs_sum + additional_inputs_amount_and_fees_for_mining_tx == bare_outputs_sum, false,
"tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum) <<
") + additional inputs and fees (" << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx) <<
") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
}
}
return true;
// pre-HF4 txs
return check_tx_bare_balance(tx, additional_inputs_amount_and_fees_for_mining_tx);
}
//------------------------------------------------------------------
bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral)
@ -780,7 +826,7 @@ namespace currency
template<class t_extra_typename>
bool operator()(const t_extra_typename& k) const
{
//do notheing for rest
//do nothing for rest
return true;
}
};
@ -1666,7 +1712,7 @@ namespace currency
const account_keys& sender_account_keys, const uint64_t tx_flags, outputs_generation_context& outs_gen_context, transaction& tx, bool last_output)
{
bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey;
CHECK_AND_ASSERT_MES(se.is_zarcanum(), false, "sources contains a non-zarcanum input");
CHECK_AND_ASSERT_MES(se.is_zc(), false, "sources contains a non-zc input");
CHECK_AND_ASSERT_MES(input_index < tx.vin.size(), false, "input_index (" << input_index << ") is out-of-bounds, vin.size = " << tx.vin.size());
CHECK_AND_ASSERT_MES(tx.vin[input_index].type() == typeid(txin_zc_input), false, "Unexpected type of input #" << input_index);
@ -1825,7 +1871,7 @@ namespace currency
bool r = false;
transaction& tx = result.tx;
crypto::secret_key& one_time_secret_key = result.one_time_key;
crypto::secret_key& one_time_tx_secret_key = result.one_time_key;
result.ftp = ftp;
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outs (" << destinations.size() << ")! Tx can't be constructed.");
@ -1856,7 +1902,7 @@ namespace currency
txkey = keypair::generate();
add_tx_pub_key_to_extra(tx, txkey.pub);
one_time_secret_key = txkey.sec;
one_time_tx_secret_key = txkey.sec;
//add flags
etc_tx_flags16_t e = AUTO_VAL_INIT(e);
@ -1870,7 +1916,7 @@ namespace currency
else
{
txkey.pub = get_tx_pub_key_from_extra(tx);
txkey.sec = one_time_secret_key;
txkey.sec = one_time_tx_secret_key;
CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided");
//separately encrypt attachments without putting extra
@ -1893,28 +1939,7 @@ namespace currency
uint64_t native_coins_input_sum = 0;
crypto::public_key asset_id_for_asset_operation = currency::null_pkey;
asset_descriptor_operation* pado = nullptr;
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
if (pado)
{
CHECK_AND_ASSERT_MES(pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation");
crypto::secret_key stub = AUTO_VAL_INIT(stub);
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_secret_key, stub, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
CHECK_AND_ASSERT_MES(r, false, "Failed to derive_public_key_from_tx_and_account_pub_key()");
//also assign this asset id to destinations
calculate_asset_id(pado->descriptor.owner, nullptr, &asset_id_for_asset_operation);
}
}
std::vector<input_generation_context_data> in_contexts;
//we'll aggregate Zarcanum outs into one txin_zarcanum_inputs
//txin_zarcanum_inputs ins_zc = AUTO_VAL_INIT(ins_zc);
std::vector<size_t> inputs_mapping;
size_t current_index = 0;
inputs_mapping.resize(sources.size());
@ -1928,6 +1953,7 @@ namespace currency
in_contexts.push_back(input_generation_context_data{});
input_generation_context_data& in_context = in_contexts.back();
// sort src_entr.outputs entries by global out index, put it to in_context.outputs, convert to relative gindices, and put new real out index into in_context.real_out_index
in_context.outputs = prepare_outputs_entries_for_key_offsets(src_entr.outputs, src_entr.real_output, in_context.real_out_index);
if(src_entr.is_multisig())
@ -1999,7 +2025,7 @@ namespace currency
//TODO: Might need some refactoring since this scheme is not the clearest one(did it this way for now to keep less changes to not broke anything)
//potentially this approach might help to support htlc and multisig without making to complicated code
if (src_entr.is_zarcanum())
if (src_entr.is_zc())
{
has_zc_inputs = true;
txin_zc_input zc_in = AUTO_VAL_INIT(zc_in);
@ -2021,36 +2047,58 @@ namespace currency
native_coins_input_sum += src_entr.amount;
}
uint64_t amount_of_emitted_asset = 0;
//
// OUTs
//
std::vector<tx_destination_entry> shuffled_dsts(destinations);
if (asset_id_for_asset_operation != currency::null_pkey)
{
//must be asset publication
for (auto& item : shuffled_dsts)
{
if (item.asset_id == currency::ffff_pkey)
{
item.asset_id = asset_id_for_asset_operation;
amount_of_emitted_asset += item.amount;
}
}
CHECK_AND_ASSERT_MES(pado, false, "pado is null ??");
pado->descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
}
size_t outputs_to_be_constructed = shuffled_dsts.size();
outputs_generation_context outs_gen_context(outputs_to_be_constructed); // auxiliary data for each output
// ASSET oprations handling
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
asset_descriptor_operation* pado = nullptr;
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
if (pado)
{
// only operation register is supported atm
CHECK_AND_ASSERT_MES(pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation: " << (int)pado->operation_type);
crypto::secret_key asset_control_key{};
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
calculate_asset_id(pado->descriptor.owner, &outs_gen_context.ao_asset_id_pt, &outs_gen_context.ao_asset_id);
// calculate amount blinding mask
outs_gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
for (auto& item : shuffled_dsts)
{
if (item.asset_id == currency::ffff_pkey)
{
item.asset_id = outs_gen_context.ao_asset_id; // set calculated asset_id to the asset's outputs, if this asset is being emitted within this tx
amount_of_emitted_asset += item.amount;
}
}
pado->descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
outs_gen_context.ao_amount_commitment = amount_of_emitted_asset * outs_gen_context.ao_asset_id_pt + outs_gen_context.ao_amount_blinding_mask * crypto::c_point_G;
pado->opt_amount_commitment = (crypto::c_scalar_1div8 * outs_gen_context.ao_amount_commitment).to_public_key();
}
}
// "Shuffle" outs
if (shuffle)
std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; });
// TODO: consider "Shuffle" inputs
// construct outputs
uint64_t native_coins_output_sum = 0;
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
size_t outputs_to_be_constructed = shuffled_dsts.size();
outputs_generation_context outs_gen_context(outputs_to_be_constructed); // auxiliary data for each output
uint64_t range_proof_start_index = output_index;
std::set<uint16_t> deriv_cache;
for(size_t j = 0; j < outputs_to_be_constructed; ++j, ++output_index)
@ -2068,16 +2116,6 @@ namespace currency
native_coins_output_sum += dst_entr.amount;
}
//check money
//if (!(flags&TX_FLAG_SIGNATURE_MODE_SEPARATE))
//{
// if (summary_outs_money > summary_inputs_money)
// {
// LOG_ERROR("Transaction inputs money (" << print_money_brief(summary_inputs_money) << ") is less than outputs money (" << print_money_brief(summary_outs_money) << ")");
// return false;
// }
//}
//process offers and put there offers derived keys
uint64_t att_count = 0;
for (auto& o : tx.attachment)
@ -2089,7 +2127,7 @@ namespace currency
{
CHECK_AND_ASSERT_MES(tsa.security.size() == 1, false, "Wrong tsa.security.size() = " << tsa.security.size());
r = derive_public_key_from_target_address(sender_account_keys.account_address, one_time_secret_key, att_count, tsa.security.back());
r = derive_public_key_from_target_address(sender_account_keys.account_address, one_time_tx_secret_key, att_count, tsa.security.back());
CHECK_AND_ASSERT_MES(r, false, "Failed to derive_public_key_from_target_address");
}
att_count++;
@ -2106,33 +2144,14 @@ namespace currency
//2 sort the inputs in given range
std::sort(tx.vin.begin() + input_starter_index, tx.vin.end(), less_txin_v);
}
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
// asset surjeciton proof
currency::zc_asset_surjection_proof asp{};
bool r = generate_asset_surjection_proof(asp);
CHECK_AND_ASSERT_MES(r, false, "generete_asset_surjection_proof failed");
tx.attachment.push_back(asp);
// add range proofs
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
r = generate_zc_outs_range_proof(range_proof_start_index, outputs_to_be_constructed, outs_gen_context, tx.vout, range_proofs);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
tx.attachment.push_back(range_proofs);
// add explicit fee info
r = add_tx_fee_amount_to_extra(tx, native_coins_input_sum - native_coins_output_sum);
CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed");
if (!has_zc_inputs)
{
r = generate_tx_balance_proof(tx, outs_gen_context);
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
}
}
// attachments container should be sealed by now
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
// for separately signed tx each input has to contain information about corresponding outputs, extra entries and attachments
@ -2154,13 +2173,37 @@ namespace currency
if (tx.attachment.size())
add_attachments_info_to_extra(tx.extra, tx.attachment);
}
//
// generate ring signatures
// generate proofs and signatures
// (any changes made below should only affect the signatures/proofs and should not impact the prefix hash calculation)
//
crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, tx_prefix_hash);
//size_t input_index = input_starter_index;
//size_t in_context_index = 0;
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
// proofs (transaction-wise, not pre-input)
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
// asset surjeciton proof
currency::zc_asset_surjection_proof asp{};
bool r = generate_asset_surjection_proof(tx_prefix_hash, asp);
CHECK_AND_ASSERT_MES(r, false, "generete_asset_surjection_proof failed");
tx.proofs.emplace_back(std::move(asp));
// add range proofs
currency::zc_outs_range_proof range_proofs = AUTO_VAL_INIT(range_proofs);
r = generate_zc_outs_range_proof(tx_prefix_hash, range_proof_start_index, outputs_to_be_constructed, outs_gen_context, tx.vout, range_proofs);
CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()");
tx.proofs.emplace_back(std::move(range_proofs));
if (!has_zc_inputs)
{
r = generate_tx_balance_proof(tx, tx_prefix_hash, outs_gen_context);
CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed");
}
}
// ring signatures (per-input proofs)
r = false;
for (size_t i_ = 0; i_ != sources.size(); i_++)
{
@ -2171,7 +2214,7 @@ namespace currency
CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed");
std::stringstream ss_ring_s;
if (source_entry.is_zarcanum())
if (source_entry.is_zc())
{
// ZC
// blinding_masks_sum is supposed to be sum(mask of all tx output) - sum(masks of all pseudo out commitments)
@ -2466,12 +2509,16 @@ namespace currency
VARIANT_SWITCH_END();
}
VARIANT_CASE_CONST(tx_out_zarcanum, o)
if (!check_key(o.amount_commitment))
{
if (!check_key(o.stealth_address))
return false;
if (!check_key(o.concealing_point))
return false;
if (!check_key(o.stealth_address))
if (!check_key(o.amount_commitment))
return false;
if (!check_key(o.blinded_asset_id))
return false;
}
VARIANT_SWITCH_END();
}
return true;
@ -2559,6 +2606,7 @@ namespace currency
return res;
}
//---------------------------------------------------------------
// out_key.key =?= Hs(derivation || output_index) * G + addr.spend_public_key
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
{
crypto::public_key pk;
@ -2611,12 +2659,12 @@ namespace currency
}
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation)
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation)
{
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
if (null_pkey == tx_pub_key)
return false;
return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered, derivation);
return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, sum_of_native_outs, derivation);
}
//---------------------------------------------------------------
bool check_tx_derivation_hint(const transaction& tx, const crypto::key_derivation& derivation)
@ -2665,22 +2713,22 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation)
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation)
{
std::list<htlc_info> htlc_info_list;
return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered, derivation, htlc_info_list);
return lookup_acc_outs(acc, tx, tx_pub_key, outs, sum_of_native_outs, derivation, htlc_info_list);
}
//---------------------------------------------------------------
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list)
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list)
{
money_transfered = 0;
sum_of_native_outs = 0;
bool r = generate_key_derivation(tx_pub_key, acc.view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "unable to generate derivation from tx_pub = " << tx_pub_key << " * view_sec, invalid tx_pub?");
if (is_coinbase(tx) && get_block_height(tx) == 0 && tx_pub_key == ggenesis_tx_pub_key)
{
//genesis coinbase
return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, money_transfered, derivation);
return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, sum_of_native_outs, derivation);
}
if (!check_tx_derivation_hint(tx, derivation))
@ -2697,13 +2745,13 @@ namespace currency
if (is_out_to_acc(acc.account_address, t, derivation, output_index))
{
outs.emplace_back(output_index, o.amount);
money_transfered += o.amount;
sum_of_native_outs += o.amount;
}
VARIANT_CASE_CONST(txout_multisig, t)
if (is_out_to_acc(acc.account_address, t, derivation, output_index))
{
outs.emplace_back(output_index, o.amount); // TODO: @#@# consider this
//don't cout this money
//don't cout this money in sum_of_native_outs
}
VARIANT_CASE_CONST(txout_htlc, htlc)
htlc_info hi = AUTO_VAL_INIT(hi);
@ -2717,6 +2765,11 @@ namespace currency
hi.hltc_our_out_is_before_expiration = false;
htlc_info_list.push_back(hi);
}
else
{
LOG_ERROR("lookup_acc_outs: handling txout_htlc went wrong, output_index: " << output_index);
return false;
}
outs.emplace_back(output_index, o.amount);
VARIANT_CASE_OTHER()
LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name());
@ -2730,9 +2783,11 @@ namespace currency
crypto::scalar_t amount_blinding_mask = 0, asset_id_blinding_mask = 0;
if (is_out_to_acc(acc.account_address, zo, derivation, output_index, amount, asset_id, amount_blinding_mask, asset_id_blinding_mask))
{
crypto::point_t asset_id_pt = crypto::point_t(zo.blinded_asset_id) - asset_id_blinding_mask * crypto::c_point_X;
outs.emplace_back(output_index, amount, amount_blinding_mask, asset_id_blinding_mask, asset_id_pt.to_public_key());
money_transfered += amount;
crypto::point_t asset_id_pt = crypto::point_t(zo.blinded_asset_id).modify_mul8() - asset_id_blinding_mask * crypto::c_point_X;
crypto::public_key asset_id = asset_id_pt.to_public_key();
outs.emplace_back(output_index, amount, amount_blinding_mask, asset_id_blinding_mask, asset_id);
if (asset_id == currency::native_coin_asset_id)
sum_of_native_outs += amount;
}
}
VARIANT_SWITCH_END();

View file

@ -238,7 +238,9 @@ namespace currency
};
bool verify_multiple_zc_outs_range_proofs(const std::vector<zc_outs_range_proofs_with_commitments>& range_proofs);
bool check_tx_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool validate_asset_operation(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, crypto::public_key& asset_id);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
size_t current_block_size,
@ -320,9 +322,9 @@ namespace currency
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index);
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, uint64_t& sum_of_native_outs, crypto::key_derivation& derivation);
bool get_tx_fee(const transaction& tx, uint64_t & fee);
uint64_t get_tx_fee(const transaction& tx);
bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral);