Skip to content

Commit 974c3dc

Browse files
committed
dgb: rescope to the reachable readvertise path; label broadcast_share pre-wiring
A caller-side reachability trace shows DGB is not symmetric with btc/bch: main_dgb.cpp binds no create/mint-share fn, so dgb::NodeImpl::broadcast_share and notify_local_share have zero callers repo-wide -- DGB never mints a local share today (#884). DGB's live path into send_shares is readvertise_best_share() (ROOT-2 re-advert on best-change plus a 10s one-shot timer), which re-pushes PEER-RECEIVED shares and deliberately bypasses the de-dup set. Verified independently: set_mint_share_fn / set_create_share_fn / broadcast_share / notify_local_share have zero occurrences in main_dgb.cpp; the only set_mint_share_fn binding in the tree is main_dash.cpp:1854 plus dgb's own work_source_test. readvertise_best_share is called from node.cpp:1767 and 1774. BTC (main_btc.cpp:1336 after lk.unlock() at :1323) and BCH (pool_entrypoint.hpp:564 after lk.unlock() at :562) are both live and unchanged. Changes: - dgb: extract the readvertise recording rule into readvertise_and_record() and wire readvertise_best_share() through it. This is DGB's live reward-critical marking discipline: m_last_broadcast_to is what a peer disconnect within 10s converts into m_rejected_share_hashes, and the readvertise walk `continue`s past rejected hashes permanently. Recording the OFFERED batch would let a share the F3 gate merely withheld be blamed for someone else's drop and excluded from every future re-advert -- a propagation loss for the whole sharechain, since DGB re-advertises peer-received shares. - dgb: rescope the KATs onto that live path. The gate cases (partition_backable) and the new DgbReadvertiseRecording cases drive code production executes; the broadcast_and_mark cases are renamed DgbBroadcastMarkingPrewired_NotReachedToday so no reader mistakes them for live protection. Removes the broadcast_share de-dup-walk KAT, which modelled an unreachable function -- the shape of the LTC #873 miss. - dgb: label NodeImpl::broadcast_share in source as pre-wiring for #884. The F2 fix stays so the seam is correct when the mint path is bound and so the three coins remain symmetric, but it protects nothing at runtime today. - btc/bch: document the ROOT-2 interaction at readvertise_best(). Marking is now a strict subset of what the pre-fix code marked, so the walk breaks later or in the same place, never earlier: the re-advert re-pushes a superset of what it used to. Monotonically better, strictly better for head shares minted while no peer was connected. It does not fully close ROOT-2 here -- shares already accepted by another peer stay marked and the walk still breaks, as before. That needs the ltc/dgb-style de-dup-bypass readvertise; pre-existing, out of scope. No behaviour change in this commit for btc/bch. Mutation-verified red on the DGB live path: recording the offered batch instead of what was written reddens WithheldShareIsNeverBlamedForAPeerDrop; dropping the empty-send skip reddens PeerThatReceivedNothingIsNotRecorded; deleting the gate reddens 2 DgbBroadcastGate cases.
1 parent e6f3344 commit 974c3dc

5 files changed

Lines changed: 234 additions & 107 deletions

File tree

src/impl/bch/node.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,20 @@ uint256 NodeImpl::advertised_best_share()
10531053
return uint256::ZERO;
10541054
}
10551055

