> ## Documentation Index
> Fetch the complete documentation index at: https://docs.intention.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# 儲存與證明

> 已提交狀態如何持久化到三個 RocksDB 儲存區中，如何由帶版本的 Merkle 樹和累加器提供認證，以及如何隨時間修剪。

已提交狀態必須滿足兩項相互拉扯的需求。執行需要快速拿到某個鍵的當前值，每秒數百萬次。驗證需要一份證明，說明在某個特定版本上該值確實就是網路所聲稱的那個。用同一種結構同時服務兩邊，只會兩件事都做不好。

所以儲存把問題拆到彼此獨立的儲存區裡，每一個都按自己的存取模式來塑形。

<h2 id="three-stores">
  三個儲存區
</h2>

<div className="dg" data-dg="storage-stores">
  <div className="dg-c" style={{aspectRatio:"720 / 332"}}>
    <svg className="dg-w" viewBox="0 0 720 332" aria-hidden="true">
      <path className="dg-wire dg--green dg-dash" d="M 434.00 48.00 L 459.60 48.00" />

      <path className="dg-head dg--green" d="M 466.00 48.00 L 459.60 52.40 L 459.60 43.60 Z" />

      <path className="dg-wire dg--green dg-dash" d="M 434.00 144.00 L 459.60 144.00" />

      <path className="dg-head dg--green" d="M 466.00 144.00 L 459.60 148.40 L 459.60 139.60 Z" />

      <path className="dg-wire dg--green dg-dash" d="M 434.00 240.00 L 459.60 240.00" />

      <path className="dg-head dg--green" d="M 466.00 240.00 L 459.60 244.40 L 459.60 235.60 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 172.54 53.91" />

      <path className="dg-head dg--blue" d="M 175.00 48.00 L 176.60 55.60 L 168.48 52.22 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 168.60 144.00" />

      <path className="dg-head dg--blue" d="M 175.00 144.00 L 168.60 148.40 L 168.60 139.60 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 172.54 234.09" />

      <path className="dg-head dg--blue" d="M 175.00 240.00 L 168.48 235.78 L 176.60 232.40 Z" />
    </svg>

    <div className="dg-b dg--blue" style={{left:"0.0000%",top:"31.3253%",width:"18.0556%",height:"24.0964%"}}><span className="dg-t">已提交區塊</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"2.4096%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">帳本儲存區</span><span className="dg-s">交易 · 輸出 · 事件 · 寫入集 · 累加器 · 區塊中繼資料</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"2.4096%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">重放與稽核</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"31.3253%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">狀態 KV 儲存區</span><span className="dg-s">當前值與歷史值，分成十六個分片，高頻狀態另有一層</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"31.3253%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">查詢與執行</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"60.2410%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">狀態 Merkle 儲存區</span><span className="dg-s">一棵帶版本的稀疏 Merkle 樹，外加追蹤被取代節點的索引</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"60.2410%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">驗證 — 證明</span></div>
    <div className="dg-free" style={{left:"0.0000%",top:"89.1566%",width:"100.0000%"}}><div className="dg-n">只要取值的讀取，不必為樹走訪付出代價；而一份證明，也不必從一個專為點查詢最佳化的儲存區裡重建出來。</div></div>
  </div>
</div>

**帳本儲存區**保存鏈的歷史：交易、交易的輸出與輔助資料、事件、寫入集、區塊中繼資料，以及累加器。這是你用來重放的東西。

**狀態 KV 儲存區**保存狀態值，按鍵和版本編址。這是執行與查詢讀取的東西。它**分成十六個分片**，因此一個區塊的寫入會散到十六個相互獨立的 RocksDB 實例上，不必爭搶同一個。高頻存取的狀態另外保存在自己的一層裡，這樣活躍市場的工作集，就不必從鏈上有史以來存過的所有東西裡去撈。

**狀態 Merkle 儲存區**保存認證結構：用來證明某個值的樹節點，以及追蹤哪些節點已被取代的索引。

拆開的好處是：只要取值的讀取，不必為樹走訪付出代價；而一份證明，也不必從一個專為點查詢最佳化的儲存區裡重建出來。

<h2 id="authentication">
  認證
</h2>

兩種 Merkle 結構做的是不同的工作。

<div className="dg" data-dg="storage-proofs">
  <div className="dg-c" style={{aspectRatio:"720 / 400"}}>
    <svg className="dg-w" viewBox="0 0 720 400" aria-hidden="true">
      <path className="dg-wire" d="M 173.50 98.50 L 173.50 110.10" />

      <path className="dg-head" d="M 173.50 116.50 L 169.10 110.10 L 177.90 110.10 Z" />

      <path className="dg-wire" d="M 173.50 169.00 L 173.50 180.60" />

      <path className="dg-head" d="M 173.50 187.00 L 169.10 180.60 L 177.90 180.60 Z" />

      <path className="dg-wire" d="M 173.50 239.50 L 173.50 251.10" />

      <path className="dg-head" d="M 173.50 257.50 L 169.10 251.10 L 177.90 251.10 Z" />

      <path className="dg-wire" d="M 546.50 122.00 L 546.50 133.60" />

      <path className="dg-head" d="M 546.50 140.00 L 542.10 133.60 L 550.90 133.60 Z" />

      <path className="dg-wire" d="M 546.50 216.00 L 546.50 227.60" />

      <path className="dg-head" d="M 546.50 234.00 L 542.10 227.60 L 550.90 227.60 Z" />
    </svg>

    <div className="dg-band" style={{left:"0.0000%",top:"6.5000%",width:"48.1944%",height:"72.5000%"}}><span className="dg-cap">帶版本的稀疏 Merkle 樹</span></div>
    <div className="dg-band" style={{left:"51.8056%",top:"6.5000%",width:"48.1944%",height:"72.5000%"}}><span className="dg-cap">累加器</span></div>
    <div className="dg-b dg--blue" style={{left:"2.2222%",top:"12.5000%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">你的鍵及其值</span></div>
    <div className="dg-b" style={{left:"2.2222%",top:"30.1250%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">兄弟節點雜湊</span></div>
    <div className="dg-b" style={{left:"2.2222%",top:"47.7500%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">兄弟節點雜湊</span></div>
    <div className="dg-b dg--green" style={{left:"2.2222%",top:"65.3750%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">狀態根，由共識提交</span></div>
    <div className="dg-b dg--blue" style={{left:"54.0278%",top:"12.5000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">你的交易，或一個事件</span></div>
    <div className="dg-b" style={{left:"54.0278%",top:"36.0000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">交易累加器 · 事件累加器</span><span className="dg-s">各自承諾到目前為止按順序包含的全部內容</span></div>
    <div className="dg-b dg--green" style={{left:"54.0278%",top:"59.5000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">帳本根，由共識提交</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"0.0000%",top:"83.0000%",width:"100.0000%",height:"14.5000%"}}><span className="dg-s">樹證明某個值曾是什麼；累加器證明發生了什麼、以何種順序發生。兩者合起來，「這筆交易在鏈上的這個位置」不必持有整條鏈就能證明。</span></div>
  </div>
</div>

**一棵帶版本的稀疏 Merkle 樹**為狀態提供認證。每個鍵的位置由自己的雜湊決定，而樹的每個版本都共享那些沒有變化的節點：所以在一個區塊裡寫入一個鍵，增加的是一條路徑，不是一棵樹。某個鍵在某個版本上的證明，就是從那個鍵的葉子，一路走到網路提交的那個根。

**累加器**為順序提供認證。一個累加交易，一個累加事件，各自產生一個根，承諾了到目前為止按順序包含的全部內容。有了它，「這筆交易在鏈上的這個位置」不必持有整條鏈就能證明。

兩者之間的分工：狀態樹證明**某個值曾是什麼**，累加器證明**發生了什麼以及以何種順序發生**。

<h3 id="speculative-state">
  推測狀態
</h3>

一個區塊的結果，在提交之前就已經存在。與其先寫進持久化的樹、區塊沒提交再撤回來，未提交的狀態改放在一層**記憶體內稀疏 Merkle 覆蓋層**裡，疊在最近一個已提交版本之上。

執行透過這層覆蓋讀取，看到的是一致的視圖。區塊提交了，覆蓋層就物化下來；沒有提交，覆蓋層直接丟掉，持久化儲存從頭到尾沒被碰過。正是這一點，讓推測執行不會在儲存裡留下殘渣。

<h3 id="caching">
  快取
</h3>

樹節點在兩個層次上快取：上層是一個感知版本的快取，保持近期版本可定址；底下再一層最近最少使用（LRU）快取。一條交易鏈的存取模式——一小組每個區塊都會碰到的熱點鍵，加上一條極少碰到的長尾——正是這類快取針對的形態。

<h2 id="pruning">
  修剪
</h2>

永久保留每一個版本是一種選擇，不是一項要求。三個相互獨立的修剪器分別針對這三個儲存區運行，各有自己的保留策略：一個針對帳本，一個針對狀態值，一個針對 Merkle 節點。

Merkle 修剪器和狀態值修剪器靠**過期索引**驅動，而這些索引是和資料同時寫下去的。某個版本一旦取代了某個節點或某個值，被取代的條目就會在該版本上記為過期。於是修剪變成對一個索引做範圍掃描，不必到處搜尋垃圾：寫入方早就講明了什麼會變成可回收，以及在什麼時候。

<Note>
  保留策略是維運上的決定，而且有實際後果。修剪得積極的節點，當前狀態提供得很有效率，卻答不了歷史查詢，也沒辦法替一個從更早處起步的節點做狀態同步。歸檔節點保留一切，並為此付出代價。參見[運行節點](/zh-Hant/developers/run-a-node)。
</Note>

<h2 id="backup-and-restore">
  備份與還原
</h2>

這些儲存區可以獨立於運行中的節點備份和還原。正因如此，才有辦法從快照架起一個節點，不必從創世開始重放；也才有辦法拿已提交的根去驗證還原後的節點狀態，而不是只能選擇相信那份備份。

<h2 id="where-to-go-next">
  後續閱讀
</h2>

<CardGroup cols={2}>
  <Card title="狀態同步" href="/zh-Hant/protocol/architecture/state/sync">
    節點怎麼不重放全部歷史就追上這條鏈。
  </Card>

  <Card title="狀態模型" href="/zh-Hant/protocol/architecture/state/model">
    儲存的是什麼，以及哪一種表示是權威。
  </Card>

  <Card title="索引器" href="/zh-Hant/protocol/architecture/indexer">
    從已提交紀錄中重建歷史。
  </Card>

  <Card title="運行節點" href="/zh-Hant/developers/run-a-node">
    節點角色，以及如何諮詢節點營運事宜。
  </Card>
</CardGroup>
