From f8ad7f81e6d757956faf2c3a296aa7ef4dcabc11 Mon Sep 17 00:00:00 2001 From: Stevan Andjelkovic Date: Thu, 18 Mar 2021 15:20:01 +0100 Subject: [PATCH] test(sut/broadcast): fix classic delivery implementation --- src/sut/broadcast/broadcast.go | 80 +++++++++++++++++++++-------- src/sut/broadcast/broadcast_test.go | 7 ++- 2 files changed, 66 insertions(+), 21 deletions(-) diff --git a/src/sut/broadcast/broadcast.go b/src/sut/broadcast/broadcast.go index b0079ea2..d845d77e 100644 --- a/src/sut/broadcast/broadcast.go +++ b/src/sut/broadcast/broadcast.go @@ -83,15 +83,24 @@ func NewNodeA(round Round) *Node { func NewNode(round Round, neighbour string) *Node { var broadcast bool switch round { - case SimpleDeliv, RetryDeliv: + case SimpleDeliv, RetryDeliv, ClassicDeliv: broadcast = false - case RedunDeliv, AckDeliv, ClassicDeliv: + case RedunDeliv, AckDeliv: broadcast = true default: panic("Unknown round") } neighbours := make(map[string]bool) neighbours[neighbour] = broadcast + + if round == ClassicDeliv { + // Normally node A isn't considered a neighbour, but in the + // classic delivery example it seems like node B and C should + // send messages back to A. + neighbours["A"] = broadcast + neighbours[neighbour] = broadcast + } + return &Node{ Log: "", Neighbours: neighbours, @@ -105,14 +114,28 @@ func (n *Node) Receive(_ time.Time, from string, event lib.InEvent) []lib.OutEve case *lib.InternalMessage: switch msg := (*ev).Message.(type) { case Broadcast: - n.Log = msg.Data if n.Round == AckDeliv { ack := lib.OutEvent{ To: lib.Singleton(from), Args: &lib.InternalMessage{Ack{}}, } oevs = append(oevs, ack) + } else if n.Round == ClassicDeliv && n.Log != msg.Data { + // Broadcast back each new message to all + // neighbours, once. + var neighbours []lib.Receiver + for neighbour, _ := range n.Neighbours { + neighbours = append(neighbours, neighbour) + } + oev := lib.OutEvent{ + To: lib.Set(neighbours...), + Args: &lib.InternalMessage{Broadcast{ + Data: msg.Data, + }}, + } + oevs = append(oevs, oev) } + n.Log = msg.Data case Ack: if n.Round != AckDeliv { panic("Got unexpected Ack message") @@ -152,18 +175,21 @@ func (n *Node) Timer(at time.Time) []lib.OutEvent { } oevs = append(oevs, oev) - // Renew the timer. - duration, err := time.ParseDuration("500ms") - if err != nil { - panic(err) - } - oev2 := lib.OutEvent{ - To: lib.Singleton("scheduler"), - Args: &lib.Timer{ - Duration: duration, - }, + if n.Round != ClassicDeliv { + + // Renew the timer. + duration, err := time.ParseDuration("500ms") + if err != nil { + panic(err) + } + oev2 := lib.OutEvent{ + To: lib.Singleton("scheduler"), + Args: &lib.Timer{ + Duration: duration, + }, + } + oevs = append(oevs, oev2) } - oevs = append(oevs, oev2) return oevs } @@ -174,12 +200,26 @@ func (n *Node) Init() []lib.OutEvent { if err != nil { panic(err) } - oev := lib.OutEvent{ - To: lib.Singleton("scheduler"), - Args: &lib.Timer{ - Duration: duration, - }, + if n.Round == ClassicDeliv { + // Only set the timer on node A, otherwise we won't find the + // counterexample with EFF = 3. + if n.Log == "Hello world!" { + oev := lib.OutEvent{ + To: lib.Singleton("scheduler"), + Args: &lib.Timer{ + Duration: duration, + }, + } + oevs = append(oevs, oev) + } + } else { + oev := lib.OutEvent{ + To: lib.Singleton("scheduler"), + Args: &lib.Timer{ + Duration: duration, + }, + } + oevs = append(oevs, oev) } - oevs = append(oevs, oev) return oevs } diff --git a/src/sut/broadcast/broadcast_test.go b/src/sut/broadcast/broadcast_test.go index 24064dbd..3cbf0a42 100644 --- a/src/sut/broadcast/broadcast_test.go +++ b/src/sut/broadcast/broadcast_test.go @@ -43,7 +43,12 @@ func many(round Round, t *testing.T) { var faults []lib.Fault failSpec := lib.FailSpec{ - EFF: 5, + // NOTE: EFF is set to 2 in the paper. There's a mismatch here, + // because in the paper two nodes can send messages at the same + // time, we can't. And we also got timers which increase the + // logical clock, which means we sometimes need a higher EFF in + // order to find the problem. + EFF: 3, Crashes: 1, EOT: 10, }