Skip to main content
IntentionKernel 是已提交區塊變成交易狀態的地方。它不是一台執行任意程式的通用虛擬機器:它的指令集,就是衍生性商品交易場所需要的那一組金融操作,逐條列舉,每一條都有協議看得懂的既定效果。 正是這個區別,讓這個網路有資格對交易本身作出斷言。一條通用鏈只能告訴你某筆交易有簽章、而且沒有中止;它沒辦法告訴你:這筆交易撤掉的,是訂單簿上某個具體位置的某一筆具體訂單。因為呼叫的含義對它是不透明的。在這裡,含義就是指令本身。

封閉世界執行

把指令集封閉起來,只是內核重複了四次的同一個動作的一個實例。每一次,可能發生的事情都被提前枚舉完,落在集合之外的東西是被拒絕,而不是被處理。
操作
不在枚舉集合裡的 payload——在驗證階段被拒,不是執行期
剛才被要求做的究竟是什麼
真相
把每區塊工作集當成權威。它是日誌,引擎狀態才是來源
此刻什麼是真的
輸入
任何在兩台機器上會不同的東西:牆鐘、熵、浮點、雜湊序
換一個節點還是不是這些位元組
因果
無主的狀態變更。不屬於任何使用者交易的效果走系統通道,不是豁免
這一筆為什麼會發生
封閉的是
拒絕的是
於是帳本能回答
四重封閉,同一個動作:把空間提前枚舉完,拒絕落在外面的一切。
這不是四條各自獨立的優點。每一條都為下一條承重:封閉操作,才讓一條指令的含義可以還原;只有一份權威狀態,「結果」這個詞才有定義;封閉輸入,那個結果才能在別的機器上重現;封閉因果,結果才能被追回到產生它的那次請求。少掉任何一條,問責鏈就在那一環斷掉。 四條合起來買到的東西值得起個名字,因為傳統場所買同一樣東西要貴得多。交易所的稽核軌跡是在交易系統旁邊拼裝出來、再申報出去的——正因為如此,它才可能跟系統對不上,對帳才成為一個常設崗位,場所之間的時鐘同步才成為一條監管要求而不是實作細節。在這裡沒有第二份紀錄可對。稽核軌跡就是執行本身。 本頁餘下的部分,就是這四重封閉的細節。

指令集

參與者或驗證者能做的每一件事,都屬於一組固定的、帶型別的操作: 載荷不屬於這個集合的交易,在驗證階段就會被拒絕。這個集合只能透過協議升級改變,絕不會因為部署了什麼新東西而改變。

執行一個區塊

執行是一串固定的階段序列。這個次序不是實作細節:它決定了一次強平看不看得到觸發它的那個價格,也決定了一筆撤單能不能搶在到來的吃單之前生效。
價格固定本區塊的標記價格
載入讀入本區塊的帳戶與訂單
資金費結算資金費收付
風險金庫減倉 → 強平 → ADL
撮合撮合前 → 撮合 → 撮合後
定案收集輸出,清除無用狀態
每個下游階段面對的是每個商品一個價格,不是不斷變動的價格
按載入時的部位結算,不按最後的部位
被迫產生的流量先了結,才放行新的自主流量
跑在風險之後,所以同一區塊裡的訂單無法對強平搶先交易
歸零的部位和已清空的帳戶不會留存
一個區塊,六個階段
這個位置決定了什麼
條件單就在這一序列裡掃描並推進,所以本區塊標記價格觸發的條件,在本區塊內就生效,不留到下一個區塊。
價格最先運行,固定本區塊後續要用的標記價格,因此每個下游階段面對的是每個商品一個價格,不是一個不斷變動的價格。載入讀入本區塊涉及的帳戶和訂單。資金費按載入時的部位結算資金費。風險按順序跑三個階段——先金庫減倉,再強平,然後自動減倉——讓被迫產生的流量先了結,之後才放行新的自主流量。撮合隨後跑它自己的三個階段,產出成交。定案收集發生了變化的內容,並清除不再需要存在的狀態,例如歸零的部位和已清空的帳戶。 條件單就在這一序列裡掃描、推進生命週期,所以本區塊的標記價格觸發的條件,在本區塊內就生效,不會留到下一個區塊。
強平跑在撮合之前,所以同一個區塊裡的訂單無法對強平搶先交易。等到自主訂單開始撮合,強平產生的流量已經了結。

