進入的路徑
已簽署交易
驗證簽章 · 格式 · 帳戶狀態 · 發送方付不付得起
丟棄,並回傳原因不會悄無聲息 — 提交者知道為什麼
交易儲存區
向對等節點廣播
批次組成,然後共識
驗證廉價、而且只在本地做,因此下游昂貴的資源只花在真正可能執行的交易上。
拒絕
接受
交易如何暫存
通過的交易不是放在一個扁平佇列裡。儲存區在同一個集合之上維護了若干視圖,每個視圖回答一個不同的問題。同一份已接受交易集合在它之上的五個視圖,不是五條佇列
按帳戶排序對這個發送方來說,下一筆該是哪一筆?
優先級索引在所有發送方之間,應該先把什麼交給共識?
過期索引什麼已經過了期限?
時間線索引這個對等節點還沒聽說過什麼?
停放區什麼格式正確,但還不具備資格?
停放區正是串接缺陷暴露的地方:交易合法、卻還排不到發送方的下一位,會被停放而不是拒絕 — 前面的缺口一填上就立刻可用。
停放區最值得注意,因為有一類串接缺陷正是在這裡暴露出來的。交易可以完全合法,卻仍然排不到發送方佇列的下一位,最常見的原因是同一帳戶更早的一筆交易還沒到,或還沒提交。這種交易會停放起來,不會拒絕:交易仍然留著,前面的缺口一填上就立刻可用。所以用戶端亂序提交,遇到的是延遲,不是失敗;但用戶端如果始終不去補上缺口,這些工作就會一直停在那裡,直到過期。
時間線索引讓對等傳播變成增量的。每個對等節點都記著「已經服務到時間線的哪個位置」,所以一次廣播只發這個節點缺的部分,不會把整個池子重發一遍。時間線分桶存放,不是一條單佇列,流量很大的發送方因此霸佔不了每一個廣播位。
傳播與公平
各節點不是各自獨立得知交易的。節點一旦接受某筆交易,就把它廣播給對等節點,而對等節點並非一視同仁:上游對等節點優先,好讓交易朝著能處理它的驗證者移動,不在網路中均勻擴散。 公平性按近期歷史追蹤,不是逐條訊息強制。記憶池維護一份滾動紀錄,記下最近是哪些發送方、哪些類型的流量吃掉了容量,再據此調整接下來先服務誰。正是這個機制,讓某個帳戶的下單撤單風暴擠不掉網路其餘部分,同時又不必按帳戶設硬性速率限制——那種限制會誤傷正常的造市。交接給共識
共識不是從記憶池裡一筆一筆取交易。交易先匯集成批次,批次在背景傳播給各驗證者,並逐一得到確認,直到發起方能證明網路中已有足夠多的節點持有這個批次。到那時,區塊提案才能引用它。 結果是,區塊提案攜帶的是批次摘要,不是交易本體,所以吞吐量上升時共識訊息的大小保持不變;已提交的區塊也總是可重放的,因為背後的資料在被引用之前就已經證明可用。這個證明怎麼形成、怎麼使用,參見 IntentionBFT。這也是為什麼記憶池的准入不等於納入區塊。交易獲准進池、寫入、廣播出去,也只是進了佇列,還沒有排序。共識提交包含它的那個區塊之前,一筆交易的命運沒有任何一部分是確定的。
這對用戶端意味著什麼
- 提交時被拒絕是有資訊量的。 拒絕發生在交易存下來之前,給出的原因說的是用戶端修得掉的東西。
- 沉默不等於拒絕。 交易可能正停放在用戶端自己製造的缺口後面。要追蹤自己提交了什麼、又上鏈了什麼,不要把收不到確認當成被丟棄。
- 帳戶內部的順序重要,帳戶之間的順序不重要。 同一個發送方的兩筆交易有確定的先後。不同發送方的兩筆交易由共識排序,而不是由誰先提交決定。
- 撤單在記憶池裡沒有特權。 撤單的優先級來自內核執行:同一個區塊內,撤單先於主動吃單執行。這不是排隊帶來的性質。