Compare commits

...
Sign in to create a new pull request.

14 commits

Author SHA1 Message Date
cryptozoidberg
057856b953
added todo to test 2024-02-14 02:09:26 +04:00
cryptozoidberg
ecbc437c0c
fixes over multiasset tests to fix transfer ownership of asset 2024-02-14 02:02:13 +04:00
cryptozoidberg
52bab97374
transfer asset ownership - implemented first test 2024-02-13 22:36:47 +04:00
cryptozoidberg
cb0e2c3650
fixes related multriasset tests 2024-02-13 19:21:25 +04:00
cryptozoidberg
f3367b895a
signing prefix with ado 2024-02-13 16:19:46 +04:00
cryptozoidberg
735a5adfde
asset ownership proov validation replaced with prefix signed with schnorr signature 2024-02-13 15:52:28 +04:00
cryptozoidberg
9fac4c8f49
changing signature scheme for ado 2024-02-13 15:52:27 +04:00
sowle
10c0ee541a
crypto: generate_schnorr_sig version for public_key and secret_key types 2024-02-13 12:47:20 +01:00
sowle
47a11bba99
serialization tags for asset_operation_ownership_proof 2024-02-13 12:19:10 +01:00
sowle
0f43835f17
crypto: default template argument for generate/verify_schnorr_sig 2024-02-13 12:18:08 +01:00
sowle
31857b8440
struct asset_operation_ownership_proof added 2024-02-13 11:14:05 +01:00
cryptozoidberg
9613215a87
assets: thirdparty assets not erasing from own list 2024-02-12 23:01:12 +04:00
cryptozoidberg
a39c42a1b5
assets: implemented ownership transfer 2024-02-12 22:56:47 +04:00
cryptozoidberg
922ec739dc
allowed transfering assets membership 2024-02-12 17:56:32 +04:00
11 changed files with 370 additions and 246 deletions

View file

@ -509,6 +509,10 @@ namespace misc_utils
} }
} }
void UNSUBSCRIBE_ALL()
{
m_callbacks.clear();
}
template<typename param_t> template<typename param_t>
void RAISE_DEBUG_EVENT(const param_t& p) void RAISE_DEBUG_EVENT(const param_t& p)

View file

@ -84,46 +84,47 @@ namespace crypto
scalar_t y; scalar_t y;
}; };
template<generator_tag gen>
template<typename generator_t>
inline bool generate_schnorr_sig_custom_generator(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result, const generator_t& g_point_g)
{
#ifndef NDEBUG
if (A != secret_a * g_point_g)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * g_point_g;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
}
template<generator_tag gen = gt_G>
inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result); inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result);
template<> template<>
inline bool generate_schnorr_sig<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) inline bool generate_schnorr_sig<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{ {
#ifndef NDEBUG return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_G);
if (A != secret_a * c_point_G)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_G;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
} }
template<> template<>
inline bool generate_schnorr_sig<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) inline bool generate_schnorr_sig<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{ {
#ifndef NDEBUG return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_X);
if (A != secret_a * c_point_X)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_X;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
} }
template<generator_tag gen> inline bool generate_schnorr_sig(const hash& m, const public_key& A, const secret_key& secret_a, generic_schnorr_sig& result)
{
return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result);
}
template<generator_tag gen = gt_G>
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept; inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
// TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept; // TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept;

View file

@ -4088,13 +4088,15 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a
{ {
// asset_id = AUTO_VAL_INIT(asset_id); // 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(validate_asset_operation_balance_proof(tx, tx_id, ado, asset_id), false, "asset operation validation failed!");
CHECK_AND_ASSERT_MES(avc.ado.opt_proof.has_value(), false, "Ownership validation failed - missing signature"); asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
bool r = get_type_in_variant_container(avc.tx.proofs, aoop);
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed - missing signature");
CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0"); CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0");
crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner; crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner;
return crypto::check_signature(get_signature_hash_for_asset_operation(avc.ado), owner_key, *avc.ado.opt_proof); return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado)
@ -4126,7 +4128,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_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 // 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); bool r = validate_ado_ownership(avc);
CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting"); CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting");

View file

