1
0
Fork 0
forked from lthn/blockchain

implemented proper versioning in serialization asset_descriptor_* structs + serialization refactoring + boost serialization maps versioning self-vaidation

This commit is contained in:
cryptozoidberg 2024-10-18 00:26:30 +04:00
parent 2c72622d7e
commit b2e9872645
No known key found for this signature in database
GPG key ID: 2E10CC61CAC8F36D
6 changed files with 221 additions and 38 deletions

View file

@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <type_traits>
#include <boost/pfr.hpp>
#define BEGIN_BOOST_SERIALIZATION() template <class t_archive> void serialize(t_archive &_arch, const unsigned int ver) {
@ -26,6 +28,57 @@ template<size_t A, size_t B> struct TAssertEquality {
#define END_BOOST_SERIALIZATION() }
/**********************************************************************************************************************************
This serialization closing macro adds self-validation by checking the total number of fields in the structure using boost::pfr.
Note: "num_fields" does NOT represent the number of fields included in the serialization. Instead, it indicates the total number
of fields in the structure, some of which might not be included in the serialization for valid reasons. If someone adds new
fields to the structure but forgets to update the serialization map, the compilation will fail. Any update to "num_fields" must
be accompanied by a thorough review of the serialization map to ensure no fields are omitted.
**********************************************************************************************************************************/
#define END_BOOST_SERIALIZATION_TOTAL_FIELDS(num_fields) static_assert(num_fields == boost::pfr::tuple_size<std::remove_reference<decltype(*this)>::type>::value, "Unexpected number of fields!"); }
#define BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(current_version) static const unsigned int current_boost_version_serialization_version = current_version;
#define LOOP_BACK_BOOST_SERIALIZATION_VERSION(type) BOOST_CLASS_VERSION(type, type::current_boost_version_serialization_version);
template<bool IsSaving, typename destination_t>
struct boost_transition_t {};
template<typename destination_t>
struct boost_transition_t<true, destination_t>
{
template <typename archive, typename origin_type>
static void chain_serialize(archive& ar, const origin_type& origin_tx)
{
destination_t dst_tx = AUTO_VAL_INIT(dst_tx);
transition_convert(origin_tx, dst_tx);
ar & dst_tx;
}
};
template<typename destination_t>
struct boost_transition_t<false, destination_t>
{
template <typename archive, typename origin_type>
static void chain_serialize(archive& ar, origin_type& origin_tx)
{
// TODO: consider using move semantic for temporary 'dst_tx'
destination_t dst_tx = AUTO_VAL_INIT(dst_tx);
ar & dst_tx;
transition_convert(dst_tx, origin_tx);
}
};
#define BOOST_CHAIN_TRANSITION_VER(obj_version, old_type) if (obj_version == ver) {boost_transition_t<t_archive::is_saving::value, old_type>::chain_serialize(_arch, *this);return;}
#define BOOST_CHAIN_TRANSITION_IF_COND_TRUE(condition, old_type) if (condition) {boost_transition_t<t_archive::is_saving::value, old_type>::chain_serialize(_arch, *this);return;}
/*
example of use:

View file

@ -696,9 +696,17 @@ namespace currency
}
};
#define ASSET_DESCRIPTOR_BASE_STRUCTURE_VER 1
#define ASSET_DESCRIPTOR_BASE_STRUCTURE_LAST_VER 2
typedef boost::variant<crypto::public_key, crypto::eth_public_key> asset_owner_pub_key_v;
struct dummy{
BEGIN_SERIALIZE()
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION_TOTAL_FIELDS(0)
};
typedef boost::variant<dummy> asset_descriptor_base_etc_fields;
struct asset_descriptor_base
{
@ -710,11 +718,14 @@ namespace currency
std::string meta_info;
crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8
bool hidden_supply = false;
uint8_t version = 0;
//version 1 members
boost::optional<crypto::eth_public_key> owner_eth_pub_key; // note: the size is 33 bytes (if present) // NOTE: using boost::optional instead of std::optional because of the Boost compilation issue: https://github.com/boostorg/serialization/issues/319 -- sowle
//version 2 members
std::vector<asset_descriptor_base_etc_fields> etc; //container for future use if we would be adding some optional parameters that is not known yet, but without mess related to format version
uint8_t version = ASSET_DESCRIPTOR_BASE_STRUCTURE_VER;
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_BASE_STRUCTURE_VER, version)
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_BASE_STRUCTURE_LAST_VER, version)
FIELD(total_max_supply)
FIELD(current_supply)
FIELD(decimal_point)
@ -725,8 +736,11 @@ namespace currency
FIELD(hidden_supply)
END_VERSION_UNDER(1)
FIELD(owner_eth_pub_key)
END_VERSION_UNDER(2)
FIELD(etc)
END_SERIALIZE()
BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(2)
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(total_max_supply)
BOOST_SERIALIZE(current_supply)
@ -738,7 +752,10 @@ namespace currency
BOOST_SERIALIZE(hidden_supply)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(owner_eth_pub_key)
END_BOOST_SERIALIZATION()
BOOST_END_VERSION_UNDER(2)
BOOST_SERIALIZE(etc)
BOOST_SERIALIZE(version)
END_BOOST_SERIALIZATION_TOTAL_FIELDS(11)
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for a given asset, cannot be changed after deployment.") DOC_EXMP(1000000000000000000) DOC_END
@ -778,38 +795,56 @@ namespace currency
#define ASSET_DESCRIPTOR_OPERATION_UPDATE 3
#define ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN 4
#define ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER 1
#define ASSET_DESCRIPTOR_OPERATION_LAST_VER 2
typedef boost::variant<dummy> asset_descriptor_operator_etc_fields;
struct asset_descriptor_operation
{
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
crypto::public_key amount_commitment; // premultiplied by 1/8
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER;
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
uint8_t version = 1;
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion)
boost::optional<crypto::public_key> opt_amount_commitment; // premultiplied by 1/8
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
boost::optional<asset_descriptor_base> opt_descriptor; //used in deploy/update
boost::optional<uint64_t> opt_amount; //used in burn/emit
std::vector<asset_descriptor_operator_etc_fields> etc; //reserved for future use
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_LAST_VER, version)
CHAIN_TRANSITION_VER(0, asset_descriptor_operation_v1)
CHAIN_TRANSITION_VER(1, asset_descriptor_operation_v1)
FIELD(operation_type)
FIELD(descriptor)
FIELD(amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_amount_commitment)
FIELD(opt_asset_id)
FIELD(opt_descriptor)
FIELD(opt_amount)
FIELD(etc)
END_SERIALIZE()
BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(2)
BEGIN_BOOST_SERIALIZATION()
BOOST_CHAIN_TRANSITION_VER(1, asset_descriptor_operation_v1)
BOOST_CHAIN_TRANSITION_VER(0, asset_descriptor_operation_v1)
BOOST_SERIALIZE(version)
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_amount_commitment)
BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION()
BOOST_SERIALIZE(opt_descriptor)
BOOST_SERIALIZE(opt_amount)
BOOST_SERIALIZE(etc)
END_BOOST_SERIALIZATION_TOTAL_FIELDS(7)
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END
KV_SERIALIZE(descriptor) DOC_DSCR("Asset descriptor") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitment) DOC_DSCR("Amount commitment") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END
KV_SERIALIZE(version) DOC_DSCR("Asset operation type struct version") DOC_EXMP(2) DOC_END
KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(opt_amount_commitment) DOC_DSCR("Asset operation amount commitment(optional)") DOC_EXMP("5688b56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.(optional)") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END
KV_SERIALIZE(opt_descriptor) DOC_DSCR("Asset operation amount commitment(optional)") DOC_EXMP_AUTO() DOC_END
KV_SERIALIZE(opt_amount) DOC_DSCR("Asset operation amount(optional, needed only for burn/emit)") DOC_EXMP_AUTO() DOC_END
//KV_SERIALIZE(etc) DOC_DSCR("Extra operations") DOC_EXMP_AUTO() DOC_END <---- serialization for variant not supported yet
END_KV_SERIALIZE_MAP()
};
struct asset_operation_proof
@ -824,6 +859,7 @@ namespace currency
FIELD(opt_amount_commitment_g_proof)
END_SERIALIZE()
BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(1)
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(opt_amount_commitment_composition_proof)
BOOST_SERIALIZE(opt_amount_commitment_g_proof)
@ -842,6 +878,7 @@ namespace currency
FIELD(gss)
END_SERIALIZE()
BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(1)
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(gss)
BOOST_END_VERSION_UNDER(1)
@ -1023,6 +1060,19 @@ namespace currency
FIELD(signatures)
FIELD(proofs)
END_SERIALIZE()
BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(0)
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(version)
BOOST_SERIALIZE(vin)
BOOST_SERIALIZE(vout)
BOOST_SERIALIZE(extra)
BOOST_SERIALIZE(signatures)
BOOST_SERIALIZE(attachment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(proofs)
END_BOOST_SERIALIZATION_TOTAL_FIELDS(4)
};
@ -1158,9 +1208,12 @@ BLOB_SERIALIZER(currency::txout_to_key);
VARIANT_TAG(json_archive, type_name, json_tag)
BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1);
BOOST_CLASS_VERSION(currency::asset_operation_proof, 1);
BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1);
LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_descriptor_operation);
LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_descriptor_base);
LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_operation_proof);
LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_operation_ownership_proof);
LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::transaction);
// txin_v variant currency
@ -1235,7 +1288,8 @@ SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof_eth, 52, "asset_operation_ownership_proof_eth");
SET_VARIANT_TAGS(crypto::eth_public_key, 60, "eth_public_key");
//SET_VARIANT_TAGS(crypto::eth_signature, 61, "eth_signature");s
//SET_VARIANT_TAGS(crypto::eth_signature, 61, "eth_signature");
SET_VARIANT_TAGS(currency::dummy, 62, "dummy");

View file

@ -116,3 +116,74 @@ bool transition_convert(const transaction_v1& from, transaction_current_t& to)
}
return true;
}
struct asset_descriptor_operation_v1
{
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
crypto::public_key amount_commitment; // premultiplied by 1/8
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = 1;
BEGIN_VERSIONED_SERIALIZE(1, verion)
FIELD(operation_type)
FIELD(descriptor)
FIELD(amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_asset_id)
END_SERIALIZE()
//this map doesn't store internal version member, but it set it by default to val "1", which then transfered via transition_convert() to destination struct
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION()
};
template<typename asset_descriptor_operation_t>
bool transition_convert(const asset_descriptor_operation_t& from, asset_descriptor_operation_v1& to)
{
to.verion = from.version;
to.operation_type = from.operation_type;
if(from.opt_descriptor.has_value())
{
to.descriptor = *from.opt_descriptor;
}
else
{
throw std::runtime_error(std::string("Unexpected: missing descriptor in from transaction_current_t"));
}
if (from.opt_amount_commitment.has_value())
{
to.amount_commitment = *from.opt_amount_commitment;
}
else
{
throw std::runtime_error(std::string("Unexpected: missing amount_commitment in from transaction_current_t"));
}
to.opt_asset_id = from.opt_asset_id;
if(from.opt_amount.has_value() || from.etc.size())
{
throw std::runtime_error(std::string("Unexpected: opt_amount or etc have values during convention, looks like object slicing with information getting lost"));
}
return true;
}
template<typename asset_descriptor_operation_t>
bool transition_convert(const asset_descriptor_operation_v1& from, asset_descriptor_operation_t& to)
{
to.operation_type = from.operation_type;
to.opt_descriptor = from.descriptor;
to.opt_amount_commitment = from.amount_commitment;
to.opt_asset_id = to.opt_asset_id; // target asset_id - for update/emit
to.version = from.verion;
return true;
}

View file

@ -222,16 +222,7 @@ namespace boost
a & x.buff;
}
template <class Archive>
inline void serialize(Archive &a, currency::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.signatures;
a & x.attachment;
}
template <class Archive>
inline void serialize(Archive &a, currency::keypair &kp, const boost::serialization::version_type ver)

View file

@ -1209,7 +1209,13 @@ namespace currency
tv.short_view = std::string("op:") + get_asset_operation_type_string(ado.operation_type, true);
if (ado.opt_asset_id.has_value())
tv.short_view += std::string(" , id:") + crypto::pod_to_hex(ado.opt_asset_id);
tv.details_view = tv.short_view + std::string(" , ticker:") + ado.descriptor.ticker + std::string(" , cur.supply:") + print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point);
tv.details_view = tv.short_view;
if (ado.opt_descriptor.has_value())
{
tv.details_view += std::string(" , ticker:") + ado.opt_descriptor->ticker + std::string(" , cur.supply:") + print_money_brief(ado.opt_descriptor->current_supply, ado.opt_descriptor->decimal_point);
}
//@#@ TODO: add other info from asset_descriptor_operation v2+
return true;
}
template<typename t_type>

View file

@ -124,6 +124,14 @@ namespace currency
//-----------------------------------------------------------------------------------------------------
void miner::do_print_hashrate(bool do_hr)
{
#ifdef _DEBUG
currency::asset_descriptor_operation ado;
std::stringstream ss;
bool r = tools::portble_serialize_obj_to_stream(ado, ss);
std::cout << r;
#endif
m_do_print_hashrate = do_hr;
}
//-----------------------------------------------------------------------------------------------------