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:
parent
2c72622d7e
commit
b2e9872645
6 changed files with 221 additions and 38 deletions
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue