forked from lthn/blockchain
implemented proper versioning for binary serialization
This commit is contained in:
parent
2ba139ebaf
commit
213cb4f85c
3 changed files with 207 additions and 1 deletions
|
|
@ -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<uint8_t> buff; //stub
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ inline bool do_serialize(Archive &ar, T &v)
|
|||
#define VARIANT_TAG(A, T, Tg) \
|
||||
template <bool W> struct variant_serialization_traits<A<W>, T> { static inline typename A<W>::variant_tag_type get_tag() { return Tg; } }
|
||||
#define BEGIN_SERIALIZE() \
|
||||
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) {
|
||||
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) {uint8_t s_current_version = 0; uint8_t s_version = 0;
|
||||
#define BEGIN_SERIALIZE_OBJECT() \
|
||||
template <bool W, template <bool> class Archive> bool do_serialize(Archive<W> &_ser_ar) { _ser_ar.begin_object(); bool _ser_res = do_serialize_object(_ser_ar); _ser_ar.end_object(); return _ser_res; } \
|
||||
template <bool W, template <bool> class Archive> bool do_serialize_object(Archive<W> &_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; }
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -740,3 +740,166 @@ TEST(Serialization, serializes_transacion_versions)
|
|||
|
||||
validate_tx_serialisation(tx);
|
||||
}
|
||||
|
||||
struct A
|
||||
{
|
||||
std::string one;
|
||||
std::string two;
|
||||
std::vector<std::string> vector_one;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(one)
|
||||
FIELD(two)
|
||||
FIELD(vector_one)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct A_v1 : public A
|
||||
{
|
||||
std::vector<std::string> 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<std::string> vector_3;
|
||||
std::vector<std::string> 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<std::string> 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<const A&>(lhs) == static_cast<const A&>(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<const A_v1&>(lhs) == static_cast<const A_v1&>(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<const A_v2&>(lhs) == static_cast<const A_v2&>(rhs)))
|
||||
return false;
|
||||
if ((lhs.vector_5 != rhs.vector_5))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename first, typename second>
|
||||
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<second&>(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_v1>(a);
|
||||
ASSERT_TRUE(r);
|
||||
r = perform_test_ser_vers<A_v2>(a);
|
||||
ASSERT_TRUE(r);
|
||||
r = perform_test_ser_vers<A_v3>(a);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
r = perform_test_ser_vers<A_v2>(a_1);
|
||||
ASSERT_TRUE(r);
|
||||
r = perform_test_ser_vers<A_v3>(a_1);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
r = perform_test_ser_vers<A_v3>(a_2);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
r = perform_test_ser_vers<A_v3>(a_3);
|
||||
ASSERT_TRUE(r);
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue