Skip to content

Commit c3f0581

Browse files
authored
Merge branch 'main' into javierdiaz/trace-translator
2 parents 1adbaa9 + 4d23b82 commit c3f0581

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+5565
-1102
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: "Build Leios Design PDF"
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "docs/leios-design/**"
7+
- "nix/artifacts.nix"
8+
- ".github/workflows/leios-design.yaml"
9+
push:
10+
branches:
11+
- main
12+
paths:
13+
- "docs/leios-design/**"
14+
- "nix/artifacts.nix"
15+
workflow_dispatch: # Allow manual triggering
16+
17+
permissions:
18+
contents: read
19+
actions: read
20+
21+
# Prevent redundant workflow runs
22+
concurrency:
23+
group: ${{ github.workflow }}-${{ github.ref }}
24+
cancel-in-progress: true
25+
26+
jobs:
27+
build-pdf:
28+
name: "Build Leios Design PDF"
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: 📥 Checkout repository
32+
uses: actions/checkout@v4
33+
with:
34+
fetch-depth: 1
35+
36+
- name: 🛠️ Install Nix
37+
uses: cachix/install-nix-action@v27
38+
with:
39+
nix_path: nixpkgs=channel:nixos-unstable
40+
extra_nix_config: |
41+
experimental-features = nix-command flakes
42+
accept-flake-config = true
43+
extra-substituters = https://cache.iog.io
44+
extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=
45+
46+
- name: 🗂️ Setup Cachix for IOG cache
47+
uses: cachix/cachix-action@v15
48+
with:
49+
name: iog
50+
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
51+
skipPush: true
52+
53+
- name: 🏗️ Build PDF using Nix
54+
run: |
55+
echo "Building Leios Design PDF..."
56+
nix build .#leiosDesignPdf -L
57+
58+
# Verify the PDF was created
59+
if [ ! -f result/leios-design.pdf ]; then
60+
echo "Error: PDF file was not created"
61+
exit 1
62+
fi
63+
64+
# Show file size and info
65+
ls -lh result/leios-design.pdf
66+
file result/leios-design.pdf
67+
68+
- name: 📊 Get PDF metadata
69+
run: |
70+
# Get basic file info
71+
echo "PDF file size: $(stat -c%s result/leios-design.pdf) bytes"
72+
echo "PDF creation date: $(stat -c%y result/leios-design.pdf)"
73+
74+
# If pdfinfo is available, show more details
75+
if command -v pdfinfo &> /dev/null; then
76+
echo "PDF metadata:"
77+
pdfinfo result/leios-design.pdf || true
78+
fi
79+
80+
- name: 🚀 Upload PDF artifact
81+
uses: actions/upload-artifact@v4
82+
with:
83+
name: leios-design-pdf-${{ github.sha }}
84+
path: result/leios-design.pdf
85+
if-no-files-found: error
86+
retention-days: 30
87+
88+
- name: 📄 Add PDF info to job summary
89+
run: |
90+
echo "## 📄 Leios Design PDF Generated" >> $GITHUB_STEP_SUMMARY
91+
echo "" >> $GITHUB_STEP_SUMMARY
92+
echo "✅ Successfully built PDF from markdown source" >> $GITHUB_STEP_SUMMARY
93+
echo "" >> $GITHUB_STEP_SUMMARY
94+
echo "**File details:**" >> $GITHUB_STEP_SUMMARY
95+
echo "- Size: $(stat -c%s result/leios-design.pdf) bytes" >> $GITHUB_STEP_SUMMARY
96+
echo "- Generated: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
97+
echo "- Commit: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
98+
echo "" >> $GITHUB_STEP_SUMMARY
99+
echo "The PDF is available as a workflow artifact named \`leios-design-pdf-${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY

analysis/markov/Linleios.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
import Linleios.Evolve
2+
3+
/-!
4+
# Linleios: a Markovian model of Linear Leios
5+
-/

