..

本文描述了dingir-exchange如何处理交易流程:以tradejs为例

背景

1、关于 dingir-exchange
官方描述是基于Rust语言开发的交易所,更具体的可以看具体的官方文档1

2、为什么学习它
1)对Rust语言感兴趣,并且做过基于Rust的服务端开源项目。
2)该项目处于相对初级阶段,想从头跟一下别人的工作方法。


工程模块简介2

.
├── Cargo.lock #Cargo自动生成的文件不需要修改。(为什么不添加到.gitignore中?)
├── Cargo.toml #工程配置文件,包括基本信息、依赖、特性等
├── Makefile #Makefile文件
├── README.md #说明
├── build.rs #自定义构建流程用
├── config.yaml #一些配置信息
├── docker #包含docker相关的配置文件
├── examples #例子,包含了该文用到的trade.js
├── migrations #sql
├── proto #包含matchengine.proto
├── rust-toolchain #rust-toolchain
├── rustfmt.toml #rustfmt.toml
├── scripts #安装该工程的依赖shell脚本
├── src #源码所在的文件夹
└── target #rust编译输出文件夹。(添加大了.gitigore中)

对于该文来说,主要聚焦在2个目录中,examples和src,其他相关的文件不作为重点考虑。

-建议
1、Cargo.lock 可以添加到 .gitignore 中。
2、既然是开源的项目,其实应该加上License。


examples & src

examples - trade.js

example是基于JavaScript实现的,不难理解,去掉无关紧要的代码,该文件的代码可以简化为

async function main() {
 const askOrder = await orderPut(
    userId,
    market,
    ORDER_SIDE_ASK,
    ORDER_TYPE_LIMIT,
    /*amount*/ "4",
    /*price*/ "1.1",
    fee,
    fee
  );
  const bidOrder = await orderPut(
    userId,
    market,
    ORDER_SIDE_BID,
    ORDER_TYPE_LIMIT,
    /*amount*/ "10",
    /*price*/ "1.1",
    fee,
    fee
  );

  return [askOrder.id, bidOrder.id];
}

就是撮合 askOrder 和 bidOrder,其中 orderPut 是引自 client.mjs 的方法,mjs 表示该文件是JavaScript的一个模块,可参考文章3关于JavaScript模块的介绍。

examples - client.mjs

关于 orderPut 方法,直接调用了 client 的 OrderPut 方法,参数进行了透传,其中 client 定义如下:

const client = caller(`${server}`, { file, load }, "Matchengine");

caller 为 import caller from "@eeston/grpc-caller"grpc-caller 是JavaScript版本的 gRPC 客户端,详细用法见4介绍。


matchengine.proto

OrderPut 声明如下

rpc OrderPut(OrderPutRequest) returns (OrderInfo) {
option (google.api.http) = {
  post : "/order"
  body : "*"
};
}

src

src - server.rs - order_put

简化后的实现,主要是调用了 controller 中的 order_put 方法:

async fn order_put(&self, request: Request<OrderPutRequest>) -> Result<Response<OrderInfo>, Status> {
	ctrl.order_put(true, request.into_inner())
}

src - controller - order_put

这里的主要实现就是调用 market 的 order_put 。

pub fn order_put(&mut self, real: bool, req: OrderPutRequest) -> Result<OrderInfo, Status> {

    let order = market
        .put_order(&mut self.sequencer, balance_manager.into(), persistor, order_input)
        .map_err(|e| Status::unknown(format!("{}", e)))?;

}

src - market - order_put

该方法主要是对 order 的处理,调用真正的撮合方法 execute_order

self.execute_order(sequencer, &mut balance_manager, &mut persistor, order, &quote_limit);

到此,交易撮合完成。


  1. dingir-exchange

  2. 鉴于项目后期会重构,本文所描述的代码都是基于 2021-5-28 日最后提交。 

  3. mjs

  4. grpc-caller