mirror of https://github.com/zcash/zips.git
Merge pull request #523 from daira/zip-221-pseudocode
ZIP 221: update pseudocode for NU5, and fix a typo
This commit is contained in:
commit
1458078183
|
@ -362,7 +362,6 @@ License: MIT</pre>
|
|||
<p>Once the MMR has been generated, we produce <code>hashChainHistoryRoot</code>, which we define as the BLAKE2b-256 digest of the serialization of the root node.</p>
|
||||
</section>
|
||||
<section id="tree-nodes-and-hashing-pseudocode"><h3><span class="section-heading">Tree nodes and hashing (pseudocode)</span><span class="section-anchor"> <a rel="bookmark" href="#tree-nodes-and-hashing-pseudocode"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h3>
|
||||
<p>Note that this pseudocode reflects the specification prior to NU5 activation.</p>
|
||||
<pre data-language="python"><span class="k">def</span> <span class="nf">H</span><span class="p">(</span><span class="n">msg</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">,</span> <span class="n">consensusBranchId</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="n">blake2b256</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">personalization</span><span class="o">=</span><span class="sa">b</span><span class="s1">'ZcashHistory'</span> <span class="o">+</span> <span class="n">consensusBranchId</span><span class="p">)</span>
|
||||
|
||||
|
@ -377,12 +376,16 @@ License: MIT</pre>
|
|||
<span class="n">nLatestTimestamp</span><span class="p">:</span> <span class="nb">int</span>
|
||||
<span class="n">nEarliestTargetBits</span><span class="p">:</span> <span class="nb">int</span>
|
||||
<span class="n">nLatestTargetBits</span><span class="p">:</span> <span class="nb">int</span>
|
||||
<span class="n">hashEarliestSaplingRoot</span><span class="p">:</span> <span class="nb">bytes</span> <span class="c1"># left child's sapling root</span>
|
||||
<span class="n">hashLatestSaplingRoot</span><span class="p">:</span> <span class="nb">bytes</span> <span class="c1"># right child's sapling root</span>
|
||||
<span class="n">hashEarliestSaplingRoot</span><span class="p">:</span> <span class="nb">bytes</span> <span class="c1"># left child's Sapling root</span>
|
||||
<span class="n">hashLatestSaplingRoot</span><span class="p">:</span> <span class="nb">bytes</span> <span class="c1"># right child's Sapling root</span>
|
||||
<span class="n">nSubTreeTotalWork</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># total difficulty accumulated within each subtree</span>
|
||||
<span class="n">nEarliestHeight</span><span class="p">:</span> <span class="nb">int</span>
|
||||
<span class="n">nLatestHeight</span><span class="p">:</span> <span class="nb">int</span>
|
||||
<span class="n">nSaplingTxCount</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># number of Sapling transactions in block</span>
|
||||
<span class="c1"># NU5 only.</span>
|
||||
<span class="n">hashEarliestOrchardRoot</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bytes</span><span class="p">]</span> <span class="c1"># left child's Orchard root</span>
|
||||
<span class="n">hashLatestOrchardRoot</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">bytes</span><span class="p">]</span> <span class="c1"># right child's Orchard root</span>
|
||||
<span class="n">nSaplingTxCount</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># number of Orchard transactions in block</span>
|
||||
|
||||
<span class="n">consensusBranchId</span><span class="p">:</span> <span class="nb">bytes</span>
|
||||
|
||||
|
@ -403,12 +406,14 @@ License: MIT</pre>
|
|||
<span class="n">nEarliestHeight</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">height</span><span class="p">,</span>
|
||||
<span class="n">nLatestHeight</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">height</span><span class="p">,</span>
|
||||
<span class="n">nSaplingTxCount</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">sapling_tx_count</span><span class="p">,</span>
|
||||
<span class="n">hashEarliestOrchardRoot</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">orchard_root</span><span class="p">,</span>
|
||||
<span class="n">hashLatestOrchardRoot</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">orchard_root</span><span class="p">,</span>
|
||||
<span class="n">nOrchardTxCount</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">orchard_tx_count</span><span class="p">,</span>
|
||||
<span class="n">consensusBranchId</span><span class="o">=</span><span class="n">block</span><span class="o">.</span><span class="n">consensusBranchId</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
<span class="sd">'''serializes a node'''</span>
|
||||
<span class="k">return</span> <span class="p">(</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">hashSubtreeCommitment</span>
|
||||
<span class="n">buf</span> <span class="o">=</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">hashSubtreeCommitment</span>
|
||||
<span class="o">+</span> <span class="n">serialize_uint32</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nEarliestTimestamp</span><span class="p">)</span>
|
||||
<span class="o">+</span> <span class="n">serialize_uint32</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nLatestTimestamp</span><span class="p">)</span>
|
||||
<span class="o">+</span> <span class="n">serialize_uint32</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nEarliestTargetBits</span><span class="p">)</span>
|
||||
|
@ -419,6 +424,11 @@ License: MIT</pre>
|
|||
<span class="o">+</span> <span class="n">serialize_compact_uint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nEarliestHeight</span><span class="p">)</span>
|
||||
<span class="o">+</span> <span class="n">serialize_compact_uint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nLatestHeight</span><span class="p">)</span>
|
||||
<span class="o">+</span> <span class="n">serialize_compact_uint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nSaplingTxCount</span><span class="p">))</span>
|
||||
<span class="k">if</span> <span class="n">hashEarliestOrchardRoot</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
|
||||
<span class="n">buf</span> <span class="o">+=</span> <span class="p">(</span><span class="n">hashEarliestOrchardRoot</span>
|
||||
<span class="o">+</span> <span class="n">hashLatestOrchardRoot</span>
|
||||
<span class="o">+</span> <span class="n">serialize_compact_uint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nOrchardTxCount</span><span class="p">))</span>
|
||||
<span class="k">return</span> <span class="n">buf</span>
|
||||
|
||||
|
||||
<span class="k">def</span> <span class="nf">make_parent</span><span class="p">(</span>
|
||||
|
@ -439,6 +449,11 @@ License: MIT</pre>
|
|||
<span class="n">nEarliestHeight</span><span class="o">=</span><span class="n">left_child</span><span class="o">.</span><span class="n">nEarliestHeight</span><span class="p">,</span>
|
||||
<span class="n">nLatestHeight</span><span class="o">=</span><span class="n">right_child</span><span class="o">.</span><span class="n">nLatestHeight</span><span class="p">,</span>
|
||||
<span class="n">nSaplingTxCount</span><span class="o">=</span><span class="n">left_child</span><span class="o">.</span><span class="n">nSaplingTxCount</span> <span class="o">+</span> <span class="n">right_child</span><span class="o">.</span><span class="n">nSaplingTxCount</span><span class="p">,</span>
|
||||
<span class="n">hashEarliestOrchardRoot</span><span class="o">=</span><span class="n">left_child</span><span class="o">.</span><span class="n">orchard_root</span><span class="p">,</span>
|
||||
<span class="n">hashLatestOrchardRoot</span><span class="o">=</span><span class="n">right_child</span><span class="o">.</span><span class="n">orchard_root</span><span class="p">,</span>
|
||||
<span class="n">nOrchardTxCount</span><span class="o">=</span><span class="p">(</span><span class="n">left_child</span><span class="o">.</span><span class="n">nOrchardTxCount</span> <span class="o">+</span> <span class="n">right_child</span><span class="o">.</span><span class="n">nOrchardTxCount</span>
|
||||
<span class="k">if</span> <span class="n">left_child</span><span class="o">.</span><span class="n">nOrchardTxCount</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">right_child</span><span class="o">.</span><span class="n">nOrchardTxCount</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span>
|
||||
<span class="k">else</span> <span class="bp">None</span><span class="p">),</span>
|
||||
<span class="n">consensusBranchId</span><span class="o">=</span><span class="n">left_child</span><span class="o">.</span><span class="n">consensusBranchId</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">make_root_commitment</span><span class="p">(</span><span class="n">root</span><span class="p">:</span> <span class="n">ZcashMMRNode</span><span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
|
||||
|
@ -556,7 +571,7 @@ License: MIT</pre>
|
|||
<section id="rationale"><h2><span class="section-heading">Rationale</span><span class="section-anchor"> <a rel="bookmark" href="#rationale"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h2>
|
||||
<section id="tree-nodes"><h3><span class="section-heading">Tree nodes</span><span class="section-anchor"> <a rel="bookmark" href="#tree-nodes"><img width="24" height="24" src="assets/images/section-anchor.png" alt=""></a></span></h3>
|
||||
<p>Nodes in the commitment tree are canonical and immutable. They are cheap to generate, as (with the exception of <code>nSaplingTxCount</code> and <code>nOrchardTxCount</code>) all metadata is already generated during block construction and/or checked during block validation. Nodes are relatively compact in memory. As of the original publication of this ZIP, approximately 140,000 blocks had elapsed since Sapling activation. Assuming a 164-byte commitment to each of these, we would have generated approximately 24 MB of additional storage cost for the set of leaf nodes (and an additional ~24 MB for storage of intermediate nodes).</p>
|
||||
<p><code>hashSubtreeCommitment</code> forms the strucuture of the commitment tree. Other metadata commitments were chosen to serve specific purposes. Originally variable-length commitments were placed last, so that most metadata in a node could be directly indexed. We considered using fixed-length commitments here, but opted for variable-length, in order to marginally reduce the memory requirements for managing and updating the commitment trees.</p>
|
||||
<p><code>hashSubtreeCommitment</code> forms the structure of the commitment tree. Other metadata commitments were chosen to serve specific purposes. Originally variable-length commitments were placed last, so that most metadata in a node could be directly indexed. We considered using fixed-length commitments here, but opted for variable-length, in order to marginally reduce the memory requirements for managing and updating the commitment trees.</p>
|
||||
<p>Orchard fields are placed last, in order to avoid complicating existing uses of the other fields.</p>
|
||||
<p>In leaf nodes, some information is repeated. We chose to do this so that leaf nodes could be treated identically to internal and root nodes for all algorithms and (de)serializers. Leaf nodes are easily identifiable, as they will show proof of work in the <code>hashSubtreeCommitment</code> field (which commits to the block hash for leaf nodes), and their block range (calculated as <code>nLatestHeight</code> - (<code>nEarliestHeight</code> - 1)) will be precisely 1.</p>
|
||||
<p>Personalized BLAKE2b-256 was selected to match existing Zcash conventions. Adding the consensus branch ID to the hash personalization string ensures that valid nodes from one consensus branch cannot be used to make false statements about parallel consensus branches.</p>
|
||||
|
|
28
zip-0221.rst
28
zip-0221.rst
|
@ -376,8 +376,6 @@ the BLAKE2b-256 digest of the serialization of the root node.
|
|||
Tree nodes and hashing (pseudocode)
|
||||
-----------------------------------
|
||||
|
||||
Note that this pseudocode reflects the specification prior to NU5 activation.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def H(msg: bytes, consensusBranchId: bytes) -> bytes:
|
||||
|
@ -394,12 +392,16 @@ Note that this pseudocode reflects the specification prior to NU5 activation.
|
|||
nLatestTimestamp: int
|
||||
nEarliestTargetBits: int
|
||||
nLatestTargetBits: int
|
||||
hashEarliestSaplingRoot: bytes # left child's sapling root
|
||||
hashLatestSaplingRoot: bytes # right child's sapling root
|
||||
hashEarliestSaplingRoot: bytes # left child's Sapling root
|
||||
hashLatestSaplingRoot: bytes # right child's Sapling root
|
||||
nSubTreeTotalWork: int # total difficulty accumulated within each subtree
|
||||
nEarliestHeight: int
|
||||
nLatestHeight: int
|
||||
nSaplingTxCount: int # number of Sapling transactions in block
|
||||
# NU5 only.
|
||||
hashEarliestOrchardRoot: Optional[bytes] # left child's Orchard root
|
||||
hashLatestOrchardRoot: Optional[bytes] # right child's Orchard root
|
||||
nSaplingTxCount: Optional[int] # number of Orchard transactions in block
|
||||
|
||||
consensusBranchId: bytes
|
||||
|
||||
|
@ -420,12 +422,14 @@ Note that this pseudocode reflects the specification prior to NU5 activation.
|
|||
nEarliestHeight=block.height,
|
||||
nLatestHeight=block.height,
|
||||
nSaplingTxCount=block.sapling_tx_count,
|
||||
hashEarliestOrchardRoot=block.orchard_root,
|
||||
hashLatestOrchardRoot=block.orchard_root,
|
||||
nOrchardTxCount=block.orchard_tx_count,
|
||||
consensusBranchId=block.consensusBranchId)
|
||||
|
||||
def serialize(self) -> bytes:
|
||||
'''serializes a node'''
|
||||
return (
|
||||
self.hashSubtreeCommitment
|
||||
buf = (self.hashSubtreeCommitment
|
||||
+ serialize_uint32(self.nEarliestTimestamp)
|
||||
+ serialize_uint32(self.nLatestTimestamp)
|
||||
+ serialize_uint32(self.nEarliestTargetBits)
|
||||
|
@ -436,6 +440,11 @@ Note that this pseudocode reflects the specification prior to NU5 activation.
|
|||
+ serialize_compact_uint(self.nEarliestHeight)
|
||||
+ serialize_compact_uint(self.nLatestHeight)
|
||||
+ serialize_compact_uint(self.nSaplingTxCount))
|
||||
if hashEarliestOrchardRoot is not None:
|
||||
buf += (hashEarliestOrchardRoot
|
||||
+ hashLatestOrchardRoot
|
||||
+ serialize_compact_uint(self.nOrchardTxCount))
|
||||
return buf
|
||||
|
||||
|
||||
def make_parent(
|
||||
|
@ -456,6 +465,11 @@ Note that this pseudocode reflects the specification prior to NU5 activation.
|
|||
nEarliestHeight=left_child.nEarliestHeight,
|
||||
nLatestHeight=right_child.nLatestHeight,
|
||||
nSaplingTxCount=left_child.nSaplingTxCount + right_child.nSaplingTxCount,
|
||||
hashEarliestOrchardRoot=left_child.orchard_root,
|
||||
hashLatestOrchardRoot=right_child.orchard_root,
|
||||
nOrchardTxCount=(left_child.nOrchardTxCount + right_child.nOrchardTxCount
|
||||
if left_child.nOrchardTxCount is not None and right_child.nOrchardTxCount is not None
|
||||
else None),
|
||||
consensusBranchId=left_child.consensusBranchId)
|
||||
|
||||
def make_root_commitment(root: ZcashMMRNode) -> bytes:
|
||||
|
@ -600,7 +614,7 @@ relatively compact in memory. As of the original publication of this ZIP, approx
|
|||
each of these, we would have generated approximately 24 MB of additional storage cost for
|
||||
the set of leaf nodes (and an additional ~24 MB for storage of intermediate nodes).
|
||||
|
||||
``hashSubtreeCommitment`` forms the strucuture of the commitment tree. Other metadata
|
||||
``hashSubtreeCommitment`` forms the structure of the commitment tree. Other metadata
|
||||
commitments were chosen to serve specific purposes. Originally variable-length commitments
|
||||
were placed last, so that most metadata in a node could be directly indexed. We considered
|
||||
using fixed-length commitments here, but opted for variable-length, in order to marginally
|
||||
|
|
Loading…
Reference in New Issue