diff --git a/mysticeti.nim b/mysticeti.nim index 3316787..f5f5711 100644 --- a/mysticeti.nim +++ b/mysticeti.nim @@ -1,6 +1,7 @@ import ./mysticeti/validator export validator.Validator +export validator.Committee export validator.ProposalStatus export validator.new export validator.identifier @@ -24,6 +25,9 @@ export blocks.signer import ./mysticeti/signing +export signing.Identity +export signing.init +export signing.identifier export signing.`$` import ./mysticeti/hashing diff --git a/mysticeti/validator.nim b/mysticeti/validator.nim index 30ab071..c697030 100644 --- a/mysticeti/validator.nim +++ b/mysticeti/validator.nim @@ -6,7 +6,11 @@ import ./blocks type Validator*[Signing, Hashing] = ref object identity: Identity[Signing] + committee: Committee[Signing] round: Round[Signing, Hashing] + Committee*[Signing] = ref object + stakes: Table[Identifier[Signing], Stake] + Stake = float64 Round[Signing, Hashing] = ref object number: uint64 previous: ?Round[Signing, Hashing] @@ -19,10 +23,12 @@ type toSkip toCommit -proc new*(T: type Validator): T = - let identity = Identity[T.Signing].init() +func new*(T: type Validator; identity: Identity, committee: Committee): T = let round = Round[T.Signing, T.Hashing](number: 0) - T(identity: identity, round: round) + T(identity: identity, committee: committee, round: round) + +func new*(_: type Committee, stakes: openArray[(Identifier, Stake)]): auto = + Committee[Identifier.Signing](stakes: stakes.toTable) func new*(_: type Round, number: uint64, previous: Round): auto = Round(number: number, previous: some previous) diff --git a/tests/testValidator.nim b/tests/testValidator.nim index fe3be78..e718d38 100644 --- a/tests/testValidator.nim +++ b/tests/testValidator.nim @@ -7,55 +7,64 @@ import ./mocks suite "Validator": type Validator = mysticeti.Validator[MockSigning, MockHashing] + type Identity = mysticeti.Identity[MockSigning] - var validator: Validator - var validator2, validator3: Validator + var validator1, validator2, validator3, validator4: Validator setup: - validator = Validator.new() - validator2 = Validator.new() - validator3 = Validator.new() + let identity1, identity2, identity3, identity4 = Identity.init() + let committee = Committee.new({ + identity1.identifier: 1/4, + identity2.identifier: 1/4, + identity3.identifier: 1/4, + identity4.identifier: 1/4 + }) + validator1 = Validator.new(identity1, committee) + validator2 = Validator.new(identity2, committee) + validator3 = Validator.new(identity3, committee) + validator4 = Validator.new(identity4, committee) - test "has a unique identifier": - check Validator.new().identifier != Validator.new().identifier test "starts at round 0": - check validator.round == 0 + check validator1.round == 0 test "can move to next round": - validator.nextRound() - check validator.round == 1 - validator.nextRound() - validator.nextRound() - check validator.round == 3 + validator1.nextRound() + check validator1.round == 1 + validator1.nextRound() + validator1.nextRound() + check validator1.round == 3 test "validators sign their proposals": - let proposal = validator.propose(seq[Transaction].example) - check proposal.blck.author == validator.identifier - check proposal.signer == validator.identifier + let proposal = validator1.propose(seq[Transaction].example) + check proposal.blck.author == validator1.identifier + check proposal.signer == validator1.identifier test "validator cannot propose more than once in a round": - discard validator.propose(seq[Transaction].example) + discard validator1.propose(seq[Transaction].example) expect AssertionDefect: - discard validator.propose(seq[Transaction].example) + discard validator1.propose(seq[Transaction].example) test "by default our own proposals are undecided": - let proposal = validator.propose(seq[Transaction].example) - check validator.status(proposal) == some ProposalStatus.undecided + let proposal = validator1.propose(seq[Transaction].example) + check validator1.status(proposal) == some ProposalStatus.undecided test "by default received proposals are undecided": let proposal = validator2.propose(seq[Transaction].example) - validator.receive(proposal) - check validator.status(proposal) == some ProposalStatus.undecided + validator1.receive(proposal) + check validator1.status(proposal) == some ProposalStatus.undecided test "validator includes blocks from previous round as parents": - let proposal1 = validator.propose(seq[Transaction].example) + let proposal1 = validator1.propose(seq[Transaction].example) let proposal2 = validator2.propose(seq[Transaction].example) let proposal3 = validator3.propose(seq[Transaction].example) - validator.receive(proposal2) - validator.receive(proposal3) - validator.nextRound() - let proposal4 = validator.propose(seq[Transaction].example) - check proposal1.blck.blockHash in proposal4.blck.parents - check proposal2.blck.blockHash in proposal4.blck.parents - check proposal3.blck.blockHash in proposal4.blck.parents + let proposal4 = validator4.propose(seq[Transaction].example) + validator1.receive(proposal2) + validator1.receive(proposal3) + validator1.receive(proposal4) + validator1.nextRound() + let proposal5 = validator1.propose(seq[Transaction].example) + check proposal1.blck.blockHash in proposal5.blck.parents + check proposal2.blck.blockHash in proposal5.blck.parents + check proposal3.blck.blockHash in proposal5.blck.parents + check proposal4.blck.blockHash in proposal5.blck.parents