Skip to content

Commit a35d9c6

Browse files
committed
evo: prohibit entries with duplicate addresses in ExtNetInfo
MnNetInfo cannot store duplicate entries as it can store only one entry, so it cannot emit NetInfoStatus::Duplicate.
1 parent 56b1bb6 commit a35d9c6

File tree

4 files changed

+45
-0
lines changed

4 files changed

+45
-0
lines changed

src/evo/deterministicmns.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ static bool CheckService(const ProTx& proTx, TxValidationState& state)
910910
return true;
911911
// Shouldn't be possible during self-checks
912912
case NetInfoStatus::BadInput:
913+
case NetInfoStatus::Duplicate:
913914
case NetInfoStatus::MaxLimit:
914915
assert(false);
915916
} // no default case, so the compiler can warn about missing cases

src/evo/netinfo.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,13 +259,35 @@ std::string MnNetInfo::ToString() const
259259
return IsEmpty() ? "MnNetInfo()" : strprintf("MnNetInfo([%s])", m_addr.ToString());
260260
}
261261

262+
bool ExtNetInfo::HasDuplicates() const
263+
{
264+
std::unordered_set<std::string> known{};
265+
for (const NetInfoEntry& entry : m_data) {
266+
if (auto [_, inserted] = known.insert(entry.ToStringAddr()); !inserted) {
267+
return true;
268+
}
269+
}
270+
ASSERT_IF_DEBUG(known.size() == m_data.size());
271+
return false;
272+
}
273+
274+
bool ExtNetInfo::IsDuplicateCandidate(const NetInfoEntry& candidate) const
275+
{
276+
const std::string& candidate_str{candidate.ToStringAddr()};
277+
return std::any_of(m_data.begin(), m_data.end(),
278+
[&candidate_str](const auto& entry) { return candidate_str == entry.ToStringAddr(); });
279+
}
280+
262281
NetInfoStatus ExtNetInfo::ProcessCandidate(const NetInfoEntry& candidate)
263282
{
264283
assert(candidate.IsTriviallyValid());
265284

266285
if (m_data.size() >= MAX_ENTRIES_EXTNETINFO) {
267286
return NetInfoStatus::MaxLimit;
268287
}
288+
if (IsDuplicateCandidate(candidate)) {
289+
return NetInfoStatus::Duplicate;
290+
}
269291
m_data.push_back(candidate);
270292

271293
return NetInfoStatus::Success;
@@ -331,6 +353,9 @@ NetInfoStatus ExtNetInfo::Validate() const
331353
if (m_version == 0 || m_version > CURRENT_VERSION || m_data.empty()) {
332354
return NetInfoStatus::Malformed;
333355
}
356+
if (HasDuplicates()) {
357+
return NetInfoStatus::Duplicate;
358+
}
334359
for (const auto& entry : m_data) {
335360
if (!entry.IsTriviallyValid()) {
336361
// Trivially invalid NetInfoEntry, no point checking against consensus rules

src/evo/netinfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static constexpr uint8_t MAX_ENTRIES_EXTNETINFO{4};
2121
enum class NetInfoStatus : uint8_t {
2222
// Managing entries
2323
BadInput,
24+
Duplicate,
2425
MaxLimit,
2526

2627
// Validation
@@ -44,6 +45,8 @@ constexpr std::string_view NISToString(const NetInfoStatus code)
4445
return "invalid port";
4546
case NetInfoStatus::BadType:
4647
return "invalid address type";
48+
case NetInfoStatus::Duplicate:
49+
return "duplicate";
4750
case NetInfoStatus::NotRoutable:
4851
return "unroutable address";
4952
case NetInfoStatus::Malformed:
@@ -228,6 +231,12 @@ class ExtNetInfo final : public NetInfoInterface
228231
/** Update if serialization or ruleset changed */
229232
static constexpr uint8_t CURRENT_VERSION{1};
230233

234+
/** Returns true if there are addr:port duplicates in the object */
235+
bool HasDuplicates() const;
236+
237+
/** Returns true if candidate is an addr:port duplicate in the object */
238+
bool IsDuplicateCandidate(const NetInfoEntry& candidate) const;
239+
231240
/** Validate uniqueness requirements and add to object if passed */
232241
NetInfoStatus ProcessCandidate(const NetInfoEntry& candidate);
233242

src/test/evo_netinfo_tests.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ BOOST_FIXTURE_TEST_CASE(extnetinfo_rules_reg, RegTestingSetup)
126126
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.5:9998"), NetInfoStatus::MaxLimit);
127127
ValidateGetEntries(netInfo.GetEntries(), /*expected_size=*/MAX_ENTRIES_EXTNETINFO);
128128
}
129+
130+
{
131+
// ExtNetInfo does not allow storing duplicates
132+
ExtNetInfo netInfo;
133+
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.1:9998"), NetInfoStatus::Success);
134+
// Exact duplicates are prohibited
135+
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.1:9998"), NetInfoStatus::Duplicate);
136+
// Partial duplicates (same address, different port) are also prohibited
137+
BOOST_CHECK_EQUAL(netInfo.AddEntry("1.1.1.1:9997"), NetInfoStatus::Duplicate);
138+
}
129139
}
130140

131141
BOOST_AUTO_TEST_CASE(netinfo_ser)

0 commit comments

Comments
 (0)