analysis/markov/Linleios/Evolve.lean

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ open Lean.ToJson (toJson)
1111
open Std (HashMap)
1212

1313

14+
/--
15+
Try to forge an RB in this substep, given the state and environment.
16+
-/
1417
def forgeRb {env : Environment} (state : State) : Outcomes :=
1518
let state' :=
1619
{
@@ -23,6 +26,9 @@ def forgeRb {env : Environment} (state : State) : Outcomes :=
2326
, ({state' with hasRb := false, canCertify := false}, 1 - p)
2427
]
2528

29+
/--
30+
Try to include a certificate in the latest RB being forged in this substep, given the state and environment.
31+
-/
2632
def certify {env : Environment} (state : State) : Outcomes :=
2733
if state.hasRb && state.canCertify
2834
then let p := env.pSpacingOkay
@@ -32,6 +38,9 @@ def certify {env : Environment} (state : State) : Outcomes :=
3238
]
3339
else [(state, 1)]
3440

41+
/--
42+
Try to forge an EB in this substep, given the state and environment.
43+
-/
3544
def forgeEb {env : Environment} (state : State) : Outcomes :=
3645
if state.hasRb
3746
then let p := 1 - env.pLate
@@ -41,6 +50,9 @@ def forgeEb {env : Environment} (state : State) : Outcomes :=
4150
]
4251
else [(state, 1)]
4352

53+
/--
54+
Try to vote for an EB in this substep, given the state and environment.
55+
-/
4456
def vote {env : Environment} (state : State) : Outcomes :=
4557
if state.hasRb
4658
then let p := env.pQuorum
@@ -50,13 +62,22 @@ def vote {env : Environment} (state : State) : Outcomes :=
5062
]
5163
else [(state, 1)]
5264

65+
/--
66+
Step forward to the next potential block.
67+
-/
5368
def step {env : Environment} : List (State → Outcomes) :=
5469
[@forgeRb env, @certify env, @forgeEb env, @vote env]
5570

5671

72+
/--
73+
Discard probabilities below the specified threshold.
74+
-/
5775
def prune (ε : Float) : Probabilities → Probabilities :=
5876
HashMap.filter (fun _ p => p > ε)
5977

78+
/--
79+
Evolve state probabilities on step forward according the a transition function.
80+
-/
6081
def evolve (transition : State → Outcomes) : Probabilities → Probabilities :=
6182
HashMap.fold
6283
(
@@ -68,19 +89,32 @@ def evolve (transition : State → Outcomes) : Probabilities → Probabilities :
6889
)
6990
7091

92+
/--
93+
Chain a sequence of transitions sequentially, evolving probabilities.
94+
-/
7195
def chain (transitions : List (State → Outcomes)) : Probabilities → Probabilities :=
7296
match transitions with
7397
| [] => id
7498
| (t :: ts) => chain ts ∘ evolve t
7599

100+
/--
101+
Simulate the specified number of potential blocks, given a starting set of probabilities.
102+
-/
76103
def simulate (env : Environment) (start : Probabilities) (ε : Float) : Nat → Probabilities
77104
| 0 => start
78105
| n + 1 => let state' := prune ε $ chain (@step env) start
79106
simulate env state' ε n
80107

108+
109+
/--
110+
Compute the total probabilities of a set of states.
111+
-/
81112
def totalProbability (states : Probabilities) : Probability :=
82113
states.values.sum
83114

115+
/--
116+
Compute the distribution of EB counts.
117+
-/
84118
def ebDistribution : Probabilities → HashMap Nat Probability :=
85119
HashMap.fold
86120
(
@@ -90,13 +124,19 @@ def ebDistribution : Probabilities → HashMap Nat Probability :=
90124
)
91125
92126

127+
/--
128+
Format the distribution of EB counts as JSON.
129+
-/
93130
def ebDistributionJson : Probabilities → Json :=
94131
Json.mkObj
95132
∘ List.map (fun ⟨k, v⟩ => ⟨toString k, toJson v⟩)
96133
∘ (fun z => z.mergeSort (by exact fun x y => x.fst ≤ y.fst))
97134
∘ HashMap.toList
98135
∘ ebDistribution
99136

