1
0
Fork 0
forked from lthn/blockchain

assets: implemented ownership transfer

This commit is contained in:
cryptozoidberg 2024-02-12 22:56:47 +04:00
parent 922ec739dc
commit a39c42a1b5
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
5 changed files with 159 additions and 85 deletions

View file

@ -4126,7 +4126,7 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has
CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered");
// check ownership permission
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || 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");

View file

@ -2154,14 +2154,16 @@ namespace currency
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::secret_key asset_control_key{};
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
//crypto::secret_key asset_control_key{};
//bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
//CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
ado.descriptor.owner = sender_account_keys.account_address.spend_public_key;
calculate_asset_id(ado.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, tx_key.pub);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec, tx_key.pub);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2178,6 +2180,38 @@ namespace currency
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;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(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, tx_key.sec, tx_key.pub);
gen_context.ao_commitment_in_outputs = true;
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_burned_assets = 0;
for (auto& item : ftp.sources)
{
if (item.asset_id == gen_context.ao_asset_id)
{
amount_of_burned_assets += item.amount;
}
}
for (auto& item : ftp.prepared_destinations)
{
if (item.asset_id == gen_context.ao_asset_id)
{
CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount(" << item.amount << ")");
amount_of_burned_assets -= item.amount;
}
}
ado.descriptor.current_supply -= amount_of_burned_assets;
gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
else
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
@ -2187,7 +2221,7 @@ namespace currency
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(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, ftp.asset_control_key, tx_key.pub);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec, tx_key.pub);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2212,46 +2246,23 @@ namespace currency
//fields that not supposed to be changed?
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(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, ftp.asset_control_key, tx_key.pub);
gen_context.ao_commitment_in_outputs = true;
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_burned_assets = 0;
for (auto& item: ftp.sources)
{
if (item.asset_id == gen_context.ao_asset_id)
{
amount_of_burned_assets += item.amount;
}
}
for (auto& item : ftp.prepared_destinations)
{
if (item.asset_id == gen_context.ao_asset_id )
{
CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount("<< item.amount << ")");
amount_of_burned_assets -= item.amount;
}
}
ado.descriptor.current_supply -= amount_of_burned_assets;
gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado });
//seal it with owners signature
crypto::signature sig = currency::null_sig;
crypto::public_key pub_k = currency::null_pkey;
crypto::secret_key_to_public_key(ftp.asset_control_key, pub_k);
crypto::generate_signature(get_signature_hash_for_asset_operation(ado), pub_k, ftp.asset_control_key, sig);
crypto::hash h = get_signature_hash_for_asset_operation(ado)
if (ftp.pthirdparty_sign_handler)
{
bool r = ftp.pthirdparty_sign_handler->sign(h, ftp.ado_current_asset_owner, sig);
CHECK_AND_ASSERT_MES(r, false, "asset thirparty sign failed");
}
else
{
crypto::public_key pub_k = currency::null_pkey;
crypto::secret_key_to_public_key(sender_account_keys.spend_secret_key, pub_k);
CHECK_AND_ASSERT_MES(ftp.ado_current_asset_owner == pub_k, false, "asset owner key not matched with provided private key for asset operation signing");
crypto::generate_signature(h, pub_k, account_keys.spend_secret_key, sig);
}
ado.opt_proof = sig;
}
return true;

View file

@ -134,15 +134,18 @@ namespace currency
END_KV_SERIALIZE_MAP()
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct thirdparty_sign_handler
{
virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::signature& sig);
};
struct finalize_tx_param
{
uint64_t unlock_time;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
@ -158,10 +161,14 @@ namespace currency
crypto::public_key spend_pub_key; // only for validations
uint64_t tx_version;
uint64_t mode_separate_fee = 0;
crypto::secret_key asset_control_key = currency::null_skey;
epee::misc_utils::events_dispatcher* pevents_dispatcher;
tx_generation_context gen_context{}; // solely for consolidated txs
//crypto::secret_key asset_control_key = currency::null_skey;
crypto::public_key ado_current_asset_owner = null_pkey;
thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
BEGIN_SERIALIZE_OBJECT()
FIELD(unlock_time)
@ -179,9 +186,11 @@ namespace currency
FIELD(spend_pub_key)
FIELD(tx_version)
FIELD(mode_separate_fee)
FIELD(asset_control_key)
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
FIELD(gen_context);
}
FIELD(ado_current_asset_owner)
END_SERIALIZE()
};

View file