1056+
// ROOT-2 re-advert. Unlike ltc/dgb (which have a dedicated readvertise that
1057+
// bypasses the de-dup set), this delegates to broadcast_share, so the walk still
1058+
// breaks on the first hash already in m_shared_share_hashes.
1059+
//
1060+
// Interaction with the F2 marking change: marking is now a strict SUBSET of what
1061+
// the pre-fix code marked (only hashes a peer actually accepted). The walk breaks
1062+
// later or in the same place, never earlier, so this re-advert re-pushes a
1063+
// superset of what it used to — monotonically better, no regression. It is
1064+
// strictly better in the case that motivated ROOT-2: head shares minted while no
1065+
// peer was connected are no longer marked, so a peer that handshook during the
1066+
// empty window now receives them. It does NOT fully close ROOT-2 here — head
1067+
// shares already accepted by some OTHER peer stay marked and the walk still
1068+
// breaks, exactly as before. Closing that needs the ltc/dgb-style de-dup-bypass
1069+
// readvertise; pre-existing gap, out of scope for this change.
10561070
void NodeImpl::readvertise_best()
10571071
{
10581072
if (m_peers.empty())

src/impl/btc/node.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,20 @@ uint256 NodeImpl::advertised_best_share()
11351135
return uint256::ZERO;
11361136
}
11371137

1138+
// ROOT-2 re-advert. Unlike ltc/dgb (which have a dedicated readvertise that
1139+
// bypasses the de-dup set), this delegates to broadcast_share, so the walk still
1140+
// breaks on the first hash already in m_shared_share_hashes.
1141+
//
1142+
// Interaction with the F2 marking change: marking is now a strict SUBSET of what
1143+
// the pre-fix code marked (only hashes a peer actually accepted). The walk breaks
1144+
// later or in the same place, never earlier, so this re-advert re-pushes a
1145+
// superset of what it used to — monotonically better, no regression. It is
1146+
// strictly better in the case that motivated ROOT-2: head shares minted while no
1147+
// peer was connected are no longer marked, so a peer that handshook during the
1148+
// empty window now receives them. It does NOT fully close ROOT-2 here — head
1149+
// shares already accepted by some OTHER peer stay marked and the walk still
1150+
// breaks, exactly as before. Closing that needs the ltc/dgb-style de-dup-bypass
1151+
// readvertise; pre-existing gap, out of scope for this change.
11381152
void NodeImpl::readvertise_best()
11391153
{
11401154
if (m_peers.empty())

src/impl/dgb/known_txs_retention.hpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@
3333
// try_to_lock missed, or there were no peers — because the de-dup set then
3434
// breaks the walk forever and nothing re-pushes it.
3535
//
36+
// readvertise_and_record() — DGB-ONLY. The marking discipline for the
37+
// advertise-only ROOT-2 re-push, which is DGB's LIVE path (see below).
38+
//
39+
// DGB REACHABILITY — differs from btc/bch; read this before trusting the file.
40+
// main_dgb.cpp binds NO create/mint-share fn, so dgb::NodeImpl::broadcast_share
41+
// and notify_local_share have ZERO callers repo-wide: DGB never mints a local
42+
// share today (tracked as #884). The live DGB path into send_shares is
43+
// readvertise_best_share() (ROOT-2 re-advert, on best-change and on a timer),
44+
// which re-pushes PEER-RECEIVED shares and deliberately bypasses the de-dup
45+
// set. Therefore, on DGB:
46+
// partition_backable() — LIVE (send_shares, reached via readvertise)
47+
// readvertise_and_record() — LIVE (readvertise_best_share)
48+
// broadcast_and_mark() — PRE-WIRED; dead until #884 binds the mint seam.
49+
// Anything asserting the DGB gate through a locally-minted share broadcast is
50+
// exercising a path production never takes.
51+
//
3652
// NOTE (de-dup): the same primitives now exist per-coin (btc/dgb/bch/dash) while
3753
// the LTC lane hoists all_txs_backable into src/core/. Once both land, these
3854
// per-coin headers should be collapsed onto that core hoist.
@@ -178,4 +194,38 @@ inline std::size_t broadcast_and_mark(MarkedSet& marked, Peers& peers,
178194
return actually_sent.size();
179195
}
180196

197+
// Advertise-only ROOT-2 re-push (readvertise_best_share) — DGB's LIVE marking
198+
// path. Offers `to_send` to every peer via `send`, which reports what it
199+
// ACTUALLY wrote, and records that report — never the offered batch — through
200+
// `record(peer, sent)`. A peer that received nothing gets NO record at all.
201+
// Returns the number of peers reached.
202+
//
203+
// Why the recording rule is reward-critical and not cosmetic: m_last_broadcast_to
204+
// is what converts a peer disconnect within 10s into m_rejected_share_hashes
205+
// entries, and the readvertise walk `continue`s past every rejected hash —
206+
// permanently. Recording the OFFERED batch would let a share the F3 completeness
207+
// gate merely withheld be blamed for someone else's disconnect, turning a
208+
// transient, self-healing skip into permanent exclusion from every future
209+
// re-advert. DGB re-advertises PEER-RECEIVED shares, so that is a propagation
210+
// loss for the whole sharechain, not only for us.
211+
template <typename Peers, typename SendFn, typename RecordFn>
212+
inline std::size_t readvertise_and_record(Peers& peers,
213+
const std::vector<uint256>& to_send,
214+
SendFn send,
215+
RecordFn record)
216+
{
217+
if (to_send.empty())
218+
return 0;
219+
220+
std::size_t peers_reached = 0;
221+
for (auto& entry : peers) {
222+
const std::vector<uint256> sent = send(entry.second);
223+
if (sent.empty())
224+
continue; // nothing written -> nothing a later drop may blame
225+
record(entry.second, sent);
226+
++peers_reached;
227+
}
228+
return peers_reached;
229+
}
230+
181231
} // namespace dgb

