bitcoin交易网站实现

选型

  • c/c++ 语言,bitcoin最核心的版本是用c/c++实现,但由于最初版本源码结构太差,现在比以前好了很多,但还是在继续调整。由于c/c++语言本身的问题,库引入都是比较麻烦的事情。它的有点相对其他实现比较稳定

  • golang语言,有bitcoin的实现btcd,但最近没有更新,有些bip也没有实现;另外有开发者尝试用golang实现的例子,如这个,这个,借鉴的内容会多一些。

其他如js,但并不是个人擅长,也不是区块链的核心语言系列,就不考虑。上面两种选哪种都ok,看个人擅长,这边就选择使用golang。

接口选择方面,直接调用bitcoin core的rpc接口或者使用blockchain.com的api。这里选择了第一种。

实现方法

一般来说要实现交易所或者交易网站的功能,要实现三块功能:地址管理、充值、提现

  • 地址管理

    • 目标:
      • 方便管理用户的地址
      • 保存好私钥的安全性
    • 实现:
      • 一般来说使用HD钱包的方式生成地址
      • 地址类型一般用着两种:P2PKH和p2sh-p2wpkh,后台生成用统一用一种即可,第二种打包费用更低
      • 公钥和私钥都使用压缩格式
      • 私钥的存储需要隔离,有几个维度
        • 存储的数据库要独立
        • 对数据库中的内容需要加密
        • 启动的时候,从root启动,解密私钥的秘钥从环境变量读取或者从文件读取(启动完成后把文件删除)
  • 充值

    • 目标:
      • 玩家充值:玩家充值后,应立即感知到充值行为
        • 充值到某个帐号,就无法识别出是哪个玩家进行了充值,所以需要对每个帐号生成一个区块链地址,玩家向这个地址充值
      • 充值服务可随时更新
    • 实现:
      • 用一个goroutine监控交易池,一旦发现交易池中有游戏中玩家的对应地址,就记录玩家充值状态到缓存,设置超时60分钟;遍列过的交易不再重复查看
      • 用一个goroutine监控[1,3)个确认的区块,如果发现其中有玩家的对应地址,就记录玩家充值状态到缓存,设置超时30分钟;遍列过的区块不在查看,遍列过的交易不再重复查看;防止交易池漏查、重启过程中漏查
      • 用一个goroutine监控3个确认以上的区块,如果发现其中有玩家的对应地址,就记录玩家充值状态到数据库;并记录到扫描高度,以防止重启丢失充值记录。
      • 注意点
        • 玩家的充值地址需要同步到内存中,方便快速查找;有新帐号创建的时候,要先同步过来,在创建成功
        • 目前2018-08-30每个区块大约有100-3000个交易不等
        • 交易池中大约有4000+的交易
        • 提取交易信息接口getrawtransaction “txid” ( verbose “blockhash” ) ,需要在bitcoind启动的时候添加-txindex,获取所有的交易索引
    • 风险控制:
      • 软分叉,忽略
      • 硬分叉,使用网络接口监控异常,一旦出现警告,停止服务
        • getnetworkinfo 提取warnings信息
  • 提现

    • 目标:
      • 玩家提现,将中心的对应货币转到链上,且收取一定的手续费用
      • 将玩家的充值,全部转到某个Master帐号上
      • Master帐号充值后,能发现其未使用的UTXO,并录入库
    • 实现:
      • 玩家的提现
        • 发起请求,将玩家的提现请求录入到提现队列,如NSQ,并入库
        • 处理请求,每一个Master帐号对应一个goroutine,每个goroutine从队列中提取请求,处理后发到链上。所有的转账处理的goroutine由Manager goroutine创建,当发现新帐号的时候,立即开启一个新的goroutine
          • 当账户金额不足时,告警
          • 未确认数提现达到一定值时,此账号停止提现
          • 可重发所有请求
        • 确认请求,单独起一个goroutine,监控这些提现行为,达到3个确认后,就同步入库
      • 玩家的充值
        • 单独起一个goroutine,检查充值量和充值额度,当达到一定条件,就将用户的比特币转到一个Master帐号
      • 录入Master帐号的UTXO
        • 单独起一个goroutine,检查Master帐号的充值和玩家的充值的合并,方法跟充值服务的实现差不多