combine generic types for signing and hashing

This commit is contained in:
Mark Spanbroek 2024-11-06 13:45:37 +01:00
parent fcf32043a1
commit c600c5a2ef
24 changed files with 117 additions and 96 deletions

View File

@ -1,3 +1,7 @@
import ./mysticeti/dependencies
export dependencies.Dependencies
import ./mysticeti/validator
export validator.Validator

View File

@ -7,3 +7,7 @@ import pkg/questionable/results
export questionable
export results
import ./dependencies
export dependencies

View File

@ -4,20 +4,20 @@ import ./blockid
import ./transaction
type
Block*[Hashing] = object
Block*[Dependencies] = object
author: CommitteeMember
round: uint64
parents: seq[BlockId[Hashing]]
parents: seq[BlockId[Dependencies]]
transactions: seq[Transaction]
func new*[Hashing](
_: type Block[Hashing];
func new*[Dependencies](
_: type Block[Dependencies];
author: CommitteeMember,
round: uint64,
parents: seq[BlockId[Hashing]],
parents: seq[BlockId[Dependencies]],
transactions: seq[Transaction]
): auto =
Block[Hashing](
Block[Dependencies](
author: author,
round: round,
parents: parents,
@ -40,8 +40,8 @@ func toBytes*(blck: Block): seq[byte] =
cast[seq[byte]]($blck) # TODO: proper serialization
func id*(blck: Block): auto =
BlockId.new(
BlockId[Block.Dependencies].new(
blck.author,
blck.round,
Block.Hashing.hash(blck.toBytes)
Hash[Block.Dependencies].hash(blck.toBytes)
)

View File

@ -1,18 +1,18 @@
import ../committee
import ../hashing
type BlockId*[Hashing] = object
type BlockId*[Dependencies] = object
author: CommitteeMember
round: uint64
hash: Hash[Hashing]
hash: Hash[Dependencies]
func new*(
_: type BlockId,
T: type BlockId,
author: CommitteeMember,
round: uint64,
hash: Hash
): auto =
BlockId[Hash.Hashing](
T(
author: author,
round: round,
hash: hash

View File

@ -1,12 +1,13 @@
import ../basics
import ../signing
import ./blck
type SignedBlock*[Signing, Hashing] = object
blck: Block[Hashing]
signature: Signature[Signing]
type SignedBlock*[Dependencies] = object
blck: Block[Dependencies]
signature: Signature[Dependencies]
func new*(_: type SignedBlock, blck: Block, signature: Signature): auto =
SignedBlock[Signature.Signing, Block.Hashing](blck: blck, signature: signature)
SignedBlock[Block.Dependencies](blck: blck, signature: signature)
func blck*(signed: SignedBlock): auto =
signed.blck

View File

@ -3,13 +3,13 @@ import ../signing
import ./members
type
Committee*[Signing] = ref object
members: seq[Identifier[Signing]]
Committee*[Dependencies] = ref object
members: seq[Identifier[Dependencies]]
stakes: seq[Stake]
Stake* = float64
func new*(_: type Committee, stakes: openArray[(Identifier, Stake)]): auto =
var committee = Committee[Identifier.Signing]()
func new*(T: type Committee, stakes: openArray[(Identifier, Stake)]): auto =
var committee = T()
for (member, stake) in stakes:
committee.members.add(member)
committee.stakes.add(stake)

View File

@ -0,0 +1 @@
type Dependencies*[Signing, Hashing] = object

View File

@ -1,11 +1,11 @@
type
Hash*[Hashing] = object
value: Hashing.Hash
Hash*[Dependencies] = object
value: Dependencies.Hashing.Hash
Hashing*[Hash] = object
func hash*(T: type Hashing, bytes: openArray[byte]): auto =
func hash*(T: type Hash, bytes: openArray[byte]): auto =
mixin hash
Hash[T](value: T.Hash.hash(bytes))
T(value: T.Dependencies.Hashing.Hash.hash(bytes))
func `$`*(hash: Hash): string =
$hash.value

View File

@ -1,27 +1,27 @@
type
Identity*[Signing] = object
value: Signing.Identity
Identifier*[Signing] = object
value: Signing.Identifier
Signature*[Signing] = object
value: Signing.Signature
Identity*[Dependencies] = object
value: Dependencies.Signing.Identity
Identifier*[Dependencies] = object
value: Dependencies.Signing.Identifier
Signature*[Dependencies] = object
value: Dependencies.Signing.Signature
Signing*[Identity, Identifier, Signature] = object
proc init*[Signing](_: type Identity[Signing]): Identity[Signing] =
proc init*(T: type Identity): T =
mixin init
Identity[Signing](value: Signing.Identity.init())
T(value: T.Dependencies.Signing.Identity.init())
func identifier*(identity: Identity): auto =
mixin identifier
Identifier[Identity.Signing](value: identity.value.identifier)
Identifier[Identity.Dependencies](value: identity.value.identifier)
func sign*(identity: Identity, bytes: openArray[byte]): auto =
mixin sign
Signature[Identity.Signing](value: identity.value.sign(bytes))
Signature[Identity.Dependencies](value: identity.value.sign(bytes))
func signer*(signature: Signature, bytes: openArray[byte]): auto =
mixin signer
Identifier[Signature.Signing](value: signature.value.signer(bytes))
Identifier[Signature.Dependencies](value: signature.value.signer(bytes))
func `$`*(identity: Identity): string =
$identity.value

View File

@ -9,11 +9,11 @@ import ./validator/checks
export slots
export checks
type Validator*[Signing, Hashing] = ref object
identity: Identity[Signing]
committee: Committee[Signing]
type Validator*[Dependencies] = ref object
identity: Identity[Dependencies]
committee: Committee[Dependencies]
membership: CommitteeMember
rounds: Rounds[Signing, Hashing]
rounds: Rounds[Dependencies]
func new*(T: type Validator; identity: Identity, committee: Committee): ?!T =
without membership =? committee.membership(identity.identifier):
@ -22,7 +22,7 @@ func new*(T: type Validator; identity: Identity, committee: Committee): ?!T =
identity: identity,
committee: committee,
membership: membership,
rounds: Rounds[T.Signing, T.Hashing].init(committee.size)
rounds: Rounds[T.Dependencies].init(committee.size)
)
func identifier*(validator: Validator): auto =
@ -77,11 +77,12 @@ func addBlock(validator: Validator, signedBlock: SignedBlock) =
validator.updateCertified(signedBlock.blck)
proc propose*(validator: Validator, transactions: seq[Transaction]): auto =
type SignedBlock = blocks.SignedBlock[Validator.Signing, Validator.Hashing]
type Block = blocks.Block[Validator.Dependencies]
type SignedBlock = blocks.SignedBlock[Validator.Dependencies]
let round = validator.rounds.latest
if round[validator.membership].proposals.len > 0:
return SignedBlock.failure "already proposed this round"
var parents: seq[BlockId[Validator.Hashing]]
var parents: seq[BlockId[Validator.Dependencies]]
var parentStake: Stake
if previous =? round.previous:
for slot in previous.slots:
@ -103,8 +104,8 @@ proc propose*(validator: Validator, transactions: seq[Transaction]): auto =
success signedBlock
func check*(validator: Validator, signed: SignedBlock): auto =
type BlockCheck = checks.BlockCheck[SignedBlock.Signing, SignedBlock.Hashing]
type BlockId = blocks.BlockId[SignedBlock.Hashing]
type BlockCheck = checks.BlockCheck[SignedBlock.Dependencies]
type BlockId = blocks.BlockId[SignedBlock.Dependencies]
without member =? validator.committee.membership(signed.signer):
return BlockCheck.invalid("block is not signed by a committee member")
if member != signed.blck.author:

View File

@ -1,3 +1,4 @@
import ../basics
import ../blocks
type
@ -5,15 +6,15 @@ type
invalid
incomplete
correct
BlockCheck*[Signing, Hashing] = object
BlockCheck*[Dependencies] = object
case verdict: BlockVerdict
of invalid:
reason: string
of incomplete:
missing: seq[BlockId[Hashing]]
missing: seq[BlockId[Dependencies]]
of correct:
blck: CorrectBlock[Signing, Hashing]
CorrectBlock*[Signing, Hashing] = distinct SignedBlock[Signing, Hashing]
blck: CorrectBlock[Dependencies]
CorrectBlock*[Dependencies] = distinct SignedBlock[Dependencies]
func invalid*(T: type BlockCheck, reason: string): T =
T(verdict: BlockVerdict.invalid, reason: reason)
@ -22,7 +23,7 @@ func incomplete*(T: type BlockCheck; missing: seq[BlockId]): T =
T(verdict: BlockVerdict.incomplete, missing: missing)
func correct*(T: type BlockCheck, signedBlock: SignedBlock): T =
let blck = CorrectBlock[SignedBlock.Signing, SignedBlock.Hashing](signedBlock)
let blck = CorrectBlock[SignedBlock.Dependencies](signedBlock)
T(verdict: BlockVerdict.correct, blck: blck)
func verdict*(check: BlockCheck): BlockVerdict =
@ -38,7 +39,7 @@ func blck*(check: BlockCheck): auto =
check.blck
func signedBlock*(correct: CorrectBlock): auto =
SignedBlock[CorrectBlock.Signing, CorrectBlock.Hashing](correct)
SignedBlock[CorrectBlock.Dependencies](correct)
func blck*(correct: CorrectBlock): auto =
correct.signedBlock.blck

View File

@ -3,14 +3,14 @@ import ../blocks
import ../committee
import ./slots
type Round*[Signing, Hashing] = ref object
type Round*[Dependencies] = ref object
number: uint64
previous, next: ?Round[Signing, Hashing]
slots: seq[ProposerSlot[Signing, Hashing]]
previous, next: ?Round[Dependencies]
slots: seq[ProposerSlot[Dependencies]]
func new*(T: type Round, number: uint64, slots: int): T =
assert slots > 0
type Slot = ProposerSlot[T.Signing, T.Hashing]
type Slot = ProposerSlot[T.Dependencies]
let slots = newSeqWith(slots, Slot.new())
T(number: number, slots: slots)

View File

@ -3,11 +3,11 @@ import ./round
export round
type Rounds*[Signing, Hashing] = object
oldest, latest: Round[Signing, Hashing]
type Rounds*[Dependencies] = object
oldest, latest: Round[Dependencies]
func init*(T: type Rounds, slots: int, start: uint64 = 0): T =
let round = Round[T.Signing, T.Hashing].new(start, slots)
let round = Round[T.Dependencies].new(start, slots)
T(oldest: round, latest: round)
func oldest*(rounds: Rounds): auto =
@ -17,7 +17,7 @@ func latest*(rounds: Rounds): auto =
rounds.latest
func addNewRound*(rounds: var Rounds) =
rounds.latest = Round[Rounds.Signing, Rounds.Hashing].new(rounds.latest)
rounds.latest = Round[Rounds.Dependencies].new(rounds.latest)
func removeOldestRound*(rounds: var Rounds) =
assert rounds.oldest.next.isSome

View File

@ -3,15 +3,15 @@ import ../blocks
import ../committee
type
ProposerSlot*[Signing, Hashing] = ref object
proposals: seq[Proposal[Signing, Hashing]]
ProposerSlot*[Dependencies] = ref object
proposals: seq[Proposal[Dependencies]]
skippedBy: Voting
status: SlotStatus
Proposal*[Signing, Hashing] = ref object
slot: ProposerSlot[Signing, Hashing]
signedBlock: SignedBlock[Signing, Hashing]
Proposal*[Dependencies] = ref object
slot: ProposerSlot[Dependencies]
signedBlock: SignedBlock[Dependencies]
certifiedBy: Voting
certificates: seq[BlockId[Hashing]]
certificates: seq[BlockId[Dependencies]]
SlotStatus* {.pure.} = enum
undecided
skip
@ -40,7 +40,7 @@ func certificates*(proposal: Proposal): auto =
proposal.certificates
func addProposal*(slot: ProposerSlot, signedBlock: SignedBlock) =
let proposal = Proposal[SignedBlock.Signing, SignedBlock.Hashing](
let proposal = Proposal[ProposerSlot.Dependencies](
slot: slot,
signedBlock: signedBlock
)

View File

@ -1,10 +1,12 @@
import ../basics
import mysticeti
import mysticeti/committee
import mysticeti/signing
suite "Committee":
type Identifier = signing.Identifier[MockSigning]
type Identifier = signing.Identifier[MockDependencies]
type Committee = committee.Committee[MockDependencies]
test "committee has numbered members":
let identifiers = array[4, Identifier].example

View File

@ -14,26 +14,26 @@ proc example*(T: type Identity): T =
T.init()
proc example*(T: type Identifier): T =
Identity[T.Signing].example.identifier
Identity[T.Dependencies].example.identifier
proc example*(T: type CommitteeMember): T =
CommitteeMember(int.example)
proc example*(T: type Hash): T =
T.Hashing.hash(seq[byte].example)
T.hash(seq[byte].example)
proc example*(T: type BlockId): T =
let author = CommitteeMember.example
let round = uint64.example
let hash = Hash[T.Hashing].example
BlockId.new(author, round, hash)
let hash = Hash[T.Dependencies].example
T.new(author, round, hash)
proc example*(
T: type Block,
author = CommitteeMember.example,
round = uint64.example
): T =
let parents = seq[BlockId[T.Hashing]].example
let parents = seq[BlockId[T.Dependencies]].example
let transactions = seq[Transaction].example
T.new(author, round, parents, transactions)
@ -42,8 +42,8 @@ proc example*(
author = CommitteeMember.example,
round = uint64.example
): T =
let identity = Identity[T.Signing].example
let blck = Block[T.Hashing].example(author = author, round = round)
let identity = Identity[T.Dependencies].example
let blck = Block[T.Dependencies].example(author = author, round = round)
identity.sign(blck)
proc example*[T](_: type seq[T], length=0..10): seq[T] =

View File

@ -1,5 +1,8 @@
import mysticeti/dependencies
import ./mocks/signing
import ./mocks/hashing
export signing
export hashing
type MockDependencies* = Dependencies[MockSigning, MockHashing]

View File

@ -2,9 +2,10 @@ import ./basics
import mysticeti
import mysticeti/blocks
type Validator* = mysticeti.Validator[MockSigning, MockHashing]
type Identity* = mysticeti.Identity[MockSigning]
type SignedBlock* = blocks.SignedBlock[MockSigning, MockHashing]
type Validator* = mysticeti.Validator[MockDependencies]
type Committee* = mysticeti.Committee[MockDependencies]
type Identity* = mysticeti.Identity[MockDependencies]
type SignedBlock* = blocks.SignedBlock[MockDependencies]
type NetworkSimulator* = object
identities: seq[Identity]

View File

@ -5,9 +5,10 @@ import mysticeti/hashing
suite "Blocks":
type Block = mysticeti.Block[MockHashing]
type BlockId = mysticeti.BlockId[MockHashing]
type Identity = mysticeti.Identity[MockSigning]
type Block = mysticeti.Block[MockDependencies]
type BlockId = mysticeti.BlockId[MockDependencies]
type Identity = mysticeti.Identity[MockDependencies]
type Hash = hashing.Hash[MockDependencies]
test "blocks have an author, a round, parents and transactions":
let author = CommitteeMember.example
@ -25,7 +26,7 @@ suite "Blocks":
let id = blck.id
check id.author == blck.author
check id.round == blck.round
check id.hash == Block.Hashing.hash(blck.toBytes)
check id.hash == Hash.hash(blck.toBytes)
test "blocks can be signed":
let signer = Identity.init

View File

@ -6,9 +6,9 @@ import mysticeti/validator/round
suite "Validator Round":
type Round = round.Round[MockSigning, MockHashing]
type Block = mysticeti.Block[MockHashing]
type SignedBlock = mysticeti.SignedBlock[MockSigning, MockHashing]
type Round = round.Round[MockDependencies]
type Block = mysticeti.Block[MockDependencies]
type SignedBlock = mysticeti.SignedBlock[MockDependencies]
test "rounds have a number":
check Round.new(0, 1).number == 0

View File

@ -3,8 +3,8 @@ import mysticeti/validator/rounds
suite "List of Validator Rounds":
type Rounds = rounds.Rounds[MockSigning, MockHashing]
type Round = rounds.Round[MockSigning, MockHashing]
type Rounds = rounds.Rounds[MockDependencies]
type Round = rounds.Round[MockDependencies]
test "has a single round initially":
let rounds = Rounds.init(slots = 4)

View File

@ -4,10 +4,10 @@ import mysticeti/validator/slots
suite "Proposer Slots":
type BlockId = mysticeti.BlockId[MockHashing]
type SignedBlock = mysticeti.SignedBlock[MockSigning, MockHashing]
type Proposal = slots.Proposal[MockSigning, MockHashing]
type ProposerSlot = slots.ProposerSlot[MockSigning, MockHashing]
type BlockId = mysticeti.BlockId[MockDependencies]
type SignedBlock = mysticeti.SignedBlock[MockDependencies]
type Proposal = slots.Proposal[MockDependencies]
type ProposerSlot = slots.ProposerSlot[MockDependencies]
var slot: ProposerSlot

View File

@ -1,8 +1,9 @@
import ../basics
import mysticeti
type Validator = mysticeti.Validator[MockSigning, MockHashing]
type Identity = mysticeti.Identity[MockSigning]
type Validator = mysticeti.Validator[MockDependencies]
type Identity = mysticeti.Identity[MockDependencies]
type Committee = mysticeti.Committee[MockDependencies]
suite "Validator":

View File

@ -7,11 +7,12 @@ import mysticeti/hashing
suite "Validator Network":
type Validator = mysticeti.Validator[MockSigning, MockHashing]
type Identity = mysticeti.Identity[MockSigning]
type Block = blocks.Block[MockHashing]
type BlockId = blocks.BlockId[MockHashing]
type Hash = hashing.Hash[MockHashing]
type Validator = mysticeti.Validator[MockDependencies]
type Committee = mysticeti.Committee[MockDependencies]
type Identity = mysticeti.Identity[MockDependencies]
type Block = blocks.Block[MockDependencies]
type BlockId = blocks.BlockId[MockDependencies]
type Hash = hashing.Hash[MockDependencies]
var simulator: NetworkSimulator