@ -402,20 +402,8 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::public_key self_check = AUTO_VAL_INIT(self_check);
crypto::secret_key asset_control_key = AUTO_VAL_INIT(asset_control_key);
bool r = derive_key_pair_from_key_pair(ptc.tx_pub_key, m_account.get_keys().spend_secret_key, asset_control_key, self_check, CRYPTO_HDS_ASSET_CONTROL_KEY);
if (!r)
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key)
{
//not critical error, continue to work
LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash());
break;
}
if (self_check != ado.descriptor.owner)
{
//still not critical error
LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash());
break;
}
crypto::public_key asset_id{};
@ -423,7 +411,6 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset");
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
asset_context.asset_descriptor = ado.descriptor;
asset_context.control_key = asset_control_key;
std::stringstream ss;
ss << "New Asset Registered:"
@ -440,22 +427,83 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_asset_id, get_asset_operation_type_string(ado.operation_type) << " failed with empty opt_asset_id");
auto it = m_own_asset_descriptors.find(*ado.opt_asset_id);
if (it == m_own_asset_descriptors.end())
break;
//asset had been updated
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE )
{
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_asset_id, get_asset_operation_type_string(ado.operation_type) << " failed with empty opt_asset_id");
auto it = m_own_asset_descriptors.find(*ado.opt_asset_id);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(it != m_own_asset_descriptors.end(), "asset with asset_id " << *ado.opt_asset_id << " not found during " << get_asset_operation_type_string(ado.operation_type));
if (it->second.asset_descriptor.owner != ado.descriptor.owner)
if (it == m_own_asset_descriptors.end())
{
//ownership of the asset had been transfered
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second });
m_own_asset_descriptors.erase(it);
if (ado.descriptor.owner == m_account.get_public_address().spend_public_key)
{
// ownership of the asset acquired
wallet_own_asset_context& asset_context = m_own_asset_descriptors[*ado.opt_asset_id];
asset_context.asset_descriptor = ado.descriptor;
std::stringstream ss;
ss << "Asset ownership acquired:"
<< ENDL << "asset id: " << *ado.opt_asset_id
<< ENDL << "Name: " << ado.descriptor.full_name
<< ENDL << "Ticker: " << ado.descriptor.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point)
<< ENDL << "Decimal Point: " << ado.descriptor.decimal_point;
add_rollback_event(ptc.height, asset_register_event{ *ado.opt_asset_id });
WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else
{
// update event of the asset that we not control, skip
break;
}
}
else
{
//asset had been updated
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
//update event for asset that we control, check if ownership is still ours
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key)
{
//ownership of the asset had been transfered
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second });
m_own_asset_descriptors.erase(it);
std::stringstream ss;
ss << "Asset ownership lost:"
<< ENDL << "asset id: " << *ado.opt_asset_id
<< ENDL << "New owner: " << ado.descriptor.owner
<< ENDL << "Name: " << ado.descriptor.full_name
<< ENDL << "Ticker: " << ado.descriptor.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point)
<< ENDL << "Decimal Point: " << ado.descriptor.decimal_point;
add_rollback_event(ptc.height, asset_register_event{ *ado.opt_asset_id });
WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else
{
//just an update of the asset
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
}
}
}
} while (false);
@ -869,7 +917,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size());
}
if (ptc.spent_own_native_inputs)
if (ptc.employed_entries.receive.size() || ptc.employed_entries.spent.size())
{
//check if there are asset_registration that belong to this wallet
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
@ -4882,7 +4930,8 @@ void wallet2::emmit_asset(const crypto::public_key asset_id, std::vector<currenc
ctp.dsts = destinations;
ctp.extra.push_back(asset_emmit_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
//ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
@ -4901,7 +4950,10 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as
construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_update_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
bool r = this->daemon_get_asset_info(asset_id, adb);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
ctp.ado_current_asset_owner = adb.owner;
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
@ -4910,8 +4962,8 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as
//----------------------------------------------------------------------------------------------------
void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, 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");
//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");
COMMAND_RPC_GET_ASSET_INFO::request req;
req.asset_id = asset_id;
COMMAND_RPC_GET_ASSET_INFO::response rsp;
@ -4934,7 +4986,7 @@ void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_b
construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_burn_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
ctp.dsts.push_back(dst_to_burn);
finalized_tx ft = AUTO_VAL_INIT(ft);
@ -6927,7 +6979,8 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate;
assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
ftp.asset_control_key = ctp.asset_deploy_control_key;
ftp.ado_current_asset_owner = ctp.ado_current_asset_owner;
ftp.pthirdparty_sign_handler = ctp.pthirdparty_sign_handler;
//
// TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id
//

View file

@ -199,6 +199,7 @@ namespace tools
END_SERIALIZE()
};
struct construct_tx_param
{
// preparing data for tx
@ -223,7 +224,9 @@ namespace tools
bool shuffle = false;
bool create_utxo_defragmentation_tx = false;
bool need_at_least_1_zc = false;
crypto::secret_key asset_deploy_control_key = currency::null_skey;
//crypto::secret_key asset_deploy_control_key = currency::null_skey;
currency::thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
crypto::public_key ado_current_asset_owner = currency::null_pkey;
};
struct mode_separate_context
@ -255,13 +258,11 @@ namespace tools
struct wallet_own_asset_context
{
currency::asset_descriptor_base asset_descriptor;
crypto::secret_key control_key;
//uint64_t height = 0;
bool thirdparty_custody = false;
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(asset_descriptor)
BOOST_SERIALIZE(control_key)
//BOOST_SERIALIZE(height)
BOOST_SERIALIZE(thirdparty_custody)
END_BOOST_SERIALIZATION()
};