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:
parent
f9b54f305a
commit
f3eb63d25c
6 changed files with 292 additions and 256 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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______________"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue