> ## 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.

# 記憶池

> 在共識把交易提交進區塊之前，交易如何被准入、暫存、排序和傳播。

記憶池（mempool）站在已簽署交易和已提交區塊之間，決定什麼值得留存、同一個發送方的交易按什麼順序變得可用、哪些對等節點會聽說某筆交易，以及需求超過容量時該丟掉什麼。

對交易網路來說，這是承重結構，不是附屬品。下單和撤單流量突發、集中在少數發送方，而且對延遲的敏感是不對稱的：撤單遲到，比訂單遲到更糟。下面這些結構之所以存在，就是因為單一的先進先出佇列上述任何一點都應付不好。

<h2 id="the-path-in">
  進入的路徑
</h2>

<div className="dg" data-dg="mempool-admission">
  <div className="dg-c" style={{aspectRatio:"720 / 252"}}>
    <svg className="dg-w" viewBox="0 0 720 252" aria-hidden="true">
      <path className="dg-wire dg--blue" d="M 124.00 145.00 L 145.60 145.00" />

      <path className="dg-head dg--blue" d="M 152.00 145.00 L 145.60 149.40 L 145.60 140.60 Z" />

      <path className="dg-wire dg--orange" d="M 340.00 145.00 L 356.00 145.00 L 356.00 46.00 L 365.60 46.00" />

      <path className="dg-head dg--orange" d="M 372.00 46.00 L 365.60 50.40 L 365.60 41.60 Z" />

      <path className="dg-wire dg--sky" d="M 340.00 145.00 L 365.60 145.00" />

      <path className="dg-head dg--sky" d="M 372.00 145.00 L 365.60 149.40 L 365.60 140.60 Z" />

      <path className="dg-wire dg--sky dg-soft" d="M 541.00 145.00 L 566.40 120.45" />

      <path className="dg-head dg--sky" d="M 571.00 116.00 L 569.46 123.61 L 563.34 117.28 Z" />

      <path className="dg-wire dg--sky dg-soft" d="M 541.00 145.00 L 566.55 171.40" />

      <path className="dg-head dg--sky" d="M 571.00 176.00 L 563.39 174.46 L 569.71 168.34 Z" />
    </svg>

    <div className="dg-b dg--blue" style={{left:"0.0000%",top:"46.8254%",width:"16.6667%",height:"21.4286%"}}><span className="dg-t">已簽署交易</span></div>
    <div className="dg-b dg--yellow" style={{left:"21.6667%",top:"42.8571%",width:"25.0000%",height:"29.3651%"}}><span className="dg-t">驗證</span><span className="dg-s">簽章 · 格式 · 帳戶狀態 · 發送方付不付得起</span></div>
    <div className="dg-b dg--orange dg-left" style={{left:"52.2222%",top:"7.9365%",width:"47.7778%",height:"20.6349%"}}><span className="dg-t">丟棄，並回傳原因</span><span className="dg-s">不會悄無聲息 — 提交者知道為什麼</span></div>
    <div className="dg-b dg--sky" style={{left:"52.2222%",top:"46.8254%",width:"22.2222%",height:"21.4286%"}}><span className="dg-t">交易儲存區</span></div>
    <div className="dg-b dg--sky" style={{left:"80.0000%",top:"36.5079%",width:"20.0000%",height:"19.0476%"}}><span className="dg-t">向對等節點廣播</span></div>
    <div className="dg-b dg--sky" style={{left:"80.0000%",top:"60.3175%",width:"20.0000%",height:"19.0476%"}}><span className="dg-t">批次組成，然後共識</span></div>
    <div className="dg-free" style={{left:"0.0000%",top:"85.7143%",width:"100.0000%"}}><div className="dg-n">驗證廉價、而且只在本地做，因此下游昂貴的資源只花在真正可能執行的交易上。</div></div>
    <div className="dg-lbl" style={{left:"49.4444%",top:"36.5079%"}}>拒絕</div>
    <div className="dg-lbl" style={{left:"49.4444%",top:"51.9841%"}}>接受</div>
  </div>
</div>

交易存下來之前先經過驗證。驗證廉價，而且只在本地做——簽章、格式、帳戶狀態，以及發送方付不付得起自己請求的東西——之所以要有這一關，是為了讓下游昂貴的資源只花在真正可能執行的交易上。這裡的拒絕會把原因回傳給提交者，不會讓交易悄無聲息地消失。

<h2 id="how-transactions-are-held">
  交易如何暫存
</h2>

通過的交易不是放在一個扁平佇列裡。儲存區在同一個集合之上維護了若干視圖，每個視圖回答一個不同的問題。

<div className="dg" data-dg="mempool-views">
  <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-soft" d="M 195.00 148.00 L 245.00 36.00" />

      <path className="dg-wire dg-soft" d="M 195.00 148.00 L 245.00 92.00" />

      <path className="dg-wire dg-soft" d="M 195.00 148.00 L 245.00 148.00" />

      <path className="dg-wire dg-soft" d="M 195.00 148.00 L 245.00 204.00" />

      <path className="dg-wire dg-soft" d="M 195.00 148.00 L 245.00 260.00" />
    </svg>

    <div className="dg-b dg--blue dg-round" style={{left:"0.0000%",top:"31.0241%",width:"26.3889%",height:"27.1084%"}}><span className="dg-t">同一份已接受交易集合</span><span className="dg-s">在它之上的五個視圖，不是五條佇列</span></div>
    <div className="dg-b dg--sky" style={{left:"34.7222%",top:"3.0120%",width:"65.2778%",height:"15.6627%"}}><span className="dg-t">按帳戶排序</span><span className="dg-s">對這個發送方來說，下一筆該是哪一筆？</span></div>
    <div className="dg-b dg--sky" style={{left:"34.7222%",top:"19.8795%",width:"65.2778%",height:"15.6627%"}}><span className="dg-t">優先級索引</span><span className="dg-s">在所有發送方之間，應該先把什麼交給共識？</span></div>
    <div className="dg-b dg--sky" style={{left:"34.7222%",top:"36.7470%",width:"65.2778%",height:"15.6627%"}}><span className="dg-t">過期索引</span><span className="dg-s">什麼已經過了期限？</span></div>
    <div className="dg-b dg--sky" style={{left:"34.7222%",top:"53.6145%",width:"65.2778%",height:"15.6627%"}}><span className="dg-t">時間線索引</span><span className="dg-s">這個對等節點還沒聽說過什麼？</span></div>
    <div className="dg-b dg--yellow" style={{left:"34.7222%",top:"70.4819%",width:"65.2778%",height:"15.6627%"}}><span className="dg-t">停放區</span><span className="dg-s">什麼格式正確，但還不具備資格？</span></div>
    <div className="dg-free" style={{left:"0.0000%",top:"89.1566%",width:"100.0000%"}}><div className="dg-n">停放區正是串接缺陷暴露的地方：交易合法、卻還排不到發送方的下一位，會被停放而不是拒絕 — 前面的缺口一填上就立刻可用。</div></div>
  </div>
</div>

| 視圖        | 回答的問題                |
| --------- | -------------------- |
| **按帳戶排序** | 對這個發送方來說，下一筆該是哪一筆？   |
| **優先級索引** | 在所有發送方之間，應該先把什麼交給共識？ |
| **過期索引**  | 什麼已經過了期限，應該被移除？      |
| **時間線索引** | 這個對等節點還沒聽說過什麼？       |
| **停放區**   | 什麼格式正確，但還不具備資格？      |

**停放區**最值得注意，因為有一類串接缺陷正是在這裡暴露出來的。交易可以完全合法，卻仍然排不到發送方佇列的下一位，最常見的原因是同一帳戶更早的一筆交易還沒到，或還沒提交。這種交易會停放起來，不會拒絕：交易仍然留著，前面的缺口一填上就立刻可用。所以用戶端亂序提交，遇到的是延遲，不是失敗；但用戶端如果始終不去補上缺口，這些工作就會一直停在那裡，直到過期。

**時間線索引**讓對等傳播變成增量的。每個對等節點都記著「已經服務到時間線的哪個位置」，所以一次廣播只發這個節點缺的部分，不會把整個池子重發一遍。時間線分桶存放，不是一條單佇列，流量很大的發送方因此霸佔不了每一個廣播位。

<h2 id="dissemination-and-fairness">
  傳播與公平
</h2>

各節點不是各自獨立得知交易的。節點一旦接受某筆交易，就把它廣播給對等節點，而對等節點並非一視同仁：上游對等節點優先，好讓交易朝著能處理它的驗證者移動，不在網路中均勻擴散。

公平性按近期歷史追蹤，不是逐條訊息強制。記憶池維護一份滾動紀錄，記下最近是哪些發送方、哪些類型的流量吃掉了容量，再據此調整接下來先服務誰。正是這個機制，讓某個帳戶的下單撤單風暴擠不掉網路其餘部分，同時又不必按帳戶設硬性速率限制——那種限制會誤傷正常的造市。

<h2 id="handoff-to-consensus">
  交接給共識
</h2>

共識不是從記憶池裡一筆一筆取交易。交易先匯集成**批次**，批次在背景傳播給各驗證者，並逐一得到確認，直到發起方能證明網路中已有足夠多的節點持有這個批次。到那時，區塊提案才能引用它。

結果是，區塊提案攜帶的是批次摘要，不是交易本體，所以吞吐量上升時共識訊息的大小保持不變；已提交的區塊也總是可重放的，因為背後的資料在被引用之前就已經證明可用。這個證明怎麼形成、怎麼使用，參見 [IntentionBFT](/zh-Hant/protocol/architecture/intention-bft)。

<Note>
  這也是為什麼記憶池的准入不等於納入區塊。交易獲准進池、寫入、廣播出去，也只是進了佇列，還沒有排序。共識提交包含它的那個區塊之前，一筆交易的命運沒有任何一部分是確定的。
</Note>

<h2 id="what-this-means-for-a-client">
  這對用戶端意味著什麼
</h2>

* **提交時被拒絕是有資訊量的。** 拒絕發生在交易存下來之前，給出的原因說的是用戶端修得掉的東西。
* **沉默不等於拒絕。** 交易可能正停放在用戶端自己製造的缺口後面。要追蹤自己提交了什麼、又上鏈了什麼，不要把收不到確認當成被丟棄。
* **帳戶內部的順序重要，帳戶之間的順序不重要。** 同一個發送方的兩筆交易有確定的先後。不同發送方的兩筆交易由共識排序，而不是由誰先提交決定。
* **撤單在記憶池裡沒有特權。** 撤單的優先級來自[內核執行](/zh-Hant/protocol/architecture/kernel)：同一個區塊內，撤單先於主動吃單執行。這不是排隊帶來的性質。
