Bitshares订单撮合详解
第1章 【绪言】
1.1 编写目的
bitshares作为一个去中心化的交易所,使用DPOS共识机制,用户可以在bitshares这条链上交易订单,链上具有自动撮合功能,撮合多笔订单,本文的目的是深入解析bitshares的源代码,对订单撮合部分功能进行讲解。
1.2 术语定义
transaction:字面意思是交易,在bitshares里面,transaction意义既包含通用意义上的交易:比如充值、提现、转账、发布限价单,还包含其它一些意义,如:创建账户,升级账户,创建见证人结点,等一系列操作。
signed_transaction:当见证人对transaction进行签名之后,这个transaction具有一定的效力,可以认为是被确认过的,所以是signed_transaction,signed_transaction才可以被存入区块中。
processed_transaction:被执行过的transaction,当一个transaction被签名后,才可以被执行,执行转账订单撮合等操作,只有被执行过的processed_transaction,才可以被放入区块中。
signed_block:区块结构,一个区块包含一个或多个processed_transaction。
第2章 【订单撮合原理及技术分析】
2.1 工作原理
bitshares是一个去中心化的交易所,用户可以在交易所上进行虚拟资产的交易,例如用比特币兑换以太坊等。当用户在客户端发布了一种类型的资产交易,例如以1个比特币兑换10个以太坊,客户端会将交易数据发布给所连接的见证人节点。见证人节点接收到后,生成一条transaction,将具体信息封装进这条transaction中。因为这类交易并不是实时完成,所以会以订单(order)的方式,保存进bitshares的数据库中。每一个order都有自己的过期时间,如果到达过期时间仍未匹配成功将被从数据库订单列表中删除。transaction会被全网广播,并被打包进区块里面。假如另外有用户a发布一个订单,以9个以太坊兑换1个比特币,而用户b也发布一个订单,以11个以太坊兑换1个比特币。显而易见,用户a的订单不满足需求,而用户b的订单满足需求,此时bitshares就会将用户b的订单与其进行匹配,匹配成功之后,从订单列表中删除,然后修改两个用户余额,进行相应资产的加减操作,这就是bitshares订单撮合的大致原理。
2.2 流程分析
当用户发布了一条限价单后,假如此条限价单是卖出1000个BTS,买回1个BTC,此限价单就是一个交易,即transaction。因为用户使用bitshares-ui这一层进行发布限价单,而每一个用户都是连接bitshares底层graphene网络中的见证人结点进行操作,所以用户发布的限价单会首先由该用户所连接的witness_node接收到命令。
witness_node接收到命令(本质上是一段json)后,会进行解析处理,此处对底层解析不作赘述,因为发布限价单的sell_asset,所以最终会调用到wallet.cpp中的sell_asset函数(1930行)。
创建一个signed_transaction,将限价单相关数据放入到limit_order_create_operation中去,然后sign_transaction。
下面详看sign_transaction这个函数,在sign_transaction函数中,主要对transaction进行一系列签名处理,这里不作详细说明,在签名完成之后,调用
_remote_net_broadcast->broadcast_transaction( tx )这个函数,将transaction广播出去给其它结点。
在broadcast_transaction函数中,主要进行两个操作,如下:_app.chain_database()->push_transaction(trx);
_app.p2p_node()->broadcast_transaction(trx);
第一个函数push_transaction,将transaction缓存起来,会调用db_block.cpp中的_push_transaction函数(229行),在这里执行_apply_transaction函数,_apply_transaction函数,_apply_transaction函数执行这条transaction,取出transaction里面的operation,进行一系列执行过程,并将执行结果附加到这个transaction的后面,一个signed_transaction执行过后便是一个processed_transaction了,而processed_transaction会被放入到区块里面
在apply_transaction里面,进行一系列调用,此处层次比较多,暂时不作详细说明,经过limit_order_create_evaluator的do_apply函数(market_evaluator.cpp 73行):
此处创建一个limit_order_object对象,将此limit_order_object存进数据库(object_database),然后调用apply_order函数(db_market.cpp 239行),其中关键代码在此处
根据limit_order_object对象中的price,从数据库中查询所有price满足要求的limit_order_object,然后在while循环中,进行match操作,match函数在301行,
在if判断中,判断生成的limit_order_object(简称order1)和查询到的limit_order_object(简称order2),在if为true时,order2满足order1,但order1不一定满足order2,比如order1卖出1000BTS买入1BTC,order2卖出2BTC买入2000BTS,这种情况就是order2满足order1而order1不满足order2,此时可以进行匹配,运行两次fill_order函数,第一次fill_order修改order1,第二次fill_order修改order2,下面是fill_order相关代码
首先执行pay_order函数,如下
这个函数先修改order对应用户的total_core_in_orders值,减去卖出值,再修改余额,加上买入值。
然后在if( pays == order.amount_for_sale() )判断中,判断一下,如果这次匹配的卖出等于这个order的卖出,那么代表这个order匹配成功了,执行remove函数,从数据库中删除这个order,如果小于的话,说明这个order没有完全匹配成功,进行修改操作,还是用上面的例子,order2原来卖出2BTC,但和order1匹配,order2其中1个BTC会给order1,所以此处将order2的卖出改成1BTC,仍然保留在数据库中。
在match函数最后result,如果order1被满足,返回1,如果order2被满足,返回2,如果order1和order2同时被满足,返回3。
然后回来apply_order中的while循环中,每次match,如果返回值等于2,继续匹配,如果返回值不等于2,结束循环,即优先匹配order1,尽量保证order1被匹配成功,只要order1被匹配成功立即跳出循环,order2就算部分被匹配也无所谓,只进行修改。
现在push_transaction已经执行完成,下一步是broadcast_transaction这个操作,broadcast_transaction函数最终会调用node.cpp 4938行broadcast函数
判断broadcast的消息类型是transaction,将transaction相关信息缓存进_message_cache和_new_inventory里面,并执行trigger_advertise_inventory_loop。在node.cpp的1234行advertise_inventory_loop函数中,可以看到,从_new_inventory里面取出缓存的message信息,向每个结点发送一条item_ids_inventory_message消息。一个item_ids_inventory_message包含两种信息,一个是消息类型,即transaction类型,一个是消息id,是signed_transaction的哈希。
当一个signed_transaction被广播出去之后,根据grahpene网络结构,其它见证人结点也会接收到这个transaction,见node.cpp 1758行on_message函数,on_message是专门用于处理网络上消息的函数,根据不同的消息类型,进行对应的处理,当其它结点接收到transaction后,执行process_ordinary_message(node.cpp 3864行)。在这里调用handle_transaction函数,如下图所示
在这里调用database的push_transaction函数,push_transaction函数上面有讲解,执行apply_transaction函数,进行一系列处理。因为当一个见证人结点接收到transaction并广播出去了,其它的见证人结点进行同步处理,所以所有的结点都将transaction处理了一遍,保证各个结点上数据的同步。
第3章 【总结】
每一个订单对象在数据库中都是一个limit_order_object实例,此对象包含3个关键因素:卖出的资产、买入的资产、两种资产的比价(价格)。bitshares在生成一个limit_order_object后,会从数据库中按价格进行查找,找到价格可以匹配的订单,匹配成功的订单从数据库中删除,匹配部分成功的订单会修改一下留着继续匹配,匹配后会修改两个订单发布者的对应资产余额,这就是订单撮合的流程。
Leave Bitshares订单撮合详解 to:
Read more #bitshares posts
Best Posts From lpbottle
We have not curated any of lpbottle's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.