simulate scenario from figure 4 in the Mysticeti paper

needed fix: call updateSkipped() when proposing a block
This commit is contained in:
Mark Spanbroek 2024-11-05 14:38:43 +01:00
parent f5fdf8e581
commit b757074193
4 changed files with 70 additions and 74 deletions

View File

@ -70,6 +70,12 @@ func updateCertified(validator: Validator, certificate: Block) =
let stake = validator.committee.stake(certificate.author)
proposal.certifyBy(certificate.id, stake)
func addBlock(validator: Validator, signedBlock: SignedBlock) =
if round =? validator.rounds.latest.find(signedBlock.blck.round):
round.addProposal(signedBlock)
validator.updateSkipped(signedBlock.blck)
validator.updateCertified(signedBlock.blck)
proc propose*(validator: Validator, transactions: seq[Transaction]): auto =
type SignedBlock = blocks.SignedBlock[Validator.Signing, Validator.Hashing]
let round = validator.rounds.latest
@ -93,8 +99,7 @@ proc propose*(validator: Validator, transactions: seq[Transaction]): auto =
transactions = transactions
)
let signedBlock = validator.identity.sign(blck)
round.addProposal(signedBlock)
validator.updateCertified(blck)
validator.addBlock(signedBlock)
success signedBlock
func check*(validator: Validator, signed: SignedBlock): auto =
@ -134,10 +139,7 @@ func check*(validator: Validator, signed: SignedBlock): auto =
BlockCheck.correct(signed)
func receive*(validator: Validator, correct: CorrectBlock) =
if round =? validator.rounds.latest.find(correct.blck.round):
round.addProposal(correct.signedBlock)
validator.updateSkipped(correct.blck)
validator.updateCertified(correct.blck)
validator.addBlock(correct.signedBlock)
func getBlock*(validator: Validator, id: BlockId): auto =
validator.rounds.latest.find(id)

View File

@ -0,0 +1,52 @@
import ./basics
import ./simulator
proc scenarioFigure4*(simulator: NetworkSimulator): ?!seq[seq[SignedBlock]] =
# replays scenario from Figure 4 in the Mysticeti paper
# https://arxiv.org/pdf/2310.14821v4
# note: round robin is not applied correctly in the figure from
# the Mysticeti paper, so this simulation uses different proposer
# labels from the fourth round
var proposals: seq[seq[SignedBlock]]
proposals.add(? simulator.exchangeProposals {
0: @[0, 1, 2, 3],
1: @[0, 1],
2: @[0, 2, 3],
3: @[1, 2, 3]
})
simulator.nextRound()
proposals.add(? simulator.exchangeProposals {
0: @[0, 1, 3],
1: @[0, 1, 3],
2: @[0, 3],
3: @[1, 3]
})
simulator.nextRound()
proposals.add(? simulator.exchangeProposals {
0: @[2, 3, 0, 1],
1: @[2, 3, 0, 1],
3: @[2, 3, 0, 1]
})
simulator.nextRound()
proposals.add(? simulator.exchangeProposals {
2: @[2, 3, 0, 1],
3: @[3],
0: @[2, 3, 0, 1],
1: @[2, 3, 0, 1]
})
simulator.nextRound()
proposals.add(? simulator.exchangeProposals {
2: @[],
3: @[2, 3, 0],
0: @[2, 3, 0],
1: @[2, 3, 0]
})
simulator.nextRound()
proposals.add(? simulator.exchangeProposals {
2: @[2, 3, 0],
3: @[2, 3, 0],
0: @[2, 3, 0]
})
success proposals

View File

@ -2,9 +2,9 @@ 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[MockSigning, MockHashing]
type Identity* = mysticeti.Identity[MockSigning]
type SignedBlock* = blocks.SignedBlock[MockSigning, MockHashing]
type NetworkSimulator* = object
identities: seq[Identity]

View File

@ -1,5 +1,6 @@
import ../basics
import ../simulator
import ../scenarios
import mysticeti
import mysticeti/blocks
import mysticeti/hashing
@ -269,70 +270,11 @@ suite "Multiple Validators":
check toSeq(simulator.validators[0].committed()) == second
test "commits blocks using the indirect decision rule":
# first round: proposals
let proposals = !simulator.exchangeProposals {
0: @[0, 1, 2, 3],
1: @[0, 1],
2: @[0, 2, 3],
3: @[1, 2, 3]
}
# second round: voting
simulator.nextRound()
discard !simulator.exchangeProposals {
0: @[0, 1, 3],
1: @[0, 1, 3],
2: @[0, 3],
3: @[1, 3]
}
# third round: certifying
simulator.nextRound()
discard !simulator.exchangeProposals {
0: @[0, 1, 2, 3],
1: @[0, 1, 2, 3],
3: @[0, 1, 2, 3]
}
# fourth round: anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
# fifth round: voting on anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
# sixth round: certifying anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
check toSeq(simulator.validators[0].committed()).contains(proposals[3].blck)
let proposals = !scenarioFigure4(simulator)
let committed = toSeq(simulator.validators[0].committed())
check committed.contains(proposals[0][3].blck)
test "skips blocks using the indirect decision rule":
# Modelled after Figure 3f from the Mysticeti paper
# first round: proposals
let proposals = !simulator.exchangeProposals {
0: @[0, 1, 2, 3],
1: @[0, 1],
2: @[0, 2, 3],
3: @[1, 2, 3]
}
# second round: voting
simulator.nextRound()
discard !simulator.exchangeProposals {
0: @[0, 1, 3],
1: @[0, 1, 3],
2: @[0, 3],
3: @[1, 3]
}
# third round: certifying
simulator.nextRound()
discard !simulator.exchangeProposals {
0: @[0, 1, 2, 3],
1: @[0, 1, 2, 3],
3: @[0, 1, 2, 3]
}
# fourth round: anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
# fifth round: voting on anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
# sixth round: certifying anchor
simulator.nextRound()
discard !simulator.exchangeProposals()
check not toSeq(simulator.validators[0].committed()).contains(proposals[1].blck)
let proposals = !scenarioFigure4(simulator)
let committed = toSeq(simulator.validators[0].committed())
check not committed.contains(proposals[0][1].blck)