兩類狀態

內核嚴格區分什麼會持久存在、什麼只是臨時草稿。
區塊執行期間
引擎狀態市場 · 帳戶 · 訂單簿 · 部位 · 清算所跨區塊存續
區塊工作集標記價格 · 被觸及帳戶 · 成交 · 暫存輸出只存續一個區塊
已提交鏈上狀態帶版本 · 可認證權威來源
髒資料追蹤很容易被誤當成權威。一個區塊內發生了哪些變化,是拿來建構確定性輸出的 — 不是狀態本身所在的地方。
引擎據以重建的權威來源
讀取
套用
物化
引擎狀態跨區塊存在:市場中繼資料、帳戶、訂單簿、商品狀態、清算所狀態。它回答的是「此刻什麼是真的」。 逐區塊工作集只在一個區塊執行期間存在:本區塊的輸入、開頭固定下來的標記價格、動到的帳戶和訂單,以及正在組裝的輸出。它是一本流水帳,不是事實來源。 這個區分之所以重要,是因為髒資料追蹤很容易被誤當成權威。一個區塊內發生了哪些變化,是拿來建構確定性輸出的,不是狀態本身所在的地方。把這兩者搞反,做出來的系統,答案會取決於你怎麼問。

結果為什麼可複現

這裡的確定性是強制出來的,不是指望來的。每個誠實節點在同樣的前置狀態上執行同樣的區塊,都會產出逐位元組相同的結果,因為執行路徑上沒有任何東西讀得到節點之間會有差異的輸入:
  • 全程定點數運算。 結算數學跑在整數定點數上,捨入語義是明確的:保證金在負指數上無條件進位,手續費依對哪一方有利分別無條件捨去或無條件進位。結算路徑上沒有浮點數,因為兩台機器之間只要有一次捨入差異,就是一次分叉。
  • 不用系統時鐘。 區塊內的先後使用共識提交的規範位置和區塊時間戳記,絕不使用本地時間。
  • 運行期沒有隨機性。 任何需要隨機數的地方,都從鏈上狀態確定性地導出。
  • 確定性走訪。 集合只要走訪順序會體現在輸出裡,就一定是有序的,不做雜湊隨機化。
有一個後果值得點明:區塊內的「時間」就是共識提交的那個區塊內位置,所以在一個區塊之內,不存在亞毫秒級的主機共置優勢。再加上優先級安排——撤單先於主動吃單執行——就構成一道結構性防線,讓掛在盤口的報價不會被同一區塊內到達的訂單吃掉。

風險公式是純的

保證金要求、強平價格、減倉對象選擇、手續費和未平倉合約量上限,都由公式決定,而這些公式實作成純的、無狀態的函式:接受輸入值、回傳結果,既不讀取也不修改帳本狀態。 狀態變更完全由清算所驅動:清算所呼叫這些函式,並把結果落到狀態上。持有狀態的模組——帳戶、部位、訂單簿——存放資料並暴露修改方法,但自身不驅動業務流程。 這是一條刻意劃出的邊界:一次保證金計算可以脫離環境,對著一張輸入輸出表單獨核對;任何人的餘額要變動,也有且只有一條程式碼路徑。

輸出

執行產出狀態寫入和事件,每一項都綁定到引起它的那筆交易;此外還有一條通道,容納不屬於任何單筆使用者交易的系統級影響:資金費、保險基金變動、區塊計數器。這些構成交易輸出,由狀態層提交、由索引器對外提供。 內核裡發生的任何事,下游都看得見。只要動到了狀態,就會出現在某個人的輸出裡,或者出現在系統通道裡。

後續閱讀

撮合

訂單簿、價格優先與時間優先,以及訂單有效期和自成交防護如何在其上生效。

清算所

餘額、部位與保證金發生變化的唯一路徑。

狀態模型

內核的輸出一旦提交,會變成什麼。

IntentionBFT

順序和價格是從哪裡來的。