diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 375dd6e6..af113532 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -687,6 +687,27 @@ namespace currency + struct asset_descriptor_base + { + uint64_t total_max_supply = 0; + uint64_t current_supply = 0; + uint8_t decimal_point = 12; + std::string ticker; + std::string full_name; + crypto::public_key owner = currency::null_pkey; + + BEGIN_VERSIONED_SERIALIZE() + FIELD(total_max_supply) + FIELD(current_supply) + FIELD(decimal_point) + FIELD(ticker) + FIELD(full_name) + FIELD(owner) + END_SERIALIZE() + }; + + + struct extra_padding { std::vector buff; //stub diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index b3b54e23..6e16b498 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -61,7 +61,7 @@ inline bool do_serialize(Archive &ar, T &v) #define VARIANT_TAG(A, T, Tg) \ template struct variant_serialization_traits, T> { static inline typename A::variant_tag_type get_tag() { return Tg; } } #define BEGIN_SERIALIZE() \ - template class Archive> bool do_serialize(Archive &_ser_ar) { + template class Archive> bool do_serialize(Archive &_ser_ar) {uint8_t s_current_version = 0; uint8_t s_version = 0; #define BEGIN_SERIALIZE_OBJECT() \ template class Archive> bool do_serialize(Archive &_ser_ar) { _ser_ar.begin_object(); bool _ser_res = do_serialize_object(_ser_ar); _ser_ar.end_object(); return _ser_res; } \ template class Archive> bool do_serialize_object(Archive &_ser_ar){ @@ -98,6 +98,28 @@ do { \ if (!_ser_ar.stream().good()) return false; \ } while (0); +#define VERSION() \ +do { \ + _ser_ar.tag("VERSION"); \ + if (!_ser_ar.stream().good()){break;} \ + _ser_ar.serialize_varint(s_version); \ + if (!_ser_ar.stream().good()) return false; \ + if(s_version > s_current_version) return false; \ +} while (0); + +#define CURRENT_VERSION(v) \ +do { \ + s_current_version = v; \ + if (_ser_ar.is_saving_arch()) { s_version = v; } \ +} while (0); + + + +#define BEGIN_VERSIONED_SERIALIZE() \ + BEGIN_SERIALIZE() \ + VERSION() + + #define DEFINE_SERIALIZATION_VERSION(v) inline static uint32_t get_serialization_version() { return v; } diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index e2aa25db..2ad3a6f4 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -740,3 +740,166 @@ TEST(Serialization, serializes_transacion_versions) validate_tx_serialisation(tx); } + +struct A +{ + std::string one; + std::string two; + std::vector vector_one; + + BEGIN_SERIALIZE() + FIELD(one) + FIELD(two) + FIELD(vector_one) + END_SERIALIZE() +}; + +struct A_v1 : public A +{ + std::vector vector_two; + + + BEGIN_SERIALIZE() + CURRENT_VERSION(1) + FIELD(one) + FIELD(two) + FIELD(vector_one) + VERSION() + if (s_version < 1) return true; + FIELD(vector_two) + END_SERIALIZE() +}; + +struct A_v2 : public A_v1 +{ + std::vector vector_3; + std::vector vector_4; + + + BEGIN_SERIALIZE() + CURRENT_VERSION(2) + FIELD(one) + FIELD(two) + FIELD(vector_one) + VERSION() + if (s_version < 1) return true; + FIELD(vector_two) + if (s_version < 2) return true; + FIELD(vector_3) + FIELD(vector_4) + END_SERIALIZE() +}; + +struct A_v3 : public A_v2 +{ + std::vector vector_5; + + BEGIN_SERIALIZE() + CURRENT_VERSION(3) + FIELD(one) + FIELD(two) + FIELD(vector_one) + VERSION() + if (s_version < 1) return true; + FIELD(vector_two) + if (s_version < 2) return true; + FIELD(vector_3) + FIELD(vector_4) + if (s_version < 3) return true; + FIELD(vector_4) + END_SERIALIZE() +}; + +inline bool operator==(const A& lhs, const A& rhs) +{ + if ((lhs.one != rhs.one || lhs.two != rhs.two || lhs.vector_one != rhs.vector_one)) + { + return false; + } + return true; +} + +inline bool operator==(const A_v1& lhs, const A_v1& rhs) +{ + if (!(static_cast(lhs) == static_cast(rhs))) + return false; + if ((lhs.vector_two != rhs.vector_two)) + { + return false; + } + return true; +} + +inline bool operator==(const A_v2& lhs, const A_v2& rhs) +{ + if (!(static_cast(lhs) == static_cast(rhs))) + return false; + if ((lhs.vector_3 != rhs.vector_3)) + { + return false; + } + return true; +} + +inline bool operator==(const A_v3& lhs, const A_v3& rhs) +{ + if (!(static_cast(lhs) == static_cast(rhs))) + return false; + if ((lhs.vector_5 != rhs.vector_5)) + { + return false; + } + return true; +} + +template +bool perform_test_ser_vers(second& f) +{ + string blob; + first s_s = AUTO_VAL_INIT(s_s); + if (!serialization::dump_binary(f, blob)) + return false; + if (!serialization::parse_binary(blob, s_s)) + return false; + + + if (!(f == static_cast(s_s))) + { + return false; + } + return true; +} + +TEST(Serialization, versioning2) +{ + A_v3 a_3; + a_3.one = "one"; + a_3.two = "two"; + a_3.vector_one.push_back(a_3.one); + a_3.vector_one.push_back(a_3.two); + a_3.vector_two = a_3.vector_one; + a_3.vector_5 = a_3.vector_4 = a_3.vector_3 = a_3.vector_two; + + A_v2 a_2(a_3); + A_v1 a_1(a_3); + A a(a_3); + + bool r = perform_test_ser_vers(a); + ASSERT_TRUE(r); + r = perform_test_ser_vers(a); + ASSERT_TRUE(r); + r = perform_test_ser_vers(a); + ASSERT_TRUE(r); + + r = perform_test_ser_vers(a_1); + ASSERT_TRUE(r); + r = perform_test_ser_vers(a_1); + ASSERT_TRUE(r); + + r = perform_test_ser_vers(a_2); + ASSERT_TRUE(r); + + r = perform_test_ser_vers(a_3); + ASSERT_TRUE(r); + +} \ No newline at end of file