From 93bb47fa3fa4a81d166403ca0dbafcf4960730b5 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 20 Aug 2024 10:45:49 +0200 Subject: [PATCH] skeleton implementation of validator --- mysticeti.nim | 15 +++++++++ mysticeti/basics.nim | 9 ++++++ mysticeti/identity.nim | 20 ++++++++++++ mysticeti/transactions.nim | 31 +++++++++++++++++++ mysticeti/validator.nim | 63 ++++++++++++++++++++++++++++++++++++++ tests/examples.nim | 9 ++++++ tests/nim.cfg | 1 + tests/testValidator.nim | 18 +++++++++++ 8 files changed, 166 insertions(+) create mode 100644 mysticeti.nim create mode 100644 mysticeti/basics.nim create mode 100644 mysticeti/identity.nim create mode 100644 mysticeti/transactions.nim create mode 100644 mysticeti/validator.nim create mode 100644 tests/examples.nim create mode 100644 tests/nim.cfg create mode 100644 tests/testValidator.nim diff --git a/mysticeti.nim b/mysticeti.nim new file mode 100644 index 0000000..03056f3 --- /dev/null +++ b/mysticeti.nim @@ -0,0 +1,15 @@ +import ./mysticeti/validator + +export validator.Validator +export validator.ProposalStatus +export validator.new +export validator.nextRound +export validator.propose +export validator.receive +export validator.status + +import ./mysticeti/transactions + +export transactions.Transaction +export transactions.Block +export transactions.round diff --git a/mysticeti/basics.nim b/mysticeti/basics.nim new file mode 100644 index 0000000..1f88f57 --- /dev/null +++ b/mysticeti/basics.nim @@ -0,0 +1,9 @@ +import std/tables + +export tables + +import pkg/questionable +import pkg/questionable/results + +export questionable +export results diff --git a/mysticeti/identity.nim b/mysticeti/identity.nim new file mode 100644 index 0000000..cec336b --- /dev/null +++ b/mysticeti/identity.nim @@ -0,0 +1,20 @@ +type Identity* = object +type Identifier* = object + +func init*(_: type Identity): Identity = + Identity() + +func identifier*(identity: Identity): Identifier = + discard + +type Signed*[T] = object + value: T + +func sign*[T](identity: Identity, value: T): Signed[T] = + Signed[T](value: value) + +func value*[T](signed: Signed[T]): T = + signed.value + +func signatories*[T](signed: Signed[T]): seq[Identifier] = + discard diff --git a/mysticeti/transactions.nim b/mysticeti/transactions.nim new file mode 100644 index 0000000..a3c3199 --- /dev/null +++ b/mysticeti/transactions.nim @@ -0,0 +1,31 @@ +import ./identity + +type Transaction* = object + +type + Block* = object + author: Identifier + round: uint64 + parents: seq[BlockHash] + transactions: seq[Transaction] + BlockHash* = object + +func new*( + _: type Block, + author: Identifier, + round: uint64, + parents: seq[BlockHash], + transactions: seq[Transaction] +): Block = + Block( + author: author, + round: round, + parents: parents, + transactions: transactions + ) + +func author*(blck: Block): Identifier = + blck.author + +func round*(blck: Block): uint64 = + blck.round diff --git a/mysticeti/validator.nim b/mysticeti/validator.nim new file mode 100644 index 0000000..635c649 --- /dev/null +++ b/mysticeti/validator.nim @@ -0,0 +1,63 @@ +import ./basics +import ./identity +import ./transactions + +type + Validator* = ref object + identity: Identity + round: Round + Round = ref object + number: uint64 + previous: ?Round + proposals: Table[Identifier, seq[Proposal]] + Proposal = object + blck: Block + status: ProposalStatus + ProposalStatus* = enum + undecided + toSkip + toCommit + +func new*(_: type Validator): Validator = + Validator(identity: Identity.init(), round: Round(number: 0)) + +func identifier*(validator: Validator): Identifier = + validator.identity.identifier + +func nextRound*(validator: Validator) = + let previous = validator.round + validator.round = Round(number: previous.number + 1, previous: some previous) + +func propose*(validator: Validator, transactions: seq[Transaction]): Signed[Block] = + var parents: seq[BlockHash] + let blck = Block.new( + author = validator.identifier, + round = validator.round.number, + parents = parents, + transactions = transactions + ) + let proposal = Proposal(blck: blck) + validator.round.proposals[validator.identifier] = @[proposal] + validator.identity.sign(blck) + +func receive*(validator: Validator, proposal: Signed[Block]) = + discard + +func round(validator: Validator, number: uint64): ?Round = + var round = validator.round + while round.number > number and previous =? round.previous: + round = previous + if round.number == number: + some round + else: + none Round + +func status*(validator: Validator, blck: Block): ?ProposalStatus = + if round =? round(validator, blck.round) and blck.author in round.proposals: + let proposal = round.proposals[blck.author][0] + some proposal.status + else: + none ProposalStatus + +func status*(validator: Validator, proposal: Signed[Block]): ?ProposalStatus = + validator.status(proposal.value) diff --git a/tests/examples.nim b/tests/examples.nim new file mode 100644 index 0000000..63b679b --- /dev/null +++ b/tests/examples.nim @@ -0,0 +1,9 @@ +import std/random +import std/sequtils +import mysticeti + +proc example*(_: type Transaction): Transaction = + discard + +proc example*[T](_: type seq[T], length=0..10): seq[T] = + newSeqWith(rand(length), T.example) diff --git a/tests/nim.cfg b/tests/nim.cfg new file mode 100644 index 0000000..0f840a1 --- /dev/null +++ b/tests/nim.cfg @@ -0,0 +1 @@ +--path:".." diff --git a/tests/testValidator.nim b/tests/testValidator.nim new file mode 100644 index 0000000..4235eb0 --- /dev/null +++ b/tests/testValidator.nim @@ -0,0 +1,18 @@ +import std/unittest +import pkg/questionable +import mysticeti +import ./examples + +suite "Validator": + + var validator: Validator + var validator2, validator3: Validator + + setup: + validator = Validator.new() + validator2 = Validator.new() + validator3 = Validator.new() + + test "by default proposals are undecided": + let proposal = validator.propose(seq[Transaction].example) + check validator.status(proposal) == some ProposalStatus.undecided