Skip to main content

5 - The Chia\textsf{Chia} Blockchain

In this section we finally outline the design of the Chia\textsf{Chia} blockchain as illustrated in Figure 1 from its basic building blocks PoSpace, VDFs and Signatures. These primitives are specified in §A. We'll use greek letters σ\sigma to denote PoSpace, τ\tau for VDFs and μ\mu for Signatures.

Challenge chain diagram

Figure 7: The reward, challenge and infused challenge chains. For illustration we only use 8 not 64 signage points per sub-slot.

5.1 Additional Variables and Notation for this Section

5.1.1 Variables

VariableDefinition
TiT_iTime parameter of ii-th slot (# of VDF steps per sub-slot). Recalibrated once per day for 10 minutes per sub-slot target.
spii\mathsf{spi}_ispii=defTi64\mathsf{spi}_i \stackrel{\text{\tiny def}}{=} \frac{T_i}{64}
DiD_iDifficulty parameter of ii-th slot. Recalibrated once per day for 32 blocks per slot target

5.1.2 Step to Epoch

κi\kappa_i :Number of sub-slots in iith slot. Typically κi=1\kappa_i=1 but can be larger integer to enforce a 1616 block minimum.

5.1.3 Notation for Points of Interest

To describe the Chia\textsf{Chia} chains it will be convenient to introduce some extra notation. Recall that for a VDF τ\tau or VDF chain V{\cal V} we denote with τ[t]\tau[t] or V[t]{\cal V}[t] the point tt steps into the computation. τ.t,V.t\tau.{\sf t},{\cal V}.{\sf t} is the total number of steps. Sometimes we overload notation and consider τ,V\tau,{\cal V} to denote the point at the end of the computation rather than the entire VDF or VDF chain, i.e., τ=τ[τ.t],V=V[V.t]\tau=\tau[\tau.{\sf t}],{\cal V}={\cal V}[{\cal V}.{\sf t}].

The VDF chains we'll consider (RC{\cal RC} and CC{\cal CC}) will be split into slots where the starting point of a new slot will always be an infusion point. For a point point=V[t]{\sf point}={\cal V}[t] on such a chain we denote with

PointDefinition
point.D{\sf point}.{\sf D}the total depth, i.e., the number of steps of this point since genesis
point.d{\sf point}.{\sf d}the depth of this point in the current slot
point.t{\sf point}.{\sf t}the depth of this point in its VDF
point.x{\sf point}.{\sf x}the value of the VDF chain at this point
point.π{\sf point}.\pia proof certifying the VDF computation up to this point
point+{\sf point}^+If point{\sf point} is an infusion point where some value vv gets infused, then we denote with point{\sf point} the point before infusion, and with point+=VDF.sample(point.x,v){\sf point}^+ = {\sf VDF.sample}({\sf point}.{\sf x},v) the point after infusion

The following points on the Chia\textsf{Chia} VDF chains will be defined

PointDefinition
cc_spi,j{\sf cc\_sp}_{i,j}The jjth challenge chain signage point in the iith slot (eq.(6))
rc_spi,j{\sf rc\_sp}_{i,j}The jjth reward chain signage point in the iith slot (eq.(9))
cc_sp(β){\sf cc\_sp}(\beta)he cc_spi,j{\sf cc\_sp}_{i,j} used as challenge to compute the PoSpace σ\sigma in block β\beta
rc_sp(β){\sf rc\_sp}(\beta)The rc_spi,j{\sf rc\_sp}_{i,j} whose signature μrc_sp\mu_{{\sf rc\_sp}} is in β\beta
rc_ip(β){\sf rc\_ip}(\beta)The infusion point of β\beta into RC{\cal RC} (eq.(10)

The signage point interval is the number of VDF steps between signage points, for the iith slot it's

spii=defTi/64{\sf spi}_i \stackrel{\scriptsize \sf def}{=}T_i/64

so e.g., the depth of the jjth signage point in the iith slot is rc_spi,j.d=cc_spi,j.d=jspii\mathsf{rc\_sp}_{i,j}.\mathsf{d} = \mathsf{cc\_sp}_{i,j}.\mathsf{d} = j \cdot \mathsf{spi}_i. A block in the iith slot will be infused 3 to 4 signage point intervals past its signage point.

3spii < rc_ip(βT).d  rc_sp(βT).d < 4spii3\cdot {\sf spi}_i\ <\ {\sf rc\_ip}(\beta_T).{\sf d}\ -\ {\sf rc\_sp}(\beta_T).{\sf d}\ < \ 4\cdot {\sf spi}_i

The first signage point in a slot is the last signage point after infusion

rc_spi+1,0=rc_spi,τi64+{\sf rc\_sp}_{i+1,0}={\sf rc\_sp}_{i,\tau_i\cdot 64}^+

The iith slot starts at total depth

rc_spi,0.D=j=1i1Tjκj{\sf rc\_sp}_{i,0}.{\sf D}=\sum_{j=1}^{i-1}T_j\cdot \kappa_j

5.2 The Challenge Chain

The challenge chain CC{\cal CC} is a VDF chain whose data and VDF values we'll denote as

CC=ic0,τ1CC,ic1,τ2CC,ic2,{\cal CC}={\sf ic}_0, \tau^{{\cal CC}}_1,{\sf ic}_1,\tau^{\cal CC}_2,{\sf ic}_2,\ldots

Here τiCC\tau^{\cal CC}_i is the VDF computation for the iith slot. Usually its number of VDF steps is the current time parameter TiT_i (and should take 10 minutes to compute), but in exceptional cases it can be an integer multiple κiN\kappa_i\in\mathbb{N} of that as we enforce a 16 block minimum per slot

τiCC.t=κiTitypically κi=1\tau^{\cal CC}_i.{\sf t} = \kappa_i\cdot T_i \qquad\textrm{typically $\kappa_i=1$}

The value ici{\sf ic}_i infused at the beginning of slot i+1i+1 depends on the first block in slot ii, we'll explain how exactly in §5.5.

As the VDF τiCC\tau^{\cal CC}_i of the iith slot is computed by a time lord, they release equidistant points of this computation called the challenge chain signage points, one every spii=Ti/64{\sf spi}_i=T_i/64 VDF steps or around 9.375=600/649.375=600/64 seconds

cc_spi,0,cc_spi,1,,cc_spi,τi64wherecc_spi,j=defτiCC[jspii]{\sf cc\_sp}_{i,0},{\sf cc\_sp}_{i,1},\ldots,{\sf cc\_sp}_{i,\tau_i\cdot 64}\quad\textrm{where}\quad {\sf cc\_sp}_{i,j}\stackrel{\scriptsize \sf def}{=}\tau^{\cal CC}_i[j\cdot {\sf spi}_i]
eq.(6)

The point cc_spi,τi64{\sf cc\_sp}_{i,\tau_i\cdot 64} at the end of the slot must also be broadcast as it's required to verify the VDF, but it's not used as a challenge as it's at the same depth as the first signage point cc_spi+1,0VDF.sample(cc_spi,τi64,ici){\sf cc\_sp}_{i+1,0} \gets {\sf VDF.sample}({\sf cc\_sp}_{i,\tau_i\cdot 64},{\sf ic}_i) of the next slot.

Design Choice 1: A Continuous Flow of Challenges

To get the security gains of correlated randomness, we let our PoSpace challenges depend on only one block (out of around 32) per slot, so there's a fresh challenge every 10 minutes. At the same time, we want a smooth continuous block arrival time (target is 18.75 seconds) and the challenge for each block should be revealed around 30 seconds before the block is infused (not much less to avoid orphan blocks, not much more to limit selfish mining and bribing opportunities). Deriving challenges cc_spi,1,cc_spi,2,{\sf cc\_sp}_{i,1},{\sf cc\_sp}_{i,2},\ldots deterministically from one initial challenge cc_spi,0{\sf cc\_sp}_{i,0} using a delay function as outline above achieves exactly that.

The reward chain RC{\cal RC} is a VDF chain that the time lords evaluate in parallel to CC{\cal CC} and also has signage points at the same depth as CC{\cal CC}, i.e., rc_spi,j.d=cc_spi,j.d{\sf rc\_sp}_{i,j}.{\sf d}={\sf cc\_sp}_{i,j}.{\sf d}. Before we can define RC{\cal RC} we first need to explain the content of blocks.

5.3 Trunk Blocks {#S:TB}

Whenever a farmer receives new signage points cc_spi,j,rc_spi,j{\sf cc\_sp}_{i,j},{\sf rc\_sp}_{i,j} they first check whether this points lie on a heaviest chain (cf. the discussion in §1.5) and their VDF proofs verify. If the this is the case, the farmer checks they can create a winning PoSpace proof. This process will, for a subset of the plots, produce a PoSpace σ\sigma and some additional value σ.required_iterations\sigma.{\sf required\_iterations}. Whether this PoSpace is a winning proof is now determined by the time parameter TiT_i as

winning condition : σ.required_iterations<spii(=Ti/64)\textrm{winning condition : } \sigma.{\sf required\_iterations} < {\sf spi}_i\quad (=T_i/64)
eq.(7)
Design Choice 2: Why 32 Blocks in Expectation and not Exactly?

With our winning condition we have 32 blocks per slot in expectation depending on a challenge. We could have used a different design to enforce exactly 32 challenges, but then it would be impossible to achieve our Objective 1.(c), which asks that whether a plot wins must depend solely on the challenge.

If a farmer has a winning PoSpace σ\sigma they can produce a block β=(βT,βF)\beta=(\beta_T,\beta_F) which contains the foliage block βF\beta_F and the trunk block βT\beta_T. The actual Chia\textsf{Chia} blocks are more sophisticated than our description below, but in this writeup we focus on the entries which are absolutely necessary for functionality and security of the chain and ignore entries which are there for efficiency like weight proofs for light clients or pooling. They key entries in a valid trunk block

βT=(σ,μrc_sp)\beta_T=(\sigma,\mu_{{{\sf rc\_sp}}})

are

σPoSpace.prove(S,cc_spi,j)\sigma\gets {\sf PoSpace.prove}(S,{\sf cc\_sp}_{i,j}), a proof of space for some plot SS on challenge cc_spi,j{\sf cc\_sp}_{i,j} where the proof σ\sigma satisfies the winning condition from eq.(7).

μrc_spSig.sign(S.sk,rc_spi,j)\mu_{\sf rc\_sp}\gets {{\sf Sig.sign}}(S.sk,{\sf rc\_sp}_{i,j}), a signature using the secret key of the plot SS (so it verifies under the public-key σ.pk\sigma.pk in the PoSpace) of the signage point in the rewards chain discussed in the next section.

5.4 The Reward Chain

The reward chain RC{\cal RC} is a VDF chain that time lords compute in parallel to CC{\cal CC}. Like CC{\cal CC}, RC{\cal RC} can be spilt in a sequence of slots.

RC=RC1,RC2,{\cal RC}={\cal RC}_1,{\cal RC}_2,\ldots

While in CC{\cal CC} the iith slot just contains a VDF τiCC\tau^{\cal CC}_i and the value ici{\sf ic}_i infused at the end, each slot RCi{\cal RC}_i of the RC{\cal RC} chain

RCi=τi,1RC,β1,τi,2RC,β2,βbiτi,bi+1RC,(ici,τiCC.y){\cal RC}_i=\tau^{\cal RC}_{i,1},\beta_1,\tau^{\cal RC}_{i,2},\beta_2\ldots, \beta_{b_i} \tau^{\cal RC}_{i,b_i+1},({\sf ic}_i,\tau^{\cal CC}_{i}.{\sf y})
eq.(8)

is a VDF chain with typically around 3333 infused values: around 32 blocks bib_i and at the end of the slot also the CC{\cal CC} and iCC{\sf i}{\cal CC} points at the same depth. The RC{\cal RC} signage points are

rc_spi,j=defRCi[jspii]{\sf rc\_sp}_{i,j}\stackrel{\scriptsize \sf def}{=}{\cal RC}_i[j\cdot {\sf spi}_i]
eq.(9)

Where do Blocks get Infused.

Let βT=(σ,μrc_sp)\beta_T=(\sigma,\mu_{{{\sf rc\_sp}}}) be some valid block for challenge cc_sp(βT){\sf cc\_sp}(\beta_T), its reward chain infusion point rc_ip(βT){\sf rc\_ip}(\beta_T) is then at depth

rc_ip(βT).d=rc_sp(βT).d+3spii+σ.required_iterations{\sf rc\_ip}(\beta_T).{\sf d}={\sf rc\_sp}(\beta_T).{\sf d}+3\cdot {\sf spi}_i+\sigma.{\sf required\_iterations}
eq.(10)

As σ.required_iterations\sigma.{\sf required\_iterations} is at most spii{\sf spi}_i the infusion point is somewhere between 3 and 4 signage points past the signage point it refers to. That means we have somewhere from 28.125 to 37.5 seconds for a round trip from the time lord who gossips the signage point, to a farmer who computes and gossips a block, back to the time lord who then infuses the block.

5.5 The Infused Challenge Chain

Recall that the challenge chain CC{\cal CC} is used to create PoSpace challenges, and we want these challenges to only depend on one block per slot. For this, at the end of the iith slot we infuse the PoSpace σ\sigma from the first trunk block βT\beta_T whose signage point is in the iith slot into CC{\cal CC}. We don't simply infuse σ\sigma, but to delay revealing the challenge for as long as possible and make sure it's buried deep in the chain when revealed, we run a VDF on top of σ\sigma to get the infused challenge value ici{\sf ic}_i to be infused as defined in §5.2.

Concretely, the infused challenge of the iith slot is the output of a VDF computation

ici=defτ.yτ=VDF.solve(x,t){\sf ic}_i\stackrel{\scriptsize \sf def}{=}\tau.{\sf y}\qquad \tau={\sf VDF.solve}(x,t)

on some challenge xx and time tt which are defined as follows.

Let βT=(σ,μrc_sp)\beta_T=(\sigma,\mu_{{{\sf rc\_sp}}}) be the first trunk block infused into the iith slot RCi{\cal RC}_i past the 3rd signage point, using notion as in eq.(10)

βT=βj where j=min{k : βk.d>3spi}\beta_T=\beta_j \textrm{ where }j=\min\{k\ :\ \beta_k.{\sf d}>3\cdot {\sf spi}\}

now the challenge xx is derived from the PoSpace in this block and the value of CC{\cal CC} at the depth of its infusion point

xVDF.sample(σ,CC[rc_ip(βT).D].y)\quad x\gets {\sf VDF.sample}(\sigma,{\cal CC}[{\sf rc\_ip}(\beta_T).{\sf D}].{\sf y})

the number of steps tt is the the remaining number of VDF steps in the slot, so the value ici{\sf ic}_i will be available at the end of the slot when it's required, but not earlier

t=cc_ipi,0.Drc_ip(β).Dt={\sf cc\_ip}_{i,0}.{\sf D}- {\sf rc\_ip}(\beta).{\sf D}
Security Notice 1: Why iCC depends only on σ

We only use σ\sigma, not the entire trunk block βT=(σ,μrc_sp)\beta_T=(\sigma,\mu_{{{\sf rc\_sp}}}), to compute the infused challenge ici{\sf ic}_i. This is crucial to ensure that the challenges depend only on a single challenge per slot. Had we infused the entire βT\beta_T (as we do into RC{\cal RC}), the challenges would depend on all blocks (as μrc_sp\mu_{{\sf rc\_sp}} depends on RC{\cal RC} which infuses all blocks) and we would not get security against double dipping.

Design Choice 3: Why Infusing the First Block?

Recall that by our Objective 1.(a) we want challenges to be only revealed when necessary and (b) to be immutable once revealed.

While (b) suggest to infuse the first possible block so it's buried once revealed, for (a) it would be better to use the latest possible block. We go with the first block to achieve (b), and by running a VDF on top of the block we also achieve objective (a).

Design Choice 4: Upper and Lower Bounds on Blocks per Slot

The target number of blocks per slot is 32, and there's an upper bound of 64 and lower bound of 16. These bounds make some attacks more difficult. In normal deployment the number of blocks will be close to its expectation, so these bounds should basically never be reached. The lower bound is required to bound the efficacy of double-dipping as sketched in §2.2, while the upper bound is necessary to prevent replotting attacks as explained in §1.8.3.

Objective 2: The Trunk is (almost) Ungrindeable

To prevent grinding, the only decision that influences the trunk should be whether to add a block or not. We need one exception to this rule: the time-stamps (in blocks in the foliage) are used to recalibrate the time parameter which determines the numbers of VDFs steps per slot in the trunk. This gives a minor grinding opportunity, to further limit the usability of this for attacks, the window used to calibrate the time parameter is not simply the previous epoch, but shifted XXXXXX back so the relevant time-stamp is already buried deep in the chain.

Objective 3: CC{\cal CC} (almost) only Depends on the First Block

To limit the impact of double-dipping we use correlated randomness [BDK+19]). For this the challenge chain CC{\cal CC} should only depend on the first block in every slot. If this was the case, this would allow for long-range replotting attacks. For this reason, once every sub-epoch (approx 2h) the rewards chain is infused to the challenge chain.

5.6 The Foliage

Whenever a farmer finds a winning PoSpace they can create a block β={βF,βT}\beta=\{\beta_F,\beta_T\} which contains the trunk block βT\beta_T as discussed above, and a foliage block

βF={data,μF}\beta_F=\{{\sf data},\mu_F\}

which contains the payload of the block data{\sf data} (transactions, a time-stamp) and a signature (using the key S.skS.sk as for murc_spmu_{\sf rc\_sp}, cf.§5.3})

μFSig.sign(S.sk,(βT,βF))\mu_F \gets {{\sf Sig.sign}}(S.sk,(\beta_T,\beta'_F))

that links this foliage block to the chain. It signs the (hashes of the) current trunk block βT\beta_T as well as the foliage block βF\beta'_F from the last transaction block as discussed below.

While every valid trunk block will typically be infused into RC{\cal RC} (unless the time lord is malicious, the block arrives too late to be infused or the slot is already at its 64 block upper limit), only a subset of the foliage blocks are included in the foliage chain FC{\cal FC} for reasons outlined below:

Objective 4: Block Arrival vs. Creation Time

We want blocks to arrive at a rather high frequency (9.3759.375 seconds on average) to achieve fast confirmation. At the same time we want to give sufficient time (28.12528.125 to 37.537.5 seconds between signage and infusion points of a block) for block creation to prevent oprhan blocks.

Objective 5: Sequential Transaction Blocks

Every block of transactions added must refer to the previous block of transactions. This way we avoid having to deal with transactions that are invalid due to previous transactions that were added but were not known to the creator of the current transaction block.

Design Choice 5: Foliage

To achieve the above objectives, we let farmers who found a winning PoSpace and can create a block always create a foliage block referring to the last transaction block before the signage point of their block. The time lord will add the foliage of a block – and thus make this block a transaction block – if no other transaction block was infused between the signage and infusion point of that block.

5.7 Fraction of Transaction Blocks

With the above rule, we expect one transaction block every (1e0.51+4)5.54\left(\frac{1}{e^{0.5}-1}+4\right)\approx 5.54 slots, that's one every 51.9551.95 seconds and corresponds to 36%36\% of all blocks.

For the interested reader, let us shortly outline how the above is determined. The signage points of consecutive transactions blocks must be at least 4 points apart as a block with signage point rc_spi{\sf rc\_sp}_i is infused somewhere between rc_spi+3{\sf rc\_sp}_{i+3} and rc_spi+4{\sf rc\_sp}_{i+4}. The gap can be bigger than 44 points if no block is found in response to rc_spi+4{\sf rc\_sp}_{i+4} and potentially more points after that. The expected number of blocks found for each slot is 0.50.5 (32 block target for 64 points). The number of blocks found for each slot is Poisson distributed with expectation 0.50.5 (3232 block target for 6464 points). With this distribution, the expected number of consecutive points with no blocks is 1e0.51\frac{1}{e^{0.5}-1}.