Skip to content

Commit b9688a0

Browse files
authored
Merge pull request #51 from cardano-scaling/push-swpuywzwoxws
Planning ledger blueprint
2 parents 9ca208f + 71de066 commit b9688a0

File tree

10 files changed

+328
-16
lines changed

10 files changed

+328
-16
lines changed

flake.nix

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
rec {
2424
inherit inputs;
2525
legacyPackages = pkgs;
26-
2726
defaultPackage = packages.mdbook;
2827
packages.mdbook = pkgs.stdenv.mkDerivation {
2928
name = "cardano-blueprint-book";

src/SUMMARY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
- [`cardano-node`'s ChainDB](storage/cardano-node-chaindb/README.md)
2121
- [Mempool](mempool/README.md)
2222
- [Ledger](ledger/README.md)
23+
- [Blocks](ledger/concepts/blocks.md)
24+
- [Determinism](ledger/concepts/determinism.md)
25+
- [The State Transition Function](ledger/state-transition.md)
26+
- [Validity](ledger/state-transition/validity.md)
2327
- [Transaction fee](ledger/transaction-fee.md)
2428
- [Block Validation](ledger/block-validation.md)
2529
- [Plutus](plutus/README.md)

src/ledger/README.md

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,49 @@
22

33
> [!WARNING]
44
>
5-
> This blueprint is a work in progress.
6-
7-
The Ledger is responsible for validating Blocks and represents the actual semantics of Cardano transactions. The format of blocks and transactions is defined in so-called **eras**: `Byron`, `Shelley`, `Allegra`, `Mary`, `Alonzo`, `Babbage` and `Conway`.
8-
9-
This blueprint is currently more of an entrypoint to already existing implementation-independent descriptions of Cardano transactions and the ledger rules. While existing work covers a lot already, the `cardano-blueprint` may serve as an incubation or staging area for material to cover gaps.
10-
11-
For starters, the [EUTxO Crash Course](https://aiken-lang.org/fundamentals/eutxo) from Aiken is a very good introduction about Cardano transactions.
12-
13-
See [Transaction fee](./transaction-fee.md) for an informal write-up on how transaction fees are currently calculated.
5+
> This blueprint is a work in progress. See [./plan.md] for the intended
6+
> restructuring.
7+
8+
The Ledger is responsible for validating Blocks and represents the actual
9+
semantics of Cardano transactions. The format of blocks and transactions is
10+
defined in so-called **eras**: `Byron`, `Shelley`, `Allegra`, `Mary`, `Alonzo`,
11+
`Babbage` and `Conway`.
12+
13+
This blueprint is currently more of an entrypoint to already existing
14+
implementation-independent descriptions of Cardano transactions and the ledger
15+
rules. While existing work covers a lot already, the `cardano-blueprint` may
16+
serve as an incubation or staging area for material to cover gaps.
17+
For starters, the [EUTxO Crash Course](https://aiken-lang.org/fundamentals/eutxo)
18+
from Aiken is a very good introduction about Cardano transactions.
19+
See [Transaction fee](./transaction-fee.md) for an informal write-up on how
20+
transaction fees are currently calculated.
1421

1522
## Ledger rules
1623

17-
The [Formal Specification](https://intersectmbo.github.io/formal-ledger-specifications/site/index.html) is the source of truth for ledger semantics. While it is currently being made more accessible by interleaving explanations with Agda definitions, its very dense on the Agda and actively worked on to close the gap latest era descriptions and the old era definitions. The Haskell implementation of the ledger holds a list of [design documents and ledger specifications](https://github.com/IntersectMBO/cardano-ledger?tab=readme-ov-file#cardano-ledger) for all eras.
18-
19-
See [Block Validation](./block-validation.md) for a description of the `Conway` era block validation rules.
24+
The [Formal Specification](https://intersectmbo.github.io/formal-ledger-specifications/site/index.html)
25+
is the source of truth for ledger semantics. While it is currently being
26+
made more accessible by interleaving explanations with Agda definitions, its
27+
very dense on the Agda and actively worked on to close the gap latest era
28+
descriptions and the old era definitions. The Haskell implementation of the
29+
ledger holds a list of [design documents and ledger specifications](https://github.com/IntersectMBO/cardano-ledger?tab=readme-ov-file#cardano-ledger)
30+
for all eras. See [Block Validation](./block-validation.md) for a description
31+
of the `Conway` era block validation rules.
2032

2133
## Block and transaction format
2234

23-
The [.cddl files in cardano-ledger](https://github.com/search?q=repo%3AIntersectMBO%2Fcardano-ledger+path%3A.cddl&type=code) define the wire-format of blocks and transactions for each era. These are self-contained for each
24-
era and are referenced in [other blueprint CDDL schemas](../codecs#cddl).
35+
The [.cddl files in cardano-ledger](https://github.com/search?q=repo%3AIntersectMBO%2Fcardano-ledger+path%3A.cddl&type=code)
36+
define the wire-format of blocks and transactions for each era. These are
37+
self-contained for each era and are referenced in
38+
[other blueprint CDDL schemas](../codecs#cddl).
2539

2640
> [!WARNING]
2741
> TODO: make ledger cddls available through blueprint directly
2842
2943
## Conformance tests
3044

31-
Despite the formal specification provides a precise definition for semantics, testing the behavior of ledger implementations against the specification and also the ledger implementations against each other is crucial. For this purpose, a conformance test suite with [implementation-independent test vectors](https://github.com/cardano-scaling/cardano-blueprint/tree/main/src/ledger/conformance-test-vectors) can be used.
45+
Despite the formal specification provides a precise definition for semantics,
46+
testing the behavior of ledger implementations against the specification
47+
and also the ledger implementations against each other is crucial. For this
48+
purpose, a conformance test suite with [implementation-independent test
49+
vectors](https://github.com/cardano-scaling/cardano-blueprint/tree/main/src/ledger/conformance-test-vectors)
50+
can be used.

src/ledger/concepts/blocks.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Ledger: Blocks
2+
3+
Blocks are a fundamental component of all blockchains and represent one of two
4+
basic units of exchange between nodes (the other being [transactions](./transactions.md)).
5+
6+
A block can itself be broken down into multiple parts:
7+
8+
```mermaid
9+
10+
block-beta
11+
block
12+
columns 1
13+
H["Header"]
14+
block
15+
columns 2
16+
BB["Transactions"]
17+
BW["Witnesses"]
18+
BA["Auxiliary Data"]
19+
BV["Transaction Validity"]
20+
end
21+
end
22+
23+
```
24+
25+
See also the [Block CDDL](https://github.com/IntersectMBO/cardano-ledger/blob/master/eras/conway/impl/cddl-files/conway.cddl#L8)
26+
for the Conway era (the latest era at the time of writing).
27+
28+
## The header/body split
29+
30+
The most important distinction in the above diagram is that there is a split
31+
between the header of the block and the body. The general guiding principle
32+
behind this is the following:
33+
34+
- The *header* contains the parts of the block relevant to the consensus
35+
protocol.
36+
- The *body* contains the parts of the block relevant to the ledger.
37+
38+
The full details and implications of this split are covered in
39+
[Implications of the Header/Body Split](../constraints/header-body-split.md).
40+
For now, we can assume that the contents of the header are not important for
41+
the ledger processing.
42+
43+
## The block body
44+
45+
The block body itself is split into four parts. This division is not conceptually
46+
necessary but is helpful for efficient processing:
47+
48+
1. The 'Transactions' section contains the bodies of all transactions. This is
49+
the only part of the block body necessary to compute the resulting ledger
50+
state (see [The ledger state transition](../state-transition.md)) - that is,
51+
provided that the block is _valid_ with regard to some _ledger state_, the
52+
resulting new state can be computed using only the data in this section.
53+
54+
2. The 'Witnesses' section contains the cryptographic witnessing necessary to
55+
evaluate the _validity_ of the transactions contained in the block. For
56+
more details on _validity_, please see the [Validity](../state-transition/validity.md)
57+
section.
58+
59+
3. The 'AuxData' section contains "auxiliary data" which is not processed
60+
as part of the ledger state. It instead contains data which may be of use
61+
to either users directly or other software interfacing with the chain. In
62+
Shelley, this was limited to "metadata', which were indeed simply binary
63+
blobs. In the Mary and Alonzo eras slightly more structure was provided to
64+
allow including native and Plutus scripts respectively.
65+
66+
4. The transaction validity contains a list of transactions in this block which
67+
are [phase-2 invalid](../state-transition/validity.md). This is held
68+
separately since this map is provided, effectively, by the node which
69+
created the block, rather than by the creators of the transactions.

src/ledger/concepts/determinism.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Determinism
2+
3+
An important principle that occurs in a few places throughout the Cardano ledger
4+
is that of determinism. Perhaps one way to summarise is would be to say: "the
5+
transaction is all you need" - that is, when trying to compute the results of
6+
a transaction, you need only look at the transaction itself rather than
7+
computing with the full ledger state.
8+
9+
There are two important instantiations of this principle:
10+
11+
## Transaction Determinism
12+
13+
This instance tells us that, given a transaction is valid, its outputs are
14+
determined fully by the transaction itself. It may be necessary to look at
15+
certain parts of the ledger state to determine whether it is valid - for
16+
example, to check that the inputs have not been spent - but assuming it is
17+
valid, the outputs created will be exactly as described in the transaction.
18+
19+
## Script determinism
20+
21+
This instance tells us that, assuming a transaction passes phase 1 validation,
22+
the validity of a script is determined only by data contained in the transaction
23+
and in the transaction outputs that it spends or references.
24+
25+
## Implications for Node Implementors
26+
27+
These properties allow node implementors to safely make certain assumptions
28+
which can speed up transaction and block processing.
29+
30+
1. When processing historical blocks, nodes need only consider (or even
31+
deserialise) [transaction bodies](./blocks.md), since the rest of the
32+
block payload can only impact the block _validity_, which is already known
33+
for historical blocks.
34+
2. Many of the more expensive checks of transaction validity need only be
35+
carried out once. In particular, the cryptographic verification and script
36+
execution need only be carried out once, when the transaction first enters
37+
the mempool. Subsequently it is required only to check that the inputs still
38+
exist.
39+
40+
To take advantage of these properties, ledger implementers must distinguish
41+
between these checks in the ledger in such a way as to allow transactions to be
42+
(re-)processed without repeating expensive computation.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ledger: Transactions
2+
3+
> This page is currently a stub
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# The Header/Body Split in Detail

src/ledger/plan.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Ledger Blueprint Planning
2+
3+
The aim is to restructure this documentation with the aim of providing a guide
4+
to somebody who might wish to implement the ledger for a compatible node.
5+
6+
To that end, we break down the documentation in various sections. Certain
7+
things make sense to document in certain ways. We wish to avoid any duplication
8+
of work already done - for example, the formal specs remain probably the best
9+
way to document the precise implementation of a pure function. However, we can
10+
provide guidance for people trying to read the specifications.
11+
12+
It is the fundamental nature of documentation to go out of date. As such, we
13+
also want to avoid referring to details of specific eras etc (which are in any
14+
case covered in the formal specs) and instead cover the general principles and
15+
details needed by all potential implementations.
16+
17+
- Concepts
18+
- Blocks
19+
- The header/body split
20+
- Transactions
21+
- Eras
22+
- The structure of an epoch
23+
- Determinism
24+
- The ledger state transition
25+
- How to read the specs
26+
- Old-style semi-formal specs
27+
- New-style Agda specifications
28+
- Validity
29+
- Multi-phase validity
30+
- Static vs dynamic checks
31+
- Ledger interfaces
32+
- To the consensus layer
33+
- Applying a block
34+
- Ticking
35+
- On an era boundary
36+
- Forecasting
37+
- Nonces
38+
- The stake distribution
39+
- To the mempool
40+
- Validating a transaction
41+
- Revalidating a transaction
42+
- To the CLI
43+
- Forecasting the leader schedule
44+
- Understanding parts of the transition
45+
- Non-integral math
46+
- Transaction fee calculation
47+
- Reward calculation
48+
- Ledger serialisation
49+
- Transaction and block formats
50+
- The ledger state
51+
- Decomposition - large and small parts
52+
- Non-canonical serialisation
53+
- Constraints on the ledger
54+
- Computational concerns
55+
- Avoiding spikes
56+
- Implications of the header/body split
57+
- Rollbacks and storage

src/ledger/state-transition.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# The ledger state transition
2+
3+
> This page is a stub.
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Transaction Validity
2+
3+
What does it mean for a transaction to be valid? The ledger specs define it
4+
quite simply: a transaction is valid if it may be applied to a valid ledger
5+
state to return another valid ledger state. We say that it is valid with regard
6+
to the initial ledger state.
7+
8+
More prosaically, for a transaction to be valid with regards to a ledger state
9+
entails the things we would expect: its inputs must exist, the spender must have
10+
the right to spend those inputs, the transaction must balance etc. In the
11+
ledger specifications, these are all written as _predicates_ - assertions that
12+
one thing equals another, for example. A failing predicate means that the
13+
transition is invalid and hence that the transaction is invalid with regard
14+
to that ledger state.
15+
16+
## Multi-phase Validity
17+
18+
Invalid transactions do not end up on the chain. Consequently, invalid
19+
transactions do not pay fees. A trivial attack on a block producing node would
20+
be to bombard it with invalid transactions. The node must verify that each
21+
transaction is invalid, but gains no benefit for performing this work.
22+
23+
In order that this not become an asymmetric resource attack, the work which
24+
must be done to validate a transaction needs be bounded. The introduction of
25+
Plutus in the Alonzo era, however, complicated this situation. Plutus scripts
26+
must necessarily be capable of performing a significant amount of work. Should
27+
this work result in the transaction being deemed invalid, that work would be
28+
uncompensated - an attacker could use relatively small amounts of their own
29+
resource (crafting a looping Plutus script is, after all, relatively easy) to
30+
force significantly larger resource expenditure from the network.
31+
32+
In order to combat this, Alonzo introduced the concept of 2-phase validity:
33+
34+
1. The first phase involves the regular checks of things such as transaction
35+
size, fee suitability, input validity etc. These checks are assumed to have
36+
bounded work. A failure in phase 1 indicates that the transaction will
37+
not be placed on chain.
38+
2. Phase 2 checks are only run if phase 1 succeeds. Phase 2 checks involve
39+
running Plutus scripts and validating that inputs locked by those scripts
40+
can be spent. A transaction failing a phase 2 check can still be put on
41+
chain. In this case, a special input called the 'collateral' is spent and
42+
donated to the fee pot. The collateral must be locked by a phase-1
43+
verifiable input - i.e. an input locked by a VKey or native script.
44+
45+
An important consideration is that phase-2 checks are _static_ (see below).
46+
Phase-2 checks are run always in the context only of the transaction and its
47+
resolved inputs (which, since we have a UTxO system, are determinstic if they
48+
exist). As such, a diligent transaction submitter should have no risk of their
49+
collateral being taken - they can validate that their script passes before
50+
submitting the transaction and then be assured that it will either pass when
51+
the transaction is included, or that the transaction will fail during phase 1
52+
(for example, if an input has been spent).[^1]
53+
54+
## Static vs Dynamic Checks
55+
56+
Since transaction validity is defined with regard to a ledger state, a change
57+
to the ledger state may result in previously valid transactions now becoming
58+
invalid. For example, the time may have moved past the transaction's validity
59+
window, or one of the inputs may have been spent.
60+
61+
Consequently, as the ledger state evolves due to new blocks being accepted,
62+
nodes need to revalidate transactions in their mempool against the new state.
63+
However, not everything needs to be revalidated. Cryptographic signatures, for
64+
example, are guaranteed to remain valid regardless of the ledger state.
65+
66+
Formally, we call a check _static_ if it can be evaluated with regard only to
67+
the contents of the transaction and its resolved inputs. Examples
68+
(non-exhaustive) of static checks include:
69+
70+
- Cryptographic signature checks
71+
- Native (multisig/timelock) scripts
72+
- Phase 2 checks (Plutus scripts)
73+
74+
_Dynamic checks_, on the other hand, require access to the UTxO or other aspects
75+
of the ledger state to compute. As such, they need to be re-evaluated each time
76+
the ledger state is updated. Obvious examples of dynamic checks include
77+
verifying that inputs exist, checking that the transaction still sits within its
78+
validity window, and validating block transaction size against the protocol
79+
parameters.
80+
81+
# Block Validity
82+
83+
> This section is currently a stub
84+
85+
# Relevance for the node developer
86+
87+
The above is mostly relevant for node developers in that it is useful to be able
88+
to run the ledger transitions with fine-grained control over which checks are
89+
computed.
90+
91+
There are four main scenarios which come into consideration:
92+
93+
1. Validating a transaction as it enters the mempool. In this case all checks
94+
must be computed.
95+
2. Re-validating a transaction after a new block has been adopted. In this case,
96+
we care only about re-running _dynamic_ checks.
97+
3. Validating a new block body downloaded from a peer. In this case all checks
98+
must be computed.
99+
4. Re-applying a block from our local storage in order to reconstruct the ledger
100+
state. Since local blocks are assumed to be trusted, we need run _no_ checks
101+
here and only apply the transition.
102+
103+
Node developers should bear these scenarios in mind when considering how to
104+
structure their node transition function.
105+
106+
[^1]: Note that there is a small addendum to this story. While theoretically
107+
anyone may validate their own Plutus scripts, many users do not run their own
108+
node and as such trust a third party to validate those scripts on their behalf.
109+
These users were concerned about accidentally losing collateral. Since
110+
collateral must be a single address, users in such a situation either had to
111+
assign precisely the 'minCollateral' to an address or put up another UTxO as
112+
collateral and risk losing more than the minimum. To assuage the fears of such
113+
folks, Babbage introduced a 'collateral return address' to which collateral in
114+
excess of the minimum required would be returned in the case of a failing
115+
script.

0 commit comments

Comments
 (0)