137+
/--
138+
Compute the RB efficiency, given a set of states.
139+
-/
100140
def rbEfficiency (states : Probabilities) : Float :=
101141
let clock := states.keys.head!.clock
102142
let rbCount :=
@@ -106,6 +146,9 @@ def rbEfficiency (states : Probabilities) : Float :=
106146
states
107147
rbCount / clock.toFloat
108148

149+
/--
150+
Compute the EB efficiency, given a set of states.
151+
-/
109152
def ebEfficiency (states : Probabilities) : Float :=
110153
let clock := states.keys.head!.clock
111154
let ebCount :=
@@ -115,6 +158,9 @@ def ebEfficiency (states : Probabilities) : Float :=
115158
states
116159
ebCount / (clock.toFloat - 1)
117160

161+
/--
162+
Compute the overall efficiency, give a set of states.
163+
-/
118164
def efficiency (states : Probabilities) : Float :=
119165
let rb := rbEfficiency states
120166
let eb := ebEfficiency states

analysis/markov/Linleios/Probability.lean

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,30 @@
22
import Linleios.Util
33

44

5+
/--
6+
Number of stake pools.
7+
-/
58
def nPools : Nat := 2500
69

10+
/--
11+
Compute a realistic stake distribution for the specified number of pools.
12+
-/
713
def stakeDistribution (nPools : Nat) : List Float :=
814
(List.range nPools).map (fun k => ((k + 1).toFloat / nPools.toFloat)^10 - (k.toFloat / nPools.toFloat)^10)
915

16+
/--
17+
Determine the distribution parameter that achieves the specified committee size.
18+
-/
1019
private def calibrateCommittee(committeeSize : Float) : Float :=
1120
let stakes : List Float := stakeDistribution nPools
1221
let f (m : Float) : Float :=
1322
let ps : List Float := stakes.map (fun s => 1 - Float.exp (- m * s))
1423
ps.sum - committeeSize
1524
bisectionSearch f committeeSize nPools.toFloat 0.5 10
1625

26+
/--
27+
Compute the mean and standard deviation of the committee size, given the probability of a successful vote and a target committee size.
28+
-/
1729
private def committeeDistribution (pSuccessfulVote committeeSize : Float) : Float × Float :=
1830
let stakes : List Float := stakeDistribution nPools
1931
let m := calibrateCommittee committeeSize
@@ -22,6 +34,9 @@ private def committeeDistribution (pSuccessfulVote committeeSize : Float) : Floa
2234
let σ := (ps.map (fun p => p * (1 - p))).sum.sqrt
2335
⟨ μ , σ ⟩
2436

37+
/--
38+
Compute the probability of a quorum, given the probability of a successful vote, the target committee size, and the quorum fraction.
39+
-/
2540
def pQuorum (pSuccessfulVote committeeSize τ : Float) : Float :=
2641
let ⟨ μ , σ ⟩ := committeeDistribution pSuccessfulVote committeeSize
2742
1 - cdfGaussian (τ * committeeSize) μ σ

analysis/markov/Linleios/Types.lean

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,44 @@ import Linleios.Probability
77
open Std (HashMap)
88

99

10+
/--
11+
Represent probabilities as floating-point numbers.
12+
-/
1013
abbrev Probability := Float
1114

12-
15+
/--
16+
The constant parameters used for computing transitions.
17+
-/
1318
structure Environment where
19+
/-- The active slot coefficient. -/
1420
activeSlotCoefficient : Probability
21+
/-- The $L_\text{hdr}$ protocol parameter. -/
1522
Lheader : Nat
23+
/-- The $L_\text{vote}$ protocol parameter. -/
1624
Lvote : Nat
25+
/-- The $L_\text{diff}$ protocol parameter. -/
1726
Ldiff : Nat
27+
/-- The probability that an RB occurs long enough after the previous RB so that an EB can be certified. -/
1828
pSpacingOkay : Probability
29+
/-- The per-step quorum probability. -/
1930
pQuorum : Probability
31+
/-- The probability that the EB and transaction data arrives too late to compute the ledger. -/
2032
pLate : Probability
33+
/-- The fraction of adversarial stake. -/
2134
fAdversary : Float
2235
deriving Repr
2336

