bitshares转账流程

in #bitshares6 years ago

第1章 【绪言】

1.1 编写目的
本文档主要讲述使用bitshares的用户进行转账操作的处理流程,转账操作是bitshares里面比较简单的一个操作。通过对转账操作的理解,可以大致理解bitshares下面数据的处理逻辑。

1.2 术语定义
transaction:字面意思是交易,在bitshares里面,transaction意义既包含通用意义上的交易:比如充值、提现、转账、发布限价单,还包含其它一些意义,如:创建账户,升级账户,创建见证人节点,等一系列操作。
signed_transaction:当见证人对transaction进行签名之后,这个transaction具有一定的效力,可以认为是被确认过的,所以是signed_transaction。
processed_transaction:被执行过的transaction,当一个transaction被签名后,才可以被执行,执行转账及订单撮合等操作,只有被执行过的processed_transaction,才可以被放入区块中。
signed_block:区块结构,一个区块包含一个或多个processed_transaction。

第2章 【转账流程分析】
2.1 工作原理
用户使用bitshares的命令行或ui界面客户端,而见证人节点为这些客户端提供websocket服务。在客户端发布转账请求后,所连接的见证人节点将生成一条transaction,将转账所有信息封装进这条transaction中,然后执行签名操作,签名过的transaction将被广播给网络上其它的见证人结点,然后,此见证人节点会执行一下这个transaction,将执行结束后的transaction放入待打包的列表中。当轮到当前见证人节点打包区块时,会从列表中取出所有的transaction,打包到区块里面。

2.2 代码分析
当用户进行一笔转账操作如下图所示:
1.png
此时该用户使用的由bitshares-ui编译的用户界面客户端,发布转账请求后,所连接的见证人节点会接收到请求命令(本质上是一段json),在websocket_api.cpp 82行on_message函数中,由见证人节点所创建的websocket服务端,接收到消息,进行解析及rpc调用,这之间的调用流程暂时不详细说明,最终会调用到wallet.cpp 1991行的transfer函数,由此函数进行转账(transfer)的处理。
2.png
如图所示 account_object from_account和account_object to_account这两行代码就是从数据库中查询转账操作的源用户和目标用户,然后新创建一个transfer_operation结构体,transfer_operation在transfer.hpp中定义
3.png
如图所示,transfer_operation中包含了transfer操作的两个用户:转账操作的来源账户和目标账户,转账资产数量,手续费数量,备注这些信息。
然后调用sign_transaction函数,对此条transaction进行签名操作,在sign_transaction最后,调用broadcast_transaction(api.cpp 163行)函数,将这个transaction广播给其它见证人结点。
在api.cpp中,首先调用_app.chain_database()->push_transaction(trx),进行数据库操作,将transaction存入数据库中,具体流程如下:
db_block.cpp 229行
4.png
调用_apply_transaction函数,apply_transaction函数的功能是执行这条transaction,生成一个processed_transaction。然后将这个processed_transaction存入_pending_tx这个缓存vector中。
在apply_transaction中,再进一步调用apply_operation函数,在apply_operation中,根据operation的类型,从_operation_evaluators找到对应的operation执行器,_operation_evaluators的初始化在db_init.cpp 130行的initialize_evaluators函数中,可以看到,在此处添加了一系列evaluator对象,evaluator类是对operation进行具体操作的类,每一种opertion对有与之对应的evaluator,如transfer_operation对应的是transfer_evaluator。
在transfer_evaluator中,我们重点关注do_apply函数
5.png
可以看到,此处进行了数据库操作,执行adjust_balance函数,看代码可以看出,adjust_balance就是对源用户的相应资产进行减法操作,对目标用户的相应资产进行加法操作。
adjust_balance在db_balance.cpp 53行
6.png
所图所示,先得到account_balance_index索引,再在索引上根据account_id找到对应的用户账户,如果没有找到对应的account_balance_object,就创建一个,如果找到,就调用account_balance_object的adjust_balance函数。
在account_object.cpp中
void account_balance_object::adjust_balance(const asset& delta)
{
assert(delta.asset_id == asset_type);
balance += delta.amount;
}
如图所示,对该对象的balance进行修改操作。

上面所有的代码都属于层级调用,bitshares大多数处理都属于单线程操作,虽然层级调用层次较多,看起来复杂,但这些所有的操作都在最外层的apply_transaction。当操作完成后,将processed_transaction缓存进_pending_tx里面。
在witness.cpp中,此处执行见证人节点的轮询操作,周期行的检查是否轮到自己出块了, 判断自己是否能出块的逻辑在 maybe_produce_block() 方法中,当轮到当前见证人结点打包区块时,调用database的generate_block(db_block.cpp)函数。
7.png
8.png
9.png

如图所示,在for循环中,从_pending_tx中取出transaction,将其放入要打包的区块即pening_block中,完成生成一个区块操作。
第3章 【总结】

本篇简单介绍了转账操作时关键代码:在底层网部层接收到消息,在wallet中生成相应的transaction,对transaction进行签名,处理transaction中的operation,修改数据库中对应的账户余额,最后将transaction打包进区块中,完成此次转账操作。