1
0
Fork 0
forked from lthn/blockchain

work related to assets altering(update,emmit,burn)

This commit is contained in:
cryptozoidberg 2023-08-03 20:01:41 +02:00
parent 2375d0fbc1
commit e347062ab1
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
11 changed files with 184 additions and 44 deletions

View file

@ -19,6 +19,9 @@ template<size_t A, size_t B> struct TAssertEquality {
#define BOOST_SERIALIZE(x) _arch & x;
#define BOOST_END_VERSION_UNDER(x) \
if(ver < x ) {return true;}
#define END_BOOST_SERIALIZATION() }

View file

@ -3812,27 +3812,90 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id)
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc)
{
// asset_id = AUTO_VAL_INIT(asset_id);
// CHECK_AND_ASSERT_MES(validate_asset_operation_balance_proof(tx, tx_id, ado, asset_id), false, "asset operation validation failed!");
CHECK_AND_ASSERT_MES(ado.op_proof.has_value(), false, "Ownership validation failed - missing signature");
CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << asset_id << " has invalid history size() == 0");
crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner;
asset_descriptor_operation ado_local = ado;
normalize_asset_operation_for_hashing(ado_local);
std::string buff = t_serializable_object_to_blob(ado_local);
crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size());
return crypto::check_signature(h, owner_key, *ado.op_proof);
}
//------------------------------------------------------------------
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);
asset_op_verification_context avc = { tx , tx_id, ado };
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::public_key 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 with id " << asset_id << " has already been registered");
calculate_asset_id(avc.ado.descriptor.owner, &avc.asset_id_pt, &avc.asset_id);
avc.asset_op_history = m_db_assets.find(avc.asset_id);
CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << asset_id << " has already been registered");
avc.amout_to_validate = ado.descriptor.current_supply;
CHECK_AND_ASSERT_MES(validate_asset_operation_balance_proof(avc), false, "asset operation validation failed!");
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);
LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << asset_id << ": " << ado.descriptor.full_name, LOG_LEVEL_1);
//TODO:
//rise_core_event(CORE_EVENT_ADD_ASSET, alias_info_to_rpc_alias_info(ai));
}
else
{
//TODO: implement other operations
CHECK_AND_ASSERT_THROW(false, "asset operation not implemented yet");
}else
{
CHECK_AND_ASSERT_MES(avc.ado.opt_asset_id, false, "asset_id not provided for asset altering operation");
avc.asset_op_history = m_db_assets.find(*avc.ado.opt_asset_id);
CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << asset_id << " has not been registered");
// check ownership permission
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
bool r = validate_ado_ownership(avc);
CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting");
}
avc.amout_to_validate = 0;
//validate balance proof
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE)
{
//check that total current_supply haven't changed
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply != avc.asset_op_history->back().descriptor.current_supply);
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT)
{
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > avc.asset_op_history->back().descriptor.current_supply);
avc.amout_to_validate = ado.descriptor.current_supply - avc.asset_op_history->back().descriptor.current_supply;
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < avc.asset_op_history->back().descriptor.current_supply);
avc.amout_to_validate = avc.asset_op_history->back().descriptor.current_supply - ado.descriptor.current_supply;
}
else
{
LOG_ERROR("Unknown operation type: " << ado.operation_type);
return false;
}
bool r = validate_asset_operation_balance_proof(avc);
CHECK_AND_ASSERT(r, false, "Balance proof validation failed for asset_descriptor_operation");
assets_container::t_value_type local_asset_history = *avc.asset_op_history;
local_asset_history.push_back(ado);
m_db_assets.set(asset_id, local_asset_history);
LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << asset_id << ": " << ado.descriptor.full_name, LOG_LEVEL_1);
//TODO:
//rise_core_event(CORE_EVENT_ADD_ASSET, alias_info_to_rpc_alias_info(ai));
}
return true;

View file

@ -654,6 +654,7 @@ namespace currency
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 validate_ado_ownership(asset_op_verification_context& avc);
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);

View file

@ -813,17 +813,26 @@ namespace currency
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
boost::optional<crypto::public_key> opt_amount_commitment; // premultiplied by 1/8
boost::optional<crypto::signature> opt_proof; // operation proof - for update/emit
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
BEGIN_VERSIONED_SERIALIZE()
CURRENT_VERSION(1)
FIELD(operation_type)
FIELD(descriptor)
FIELD(opt_amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_proof)
FIELD(opt_asset_id)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(opt_amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_proof)
BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION()
};

View file

