经过两周的调研和折腾,做了一个中心化区块链钱包雏形,在这里记录一下遇到的问题以及解决思路
问题1:如何知道某个用户充币了???
答:以以太坊举例,可以监控full-node节点的height变化,然后分析每个新增block内包含的所有交易,可以拿到每个交易的fromaddr和toaddr,所以我们可以给每个account绑定一个唯一的ethereum地址,如果交易的toaddr关联了account,那么就是这个account的充币。
问题2:如何知道交易是不是某个用户的提币???
答:提币交易签名,在投递交易到full-node之前,把交易的txhash和用户的提币信息关联起来,当发现交易的txhash关联了提币信息,那么自然就知道是哪个account的提币操作。
问题3:如何处理孤块???
答:blockwatch监控模块,要记录一个读取历史,监控block的交易的时候,每次读取一个block,都看看这个block的parent block hash是否等于上一次读取的block的hash,如果不想等,所以出现了分叉孤块。从这次读取的block开始回退,找到和读取历史重合的节点(即分叉节点),从分叉节点重新开始读取。
所以,回退的过程中,所有被回退节点内的交易都要被重新打包,逻辑层也要处理。
服务器概览
服务器分为gatesrv,transrv,signsrv,accountsrv. 数据存储使用mysql + redis, 其中redis还兼具mq的作用。
集群中使用etcd服务发现。
gatesrv
集群,无状态前端服务器,客户端直联。所有请求皆转发至其他服务器。
accountsrv
1个,账号服务器,负责分配account与地址关联(比特币,以太坊地址),负责分配account关联到哪个transrv。不考虑单点故障的话,1个足以,因为逻辑足够简单,并且账号信息都可以用redis缓存。分配account到transrv的时候,并非hash取模,而是找到负载最小的transrv(承担account最少),这样后期添加transrv的话,能够保证新导入的用户,尽量绑定在新的transrv上面。
transrv
集群,负责充币,提币,内部转账,红包玩法等等。每个transrv负责若干个account,account一旦与某个transrv关联,那么这个account终生都隶属于这个transrv。
signsrv
1个,签名服务器,负责提币审核,account的地址余额汇总到朱地址。
充币
提币
Title:提币流程
client->gatesrv:发起提币请求
Note right of gatesrv:查询redis,得到client归属的transrv
gatesrv->transrv:转发请求到对应得transrv
transrv->transrv:检查client的余额,提币合法性等
transrv->transrv:生成本地哈希localhash,写入数据库,冻结提币金额
transrv->transrv:写入redis集合blockout_req,关联localhash和提币信息
signsrv->signsrv:人工审核,同意或者拒绝localhash提币请求
signsrv->signsrv:拒绝提币:写回拒绝信息到redis队列blockout_rsp
signsrv->signsrv:同意提币:签名交易,在redis集合blockout_ctx关联txhash和localhash,写回拒绝信息到redis队列blockout_rsp
transrv->transrv:后台线程,定期查询blockout_rsp处理提币的同意与拒绝
transrv->transrv:后台线程,监控onchain交易,如果txhash关联了localhash,则处理提币