37+
/--
38+
Create an environment.
39+
40+
- `activeSlotCoefficient`: the active slot coefficient
41+
- `committeeSize`: the mean committee size
42+
- `τ`: the quorum fraction
43+
- `pRbHeaderArrives`: the probability that an RB header arrives before $L_\text{hdr}$ slots
44+
- `pEBValidates`: the probability that an EB is validated before $3 L_\text{hdr} + L_\text{vote} + L_\text{diff}$ slots
45+
- `pEbUnvalidated`: the probability that the EB and transaction data arrives too late to compute the ledger
46+
- `fAdversary`: the fraction of adversarial stake
47+
-/
2448
def makeEnvironment (Lheader Lvote Ldiff : Nat) (activeSlotCoefficient committeeSize τ pRbHeaderArrives pEbValidates pEbUnvalidated fAdversary : Float) : Environment :=
2549
{
2650
activeSlotCoefficient := activeSlotCoefficient
@@ -34,14 +58,25 @@ def makeEnvironment (Lheader Lvote Ldiff : Nat) (activeSlotCoefficient committee
3458
}
3559

3660

61+
/--
62+
The state of the chain's evolution.
63+
-/
3764
structure State where
65+
/-- The number of potential RB oppurtunities. -/
3866
clock : Nat
67+
/-- The number of RBs actually forged. -/
3968
rbCount : Nat
69+
/-- The number of EBs certified. -/
4070
ebCount : Nat
71+
/-- Whether an RB was forged in the current step. -/
4172
hasRb : Bool
73+
/-- Whether an EB could be certified in the current step. -/
4274
canCertify : Bool
4375
deriving Repr, BEq, Hashable, Inhabited
4476

77+
/--
78+
The genesis state starts when zero counts.
79+
-/
4580
theorem genesis : (default : State).clock = 0 ∧ (default : State).rbCount = 0 ∧ (default : State).ebCount = 0 := by
4681
constructor
4782
rfl
@@ -50,11 +85,16 @@ theorem genesis : (default : State).clock = 0 ∧ (default : State).rbCount = 0
5085
rfl
5186

5287

88+
/--
89+
The active states and their probabilities.
90+
-/
5391
def Probabilities := HashMap State Probability
5492
deriving Repr, EmptyCollection
5593

5694
instance : Inhabited Probabilities where
5795
default := (∅ : Probabilities).insert Inhabited.default 1
5896

5997

98+
/--
99+
An outcome is a list of new states and their probabilities. -/
60100
abbrev Outcomes := List (State × Probability)

analysis/markov/Linleios/Util.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11

2+
/--
3+
The error function.
4+
-/
25
partial def erf (x : Float) : Float :=
36
if x < 0
47
then - erf (- x)
@@ -12,9 +15,15 @@ partial def erf (x : Float) : Float :=
1215
let t := 1 / (1 + p * x)
1316
1 - (a₁ * t + a₂ * t^2 + a₃ * t^3 + a₄ * t^4 + a₅ * t^5) * Float.exp (- x^2)
1417

18+
/--
19+
The CDF for a normal distribution.
20+
-/
1521
def cdfGaussian (x μ σ : Float) : Float :=
1622
(1 + erf ((x - μ) / σ / Float.sqrt 2)) / 2
1723

24+
/--
25+
A bisection search.
26+
-/
1827
def bisectionSearch (f : Float → Float) (low high : Float) (ε : Float) (maxIter : Nat) : Float :=
1928
match maxIter with
2029
| 0 => (low + high) / 2
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.lake

0 commit comments

Comments
 (0)