Skip to content

Commit fb133cc

Browse files
committed
evo: change internal type of MnNetInfo to NetInfoEntry
1 parent 27db1dd commit fb133cc

File tree

4 files changed

+94
-12
lines changed

4 files changed

+94
-12
lines changed

src/evo/deterministicmns.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,8 @@ static bool CheckService(const ProTx& proTx, TxValidationState& state)
12131213
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-type");
12141214
case NetInfoStatus::NotRoutable:
12151215
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-addr-unroutable");
1216+
case NetInfoStatus::Malformed:
1217+
return state.Invalid(TxValidationResult::TX_BAD_SPECIAL, "bad-protx-netinfo-bad");
12161218
case NetInfoStatus::Success:
12171219
return true;
12181220
// Shouldn't be possible during self-checks

src/evo/netinfo.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ NetInfoStatus MnNetInfo::AddEntry(const std::string& input)
163163
service.has_value()) {
164164
const auto ret = ValidateService(service.value());
165165
if (ret == NetInfoStatus::Success) {
166-
m_addr = service.value();
167-
ASSERT_IF_DEBUG(m_addr != empty_service);
166+
m_addr = NetInfoEntry{service.value()};
167+
ASSERT_IF_DEBUG(GetPrimary() != empty_service);
168168
}
169169
return ret;
170170
}
@@ -175,18 +175,34 @@ CServiceList MnNetInfo::GetEntries() const
175175
{
176176
CServiceList ret;
177177
if (!IsEmpty()) {
178-
ASSERT_IF_DEBUG(m_addr != empty_service);
179-
ret.push_back(m_addr);
178+
ASSERT_IF_DEBUG(GetPrimary() != empty_service);
179+
ret.push_back(GetPrimary());
180180
}
181181
// If MnNetInfo is empty, we probably don't expect any entries to show up, so
182182
// we return a blank set instead.
183183
return ret;
184184
}
185185

186+
const CService& MnNetInfo::GetPrimary() const
187+
{
188+
if (const auto& service{m_addr.GetAddrPort()}; service.has_value()) {
189+
return *service;
190+
}
191+
return empty_service;
192+
}
193+
194+
NetInfoStatus MnNetInfo::Validate() const
195+
{
196+
if (!m_addr.IsTriviallyValid()) {
197+
return NetInfoStatus::Malformed;
198+
}
199+
return ValidateService(GetPrimary());
200+
}
201+
186202
std::string MnNetInfo::ToString() const
187203
{
188204
// Extra padding to account for padding done by the calling function.
189205
return strprintf("MnNetInfo()\n"
190-
" CService(addr=%s, port=%u)\n",
191-
m_addr.ToStringAddr(), m_addr.GetPort());
206+
" %s\n",
207+
m_addr.ToString());
192208
}

src/evo/netinfo.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum class NetInfoStatus : uint8_t {
2222
BadPort,
2323
BadType,
2424
NotRoutable,
25+
Malformed,
2526

2627
Success
2728
};
@@ -39,6 +40,8 @@ constexpr std::string_view NISToString(const NetInfoStatus code)
3940
return "invalid address type";
4041
case NetInfoStatus::NotRoutable:
4142
return "unroutable address";
43+
case NetInfoStatus::Malformed:
44+
return "malformed";
4245
case NetInfoStatus::Success:
4346
return "success";
4447
} // no default case, so the compiler can warn about missing cases
@@ -151,7 +154,7 @@ using CServiceList = std::vector<std::reference_wrapper<const CService>>;
151154
class MnNetInfo
152155
{
153156
private:
154-
CService m_addr{};
157+
NetInfoEntry m_addr{};
155158

156159
private:
157160
static NetInfoStatus ValidateService(const CService& service);
@@ -163,20 +166,38 @@ class MnNetInfo
163166
bool operator==(const MnNetInfo& rhs) const { return m_addr == rhs.m_addr; }
164167
bool operator!=(const MnNetInfo& rhs) const { return !(*this == rhs); }
165168

166-
SERIALIZE_METHODS(MnNetInfo, obj)
169+
template <typename Stream>
170+
void Serialize(Stream& s) const
171+
{
172+
if (const auto& service{m_addr.GetAddrPort()}; service.has_value()) {
173+
s << service->get();
174+
} else {
175+
s << CService{};
176+
}
177+
}
178+
179+
void Serialize(CSizeComputer& s) const
180+
{
181+
s.seek(::GetSerializeSize(CService{}, s.GetVersion()));
182+
}
183+
184+
template <typename Stream>
185+
void Unserialize(Stream& s)
167186
{
168-
READWRITE(obj.m_addr);
187+
CService service;
188+
s >> service;
189+
m_addr = NetInfoEntry{service};
169190
}
170191

171192
NetInfoStatus AddEntry(const std::string& service);
172193
CServiceList GetEntries() const;
173194

174-
const CService& GetPrimary() const { return m_addr; }
195+
const CService& GetPrimary() const;
175196
bool IsEmpty() const { return *this == MnNetInfo(); }
176-
NetInfoStatus Validate() const { return ValidateService(m_addr); }
197+
NetInfoStatus Validate() const;
177198
std::string ToString() const;
178199

179-
void Clear() { m_addr = CService(); }
200+
void Clear() { m_addr.Clear(); }
180201
};
181202