@ -557,15 +557,19 @@ namespace currency
return true;
}
//-----------------------------------------------------------------------------------------------
bool validate_asset_operation(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, crypto::public_key& asset_id)
bool validate_asset_operation_balance_proof(asset_op_verification_context& context)// 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);
CHECK_AND_ASSERT_MES(count_type_in_variant_container<asset_operation_proof>(context.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>(context.tx.proofs);
if (ado.descriptor.hidden_supply)
bool is_burn = false;
if (context.ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
is_burn = true;
}
if (context.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
@ -574,11 +578,15 @@ namespace currency
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(context.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;
crypto::point_t A = is_burn ?
crypto::point_t(context.ado.opt_amount_commitment.get()).modify_mul8() + context.amount * asset_id_pt
:
crypto::point_t(context.ado.opt_amount_commitment.get()).modify_mul8() - context.amount * asset_id_pt
;
bool r = crypto::check_signature(tx_id, A.to_public_key(), aop.opt_amount_commitment_g_proof.get());
bool r = crypto::check_signature(context.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");
}
@ -1105,6 +1113,14 @@ namespace currency
string_tools::append_pod_to_strbuff(origin_blob, origin_hs);
return origin_blob;
}
//---------------------------------------------------------------
void normalize_asset_operation_for_hashing(asset_descriptor_operation& op)
{
op.op_proof = boost::none;
}
//---------------------------------------------------------------
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr /* = CURRENCY_TO_KEY_OUT_RELAXED */)
{
@ -2309,31 +2325,34 @@ namespace currency
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, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
// calculate amount blinding mask
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 (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
if (item.asset_id == currency::null_pkey)
{
item.asset_id = 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
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");
gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
calculate_asset_id(pado->descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
// calculate amount blinding mask
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::null_pkey)
{
item.asset_id = 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
gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
//LOG_PRINT_CYAN("AO " << ": " << crypto::scalar_t(amount_of_emitted_asset) << " x " << gen_context.ao_asset_id_pt << " + " << gen_context.ao_amount_blinding_mask << " x G", LOG_LEVEL_0);
//LOG_PRINT_CYAN(" == " << gen_context.ao_amount_commitment << ", x 1/8 == " << pado->opt_amount_commitment.get(), LOG_LEVEL_0);
}

View file

@ -242,6 +242,17 @@ namespace currency
std::vector<crypto::point_t> amount_commitments;
};
struct asset_op_verification_context
{
const transaction& tx;
const crypto::hash& tx_id;
const asset_descriptor_operation& ado;
crypto::public_key asset_id = currency::null_pkey;
crypto::point_t asset_id_pt = crypto::c_point_0;
uint64_t amout_to_validate = 0;
std::shared_ptr< const std::list<asset_descriptor_operation> > asset_op_history;
};
bool verify_multiple_zc_outs_range_proofs(const std::vector<zc_outs_range_proofs_with_commitments>& range_proofs);
bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, tx_generation_context& ogc, zc_asset_surjection_proof& result);
bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id);
@ -250,7 +261,7 @@ namespace currency
const std::vector<tx_out_v>& vouts, zc_outs_range_proof& result);
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 validate_asset_operation_balance_proof(asset_op_verification_context& context);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
size_t current_block_size,
@ -433,6 +444,8 @@ namespace currency
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys);
void normalize_asset_operation_for_hashing(asset_descriptor_operation& op);
template<class t_txin_v>
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
{

@ -1 +1 @@
Subproject commit 0419d66684dd044d56681d75359d4afd859ff2ea
Subproject commit 47d405747b7c04e69b4a7fd7a4a5cf866e098627

View file

@ -113,6 +113,8 @@ do { \
if (_ser_ar.is_saving_arch()) { s_version = v; } \
} while (0);
#define END_VERSION_UNDER(x) \
if(s_version < x ) {return true;}
#define BEGIN_VERSIONED_SERIALIZE() \

View file

@ -4648,6 +4648,34 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info
m_custom_assets[new_asset_id] = ado.descriptor;
}
//----------------------------------------------------------------------------------------------------
void wallet2::update_emmit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx)
{
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
asset_descriptor_operation asset_reg_info = AUTO_VAL_INIT(asset_reg_info);
asset_reg_info.descriptor = asset_info;
asset_reg_info.operation_type = ASSET_DESCRIPTOR_OPERATION_EMMIT;
asset_reg_info.asset_id = asset_id;
construct_tx_param ctp = get_default_construct_tx_param();
ctp.dsts = destinations;
ctp.extra.push_back(asset_reg_info);
ctp.need_at_least_1_zc = true;
ctp.control_key = own_asset_entry_it->second.control_key;
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
result_tx = ft.tx;
//get generated asset id
currency::asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
bool r = get_type_in_variant_container(result_tx.extra, ado);
CHECK_AND_ASSERT_THROW_MES(r, "Failed find asset info in tx");
calculate_asset_id(ado.descriptor.owner, nullptr, &new_asset_id);
m_custom_assets[new_asset_id] = ado.descriptor;
}
//----------------------------------------------------------------------------------------------------
void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward)
{
if (!validate_alias_name(ai.m_alias))

View file

@ -292,6 +292,7 @@ namespace tools
bool shuffle = false;
bool create_utxo_defragmentation_tx = false;
bool need_at_least_1_zc = false;
crypto::secret_key control_key = currency::null_pkey;
};
struct mode_separate_context

View file

@ -1031,7 +1031,8 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY_HF(gen_no_attchments_in_coinbase, "3");
GENERATE_AND_PLAY(gen_no_attchments_in_coinbase_gentime);
GENERATE_AND_PLAY(gen_alias_tests);
//GENERATE_AND_PLAY(gen_alias_tests);
GENERATE_AND_PLAY_HF(gen_alias_tests, "4,1");
GENERATE_AND_PLAY(gen_alias_strange_data);
GENERATE_AND_PLAY(gen_alias_concurrency_with_switch);
GENERATE_AND_PLAY(gen_alias_same_alias_in_tx_pool);