技术分享——深入解析ViteX内置合约设计

前言: 这是第三篇给大家介绍关于ViteX的技术文章,本篇文章主要从ViteX整体设计、性能优化及系统可靠性三个方面介绍了vDex内置合约的设计背景、思路及方案。希望大家能更深入的理解ViteX运行机制。

ViteX作为去中心化交易所,通过内置合约vDex实现撮合引擎及ViteX经济模型的相关功能,在实现高性能的同时兼顾实现的简洁,简单的系统更健壮。在之前的一篇文章《ViteX内置合约设计与实现简介》中我们已经就内置合约的关键设计细节进行了介绍,本篇文章从几个比较有代表性的问题入手介绍一下相关的设计背景、思路及方案。

1.vDex为什么要分两个合约来实现

ViteX交易所要实现订单撮合和平台经济模型的两个核心功能,如果放在一个合约里面实现,不便于问题的聚焦,会造成问题的开发人员及外部接口使用人员的困惑,很自然的想到把他们拆分。另外,撮合引擎从概念上是基础功能,从设计之初并不对外直接暴露接口,和经济模型解耦后,便于后续的撮合引擎升级。具体拆分的两个合约是dexFund和dexTrade,dexTrade实现订单薄存储及订单撮合的功能,dexFund完成资产、挖矿及分红等ViteX经济模型相关功能。

2.为什么会有两种订单id

《ViteX内置合约设计与实现简介》介绍过订单id的详细设计,该订单id是为了最大化性能诉求而设计的,实现链上订单有序存储和高效的撮合,在这里记为baseOrderId。后续我们还添加了用户链下单tx的hash作为key的订单id,这里记为hashOrderId,和baseOrderId依赖于合约拼接生成不同,hashOrderId在用户下单的一刻就能生成,客户端可以直接把这个id暂存下来而不必等待vDex的输出,便于进行订单后续状态的追踪和操作,从这个角度看hashOrderId是客户端友好的订单id。两种订单id分别都有自己适用的场景,实现了性能和用户体验的兼顾。

3.撤单为什么有两个入口

因为订单薄的存储是在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的去中心化运行机制。

写评论,请先登录