@@ -69,32 +69,40 @@ struct Announcement {
6969 /* * Whether this is a wtxid request. */
7070 const bool m_is_wtxid : 1 ;
7171
72- /* * What state this announcement is in. */
73- State m_state : 3 ;
72+ /* * What state this announcement is in.
73+ * This is a uint8_t instead of a State to silence a GCC warning in versions prior to 8.4 and 9.3.
74+ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 */
75+ uint8_t m_state : 3 ;
76+
77+ /* * Convert m_state to a State enum. */
78+ State GetState () const { return static_cast <State>(m_state); }
79+
80+ /* * Convert a State enum to a uint8_t and store it in m_state. */
81+ void SetState (State state) { m_state = static_cast <uint8_t >(state); }
7482
7583 /* * Whether this announcement is selected. There can be at most 1 selected peer per txhash. */
7684 bool IsSelected () const
7785 {
78- return m_state == State::CANDIDATE_BEST || m_state == State::REQUESTED;
86+ return GetState () == State::CANDIDATE_BEST || GetState () == State::REQUESTED;
7987 }
8088
8189 /* * Whether this announcement is waiting for a certain time to pass. */
8290 bool IsWaiting () const
8391 {
84- return m_state == State::REQUESTED || m_state == State::CANDIDATE_DELAYED;
92+ return GetState () == State::REQUESTED || GetState () == State::CANDIDATE_DELAYED;
8593 }
8694
8795 /* * Whether this announcement can feasibly be selected if the current IsSelected() one disappears. */
8896 bool IsSelectable () const
8997 {
90- return m_state == State::CANDIDATE_READY || m_state == State::CANDIDATE_BEST;
98+ return GetState () == State::CANDIDATE_READY || GetState () == State::CANDIDATE_BEST;
9199 }
92100
93101 /* * Construct a new announcement from scratch, initially in CANDIDATE_DELAYED state. */
94102 Announcement (const GenTxid& gtxid, NodeId peer, bool preferred, std::chrono::microseconds reqtime,
95103 SequenceNumber sequence) :
96104 m_txhash (gtxid.GetHash()), m_time(reqtime), m_peer(peer), m_sequence(sequence), m_preferred(preferred),
97- m_is_wtxid (gtxid.IsWtxid()), m_state(State::CANDIDATE_DELAYED) {}
105+ m_is_wtxid (gtxid.IsWtxid()), m_state(static_cast < uint8_t >( State::CANDIDATE_DELAYED) ) {}
98106};
99107
100108// ! Type alias for priorities.
@@ -143,7 +151,7 @@ struct ByPeerViewExtractor
143151 using result_type = ByPeerView;
144152 result_type operator ()(const Announcement& ann) const
145153 {
146- return ByPeerView{ann.m_peer , ann.m_state == State::CANDIDATE_BEST, ann.m_txhash };
154+ return ByPeerView{ann.m_peer , ann.GetState () == State::CANDIDATE_BEST, ann.m_txhash };
147155 }
148156};
149157
@@ -166,8 +174,8 @@ class ByTxHashViewExtractor {
166174 using result_type = ByTxHashView;
167175 result_type operator ()(const Announcement& ann) const
168176 {
169- const Priority prio = (ann.m_state == State::CANDIDATE_READY) ? m_computer (ann) : 0 ;
170- return ByTxHashView{ann.m_txhash , ann.m_state , prio};
177+ const Priority prio = (ann.GetState () == State::CANDIDATE_READY) ? m_computer (ann) : 0 ;
178+ return ByTxHashView{ann.m_txhash , ann.GetState () , prio};
171179 }
172180};
173181
@@ -261,8 +269,8 @@ std::unordered_map<NodeId, PeerInfo> RecomputePeerInfo(const Index& index)
261269 for (const Announcement& ann : index) {
262270 PeerInfo& info = ret[ann.m_peer ];
263271 ++info.m_total ;
264- info.m_requested += (ann.m_state == State::REQUESTED);
265- info.m_completed += (ann.m_state == State::COMPLETED);
272+ info.m_requested += (ann.GetState () == State::REQUESTED);
273+ info.m_completed += (ann.GetState () == State::COMPLETED);
266274 }
267275 return ret;
268276}
@@ -274,15 +282,15 @@ std::map<uint256, TxHashInfo> ComputeTxHashInfo(const Index& index, const Priori
274282 for (const Announcement& ann : index) {
275283 TxHashInfo& info = ret[ann.m_txhash ];
276284 // Classify how many announcements of each state we have for this txhash.
277- info.m_candidate_delayed += (ann.m_state == State::CANDIDATE_DELAYED);
278- info.m_candidate_ready += (ann.m_state == State::CANDIDATE_READY);
279- info.m_candidate_best += (ann.m_state == State::CANDIDATE_BEST);
280- info.m_requested += (ann.m_state == State::REQUESTED);
285+ info.m_candidate_delayed += (ann.GetState () == State::CANDIDATE_DELAYED);
286+ info.m_candidate_ready += (ann.GetState () == State::CANDIDATE_READY);
287+ info.m_candidate_best += (ann.GetState () == State::CANDIDATE_BEST);
288+ info.m_requested += (ann.GetState () == State::REQUESTED);
281289 // And track the priority of the best CANDIDATE_READY/CANDIDATE_BEST announcements.
282- if (ann.m_state == State::CANDIDATE_BEST) {
290+ if (ann.GetState () == State::CANDIDATE_BEST) {
283291 info.m_priority_candidate_best = computer (ann);
284292 }
285- if (ann.m_state == State::CANDIDATE_READY) {
293+ if (ann.GetState () == State::CANDIDATE_READY) {
286294 info.m_priority_best_candidate_ready = std::max (info.m_priority_best_candidate_ready , computer (ann));
287295 }
288296 // Also keep track of which peers this txhash has an announcement for (so we can detect duplicates).
@@ -369,8 +377,8 @@ class TxRequestTracker::Impl {
369377 Iter<Tag> Erase (Iter<Tag> it)
370378 {
371379 auto peerit = m_peerinfo.find (it->m_peer );
372- peerit->second .m_completed -= it->m_state == State::COMPLETED;
373- peerit->second .m_requested -= it->m_state == State::REQUESTED;
380+ peerit->second .m_completed -= it->GetState () == State::COMPLETED;
381+ peerit->second .m_requested -= it->GetState () == State::REQUESTED;
374382 if (--peerit->second .m_total == 0 ) m_peerinfo.erase (peerit);
375383 return m_index.get <Tag>().erase (it);
376384 }
@@ -380,11 +388,11 @@ class TxRequestTracker::Impl {
380388 void Modify (Iter<Tag> it, Modifier modifier)
381389 {
382390 auto peerit = m_peerinfo.find (it->m_peer );
383- peerit->second .m_completed -= it->m_state == State::COMPLETED;
384- peerit->second .m_requested -= it->m_state == State::REQUESTED;
391+ peerit->second .m_completed -= it->GetState () == State::COMPLETED;
392+ peerit->second .m_requested -= it->GetState () == State::REQUESTED;
385393 m_index.get <Tag>().modify (it, std::move (modifier));
386- peerit->second .m_completed += it->m_state == State::COMPLETED;
387- peerit->second .m_requested += it->m_state == State::REQUESTED;
394+ peerit->second .m_completed += it->GetState () == State::COMPLETED;
395+ peerit->second .m_requested += it->GetState () == State::REQUESTED;
388396 }
389397
390398 // ! Convert a CANDIDATE_DELAYED announcement into a CANDIDATE_READY. If this makes it the new best
@@ -393,26 +401,26 @@ class TxRequestTracker::Impl {
393401 void PromoteCandidateReady (Iter<ByTxHash> it)
394402 {
395403 assert (it != m_index.get <ByTxHash>().end ());
396- assert (it->m_state == State::CANDIDATE_DELAYED);
404+ assert (it->GetState () == State::CANDIDATE_DELAYED);
397405 // Convert CANDIDATE_DELAYED to CANDIDATE_READY first.
398- Modify<ByTxHash>(it, [](Announcement& ann){ ann.m_state = State::CANDIDATE_READY; });
406+ Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState ( State::CANDIDATE_READY) ; });
399407 // The following code relies on the fact that the ByTxHash is sorted by txhash, and then by state (first
400408 // _DELAYED, then _READY, then _BEST/REQUESTED). Within the _READY announcements, the best one (highest
401409 // priority) comes last. Thus, if an existing _BEST exists for the same txhash that this announcement may
402410 // be preferred over, it must immediately follow the newly created _READY.
403411 auto it_next = std::next (it);
404412 if (it_next == m_index.get <ByTxHash>().end () || it_next->m_txhash != it->m_txhash ||
405- it_next->m_state == State::COMPLETED) {
413+ it_next->GetState () == State::COMPLETED) {
406414 // This is the new best CANDIDATE_READY, and there is no IsSelected() announcement for this txhash
407415 // already.
408- Modify<ByTxHash>(it, [](Announcement& ann){ ann.m_state = State::CANDIDATE_BEST; });
409- } else if (it_next->m_state == State::CANDIDATE_BEST) {
416+ Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState ( State::CANDIDATE_BEST) ; });
417+ } else if (it_next->GetState () == State::CANDIDATE_BEST) {
410418 Priority priority_old = m_computer (*it_next);
411419 Priority priority_new = m_computer (*it);
412420 if (priority_new > priority_old) {
413421 // There is a CANDIDATE_BEST announcement already, but this one is better.
414- Modify<ByTxHash>(it_next, [](Announcement& ann){ ann.m_state = State::CANDIDATE_READY; });
415- Modify<ByTxHash>(it, [](Announcement& ann){ ann.m_state = State::CANDIDATE_BEST; });
422+ Modify<ByTxHash>(it_next, [](Announcement& ann){ ann.SetState ( State::CANDIDATE_READY) ; });
423+ Modify<ByTxHash>(it, [](Announcement& ann){ ann.SetState ( State::CANDIDATE_BEST) ; });
416424 }
417425 }
418426 }
@@ -427,27 +435,27 @@ class TxRequestTracker::Impl {
427435 auto it_prev = std::prev (it);
428436 // The next best CANDIDATE_READY, if any, immediately precedes the REQUESTED or CANDIDATE_BEST
429437 // announcement in the ByTxHash index.
430- if (it_prev->m_txhash == it->m_txhash && it_prev->m_state == State::CANDIDATE_READY) {
438+ if (it_prev->m_txhash == it->m_txhash && it_prev->GetState () == State::CANDIDATE_READY) {
431439 // If one such CANDIDATE_READY exists (for this txhash), convert it to CANDIDATE_BEST.
432- Modify<ByTxHash>(it_prev, [](Announcement& ann){ ann.m_state = State::CANDIDATE_BEST; });
440+ Modify<ByTxHash>(it_prev, [](Announcement& ann){ ann.SetState ( State::CANDIDATE_BEST) ; });
433441 }
434442 }
435- Modify<ByTxHash>(it, [new_state](Announcement& ann){ ann.m_state = new_state; });
443+ Modify<ByTxHash>(it, [new_state](Announcement& ann){ ann.SetState ( new_state) ; });
436444 }
437445
438446 // ! Check if 'it' is the only announcement for a given txhash that isn't COMPLETED.
439447 bool IsOnlyNonCompleted (Iter<ByTxHash> it)
440448 {
441449 assert (it != m_index.get <ByTxHash>().end ());
442- assert (it->m_state != State::COMPLETED); // Not allowed to call this on COMPLETED announcements.
450+ assert (it->GetState () != State::COMPLETED); // Not allowed to call this on COMPLETED announcements.
443451
444452 // This announcement has a predecessor that belongs to the same txhash. Due to ordering, and the
445453 // fact that 'it' is not COMPLETED, its predecessor cannot be COMPLETED here.
446454 if (it != m_index.get <ByTxHash>().begin () && std::prev (it)->m_txhash == it->m_txhash ) return false ;
447455
448456 // This announcement has a successor that belongs to the same txhash, and is not COMPLETED.
449457 if (std::next (it) != m_index.get <ByTxHash>().end () && std::next (it)->m_txhash == it->m_txhash &&
450- std::next (it)->m_state != State::COMPLETED) return false ;
458+ std::next (it)->GetState () != State::COMPLETED) return false ;
451459
452460 return true ;
453461 }
@@ -460,7 +468,7 @@ class TxRequestTracker::Impl {
460468 assert (it != m_index.get <ByTxHash>().end ());
461469
462470 // Nothing to be done if it's already COMPLETED.
463- if (it->m_state == State::COMPLETED) return true ;
471+ if (it->GetState () == State::COMPLETED) return true ;
464472
465473 if (IsOnlyNonCompleted (it)) {
466474 // This is the last non-COMPLETED announcement for this txhash. Delete all.
@@ -490,9 +498,9 @@ class TxRequestTracker::Impl {
490498 // and convert them to CANDIDATE_READY and COMPLETED respectively.
491499 while (!m_index.empty ()) {
492500 auto it = m_index.get <ByTime>().begin ();
493- if (it->m_state == State::CANDIDATE_DELAYED && it->m_time <= now) {
501+ if (it->GetState () == State::CANDIDATE_DELAYED && it->m_time <= now) {
494502 PromoteCandidateReady (m_index.project <ByTxHash>(it));
495- } else if (it->m_state == State::REQUESTED && it->m_time <= now) {
503+ } else if (it->GetState () == State::REQUESTED && it->m_time <= now) {
496504 if (expired) expired->emplace_back (it->m_peer , ToGenTxid (*it));
497505 MakeCompleted (m_index.project <ByTxHash>(it));
498506 } else {
@@ -596,7 +604,7 @@ class TxRequestTracker::Impl {
596604 std::vector<const Announcement*> selected;
597605 auto it_peer = m_index.get <ByPeer>().lower_bound (ByPeerView{peer, true , uint256::ZERO});
598606 while (it_peer != m_index.get <ByPeer>().end () && it_peer->m_peer == peer &&
599- it_peer->m_state == State::CANDIDATE_BEST) {
607+ it_peer->GetState () == State::CANDIDATE_BEST) {
600608 selected.emplace_back (&*it_peer);
601609 ++it_peer;
602610 }
@@ -625,8 +633,8 @@ class TxRequestTracker::Impl {
625633 // returned by GetRequestable always correspond to CANDIDATE_BEST announcements).
626634
627635 it = m_index.get <ByPeer>().find (ByPeerView{peer, false , txhash});
628- if (it == m_index.get <ByPeer>().end () || (it->m_state != State::CANDIDATE_DELAYED &&
629- it->m_state != State::CANDIDATE_READY)) {
636+ if (it == m_index.get <ByPeer>().end () || (it->GetState () != State::CANDIDATE_DELAYED &&
637+ it->GetState () != State::CANDIDATE_READY)) {
630638 // There is no CANDIDATE announcement tracked for this peer, so we have nothing to do. Either this
631639 // txhash wasn't tracked at all (and the caller should have called ReceivedInv), or it was already
632640 // requested and/or completed for other reasons and this is just a superfluous RequestedTx call.
@@ -638,24 +646,24 @@ class TxRequestTracker::Impl {
638646 // other CANDIDATE_BEST or REQUESTED can exist.
639647 auto it_old = m_index.get <ByTxHash>().lower_bound (ByTxHashView{txhash, State::CANDIDATE_BEST, 0 });
640648 if (it_old != m_index.get <ByTxHash>().end () && it_old->m_txhash == txhash) {
641- if (it_old->m_state == State::CANDIDATE_BEST) {
649+ if (it_old->GetState () == State::CANDIDATE_BEST) {
642650 // The data structure's invariants require that there can be at most one CANDIDATE_BEST or one
643651 // REQUESTED announcement per txhash (but not both simultaneously), so we have to convert any
644652 // existing CANDIDATE_BEST to another CANDIDATE_* when constructing another REQUESTED.
645653 // It doesn't matter whether we pick CANDIDATE_READY or _DELAYED here, as SetTimePoint()
646654 // will correct it at GetRequestable() time. If time only goes forward, it will always be
647655 // _READY, so pick that to avoid extra work in SetTimePoint().
648- Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.m_state = State::CANDIDATE_READY; });
649- } else if (it_old->m_state == State::REQUESTED) {
656+ Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.SetState ( State::CANDIDATE_READY) ; });
657+ } else if (it_old->GetState () == State::REQUESTED) {
650658 // As we're no longer waiting for a response to the previous REQUESTED announcement, convert it
651659 // to COMPLETED. This also helps guaranteeing progress.
652- Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.m_state = State::COMPLETED; });
660+ Modify<ByTxHash>(it_old, [](Announcement& ann) { ann.SetState ( State::COMPLETED) ; });
653661 }
654662 }
655663 }
656664
657665 Modify<ByPeer>(it, [expiry](Announcement& ann) {
658- ann.m_state = State::REQUESTED;
666+ ann.SetState ( State::REQUESTED) ;
659667 ann.m_time = expiry;
660668 });
661669 }
0 commit comments