182203
#endif // BITCOIN_EVO_NETINFO_H

src/test/evo_netinfo_tests.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,54 @@ BOOST_AUTO_TEST_CASE(mnnetinfo_rules)
4848
MnNetInfo netInfo;
4949
BOOST_CHECK_EQUAL(netInfo.AddEntry(input), expected_ret);
5050
if (expected_ret != NetInfoStatus::Success) {
51+
// An empty MnNetInfo is considered malformed
52+
BOOST_CHECK_EQUAL(netInfo.Validate(), NetInfoStatus::Malformed);
5153
BOOST_CHECK(netInfo.GetEntries().empty());
5254
} else {
55+
BOOST_CHECK_EQUAL(netInfo.Validate(), NetInfoStatus::Success);
5356
ValidateGetEntries(netInfo.GetEntries(), /*expected_size=*/1);
5457
}
5558
}
5659
}
5760

61+
bool CheckIfSerSame(const CService& lhs, const MnNetInfo& rhs)
62+
{
63+
CHashWriter ss_lhs(SER_GETHASH, 0), ss_rhs(SER_GETHASH, 0);
64+
ss_lhs << lhs;
65+
ss_rhs << rhs;
66+
return ss_lhs.GetSHA256() == ss_rhs.GetSHA256();
67+
}
68+
69+
BOOST_AUTO_TEST_CASE(cservice_compatible)
70+
{
71+
// Empty values should be the same
72+
CService service;
73+
MnNetInfo netInfo;
74+
BOOST_CHECK(CheckIfSerSame(service, netInfo));
75+
76+
// Valid IPv4 address, valid port
77+
service = LookupNumeric("1.1.1.1", 9999);
78+
netInfo.Clear();
79+
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.1:9999"), NetInfoStatus::Success);
80+
BOOST_CHECK(CheckIfSerSame(service, netInfo));
81+
82+
// Valid IPv4 address, default P2P port implied
83+
service = LookupNumeric("1.1.1.1", Params().GetDefaultPort());
84+
netInfo.Clear();
85+
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.1"), NetInfoStatus::Success);
86+
BOOST_CHECK(CheckIfSerSame(service, netInfo));
87+
88+
// Lookup() failure (domains not allowed), MnNetInfo should remain empty if Lookup() failed
89+
service = CService();
90+
netInfo.Clear();
91+
BOOST_CHECK_EQUAL(netInfo.AddEntry("example.com"), NetInfoStatus::BadInput);
92+
BOOST_CHECK(CheckIfSerSame(service, netInfo));
93+
94+
// Validation failure (non-IPv4 not allowed), MnNetInfo should remain empty if ValidateService() failed
95+
service = CService();
96+
netInfo.Clear();
97+
BOOST_CHECK_EQUAL(netInfo.AddEntry("[2606:4700:4700::1111]:9999"), NetInfoStatus::BadType);
98+
BOOST_CHECK(CheckIfSerSame(service, netInfo));
99+
}
100+
58101
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)