@ -775,7 +775,6 @@ namespace currency
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor; asset_descriptor_base descriptor;
crypto::public_key amount_commitment; // premultiplied by 1/8 crypto::public_key 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 boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER; uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER;
@ -784,7 +783,6 @@ namespace currency
FIELD(descriptor) FIELD(descriptor)
FIELD(amount_commitment) FIELD(amount_commitment)
END_VERSION_UNDER(1) END_VERSION_UNDER(1)
FIELD(opt_proof)
FIELD(opt_asset_id) FIELD(opt_asset_id)
END_SERIALIZE() END_SERIALIZE()
@ -793,7 +791,6 @@ namespace currency
BOOST_SERIALIZE(descriptor) BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(amount_commitment) BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1) BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_proof)
BOOST_SERIALIZE(opt_asset_id) BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION() END_BOOST_SERIALIZATION()
}; };
@ -819,6 +816,21 @@ namespace currency
}; };
struct asset_operation_ownership_proof
{
crypto::generic_schnorr_sig_s gss;
uint8_t version = 0;
BEGIN_VERSIONED_SERIALIZE(0, version)
FIELD(gss)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(gss)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(version)
END_BOOST_SERIALIZATION()
};
struct extra_padding struct extra_padding
@ -924,7 +936,7 @@ namespace currency
typedef boost::variant<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v; 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; typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof, asset_operation_ownership_proof> proof_v;
//include backward compatibility defintions //include backward compatibility defintions
@ -1111,6 +1123,7 @@ BLOB_SERIALIZER(currency::txout_to_key);
BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1); BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1);
BOOST_CLASS_VERSION(currency::asset_operation_proof, 1); BOOST_CLASS_VERSION(currency::asset_operation_proof, 1);
BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1);
// txin_v variant currency // txin_v variant currency
@ -1181,6 +1194,7 @@ 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_descriptor_operation, 49, "asset_descriptor_base");
SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof"); SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof");
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof");

View file

@ -172,7 +172,16 @@ namespace currency
if (is_asset_emitting_transaction(tx, &ado)) if (is_asset_emitting_transaction(tx, &ado))
{ {
crypto::point_t asset_id_pt = crypto::c_point_0; crypto::point_t asset_id_pt = crypto::c_point_0;
calculate_asset_id(ado.descriptor.owner, &asset_id_pt, nullptr); // TODO @#@# optimization: this expensive calculation should be done only once if (ado.opt_asset_id)
{
//emmit on existing asset, we SHOULD not calculate asset_id, instead we use the one provided
//since the owner might have been changed since creation
asset_id_pt = crypto::point_t(*ado.opt_asset_id);
}
else
{
calculate_asset_id(ado.descriptor.owner, &asset_id_pt, nullptr); // TODO @#@# optimization: this expensive calculation should be done only once
}
pseudo_outs_blinded_asset_ids.emplace_back(asset_id_pt); // additional ring member for asset emitting tx pseudo_outs_blinded_asset_ids.emplace_back(asset_id_pt); // additional ring member for asset emitting tx
} }
@ -1137,20 +1146,21 @@ namespace currency
return origin_blob; return origin_blob;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b) bool validate_ado_update_allowed(const asset_descriptor_base& new_ado, const asset_descriptor_base& prev_ado)
{ {
if (a.total_max_supply != b.total_max_supply) return false; if (new_ado.total_max_supply != prev_ado.total_max_supply) return false;
//if (a.current_supply != b.current_supply) return false; if (new_ado.current_supply > prev_ado.total_max_supply) return false;
if (a.decimal_point != b.decimal_point) return false; if (new_ado.decimal_point != prev_ado.decimal_point) return false;
if (a.ticker != b.ticker) return false; if (new_ado.ticker != prev_ado.ticker) return false;
if (a.full_name != b.full_name) return false; if (new_ado.full_name != prev_ado.full_name) return false;
//a.meta_info; //a.meta_info;
if (a.owner != b.owner) return false; //if (a.owner != b.owner) return false;
if (a.hidden_supply != b.hidden_supply) return false; if (new_ado.hidden_supply != prev_ado.hidden_supply) return false;
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
/*
crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado) crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado)
{ {
asset_descriptor_operation ado_local = ado; asset_descriptor_operation ado_local = ado;
@ -1164,6 +1174,7 @@ namespace currency
{ {
op.opt_proof = boost::none; op.opt_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 */) 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 */)
@ -2154,14 +2165,16 @@ namespace currency
{ {
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{ {
crypto::secret_key asset_control_key{}; //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); //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"); //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_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
// calculate amount blinding mask // 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 // set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0; uint64_t amount_of_emitted_asset = 0;
@ -2178,6 +2191,41 @@ 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; 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(); 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();
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_burn{ &ado });
}
else else
{ {
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
@ -2187,7 +2235,7 @@ namespace currency
gen_context.ao_asset_id = *ado.opt_asset_id; gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id); gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id);
// calculate amount blinding mask // 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 // set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0; uint64_t amount_of_emitted_asset = 0;
@ -2212,47 +2260,27 @@ namespace currency
//fields that not supposed to be changed? //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 }); if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado });
ftp.need_to_generate_ado_proof = true;
/*
//seal it with owners signature //seal it with owners signature
crypto::signature sig = currency::null_sig; crypto::signature sig = currency::null_sig;
crypto::public_key pub_k = currency::null_pkey; crypto::hash h = get_signature_hash_for_asset_operation(ado)
crypto::secret_key_to_public_key(ftp.asset_control_key, pub_k); if (ftp.pthirdparty_sign_handler)
crypto::generate_signature(get_signature_hash_for_asset_operation(ado), pub_k, ftp.asset_control_key, sig); {
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; ado.opt_proof = sig;
*/
} }
return true; return true;
} }
@ -2679,6 +2707,25 @@ namespace currency
aop.opt_amount_commitment_g_proof = aop_g_sig; aop.opt_amount_commitment_g_proof = aop_g_sig;
tx.proofs.emplace_back(std::move(aop)); tx.proofs.emplace_back(std::move(aop));
} }
if(ftp.need_to_generate_ado_proof)
{
asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
if (ftp.pthirdparty_sign_handler)
{
//ask third party to generate proof
r = ftp.pthirdparty_sign_handler->sign(tx_prefix_hash, ftp.ado_current_asset_owner, aoop.gss);
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado by thirdparty");
}
else
{
//generate signature by wallet account
r = crypto::generate_schnorr_sig(tx_prefix_hash, ftp.ado_current_asset_owner, sender_account_keys.spend_secret_key, aoop.gss);
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado proof");
}
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop });
tx.proofs.emplace_back(aoop);
}
} }
//size_t prefix_size = get_object_blobsize(static_cast<const transaction_prefix&>(tx)); //size_t prefix_size = get_object_blobsize(static_cast<const transaction_prefix&>(tx));

