Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 36 additions & 10 deletions src/evo/dmnstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,28 +356,54 @@ class CDeterministicMNStateDiffLegacy
s >> *this;
}

// Used for testing only
template<typename Stream>
void Serialize(Stream& s) const
{
s << VARINT(fields);

boost::hana::for_each(legacy_members, [&](auto&& member) {
using BaseType = std::decay_t<decltype(member)>;
if constexpr (BaseType::mask == LegacyField_pubKeyOperator) {
if (fields & member.mask) {
// We serialize it as is, no version wrapper is used here
Copy link
Collaborator

@knst knst Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it breaking change to change serialization here like that? Or does it serve testing purpose only?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's for testing only. We read CDeterministicMNStateDiffLegacy in MigrateLegacyDiffs(), convert it to CDeterministicMNListDiff and then store the new diff. We never store CDeterministicMNStateDiffLegacy outside of tests.

s << state.pubKeyOperator;
}
} else if constexpr (BaseType::mask == LegacyField_netInfo) {
if (fields & member.mask) {
// Legacy format supports non-extended addresses only
s << NetInfoSerWrapper(const_cast<std::shared_ptr<NetInfoInterface>&>(state.netInfo),
/*is_extended=*/false);
}
} else {
if (fields & member.mask) {
s << member.get(state);
}
}
});
}

// Deserialize using legacy format
SERIALIZE_METHODS(CDeterministicMNStateDiffLegacy, obj)
template<typename Stream>
void Unserialize(Stream& s)
{
READWRITE(VARINT(obj.fields));
s >> VARINT(fields);

boost::hana::for_each(legacy_members, [&](auto&& member) {
using BaseType = std::decay_t<decltype(member)>;
if constexpr (BaseType::mask == LegacyField_pubKeyOperator) {
if (obj.fields & member.mask) {
if (fields & member.mask) {
// We'll set proper scheme later in MigrateLegacyDiffs()
READWRITE(CBLSLazyPublicKeyVersionWrapper(const_cast<CBLSLazyPublicKey&>(obj.state.pubKeyOperator),
/*legacy=*/true));
s >> CBLSLazyPublicKeyVersionWrapper(state.pubKeyOperator, /*legacy=*/true);
}
} else if constexpr (BaseType::mask == LegacyField_netInfo) {
if (obj.fields & member.mask) {
if (fields & member.mask) {
// Legacy format supports non-extended addresses only
READWRITE(NetInfoSerWrapper(const_cast<std::shared_ptr<NetInfoInterface>&>(obj.state.netInfo),
/*is_extended=*/false));
s >> NetInfoSerWrapper(state.netInfo, /*is_extended=*/false);
}
} else {
if (obj.fields & member.mask) {
READWRITE(member.get(obj.state));
if (fields & member.mask) {
s >> member.get(state);
}
}
});
Expand Down
22 changes: 19 additions & 3 deletions src/test/evo_deterministicmns_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,25 +1128,41 @@ BOOST_AUTO_TEST_CASE(migration_logic_validation)

// Create sample legacy format state diff
CDeterministicMNStateDiffLegacy legacyDiff;
legacyDiff.fields = 0x40000 | 0x0200 | 0x0800; // Legacy: nVersion, pubKeyOperator, netInfo
legacyDiff.fields = 0x40000 | 0x0200 | 0x0800 | 0x0010; // Legacy: nVersion, pubKeyOperator, netInfo, nPoSeBanHeight
legacyDiff.state.nVersion = ProTxVersion::BasicBLS;
legacyDiff.state.pubKeyOperator.Set(CBLSPublicKey{}, false);
CBLSSecretKey sk;
sk.MakeNewKey();
legacyDiff.state.pubKeyOperator.Set(sk.GetPublicKey(), false);
BOOST_CHECK(!legacyDiff.state.pubKeyOperator.IsLegacy());
legacyDiff.state.netInfo = NetInfoInterface::MakeNetInfo(ProTxVersion::BasicBLS);
BOOST_CHECK(!legacyDiff.state.IsBanned());
legacyDiff.state.BanIfNotBanned(2367316);
BOOST_CHECK(legacyDiff.state.IsBanned());
BOOST_CHECK_EQUAL(legacyDiff.state.GetBannedHeight(), 2367316);


// Test legacy class conversion (this would normally be done by CDeterministicMNListDiff)
CDataStream ss(SER_DISK, CLIENT_VERSION);
ss << legacyDiff;

CDeterministicMNStateDiffLegacy legacyDeserializer(deserialize, ss);
CDeterministicMNStateDiff convertedDiff = legacyDeserializer.ToNewFormat();
BOOST_CHECK(!legacyDiff.state.pubKeyOperator.IsLegacy());
BOOST_CHECK(convertedDiff.state.pubKeyOperator.IsLegacy());
convertedDiff.state.pubKeyOperator.SetLegacy(false);
BOOST_CHECK(!convertedDiff.state.pubKeyOperator.IsLegacy());

// Verify conversion worked correctly
uint32_t expectedNewFields = CDeterministicMNStateDiff::Field_nVersion | // 0x0001
CDeterministicMNStateDiff::Field_nPoSeBanHeight | // 0x0020
CDeterministicMNStateDiff::Field_pubKeyOperator | // 0x0400
CDeterministicMNStateDiff::Field_netInfo; // 0x1000

BOOST_CHECK_EQUAL(convertedDiff.fields, expectedNewFields);
BOOST_CHECK_EQUAL(convertedDiff.state.nVersion, ProTxVersion::BasicBLS);
BOOST_CHECK_EQUAL(convertedDiff.state.nVersion, legacyDiff.state.nVersion);
BOOST_CHECK_EQUAL(convertedDiff.state.GetBannedHeight(), legacyDiff.state.GetBannedHeight());
BOOST_CHECK(convertedDiff.state.pubKeyOperator.Get() == legacyDiff.state.pubKeyOperator.Get());
BOOST_CHECK_EQUAL(convertedDiff.state.pubKeyOperator.ToString(), legacyDiff.state.pubKeyOperator.ToString());
}

BOOST_AUTO_TEST_SUITE_END()
Loading