经过这么长时间,我们钱包业务层的业务拆解总算是完成了。前面1-7讲我们分析了钱包业务层的框架搭建、区块同步器、交易发现器、提现、归集、内部交易、回滚和通知业务。
经过这么长时间,我们钱包业务层的业务拆解总算是完成了。前面 1-7
讲我们分析了钱包业务层的框架搭建、区块同步器、交易发现器、提现、归集、内部交易、回滚和通知业务。但是前面的业务都是从局部入手来详细分析各项任务代码处理,有点缺乏整体框架的概念。而这一讲中,我们将整合前面所提到的所有模块,来从宏观层面上来理解钱包业务层这一整个系统的框架和模块。
完整项目 github
地址(如果对您有用,请给个小 star
⭐️):
exchange-wallet-service
:钱包业务层服务: <https://github.com/Shawn-Shaw-x/exchange-wallet-service>signature-machine
:离线签名机: <https://github.com/Shawn-Shaw-x/signature-machine>chains-union-rpc
:多链统一 rpc
: <https://github.com/Shawn-Shaw-x/chains-union-rpc>在上面的整体框架图中,我们可以看到,我们将一整个钱包业务层的框架划分成 8
个独立模块,每个模块都是相对独立但又相互关联作用的。
数据库迁移任务中是一个一次性任务,只需要我们在第一次执行钱包应用的时候执行一次,进行 postgre
数据库表的生成即可。它在内部实际上是执行我们写好的 sql
文件来为我们生成好对应的地址表、余额表、交易表等系统必须的底层数据库表。
在 grpc
服务中,我们对外层系统(如交易所业务层或者项目方)暴露了必须的接口。例如:业务注册、地址转换、构建未签名交易、构建已签名交易等接口。grpc
服务是一个独立的服务,运行在系统的某一个端口上,提供给外层系统调用能力。
并且,在 grpc
服务中,我们还构建了一个客户端 client
,负责在我们钱包层的系统中提供对外调用的能力(例如调用 chains-union-rpc
去执行区块链 rpc
接口的数据获取)
区块同步器是我们钱包业务系统的核心组件,相当于一个消息的生产者角色。它是一个独立的协程启动的定时任务,负责批量去获取链上的区块。并且通过获取区块内的交易,解析并筛选出来和我们系统相关的交易类型。然后推送的一个管道中,提供交易的消息。
并且,在区块的同步器中,它还负责判断本地区块是否与链上区块出现 新扫到区块的parentHash != 数据库中区块的 hash
的情况。如果出现了不相等的情况,则说明区块链中存在回滚的情况。此时,扫链同步器会暂停扫块,转而触发回滚任务(另一个协程启动的定时任务)去执行区块和交易的回滚流程。
交易发现器相当于一个消费者的角色,它负责消费处理区块同步器推送到核心交易管道(可以理解为消息队列,只是在 go
语言中内置的)中的交易。在交易的发现器中,我们系统主要做两件事情:
处理充值、提现、归集、热转冷、冷转热等交易的链上发现流程。例如充值交易,会发现并入库,同时更新 lockBalance
。而提现、归集、热转冷、冷转热交易虽然也会发现交易并修改库中状态,但却不会更新 balance
或者 lockBalance
的信(具体原因且看下面的交易状态解析)
在这里,还会进行旧交易的确认位处理,例如在充值交易中,我们只会增加 lockBalance
的值,并不去修改 balance
的值。但是交易一旦在这里得到确认,则可以减少对应的 lockBalance
的值,并加到 balance
中去。代表这这笔充值交易已经被完全确认了,无法进行回滚。
并且例如提现、归集、热转冷、冷转热交易的确认位处理,也是在这里处理。因为这些都是交易所系统内部发起的交易,例如提现:热钱包地址的 lockBalance
减少。balance
不变(交易广播发起时候 balance
已经减少了,lockBalance
增加)
在提现任务中处理中,这里主要负责的是提现任务的提取并调用 chains-union-rpc
服务去将这笔提现任务发送到区块链网络中。同时更新提现任务的状态和热钱包地址的 balance
和 lockBalance
信息(balance
减少,lockBalance
增加)
内部交易城任务的处理和提现任务的处理类似,都是将数据库的已经签名但未发送出去的交易通过调用 chains-union-rpc
的方式发送出去。同时更新内部交易任务的状态和两个钱包地址的余额。
以归集交易为例:
用户地址的 balance
减少,lockBalance
增加。
热钱包地址的 balance
不变,lockBalance
增加。
等这笔内部交易确认后:
用户地址的 balance
不变,lockBalance
减少。
热钱包地址的 balance
增加,lockBalance
减少。
我们的回滚任务处理仍然是一个定时任务去处理,它会实时监控我们的扫链同步器的回滚状态,一旦它监测到我们扫链同步器进入了回滚状态无法正常扫块。则我们的回滚任务会被触发。
在回滚任务中,主要是会根据同步器标记的出现回滚的区块,调用 chains-union-rpc
的接口去一个个区块往回找,直到寻找到这个链的分叉起始点(通过本地区块的 parentHash == 链上区块的 hash
可以找到)。这样,就能获取到我们需要回滚区块的范围。例如 10 -20
这个范围。那么我们下面将要做的是:
备份 10 - 20
这个范围的区块头信息,删除掉原来的区块头的记录。
更新充值、提现、归集、热转冷、冷转热交易的状态为 fallback
,更新对应的地址的余额信息(回滚了,资金扣除)
通知项目方(交易所业务层)去做对应的回滚处理。(这个在通知任务中处理)
因为我们交易有许多中状态,例如充值交易中会有:1.已扫到交易 2. 交易确认。3. 交易回滚。提现交易会有:1. 交易已广播。2. 交易已经扫到。 3. 交易已确认。4. 交易已回滚 等状态。我们项目方(或者钱包的业务层)需要得知这些交易的状态来进行相应的业务处理。所以我们钱包的系统中,需要启动一个单独的通知任务,去持续扫描我们数据库中的各种未通知交易,去发送 http
请求给项目方(业务层)去通知。在通知业务里面,主要做的事情有:
扫描充值、提现、归集、热转冷、冷转热、回滚等交易的各个状态未通知的交易。将其构造出通知消息,通过 http
请求的方式通知对应业务层(项目方)
更新已被通知的交易的状态为已通知,避免重复通知。
鉴于不同交易的生命周期不一样,以及其余额处理(balance
和 lockBalance
)的不一致,所以下面我们用详细的案例来分析各种交易的状态和余额变动情况。
所有案例我们都采用转账 100 ETH
的情况来进行分析。
充值交易的状态有:
充值已发现:
我们的交易同步器第一次发现这个充值的交易,被交易发现器处理,则为这个充值交易已发现的状态。
此时余额变动为用户地址的 balance
不变。lockBalance = lockBalance + 100
。表示我们得知了充值,但余额暂不可用。
充值回滚:
在充值已发现,但还未被确认的情况下。如果链上发生了回滚,则我们的回滚任务触发,充值的状态变更为已回滚。
此时的余额变动为:用户地址 balance
不变。lockBalance = lockBalance - 100
。表示为我们的余额被回滚了。
充值已确认:
如果在确认位之前,我们的充值交易没有被回滚,则可以认为这笔交易是安全有效的。(我们在交易的发现器中,查询数据库中的充值交易的区块高度是否小于链上最新高度的 k
个块,k
为我们确认位的个数)
在充值交易已确认后,余额变动为:用户地址 balance = balance + 100
。lockBalance = lockBalance - 100
;表示我们的余额从 lockBalance
中的缓存移动到真实可用的 balance
余额。
由于提现交易和归集、热转冷、冷转热交易这些内部交易一样,都是由我们交易所业务层主动发起的,所以,交易的状态会和充值有点不一样(更多)
提现未签名:
指业务层调用我们 rpc
服务提供的构建未签名交易的过程。这时候会创建一笔提现交易,但是没有签名信息,无法发送交易。
提现已签名、未广播:
指业务层将未签名的交易调用签名机去签名出来,获得签名。调用我们 rpc
服务构建已签名交易的过程,在这个过程中。已签名的交易会入库,但还未发送,等待定时任务去实际广播出去。
提现已广播:
指我们的定时任务将已签名,未广播的交易调用 chains-union-rpc
接口将交易广播出去。
此时的余额变化为:热钱包地址的 balance = balnance - 100
。 lockBalance = lockBalance + 100
。
提现已发现:
指我们扫链同步器发现这笔交易,并在交易发现器中处理已发现交易的过程。此时提现交易的 balance 和 lockBalnce
不会产生实际变动。只会更新提现交易的状态。
提现交易被回滚:
如果提现交易被回滚,则需要更新提现交易的状态为已回滚,同时热钱包地址余额信息也将更新:balance = balance + 100
。lockBalance = lockBalance - 100
;
提现已经确认:
如果提现过了确认位已被确认的情况下。则热钱包地址余额的变动情况为:balance
不变。lockBalance = lockBalance - 100
;
归集和提现、热转冷、冷转热交易一样,都是属于内部交易,也都是由我们交易所业务层主动发起的。
归集未签名:
指业务层调用我们 rpc
服务提供的构建未签名交易的过程。这时候会创建一笔归集交易,但是没有签名信息,无法发送交易。
归集已签名、未广播:
指业务层将未签名的交易调用签名机去签名出来,获得签名。调用我们 rpc
服务构建已签名交易的过程,在这个过程中。已签名的交易会入库,但还未发送,等待定时任务去实际广播出去。
归集已广播:
指我们的定时任务将已签名,未广播的交易调用 chains-union-rpc
接口将交易广播出去。
此时的余额变化为:用户地址的 balance = balnance - 100
。 lockBalance = lockBalance + 100
。热钱包地址的 balance
不变。 lockBalance = lockBalance + 100
归集已发现:
指我们扫链同步器发现这笔交易,并在交易发现器中处理已发现交易的过程。此时归集交易的 balance
和 lockBalnce
不会产生实际变动。只会更新归集交易的状态。
归集交易被回滚:
如果归集交易被回滚,则需要更新归集交易的状态为已回滚,同时用户地址余额信息也将更新:balance = balance + 100
。lockBalance = lockBalance - 100
;热钱包地址余额:balance = balance
不变。 lockBalnce = lockBalance - 100
。
归集已经确认:
如果归集过了确认位已被确认的情况下。同时用户地址余额信息也将更新:balance
不变。lockBalance = lockBalance - 100
;热钱包地址余额:balance = balance + 100
。 lockBalnce = lockBalance - 100
。
热转冷和归集、冷转热交易一样,都是属于内部交易,也都是由我们交易所业务层主动发起的。
热转冷未签名:
指业务层调用我们 rpc
服务提供的构建未签名交易的过程。这时候会创建一笔热转冷交易,但是没有签名信息,无法发送交易。
热转冷已签名、未广播:
指业务层将未签名的交易调用签名机去签名出来,获得签名。调用我们 rpc
服务提供出来的构建已签名交易的过程,在这个过程中。已签名的交易会入库,但还未发送,等待定时任务去实际广播出去。
热转冷已广播:
指我们的定时任务将已签名,未广播的交易调用 chains-union-rpc
接口将交易广播出去。
此时的余额变化为:热钱包地址的 balance = balnance - 100
。 lockBalance = lockBalance + 100
。冷钱包地址的 balance
不变。 lockBalance = lockBalance + 100
热转冷已发现:
指我们扫链同步器发现这笔交易,并在交易发现器中处理已发现交易的过程。此时热转冷交易的 balance 和 lockBalnce
不会产生实际变动。只会更新热转冷交易的状态。
热转冷交易被回滚:
如果热转冷交易被回滚,则需要更新热转冷交易的状态为已回滚,同时热钱包地址余额信息也将更新:balance = balance + 100
。lockBalance = lockBalance - 100
;冷钱包地址余额: balance
不变。 lockBalnce = lockBalance - 100
。
热转冷已经确认:
如果热转冷过了确认位已被确认的情况下。同时热钱包地址余额信息也将更新:balance
不变。lockBalance = lockBalance - 100
;冷钱包地址余额:balance = balance + 100
。 lockBalnce = lockBalance - 100
。
冷转热和归集、热转冷交易一样,都是属于内部交易,也都是由我们交易所业务层主动发起的。
冷转热未签名:
指业务层调用我们 rpc
服务提供的构建未签名交易的过程。这时候会创建一笔冷转热交易,但是没有签名信息,无法发送交易。
冷转热已签名、未广播:
指业务层将未签名的交易调用签名机去签名出来,获得签名。调用我们 rpc
服务提供出来的构建已签名交易的过程,在这个过程中。已签名的交易会入库,但还未发送,等待定时任务去实际广播出去。
冷转热已广播:
指我们的定时任务将已签名,未广播的交易调用 chains-union-rpc
接口将交易广播出去。
此时的余额变化为:冷钱包地址的 balance = balnance - 100
。lockBalance = lockBalance + 100
。热钱包地址的 balance
不变。 lockBalance = lockBalance + 100
冷转热已发现:
指我们扫链同步器发现这笔交易,并在交易发现器中处理已发现交易的过程。此时冷转热交易的 balance
和 lockBalnce
不会产生实际变动。只会更新冷转热交易的状态。
冷转热交易被回滚:
如果冷转热交易被回滚,则需要更新冷转热交易的状态为已回滚,同时冷钱包地址余额信息也将更新:balance = balance + 100
。lockBalance = lockBalance - 100
;热钱包地址余额:balance
不变。 lockBalnce = lockBalance - 100
。
冷转热已经确认:
如果冷转热过了确认位已被确认的情况下。同时冷钱包地址余额信息也将更新:balance
不变。lockBalance = lockBalance - 100
;热钱包地址余额:balance = balance + 100
。 lockBalnce = lockBalance - 100
。
至此,我们整个钱包业务系统也总结完啦。本来想简写写点的,但不知不觉间,又写了 4k+
的文字了。主要是交易状态和 balance
、lockBalance
较为复杂,讲解长了点。希望对您的钱包开发生涯有用啦。如果可以,希望您能给我的文章和 github
点点 star
⭐️。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!