View file

@ -134,15 +134,18 @@ namespace currency
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
struct htlc_info struct htlc_info
{ {
bool hltc_our_out_is_before_expiration; 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::generic_schnorr_sig& sig);
};
struct finalize_tx_param struct finalize_tx_param
{ {
uint64_t unlock_time; uint64_t unlock_time;
std::vector<currency::extra_v> extra; std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments; std::vector<currency::attachment_v> attachments;
@ -158,11 +161,16 @@ namespace currency
crypto::public_key spend_pub_key; // only for validations crypto::public_key spend_pub_key; // only for validations
uint64_t tx_version; uint64_t tx_version;
uint64_t mode_separate_fee = 0; uint64_t mode_separate_fee = 0;
crypto::secret_key asset_control_key = currency::null_skey;
epee::misc_utils::events_dispatcher* pevents_dispatcher;
epee::misc_utils::events_dispatcher* pevents_dispatcher;
tx_generation_context gen_context{}; // solely for consolidated txs 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;
mutable bool need_to_generate_ado_proof = false;
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
FIELD(unlock_time) FIELD(unlock_time)
FIELD(extra) FIELD(extra)
@ -179,9 +187,12 @@ namespace currency
FIELD(spend_pub_key) FIELD(spend_pub_key)
FIELD(tx_version) FIELD(tx_version)
FIELD(mode_separate_fee) FIELD(mode_separate_fee)
FIELD(asset_control_key)
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
FIELD(gen_context); FIELD(gen_context);
}
FIELD(ado_current_asset_owner)
FIELD(need_to_generate_ado_proof)
END_SERIALIZE() 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) if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{ {
crypto::public_key self_check = AUTO_VAL_INIT(self_check); if (ado.descriptor.owner != m_account.get_public_address().spend_public_key)
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)
{ {
//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; break;
} }
crypto::public_key asset_id{}; 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"); 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]; wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
asset_context.asset_descriptor = ado.descriptor; asset_context.asset_descriptor = ado.descriptor;
asset_context.control_key = asset_control_key;
std::stringstream ss; std::stringstream ss;
ss << "New Asset Registered:" ss << "New Asset Registered:"
@ -440,22 +427,80 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
if (m_wcallback) if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); 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"); 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); 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 == m_own_asset_descriptors.end())
if (it->second.asset_descriptor.owner != ado.descriptor.owner)
{ {
//ownership of the asset had been transfered if (ado.descriptor.owner == m_account.get_public_address().spend_public_key)
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second }); {
m_own_asset_descriptors.erase(it); // 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 else
{ {
//asset had been updated //update event for asset that we control, check if ownership is still ours
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second }); if (ado.descriptor.owner != m_account.get_public_address().spend_public_key && !it->second.thirdparty_custody)
it->second.asset_descriptor = ado.descriptor; {
//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); } while (false);
@ -869,14 +914,12 @@ 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()); 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) //check if there are asset_registration that belong to this wallet
const asset_descriptor_operation* pado = get_type_in_variant_container<const asset_descriptor_operation>(tx.extra);
if (pado && (ptc.employed_entries.receive.size() || ptc.employed_entries.spent.size() || pado->descriptor.owner == m_account.get_public_address().spend_public_key))
{ {
//check if there are asset_registration that belong to this wallet //check if there are asset_registration that belong to this wallet
asset_descriptor_operation ado = AUTO_VAL_INIT(ado); process_ado_in_new_transaction(*pado, ptc);
if (get_type_in_variant_container(tx.extra, ado))
{
process_ado_in_new_transaction(ado, ptc);
}
} }
if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation) || ptc.employed_entries.spent.size()) if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation) || ptc.employed_entries.spent.size())
@ -3333,7 +3376,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a
return total; return total;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const uint64_t wallet2::balance(const crypto::public_key& asset_id, uint64_t& unlocked) const
{ {
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances; std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances;
uint64_t dummy; uint64_t dummy;
@ -3347,6 +3390,12 @@ uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const
return it->second.total; return it->second.total;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(const crypto::public_key& asset_id) const
{
uint64_t dummy = 0;
return balance(asset_id, dummy);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const
{ {
mined = 0; mined = 0;
@ -4882,7 +4931,8 @@ void wallet2::emmit_asset(const crypto::public_key asset_id, std::vector<currenc
ctp.dsts = destinations; ctp.dsts = destinations;
ctp.extra.push_back(asset_emmit_info); ctp.extra.push_back(asset_emmit_info);
ctp.need_at_least_1_zc = true; 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); finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr); this->transfer(ctp, ft, true, nullptr);
@ -4901,7 +4951,33 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as
construct_tx_param ctp = get_default_construct_tx_param(); construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_update_info); ctp.extra.push_back(asset_update_info);
ctp.need_at_least_1_zc = true; 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);
result_tx = ft.tx;
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, 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");
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");
asset_descriptor_operation asset_update_info = AUTO_VAL_INIT(asset_update_info);
asset_update_info.descriptor = adb;
asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE;
asset_update_info.opt_asset_id = asset_id;
asset_update_info.descriptor.owner = new_owner;
construct_tx_param ctp = get_default_construct_tx_param();
ctp.ado_current_asset_owner = adb.owner;
ctp.extra.push_back(asset_update_info);
finalized_tx ft = AUTO_VAL_INIT(ft); finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr); this->transfer(ctp, ft, true, nullptr);
@ -4910,8 +4986,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) 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); //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"); //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; COMMAND_RPC_GET_ASSET_INFO::request req;
req.asset_id = asset_id; req.asset_id = asset_id;
COMMAND_RPC_GET_ASSET_INFO::response rsp; COMMAND_RPC_GET_ASSET_INFO::response rsp;
@ -4934,7 +5010,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(); construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_burn_info); ctp.extra.push_back(asset_burn_info);
ctp.need_at_least_1_zc = true; 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); ctp.dsts.push_back(dst_to_burn);
finalized_tx ft = AUTO_VAL_INIT(ft); finalized_tx ft = AUTO_VAL_INIT(ft);
@ -6927,7 +7003,8 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate; 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); 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 // TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id
// //

