mirror of
https://github.com/logos-storage/nim-mysticeti.git
synced 2026-01-02 13:43:09 +00:00
make Block a type dependency
This commit is contained in:
parent
aa4f390a1a
commit
de854cbb5f
@ -36,19 +36,8 @@ export committee.`$`
|
||||
|
||||
import ./mysticeti/blocks
|
||||
|
||||
export blocks.Block
|
||||
export blocks.BlockId
|
||||
export blocks.author
|
||||
export blocks.round
|
||||
export blocks.parents
|
||||
export blocks.id
|
||||
|
||||
import ./mysticeti/basics/immutableseq
|
||||
|
||||
export immutableseq
|
||||
|
||||
import ./mysticeti/blocks/signed
|
||||
|
||||
export signed.SignedBlock
|
||||
export signed.blck
|
||||
export signed.signer
|
||||
export blocks.new
|
||||
export blocks.SignedBlock
|
||||
export blocks.blck
|
||||
export blocks.signer
|
||||
|
||||
@ -11,7 +11,3 @@ export results
|
||||
import ./dependencies
|
||||
|
||||
export dependencies
|
||||
|
||||
import ./basics/immutableseq
|
||||
|
||||
export immutableseq
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
type ImmutableSeq*[Element] = ref object
|
||||
## Encapsulates a sequence, so that it no longer can be
|
||||
## modified, and can be passed by reference to avoid copying.
|
||||
elements: seq[Element]
|
||||
|
||||
func immutable*[Element](sequence: seq[Element]): ImmutableSeq[Element] =
|
||||
ImmutableSeq[Element](elements: sequence)
|
||||
|
||||
func copy*(sequence: ImmutableSeq): auto =
|
||||
sequence.elements
|
||||
|
||||
iterator items*(sequence: ImmutableSeq): auto =
|
||||
for element in sequence.elements:
|
||||
yield element
|
||||
|
||||
func len*(sequence: ImmutableSeq): int =
|
||||
sequence.elements.len
|
||||
|
||||
func `[]`*(sequence: ImmutableSeq, index: int): auto =
|
||||
sequence.elements[index]
|
||||
|
||||
func contains*[Element](sequence: ImmutableSeq[Element], element: Element): bool =
|
||||
sequence.elements.contains(element)
|
||||
|
||||
func `==`*(a, b: ImmutableSeq): bool =
|
||||
a.elements == b.elements
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import ./blocks/blck
|
||||
import ./blocks/blockid
|
||||
import ./blocks/signed
|
||||
|
||||
export blck
|
||||
export blockid
|
||||
export signed
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
import ../basics
|
||||
import ../committee
|
||||
import ./blockid
|
||||
|
||||
type
|
||||
Block*[Dependencies] = ref object
|
||||
author: CommitteeMember
|
||||
round: uint64
|
||||
parents: ImmutableSeq[BlockId[Dependencies.Hash]]
|
||||
transactions: ImmutableSeq[Dependencies.Transaction]
|
||||
id: ?BlockId[Dependencies.Hash]
|
||||
|
||||
func new*[Dependencies](
|
||||
_: type Block[Dependencies];
|
||||
author: CommitteeMember,
|
||||
round: uint64,
|
||||
parents: seq[BlockId[Dependencies.Hash]],
|
||||
transactions: seq[Dependencies.Transaction]
|
||||
): auto =
|
||||
Block[Dependencies](
|
||||
author: author,
|
||||
round: round,
|
||||
parents: parents.immutable,
|
||||
transactions: transactions.immutable
|
||||
)
|
||||
|
||||
func author*(blck: Block): auto =
|
||||
blck.author
|
||||
|
||||
func round*(blck: Block): uint64 =
|
||||
blck.round
|
||||
|
||||
func parents*(blck: Block): auto =
|
||||
blck.parents
|
||||
|
||||
func transactions*(blck: Block): auto =
|
||||
blck.transactions
|
||||
|
||||
func id*(blck: Block): auto =
|
||||
without var id =? blck.id:
|
||||
type Dependencies = Block.Dependencies
|
||||
mixin hash
|
||||
let blockBytes = Dependencies.Serialization.toBytes(blck)
|
||||
let blockHash = Dependencies.Hash.hash(blockBytes)
|
||||
id = BlockId.new(blck.author, blck.round, blockHash)
|
||||
blck.id = some id
|
||||
id
|
||||
@ -1,21 +1,21 @@
|
||||
import ../basics
|
||||
import ./blck
|
||||
import ./blockid
|
||||
|
||||
type SignedBlock*[Dependencies] = object
|
||||
blck: Block[Dependencies]
|
||||
blck: Dependencies.Block
|
||||
signature: Dependencies.Signature
|
||||
|
||||
func init*(
|
||||
_: type SignedBlock,
|
||||
blck: Block,
|
||||
signature: Block.Dependencies.Signature
|
||||
func init*[Dependencies](
|
||||
_: type SignedBlock[Dependencies];
|
||||
blck: Dependencies.Block,
|
||||
signature: Dependencies.Signature
|
||||
): auto =
|
||||
SignedBlock[Block.Dependencies](blck: blck, signature: signature)
|
||||
SignedBlock[Dependencies](blck: blck, signature: signature)
|
||||
|
||||
func blck*(signed: SignedBlock): auto =
|
||||
signed.blck
|
||||
|
||||
func signer*(signed: SignedBlock): auto =
|
||||
mixin signer
|
||||
mixin id
|
||||
signed.signature.signer(signed.blck.id.hash)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
type Dependencies*[
|
||||
Transaction,
|
||||
Serialization,
|
||||
Block,
|
||||
Hash,
|
||||
Identifier,
|
||||
Signature
|
||||
|
||||
@ -43,13 +43,12 @@ func primaryProposer*(validator: Validator): CommitteeMember =
|
||||
func nextRound*(validator: Validator) =
|
||||
validator.rounds.addNewRound()
|
||||
|
||||
func skips(blck: Block, round: uint64, author: CommitteeMember): bool =
|
||||
for parent in blck.parents:
|
||||
if parent.round == round and parent.author == author:
|
||||
return false
|
||||
true
|
||||
|
||||
func updateSkipped(validator: Validator, supporter: Block) =
|
||||
func updateSkipped(validator: Validator, supporter: Validator.Dependencies.Block) =
|
||||
func skips(blck: Validator.Dependencies.Block, round: uint64, author: CommitteeMember): bool =
|
||||
for parent in blck.parents:
|
||||
if parent.round == round and parent.author == author:
|
||||
return false
|
||||
true
|
||||
if round =? validator.rounds.latest.find(supporter.round) and
|
||||
previous =? round.previous:
|
||||
for proposer in previous.proposers:
|
||||
@ -59,7 +58,8 @@ func updateSkipped(validator: Validator, supporter: Block) =
|
||||
let stake = validator.committee.stake(author)
|
||||
slot.skipBy(author, stake)
|
||||
|
||||
func updateCertified(validator: Validator, certificate: Block) =
|
||||
func updateCertified(validator: Validator, certificate: Validator.Dependencies.Block) =
|
||||
mixin id
|
||||
without certifying =? validator.rounds.latest.find(certificate.round) and
|
||||
voting =? certifying.previous and
|
||||
proposing =? voting.previous:
|
||||
@ -83,6 +83,7 @@ func addBlock(validator: Validator, signedBlock: SignedBlock) =
|
||||
validator.updateCertified(signedBlock.blck)
|
||||
|
||||
func parentBlocks*(validator: Validator): auto =
|
||||
mixin id
|
||||
var parents: seq[BlockId[Validator.Dependencies.Hash]]
|
||||
if previous =? validator.rounds.latest.previous:
|
||||
for slot in previous.slots:
|
||||
@ -91,6 +92,7 @@ func parentBlocks*(validator: Validator): auto =
|
||||
parents
|
||||
|
||||
func check*(validator: Validator, signed: SignedBlock): auto =
|
||||
mixin id
|
||||
type BlockCheck = checks.BlockCheck[SignedBlock.Dependencies]
|
||||
type BlockId = blocks.BlockId[SignedBlock.Dependencies.Hash]
|
||||
without member =? validator.committee.membership(signed.signer):
|
||||
@ -141,7 +143,7 @@ func updateIndirect(validator: Validator, slot: ProposerSlot, round: Round) =
|
||||
return
|
||||
without anchorProposal =? anchor.proposal:
|
||||
return
|
||||
var todo = anchorProposal.blck.parents.copy
|
||||
var todo = anchorProposal.blck.parents
|
||||
while todo.len > 0:
|
||||
let parent = todo.pop()
|
||||
if parent.round < round.number + 2:
|
||||
@ -152,7 +154,7 @@ func updateIndirect(validator: Validator, slot: ProposerSlot, round: Round) =
|
||||
return
|
||||
without parentBlock =? round.find(parent):
|
||||
raiseAssert "parent block not found"
|
||||
todo.add(parentBlock.blck.parents.copy)
|
||||
todo.add(parentBlock.blck.parents)
|
||||
slot.skip()
|
||||
|
||||
iterator committed*(validator: Validator): auto =
|
||||
|
||||
@ -65,6 +65,7 @@ func find*(round: Round, number: uint64): ?Round =
|
||||
current = previous
|
||||
|
||||
func find*(round: Round, blockId: BlockId): auto =
|
||||
mixin id
|
||||
if found =? round.find(blockId.round):
|
||||
let slot = found[blockId.author]
|
||||
for proposal in slot.proposals:
|
||||
|
||||
@ -69,6 +69,7 @@ func certifyBy*(proposal: Proposal, certificate: BlockId, stake: Stake) =
|
||||
proposal.slot.status = SlotStatus.commit
|
||||
|
||||
func certify*(proposal, anchor: Proposal) =
|
||||
mixin id
|
||||
assert proposal.slot.status == SlotStatus.undecided
|
||||
assert anchor.slot.status == SlotStatus.commit
|
||||
assert anchor.certifiedBy.stake > 2/3
|
||||
|
||||
@ -16,24 +16,14 @@ proc example*(T: type BlockId): T =
|
||||
let hash = T.Hash.example
|
||||
BlockId.new(author, round, hash)
|
||||
|
||||
proc example*(
|
||||
T: type Block,
|
||||
author = CommitteeMember.example,
|
||||
round = uint64.example
|
||||
): T =
|
||||
type Transaction = T.Dependencies.Transaction
|
||||
let parents = seq[BlockId[T.Dependencies.Hash]].example
|
||||
let transactions = seq[Transaction].example
|
||||
T.new(author, round, parents, transactions)
|
||||
|
||||
proc example*(
|
||||
T: type SignedBlock,
|
||||
author = CommitteeMember.example,
|
||||
round = uint64.example
|
||||
): T =
|
||||
let blck = Block[T.Dependencies].example(author = author, round = round)
|
||||
let blck = T.Dependencies.Block.example(author = author, round = round)
|
||||
let signature = T.Dependencies.Signature.example
|
||||
SignedBlock.init(blck, signature)
|
||||
SignedBlock[T.Dependencies].init(blck, signature)
|
||||
|
||||
proc example*[T](_: type seq[T], length=0..10): seq[T] =
|
||||
let size = rand(length)
|
||||
@ -54,3 +44,12 @@ proc example*(T: type MockIdentifier): T =
|
||||
|
||||
proc example*(T: type MockSignature): T =
|
||||
MockIdentity.example.sign(MockHash.example)
|
||||
|
||||
proc example*(
|
||||
_: type MockBlock,
|
||||
author = CommitteeMember.example,
|
||||
round = uint64.example
|
||||
): MockBlock =
|
||||
let parents = seq[BlockId[MockHash]].example
|
||||
let transactions = seq[MockTransaction].example
|
||||
MockBlock.new(author, round, parents, transactions)
|
||||
|
||||
@ -2,16 +2,15 @@ import mysticeti/dependencies
|
||||
import ./mocks/signing
|
||||
import ./mocks/hashing
|
||||
import ./mocks/transaction
|
||||
import ./mocks/serialization
|
||||
import ./mocks/blck
|
||||
|
||||
export signing
|
||||
export hashing
|
||||
export transaction
|
||||
export serialization
|
||||
export blck
|
||||
|
||||
type MockDependencies* = Dependencies[
|
||||
MockTransaction,
|
||||
MockSerialization,
|
||||
MockBlock,
|
||||
MockHash,
|
||||
MockIdentifier,
|
||||
MockSignature
|
||||
|
||||
33
tests/mysticeti/mocks/blck.nim
Normal file
33
tests/mysticeti/mocks/blck.nim
Normal file
@ -0,0 +1,33 @@
|
||||
import mysticeti
|
||||
import mysticeti/basics
|
||||
import ./hashing
|
||||
import ./transaction
|
||||
|
||||
type MockBlock* = ref object
|
||||
author*: CommitteeMember
|
||||
round*: uint64
|
||||
parents*: seq[BlockId[MockHash]]
|
||||
transactions*: seq[MockTransaction]
|
||||
id: ?BlockId[MockHash]
|
||||
|
||||
func new*(
|
||||
_: type MockBlock,
|
||||
author: CommitteeMember,
|
||||
round: uint64,
|
||||
parents: seq[BlockId[MockHash]],
|
||||
transactions: seq[MockTransaction]
|
||||
): auto =
|
||||
MockBlock(
|
||||
author: author,
|
||||
round: round,
|
||||
parents: parents,
|
||||
transactions: transactions
|
||||
)
|
||||
|
||||
func id*(blck: MockBlock): auto =
|
||||
without var id =? blck.id:
|
||||
let blockBytes = cast[seq[byte]]($blck[])
|
||||
let blockHash = MockHash.hash(blockBytes)
|
||||
id = BlockId.new(blck.author, blck.round, blockHash)
|
||||
blck.id = some id
|
||||
id
|
||||
@ -1,32 +0,0 @@
|
||||
import std/json
|
||||
import mysticeti
|
||||
import ./transaction
|
||||
|
||||
type MockSerialization* = object
|
||||
|
||||
proc `%`*(member: CommitteeMember): JsonNode =
|
||||
%member.int
|
||||
|
||||
proc `%`*(id: BlockId): JsonNode =
|
||||
%*{
|
||||
"author": id.author,
|
||||
"round": id.round,
|
||||
"hash": $id.hash
|
||||
}
|
||||
|
||||
proc `%`*(transaction: MockTransaction): JsonNode =
|
||||
%*{
|
||||
"nonce": transaction.nonce
|
||||
}
|
||||
|
||||
proc `%`*(blck: Block): JsonNode =
|
||||
%*{
|
||||
"author": blck.author,
|
||||
"round": blck.round,
|
||||
"parents": blck.parents,
|
||||
"transactions": blck.transactions
|
||||
}
|
||||
|
||||
func toBytes*(_: type MockSerialization, blck: Block): seq[byte] =
|
||||
let json = %blck
|
||||
cast[seq[byte]]($json)
|
||||
@ -5,8 +5,8 @@ import mysticeti/blocks
|
||||
type Validator = mysticeti.Validator[MockDependencies]
|
||||
type Committee = mysticeti.Committee[MockDependencies]
|
||||
type Identity = MockIdentity
|
||||
type Transaction = MockDependencies.Transaction
|
||||
type Block = blocks.Block[MockDependencies]
|
||||
type Transaction = MockTransaction
|
||||
type Block = MockBlock
|
||||
type SignedBlock = blocks.SignedBlock[MockDependencies]
|
||||
|
||||
type NetworkSimulator* = object
|
||||
|
||||
@ -4,34 +4,12 @@ import mysticeti/blocks
|
||||
|
||||
suite "Blocks":
|
||||
|
||||
type Block = mysticeti.Block[MockDependencies]
|
||||
type BlockId = mysticeti.BlockId[MockDependencies.Hash]
|
||||
type Identity = MockIdentity
|
||||
type Transaction = MockDependencies.Transaction
|
||||
type Hash = MockDependencies.Hash
|
||||
type Serialization = MockDependencies.Serialization
|
||||
|
||||
test "blocks have an author, a round, parents and transactions":
|
||||
let author = CommitteeMember.example
|
||||
let round = uint64.example
|
||||
let parents = seq[BlockId].example
|
||||
let transactions = seq[Transaction].example
|
||||
let blck = Block.new(author, round, parents, transactions)
|
||||
check blck.author == author
|
||||
check blck.round == round
|
||||
check blck.parents == parents.immutable
|
||||
check blck.transactions == transactions.immutable
|
||||
|
||||
test "blocks have an id consisting of author, round and hash":
|
||||
let blck = Block.example
|
||||
let id = blck.id
|
||||
check id.author == blck.author
|
||||
check id.round == blck.round
|
||||
check id.hash == Hash.hash(Serialization.toBytes(blck))
|
||||
type SignedBlock = mysticeti.SignedBlock[MockDependencies]
|
||||
|
||||
test "blocks can be signed":
|
||||
let signer = Identity.init
|
||||
let blck = Block.example
|
||||
let blck = MockBlock.example
|
||||
let signature = signer.sign(blck.id.hash)
|
||||
let signed = SignedBlock.init(blck, signature)
|
||||
check signed.blck == blck
|
||||
|
||||
@ -7,7 +7,7 @@ import mysticeti/validator/round
|
||||
suite "Validator Round":
|
||||
|
||||
type Round = round.Round[MockDependencies]
|
||||
type Block = mysticeti.Block[MockDependencies]
|
||||
type Block = MockBlock
|
||||
type SignedBlock = mysticeti.SignedBlock[MockDependencies]
|
||||
|
||||
test "rounds have a number":
|
||||
|
||||
@ -6,8 +6,9 @@ import mysticeti/blocks
|
||||
|
||||
suite "Validator Network":
|
||||
|
||||
type Transaction = MockDependencies.Transaction
|
||||
type Block = blocks.Block[MockDependencies]
|
||||
type Transaction = MockTransaction
|
||||
type Block = MockBlock
|
||||
type SignedBlock = blocks.SignedBlock[MockDependencies]
|
||||
type BlockId = blocks.BlockId[MockDependencies.Hash]
|
||||
type Hash = MockDependencies.Hash
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user