diff --git a/mysticeti.nim b/mysticeti.nim index baf92ef..1063214 100644 --- a/mysticeti.nim +++ b/mysticeti.nim @@ -9,6 +9,7 @@ export validator.nextRound export validator.propose export validator.receive export validator.status +export validator.committed import ./mysticeti/committee diff --git a/mysticeti/validator.nim b/mysticeti/validator.nim index 50c2f89..17202f2 100644 --- a/mysticeti/validator.nim +++ b/mysticeti/validator.nim @@ -17,10 +17,11 @@ type skippedBy: Stake certifiedBy: Stake status: ProposalStatus - ProposalStatus* = enum + ProposalStatus* {.pure.} = enum undecided - toSkip - toCommit + skip + commit + committed func new*(T: type Validator; identity: Identity, committee: Committee): T = let round = Round[T.Signing, T.Hashing](number: 0) @@ -65,7 +66,7 @@ func updateSkipped(validator: Validator, supporter: Block) = if not supporter.hasParent(previous.number, id): slot.skippedBy += validator.committee.stake(supporter.author) if slot.skippedBy > 2/3: - slot.status = ProposalStatus.toSkip + slot.status = ProposalStatus.skip func updateCertified(validator: Validator, certificate: Block) = without (proposing, voting, _) =? validator.wave: @@ -79,7 +80,7 @@ func updateCertified(validator: Validator, certificate: Block) = if support > 2/3: proposerSlot.certifiedBy += validator.committee.stake(certificate.author) if proposerSlot.certifiedBy > 2/3: - proposerSlot.status = ProposalStatus.toCommit + proposerSlot.status = ProposalStatus.commit proc propose*(validator: Validator, transactions: seq[Transaction]): auto = assert validator.identifier notin validator.last.slots @@ -118,3 +119,19 @@ func status*(validator: Validator, blck: Block): ?ProposalStatus = func status*(validator: Validator, proposal: SignedBlock): ?ProposalStatus = validator.status(proposal.blck) + +iterator committed*(validator: Validator): auto = + var done = false + var current = some validator.first + while not done and round =? current: + for slot in round.slots.mvalues: + case slot.status + of ProposalStatus.undecided: + done = true + break + of ProposalStatus.skip, ProposalStatus.committed: + discard + of ProposalStatus.commit: + slot.status = ProposalStatus.committed + yield slot.proposal + current = round.next diff --git a/tests/mysticeti/testCommittee.nim b/tests/mysticeti/testCommittee.nim index 76334df..845e65c 100644 --- a/tests/mysticeti/testCommittee.nim +++ b/tests/mysticeti/testCommittee.nim @@ -51,7 +51,7 @@ suite "Commitee of Validators": validators[0].receive(validators[2].propose(seq[Transaction].example)) check validators[0].status(proposal) == some ProposalStatus.undecided validators[0].receive(validators[3].propose(seq[Transaction].example)) - check validators[0].status(proposal) == some ProposalStatus.toSkip + check validators[0].status(proposal) == some ProposalStatus.skip test "commits blocks that have >2f certificates": # First round: proposing @@ -65,4 +65,24 @@ suite "Commitee of Validators": validators[0].receive(validators[1].propose(seq[Transaction].example)) check validators[0].status(proposals[0]) == some ProposalStatus.undecided validators[0].receive(validators[2].propose(seq[Transaction].example)) - check validators[0].status(proposals[0]) == some ProposalStatus.toCommit + check validators[0].status(proposals[0]) == some ProposalStatus.commit + + test "can iterate over the list of committed blocks": + let first = exchangeProposals().mapIt(it.blck) + nextRound() + let second = exchangeProposals().mapIt(it.blck) + nextRound() + discard exchangeProposals() + + let committedFirst = toSeq(validators[0].committed()) + check committedFirst.len == first.len + for blck in first: + check blck in committedFirst + + nextRound() + discard exchangeProposals() + + let committedSecond = toSeq(validators[0].committed()) + check committedSecond.len == second.len + for blck in second: + check blck in committedSecond