change: drop untargeted pings when collapsing to a full

The ping ID in the URL is the only authentication on the answer, so
rescuing an untargeted ping for every node would let any node answer
for another. Rescue a ping only for the node it targets.
This commit is contained in:
Kristoffer Dalby
2026-09-30 16:57:26 +00:00
committed by Kristoffer Dalby
parent d4948da301
commit 85587e2e29
2 changed files with 8 additions and 6 deletions
+4 -3
View File
@@ -232,14 +232,15 @@ func HasFull(rs []Change) bool {
// CollapseToFull returns what nodeID receives when a full update supersedes
// changes: one [FullUpdate], then a ping-only [PingNode] for every
// [Change.PingRequest] addressed to nodeID, in order. A full renders state at
// [Change.PingRequest] targeted at nodeID, in order. A full renders state at
// drain time, so it covers every state change; a ping is a one-shot command
// the full cannot carry.
// the full cannot carry. An untargeted ping is dropped: the ID in its URL is
// all that authenticates the answer, so any node could answer for another.
func CollapseToFull(nodeID types.NodeID, changes []Change) []Change {
out := []Change{FullUpdate()}
for _, c := range changes {
if c.PingRequest != nil && c.ShouldSendToNode(nodeID) {
if c.PingRequest != nil && c.TargetNode == nodeID {
out = append(out, PingNode(nodeID, c.PingRequest))
}
}
+4 -3
View File
@@ -67,7 +67,8 @@ func TestChange_FullUpdateSubsumesAllButPing(t *testing.T) {
isCarried, ok := carried[field.Name]
require.True(t, ok, "field %s is not classified", field.Name)
var c Change
// Addressed to self, so only the field under test decides.
c := Change{TargetNode: self}
v := reflect.ValueOf(&c).Elem().FieldByIndex(field.Index)
setNonZero(t, v, self)
@@ -701,9 +702,9 @@ func TestCollapseToFullKeepsPings(t *testing.T) {
want: []Change{FullUpdate(), PingNode(self, prA)},
},
{
name: "untargeted ping is addressed to every node",
name: "untargeted ping is dropped",
changes: []Change{{Reason: "broadcast ping", PingRequest: prA}},
want: []Change{FullUpdate(), PingNode(self, prA)},
want: []Change{FullUpdate()},
},
{
name: "fulls never stack",