Skip to content

Commit

Permalink
hare3: simplify code by removing active boolean (#5197)
Browse files Browse the repository at this point in the history
even passive node will generate message but will not send it.
this is also better for debug, as anyone can see what is going on without setting up smesher.
and i will use it in a follow up to extend that message with additional stats, such as voting tallies
  • Loading branch information
dshulyak committed Oct 30, 2023
1 parent 61cf5b7 commit b629c68
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 72 deletions.
8 changes: 3 additions & 5 deletions hare3/hare.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ func (h *Hare) run(session *session) error {

walltime := h.nodeclock.LayerToTime(session.lid).Add(h.config.PreroundDelay)
if active {
h.log.Debug("active in preround", zap.Uint32("lid", session.lid.Uint32()))
h.log.Debug("active in preround. waiting for preround delay", zap.Uint32("lid", session.lid.Uint32()))
// initial set is not needed if node is not active in preround
select {
case <-h.wallclock.After(walltime.Sub(h.wallclock.Now())):
Expand All @@ -400,13 +400,12 @@ func (h *Hare) run(session *session) error {
session.proto.OnInitial(h.proposals(session))
proposalsLatency.Observe(time.Since(start).Seconds())
}
if err := h.onOutput(session, current, session.proto.Next(active)); err != nil {
if err := h.onOutput(session, current, session.proto.Next()); err != nil {
return err
}
result := false
for {
walltime = walltime.Add(h.config.RoundDuration)
active = false
current = session.proto.IterRound
start = time.Now()

Expand All @@ -416,7 +415,6 @@ func (h *Hare) run(session *session) error {
} else {
session.vrfs[i] = nil
}
active = active || session.vrfs[i] != nil
}
h.tracer.OnActive(session.vrfs)
activeLatency.Observe(time.Since(start).Seconds())
Expand All @@ -428,7 +426,7 @@ func (h *Hare) run(session *session) error {
zap.Uint8("iter", session.proto.Iter), zap.Stringer("round", session.proto.Round),
zap.Bool("active", active),
)
out := session.proto.Next(active)
out := session.proto.Next()
if out.result != nil {
result = true
}
Expand Down
135 changes: 69 additions & 66 deletions hare3/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,46 +147,51 @@ func (p *protocol) commitExists(iter uint8, match types.Hash32) bool {
return false
}

func (p *protocol) execution(out *output, active bool) {
func (p *protocol) execution(out *output) {
// 4.3 Protocol Execution
if p.Iter == 0 && p.Round >= softlock && p.Round <= wait2 {
// -1 - skipped hardlock round in iter 0
// -1 - implementation rounds starts from 0
g := grade5 - grade(p.Round-2)
p.validValues[g] = p.gossip.thresholdGossip(IterRound{Round: preround})
}
if p.Round == preround && active {
switch p.Round {
case preround:
out.message = &Message{Body: Body{
IterRound: p.IterRound,
Value: Value{Proposals: p.initial},
}}
} else if p.Round == hardlock && p.Iter > 0 {
if p.result != nil {
out.terminated = true
}
ref, values := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: notify})
if ref != nil && p.result == nil {
p.result = ref
out.result = values
if values == nil {
// receiver expects non-nil result
out.result = []types.ProposalID{}
case hardlock:
if p.Iter > 0 {
if p.result != nil {
out.terminated = true
}
ref, values := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: notify})
if ref != nil && p.result == nil {
p.result = ref
out.result = values
if values == nil {
// receiver expects non-nil result
out.result = []types.ProposalID{}
}
}
if ref, _ := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: commit}); ref != nil {
p.locked = ref
p.hardLocked = true
} else {
p.locked = nil
p.hardLocked = false
}
}
if ref, _ := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: commit}); ref != nil {
p.locked = ref
p.hardLocked = true
} else {
p.locked = nil
p.hardLocked = false
}
} else if p.Round == softlock && p.Iter > 0 && !p.hardLocked {
if ref, _ := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: commit}); ref != nil {
p.locked = ref
} else {
p.locked = nil
case softlock:
if p.Iter > 0 && !p.hardLocked {
if ref, _ := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: commit}); ref != nil {
p.locked = ref
} else {
p.locked = nil
}
}
} else if p.Round == propose && active {
case propose:
values := p.validValues[grade4]
if p.Iter > 0 {
ref, overwrite := p.thresholdProposals(IterRound{Iter: p.Iter - 1, Round: commit})
Expand All @@ -198,7 +203,7 @@ func (p *protocol) execution(out *output, active bool) {
IterRound: p.IterRound,
Value: Value{Proposals: values},
}}
} else if p.Round == commit {
case commit:
// condition (d) is realized by ordering proposals by vrf
proposed := p.gossip.gradecast(IterRound{Iter: p.Iter, Round: propose})
for _, graded := range proposed {
Expand All @@ -208,46 +213,44 @@ func (p *protocol) execution(out *output, active bool) {
}
p.validProposals[toHash(graded.values)] = graded.values
}
if active {
var ref *types.Hash32
if p.hardLocked && p.locked != nil {
ref = p.locked
} else {
for _, graded := range proposed {
id := toHash(graded.values)
// condition (c)
if _, exist := p.validProposals[id]; !exist {
continue
}
// condition (e)
if graded.grade != grade2 {
continue
}
// condition (f)
if !isSubset(graded.values, p.validValues[grade3]) {
continue
}
// condition (g)
if !isSubset(p.validValues[grade5], graded.values) &&
!p.commitExists(p.Iter-1, id) {
continue
}
// condition (h)
if p.locked != nil && *p.locked != id {
continue
}
ref = &id
break
var ref *types.Hash32
if p.hardLocked && p.locked != nil {
ref = p.locked
} else {
for _, graded := range proposed {
id := toHash(graded.values)
// condition (c)
if _, exist := p.validProposals[id]; !exist {
continue
}
// condition (e)
if graded.grade != grade2 {
continue
}
// condition (f)
if !isSubset(graded.values, p.validValues[grade3]) {
continue
}
// condition (g)
if !isSubset(p.validValues[grade5], graded.values) &&
!p.commitExists(p.Iter-1, id) {
continue
}
// condition (h)
if p.locked != nil && *p.locked != id {
continue
}
ref = &id
break
}
if ref != nil {
out.message = &Message{Body: Body{
IterRound: p.IterRound,
Value: Value{Reference: ref},
}}
}
}
} else if p.Round == notify && active {
if ref != nil {
out.message = &Message{Body: Body{
IterRound: p.IterRound,
Value: Value{Reference: ref},
}}
}
case notify:
ref := p.result
if ref == nil {
ref, _ = p.thresholdProposals(IterRound{Iter: p.Iter, Round: commit})
Expand All @@ -261,12 +264,12 @@ func (p *protocol) execution(out *output, active bool) {
}
}

func (p *protocol) Next(active bool) output {
func (p *protocol) Next() output {
p.mu.Lock()
defer p.mu.Unlock()

out := output{}
p.execution(&out, active)
p.execution(&out)
if p.Round >= softlock && p.coin != nil && !p.coinout {
coin := p.coin.LSB() != 0
out.coin = &coin
Expand Down
5 changes: 4 additions & 1 deletion hare3/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,10 @@ func TestProtocol(t *testing.T) {
}
case *toutput:
before := proto.Round
require.Equal(t, casted.output, proto.Next(casted.act), "%d", i)
out := proto.Next()
if casted.act {
require.Equal(t, casted.output, out, "%d", i)
}
logger.Debug("output",
zap.Int("i", i),
zap.Inline(casted),
Expand Down

0 comments on commit b629c68

Please sign in to comment.