View file

@ -391,9 +391,10 @@ namespace tools
void emmit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx); void emmit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx);
void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx); void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx);
void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx); void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx);
void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx);
bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb); bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb);
const std::unordered_map<crypto::public_key, wallet_own_asset_context>& get_own_assets() const { return m_own_asset_descriptors; }
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy); bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs
void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count); void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count);
@ -404,7 +405,8 @@ namespace tools
uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined, const crypto::public_key& asset_id = currency::native_coin_asset_id) const; uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined, const crypto::public_key& asset_id = currency::native_coin_asset_id) const;
bool balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const; bool balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const;
bool balance(std::list<wallet_public::asset_balance_entry>& balances, uint64_t& mined) const; bool balance(std::list<wallet_public::asset_balance_entry>& balances, uint64_t& mined) const;
uint64_t balance(crypto::public_key asset_id, uint64_t& unloked) const; uint64_t balance(const crypto::public_key& asset_id, uint64_t& unlocked) const;
uint64_t balance(const crypto::public_key& asset_id) const;
uint64_t balance(uint64_t& unloked) const; uint64_t balance(uint64_t& unloked) const;

View file

@ -199,6 +199,7 @@ namespace tools
END_SERIALIZE() END_SERIALIZE()
}; };
struct construct_tx_param struct construct_tx_param
{ {
// preparing data for tx // preparing data for tx
@ -223,7 +224,9 @@ namespace tools
bool shuffle = false; bool shuffle = false;
bool create_utxo_defragmentation_tx = false; bool create_utxo_defragmentation_tx = false;
bool need_at_least_1_zc = 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 struct mode_separate_context
@ -255,13 +258,11 @@ namespace tools
struct wallet_own_asset_context struct wallet_own_asset_context
{ {
currency::asset_descriptor_base asset_descriptor; currency::asset_descriptor_base asset_descriptor;
crypto::secret_key control_key; bool thirdparty_custody = false;
//uint64_t height = 0;
BEGIN_BOOST_SERIALIZATION() BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(asset_descriptor) BOOST_SERIALIZE(asset_descriptor)
BOOST_SERIALIZE(control_key) BOOST_SERIALIZE(thirdparty_custody)
//BOOST_SERIALIZE(height)
END_BOOST_SERIALIZATION() END_BOOST_SERIALIZATION()
}; };

View file

@ -13,9 +13,20 @@ struct wde_construct_tx_handle_asset_descriptor_operation
}; };
//Wallet Debug Events
struct wde_construct_tx_handle_asset_descriptor_operation_before_seal struct wde_construct_tx_handle_asset_descriptor_operation_before_seal
{ {
currency::asset_descriptor_operation* pado; currency::asset_descriptor_operation* pado;
}; };
struct wde_construct_tx_handle_asset_descriptor_operation_before_burn
{
currency::asset_descriptor_operation* pado;
};
struct wde_construct_tx_after_asset_ownership_proof_generated
{
currency::asset_operation_ownership_proof* pownership_proof;
};

