因為訂單薄的儲存是在dexTrade合約,撤單直接和訂單薄互動,所以最初的撤單入口也是放在dexTrade。但是下單功能因為會涉及到資金凍結所以是以dexFund合約為入口的,這就導致了下單和撤單有不同的入口。在合約實際執行的過程中會出現訂單下單後因為鏈上共識延遲沒有寫入dexTrade訂單薄就進行撤單的情況,此時撤單操作會因為不能從訂單薄查到訂單而導致執行失敗。為此,我們在dexFund合約新增了撤單入口,對同一個訂單來說因為是同一個使用者發出的交易,透過使用者鏈的交易順序性保證撤單操作肯定會在下單後上鏈執行,有效的撤單肯定可以正確執行。對比兩個撤單入口能夠發現,dexTrade合約的撤單入口因為避免dexFund合約的轉發所以更加直接和輕量級,而dexFund合約因為經過了dexFund合約會需要額外的開銷,但是該入口提供了代理撤單的先驗操作,所以如果是代理撤單就必須走dexFund合約來撤單, 具體來說dexTrade撤單入口適合實時性要求不高的普通使用者,而dexFund撤單入口適合對實時性要求較高的自動化呼叫。
4.訂單撮合效能問題
要提升撮合效能就必須要能快速的匹配待撮合訂單,常用的做法是將頭部訂單或者全部訂單都放入記憶體來實現高效的訪問。但是對於鏈上合約來說,因為受限於鏈底層提供的介面能力訪問儲存,不能做到訂單薄常駐記憶體。這時候可以考慮方式是充分利用底層儲存的特點,保證訂單薄有序儲存,這樣撮合過程只需要依次簡單迭代訪問就可以了。由此我們得到了《ViteX內建合約設計與實現簡介》所介紹的訂單id的設計方案,透過把價格作為訂單id的一部分,而訂單id是底層key有序levelDB的儲存key,這樣訂單薄在底層儲存就是價格有序,透過簡單的key順序遍歷即可完成撮合過程。這樣的實現足夠簡單也非常高效。
5.減少儲存佔用的一些辦法
鏈上儲存的成本是很高的,為了儘量減少儲存資料,我們採取了以下三種手段。第一,透過Protobuf來實現物件的序列化,從源頭減少資料量。第二, 不重複儲存不變的資料,避免冗餘,這裡主要體現在挖礦和分紅相關的指標處理部分,如果指標長期不變,則只儲存最早的一個指標,只有變更的時候才儲存新值。第三,實時清理和定時清理相結合。對於挖礦、分紅中累計的多版本指標資料,對於已經計算完結果的指標實時刪掉資料。定時清理則是針對訂單資料,為了避免訂單薄無限膨脹,會為所有訂單設定超時失效時間戳,定時透過批次介面清理這些失效訂單,實現鏈上訂單的滾動清理。
6.vDex如何提高可靠性
作為內建合約,vDex每行程式碼的實現都是協議,要保證協議的執行正確性,除了透過測試發現問題外,從設計之初就考慮如何提高模組的可靠性。vDex在最初設計的時候,一條重要的原則就是要兼顧簡潔和高效能,過於複雜的設計會成倍提高程式碼量,同時出錯概率也會相應增加。以簡潔為原則,我們的相關資料結構都儘量精簡欄位,不相關的資訊不做儲存,或者放到鏈下儲存,鏈上只處理通常不會改變的核心資料結構,盡力避免資訊冗餘,透過鏈下配套服務來實現傳統交易所的多維度的豐富查詢和展示。程式碼實現層面,控制單個函式的程式碼行數,適時進行拆分和精心命名,控制複雜度的同時也極大減少了重複程式碼的出現,結構更合理之後,每個實現細節也就更清晰,便於理解而不容易出錯。最後,透過《ViteX內建合約設計與實現簡介》提到的對賬機制,我們也能夠從另外一個角度驗證程式碼執行的正確性,同時保證使用者資產的安全。
透過以上幾個問題,我們從整體設計、效能最佳化及系統可靠性三個方面介紹了vDex內建合約的設計背景、思路及方案,這些設計細節體現了ViteX為了達成簡單、高效、透明的目標所做的實踐,希望以上介紹可以幫助大家理清ViteX的去中心化執行機制。