src/impl/dgb/node.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,12 @@ std::vector<uint256> NodeImpl::send_shares(peer_ptr peer,
836836
return sent;
837837
}
838838

839+
// PRE-WIRING — NOT REACHED ON DGB TODAY (#884). main_dgb.cpp binds no
840+
// create/mint-share fn, so this function and notify_local_share have zero
841+
// callers repo-wide: DGB never mints a local share. The F2 mark-after-send fix
842+
// below is applied so the seam is correct on the day #884 binds the mint path,
843+
// and so btc/dgb/bch stay symmetric — it protects nothing at runtime yet. DGB's
844+
// LIVE send path is readvertise_best_share() above.
839845
void NodeImpl::broadcast_share(const uint256& share_hash)
840846
{
841847
// try_to_lock per the architectural rule (node.hpp:67) — see freeze
@@ -1111,16 +1117,19 @@ void NodeImpl::readvertise_best_share()
11111117
if (to_send.empty())
11121118
return;
11131119

1120+
// Advertise-only path: deliberately ignores the de-dup set, so nothing is
1121+
// marked here. But record only what was ACTUALLY written — a share the F3
1122+
// completeness gate withheld must not be blamed for a later peer drop, which
1123+
// would mark it rejected and make the walk above `continue` past it forever.
1124+
// This is DGB's LIVE reward-critical marking path; broadcast_share below is
1125+
// dead until the mint seam is bound (#884).
11141126
auto now = std::chrono::steady_clock::now();
1115-
for (auto& [nonce, peer] : m_peers) {
1116-
// Advertise-only path: deliberately ignores the de-dup set, so nothing
1117-
// is marked here. Still record only what was ACTUALLY written — a
1118-
// gate-skipped share must not be blamed for a later peer drop (that
1119-
// would mark it rejected and block every future re-broadcast).
1120-
std::vector<uint256> sent = send_shares(peer, to_send);
1121-
if (!sent.empty())
1127+
readvertise_and_record(
1128+
m_peers, to_send,
1129+
[&](peer_ptr& peer) { return send_shares(peer, to_send); },
1130+
[&](peer_ptr& peer, const std::vector<uint256>& sent) {
11221131
m_last_broadcast_to[peer->addr()] = {sent, now};
1123-
}
1132+
});
11241133
LOG_INFO << "[readvertise] re-pushed " << to_send.size()
11251134
<< " head share(s) to " << m_peers.size() << " peer(s) (ROOT-2)";
11261135
}

0 commit comments

Comments
 (0)