View file

@ -11,65 +11,6 @@
#include "wallet/wallet_debug_events_definitions.h" #include "wallet/wallet_debug_events_definitions.h"
using namespace currency; using namespace currency;
/*
struct debug_context_event_1
{
int& i;
std::string& s;
};
//#define RAISE_DEBUG_EVENT dw.handle_type
void test_test()
{
epee::misc_utils::events_dispatcher ed;
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//thus code will be called in the tests
ed.SUBSCIRBE_DEBUG_EVENT<debug_context_event_1>([&](debug_context_event_1& d)
{
//here some operations
LOG_PRINT_L0("lala: " << d.i << d.s);
//
d.i = 10;
d.s = "33333";
});
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//this code will be in the wallet and helper functions
int i = 22;
std::string sss = "11111";
ed.RAISE_DEBUG_EVENT(debug_context_event_1{i, sss });
LOG_PRINT_L0("lala: " << i << sss);
}
*/
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#define AMOUNT_TO_TRANSFER_MULTIASSETS_BASIC (TESTS_DEFAULT_FEE) #define AMOUNT_TO_TRANSFER_MULTIASSETS_BASIC (TESTS_DEFAULT_FEE)
@ -97,6 +38,7 @@ bool multiassets_basic_test::generate(std::vector<test_event_entry>& events) con
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
//TODO: Need to make sure REWIND_BLOCKS_N and other coretests codebase are capable of following hardfork4 rules //TODO: Need to make sure REWIND_BLOCKS_N and other coretests codebase are capable of following hardfork4 rules
//in this test hardfork4 moment moved to runtime section //in this test hardfork4 moment moved to runtime section
//REWIND_BLOCKS_N_WITH_TIME(events, blk_2_inital, blk_0, alice_acc, 2);
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
DO_CALLBACK(events, "c1"); DO_CALLBACK(events, "c1");
@ -115,7 +57,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
alice_wlt->get_account().set_createtime(0); alice_wlt->get_account().set_createtime(0);
asset_descriptor_base adb = AUTO_VAL_INIT(adb); asset_descriptor_base adb = AUTO_VAL_INIT(adb);
adb.total_max_supply = 1000000000000000000; //1M coins adb.total_max_supply = 10000000000000000000; //1M coins
adb.full_name = "Test coins"; adb.full_name = "Test coins";
adb.ticker = "TCT"; adb.ticker = "TCT";
adb.decimal_point = 12; adb.decimal_point = 12;
@ -141,31 +83,13 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
miner_wlt->refresh(); miner_wlt->refresh();
alice_wlt->refresh(); alice_wlt->refresh();
uint64_t mined = 0; CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
std::unordered_map<crypto::public_key, tools::wallet_public::asset_balance_entry_base> balances; CHECK_AND_ASSERT_MES(miner_wlt->balance() == uint64_t(17517225990000000000), false, "Failed to find needed asset in result balances");
miner_wlt->balance(balances, mined);
auto it_asset = balances.find(asset_id); CHECK_AND_ASSERT_MES(alice_wlt->balance() == 0, false, "Failed to find needed asset in result balances");
auto it_native = balances.find(currency::native_coin_asset_id); CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == uint64_t(17517225990000000000), false, "Failed to find needed asset in result balances");
balances.clear();
alice_wlt->balance(balances, mined);
it_asset = balances.find(asset_id);
it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native == balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
miner_wlt->transfer(AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, alice_wlt->get_account().get_public_address(), asset_id); miner_wlt->transfer(AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, alice_wlt->get_account().get_public_address(), asset_id);
//pass over hardfork //pass over hardfork
@ -173,11 +97,9 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
alice_wlt->refresh(); alice_wlt->refresh();
uint64_t last_alice_balances = alice_wlt->balance(asset_id, mined); uint64_t last_alice_balances = alice_wlt->balance(asset_id);
CHECK_AND_ASSERT_MES(last_alice_balances == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, false, "Failed to find needed asset in result balances"); CHECK_AND_ASSERT_MES(last_alice_balances == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, false, "Failed to find needed asset in result balances");
{ {
try { try {
@ -193,7 +115,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
} }
miner_wlt->refresh(); miner_wlt->refresh();
uint64_t last_miner_balance = miner_wlt->balance(asset_id, mined); uint64_t last_miner_balance = miner_wlt->balance(asset_id);
asset_descriptor_base asset_info = AUTO_VAL_INIT(asset_info); asset_descriptor_base asset_info = AUTO_VAL_INIT(asset_info);
@ -211,7 +133,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//test update function //test update function
asset_info.meta_info = "{\"some\": \"info\"}"; asset_info.meta_info = "{\"some\": \"info\"}";
miner_wlt->update_asset(asset_id, asset_info, tx); miner_wlt->update_asset(asset_id, asset_info, tx);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2); r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 2);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
asset_descriptor_base asset_info2 = AUTO_VAL_INIT(asset_info2); asset_descriptor_base asset_info2 = AUTO_VAL_INIT(asset_info2);
@ -228,8 +150,8 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
miner_wlt->refresh(); miner_wlt->refresh();
alice_wlt->refresh(); alice_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong"); CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id, mined) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong"); CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong");
asset_descriptor_base asset_info3 = AUTO_VAL_INIT(asset_info3); asset_descriptor_base asset_info3 = AUTO_VAL_INIT(asset_info3);
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info3); r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info3);
@ -242,7 +164,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
miner_wlt->refresh(); miner_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == destinations[0].amount, false, "Miner balance wrong"); CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == destinations[0].amount, false, "Miner balance wrong");
asset_descriptor_base asset_info4 = AUTO_VAL_INIT(asset_info4); asset_descriptor_base asset_info4 = AUTO_VAL_INIT(asset_info4);
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info4); r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info4);
@ -252,10 +174,10 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//------------------- tests that trying to break stuff ------------------- //------------------- tests that trying to break stuff -------------------
//tests that trying to break stuff //tests that trying to break stuff
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation>([&](const wde_construct_tx_handle_asset_descriptor_operation& o) miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_after_asset_ownership_proof_generated>([&](const wde_construct_tx_after_asset_ownership_proof_generated& o)
{ {
crypto::signature s = currency::null_sig; //crypto::signature s = currency::null_sig;
o.pado->opt_proof = s; o.pownership_proof->gss = crypto::generic_schnorr_sig_s{};
}); });
@ -270,7 +192,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
c.get_tx_pool().purge_transactions(); c.get_tx_pool().purge_transactions();
miner_wlt->refresh(); miner_wlt->refresh();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation>(); miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
@ -317,17 +239,17 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
// check update_asset() with modified 'owner' // check update_asset() with modified 'owner'
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info); //r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info);
CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); //CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info");
asset_info.owner = currency::keypair::generate().pub; //asset_info.owner = currency::keypair::generate().pub;
miner_wlt->update_asset(asset_id, asset_info, tx); //miner_wlt->update_asset(asset_id, asset_info, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); //CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); //r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); //CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed //CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
c.get_tx_pool().purge_transactions(); //c.get_tx_pool().purge_transactions();
miner_wlt->refresh(); //miner_wlt->refresh();
// check emmit_asset() with modified 'current_supply' // check emmit_asset() with modified 'current_supply'
@ -346,13 +268,14 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//------------------- tests that trying to break stuff ------------------- //------------------- tests that trying to break stuff -------------------
//test burn that burns more than tx has //test burn that burns more than tx has
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_seal>(); miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_seal>([&](const wde_construct_tx_handle_asset_descriptor_operation_before_seal& o) miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_burn>([&](const wde_construct_tx_handle_asset_descriptor_operation_before_burn& o)
{ {
o.pado->descriptor.current_supply -= 1000000; o.pado->descriptor.current_supply -= 1000000;
}); });
miner_wlt->burn_asset(asset_id, 10000000000000, tx); miner_wlt->burn_asset(asset_id, 10000000000000, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
@ -360,8 +283,39 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
c.get_tx_pool().purge_transactions(); c.get_tx_pool().purge_transactions();
miner_wlt->refresh(); miner_wlt->refresh();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
// //
miner_wlt->transfer_asset_ownership(asset_id, alice_wlt->get_account().get_public_address().spend_public_key, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "block with a bad tx was unexpectedly mined");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
miner_wlt->refresh();
alice_wlt->refresh();
auto miner_own_assets = miner_wlt->get_own_assets();
auto alice_own_assets = alice_wlt->get_own_assets();
CHECK_AND_ASSERT_MES(miner_own_assets.size() == 0, false, "Miner wlt still think he own asset");
CHECK_AND_ASSERT_MES(alice_own_assets.size() == 1, false, "Alice still don't know she own asset");
uint64_t balance_alice_native = alice_wlt->balance();
uint64_t balance_miner_native = miner_wlt->balance();
uint64_t balance_alice_asset = alice_wlt->balance(asset_id);
uint64_t balance_miner_asset = miner_wlt->balance(asset_id);
alice_wlt->emmit_asset(asset_id, destinations, tx);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
miner_wlt->refresh();
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == balance_miner_asset + destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == balance_alice_asset + destinations[1].amount, false, "Alice balance wrong");
//TODO: attempt to emmmit from old key, attempt to emmit from more then max supply
return true; return true;
} }
@ -432,7 +386,7 @@ bool assets_and_explicit_native_coins_in_outs::generate(std::vector<test_event_e
MAKE_TX(events, tx_1, alice_acc, alice_acc, m_alice_initial_balance - TESTS_DEFAULT_FEE, blk_1r); MAKE_TX(events, tx_1, alice_acc, alice_acc, m_alice_initial_balance - TESTS_DEFAULT_FEE, blk_1r);
CHECK_AND_ASSERT_MES(tx_1.vout.size() == 2, false, "unexpected tx_1.vout.size : " << tx_1.vout.size()); CHECK_AND_ASSERT_MES(tx_1.vout.size() == 2, false, "unexpected tx_1.vout.size : " << tx_1.vout.size());
// make sure that all tx_1 outputs have explicit hative coin asset id // make sure that all tx_1 outputs have explicit native coin asset id
for(auto& out : tx_1.vout) for(auto& out : tx_1.vout)
{ {
CHECK_AND_ASSERT_MES(out.type() == typeid(tx_out_zarcanum), false, "invalid out type"); CHECK_AND_ASSERT_MES(out.type() == typeid(tx_out_zarcanum), false, "invalid out type");