mirror of
https://github.com/logos-storage/nim-mysticeti.git
synced 2026-01-02 13:43:09 +00:00
combine generic types for signing and hashing
This commit is contained in:
parent
fcf32043a1
commit
c600c5a2ef
@ -1,3 +1,7 @@
|
||||
import ./mysticeti/dependencies
|
||||
|
||||
export dependencies.Dependencies
|
||||
|
||||
import ./mysticeti/validator
|
||||
|
||||
export validator.Validator
|
||||
|
||||
@ -7,3 +7,7 @@ import pkg/questionable/results
|
||||
|
||||
export questionable
|
||||
export results
|
||||
|
||||
import ./dependencies
|
||||
|
||||
export dependencies
|
||||
|
||||
@ -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)
|
||||
)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
1
mysticeti/dependencies.nim
Normal file
1
mysticeti/dependencies.nim
Normal file
@ -0,0 +1 @@
|
||||
type Dependencies*[Signing, Hashing] = object
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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] =
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
import mysticeti/dependencies
|
||||
import ./mocks/signing
|
||||
import ./mocks/hashing
|
||||
|
||||
export signing
|
||||
export hashing
|
||||
|
||||
type MockDependencies* = Dependencies[MockSigning, MockHashing]
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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":
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user