资讯专栏INFORMATION COLUMN

如何设计一个比特币钱包服务

G9YH / 2248人阅读

摘要:原文链接如何设计一个比特币钱包服务概述总所周知,比特币全节点的实现目前有两个版本,一个是中本聪写的原版,一个是语言写的。查询最新区块高度,钱包转账后通过区块高度来计算交易是否已经确认,比特币是个区块确认。

原文链接 https://github.com/liyue201/b...

如何设计一个比特币钱包服务 概述

总所周知,比特币全节点的实现目前有两个版本,一个是中本聪c++写的原版bitcoin core,一个是go语言写的btcd。这两个版本从功能上并没有多大差异,都实现了比特币协议。从理论上讲,比特币网络中的每个全节点只要遵循相同的比特币协议,至于用什么语言实现,用什么方式存储都是无所谓的。bitcoin core和btcd都没有实现通用的钱包服务,这里说的钱包服务指的是一个可以给钱包app提供所数据的服务,私钥保存在钱包app中,用户交易在钱包app中签名,再将签名数据发给钱包服务,再由钱包服务转发到全节点上链,如图:

所幸的是全节点提供了一些JSON RPC接口,通过这些接口可以读取区块数据和发起转账交易。但是能读到的数据还是太原始了,就连获取某个地址的余额都做不到。因为比特币使用的是UTXO账号体系,并没有一个统一的地方存储地址余额,只有UTXO。而UTXO是分散在每个区块中的,要想知道某个地址的UTXO,需要从第一个区块开始遍历。有些人说这样设计可以更好的并发执行,这个鄙人真的不敢苟同。说可以更好的溯源倒是真的,因为每一笔交易都可以追溯到上一笔交易。

钱包服务功能

好了,废话不多说,我们看一下一个钱包服务应该具备什么样的功能。

(1)查询任意一个地址的余额,钱包需要知道自己地址的余额。

(2)查询任意一个地址的UTXO,钱包转账时需要UTXO来签名打包。

(3)发起转账交易。钱包需要调服务发起转账交易。

(4)查询任意一个地址的历史交易记录。

(5)查询最新区块高度,钱包转账后通过区块高度来计算交易是否已经确认,比特币是6个区块确认。

第(1)(2)点实际上是一个问题,知道UTXO自然就知道余额了。第(3)(5)可以直接调全节点接口。所以钱包服务的难点只剩下(2)(4)这两个功能。钱包服务要做的就是从全节点从第一个区块开始遍历读取所有的交易记录,并推导出每个地址当前区块高度的UTXO,再将这个信息保存到数据库中方便钱包使用。

全节点选择

bitcoin core 虽然是原版的比特币全节点,但是他只提供了http接口,没有websocket接口,不能实时推送未上链的交易。一个体验好的钱包不仅要获取已经上链的交易记录,也要知道未上链的交易。btcd不仅提供了http接口,还有websocket,所以btcd应该是更好的选择。

数据库选型

到目前为止(2018-12-26)比特币的交易量是3.6亿,因为一笔交易涉及到多个输入和多个输出地址(如果你研究过区块链浏览器上的数据,会发现一笔交易几千个输入和几千个输出都是很正常的,这样可以省矿工费,可能是交易所转账),解析出来后大约是16.6亿条(这个我自己跑的数据)。若是用传统的关系型数据库肯定扛不住的,所以一般人都会往nosql或者列式数据库方向考虑,比如用mongo或cassandra等。虽然能够解决问题,但是面对这么大的数据,这类型的数据库都需要部署分片集群。对于一个小创业公司来说,如果用户不是很多,从运维成本上来看,是不是都点杀鸡用牛刀大感觉呢。有没有经济实惠的方案?当然有,比如leveldb和rocksdb这类kv嵌入式数据库,只需要单个机器就可以满足要求。在几亿数据量情况下,leveldb在普通硬盘上读写速度可以达到几万每秒,使用ssd硬盘更快,而且内存占用极少。当然使用leveldb或rocksdb,也有其缺点,就是单机数据安全的问题,如果硬盘坏了怎么办。恰好我们这个业务对数据的安全性要求并不高,因为所有数据都是从全节点来的,要是硬盘坏了,大不了重新跑一遍数据。rocksdb是facebook的开源产品,据说是对leveldb做了优化,性能更强。rocksdb是c++写的,而leveldb除了c++版本之外,还有go语言版本,比特币全节点btcd和以太坊全节点geth都是用的go版本的leveldb。最终我选择了leveldb,因为我的服务是用go写的,虽然go也可以通过cgo调用C++,但是代码写起来没有纯go那么舒服。

数据结构

leveldb是kv数据库,没有表的概念,所以数据结构的设计非常关键。比如地址的历史交易记录,在关系型数据库中可以建一个以地址为索引的历史交易记录表。而kv数据库则没有索引的概念。好在level的key是有序的,可以根据key的顺序读取内容。根据这个特性,我们可以这样设计索引,每个地址的交易是一组key,这组key在数据库的所有key中是紧挨着的。这样只要知道某个地址的第一个索引key就可以按顺序读到这个地址的其他交易。因为一个交易涉及到多个输入地址和输出地址所以需要索引跟数据分开,对于utxo只关联到一个地址,就不需要多带带设计索引了,索引跟数据可以放在一起。

数据结构设计好了,该怎么存。这个就是序列化的问题了,可以是json,或者go自带的gob,也可以自己写。最后从编码难度,执行效率和压缩率等方面综合考虑采用了protobuf。这是我的proto文件

syntax = "proto3";

package models;

//key:  utxo-{addr}-{Transaction.id}-{Transaction.vout}
message Utxo {
   string  txId            = 1;
   uint32  vout            = 2;
   int64   amount          = 3;
   string  scriptPubKey    = 4;
}

//context
//key:  context
message Context {
   int64               blockHeight      = 1;   // 当前处理的区块高度
   string              blockHash        = 2;   // 当前处理的区块hash
   int32               blockTotalTx     = 3;   // 当前区块的交易数
   int32               BlockProcessedTx = 4;   // 当前区块已经处理的交易数
   int64               totalTx          = 5;   // 总共的交易数
   int64               totalTxNode      = 6;   //
}

message TxInput {
   string  txId    = 1;    //上一笔交易id
   uint32  vout    = 2;    //上一笔交易输出的idx
   string  addr    = 3;    //通过查询获得
   int64   amount  = 4;    //通过查询获得
}

message TxOutput {
   string  addr         = 1;
   int64   amount       = 2;
   uint32  vout         = 3;
   string  scriptPubKey = 4;
}

//key:  tx-{Transaction.txId}
message Transaction {
   int64   id                  = 1; //自增di
   string  txId                = 2;
   int64   blockTime           = 3;
   string  blockHash           = 4;
   int64   blockHeight         = 5;
   repeated TxInput inputs     = 6;
   repeated TxOutput outputs   = 7;
}

//key: txnode-{addr}-{TxNode.id}
message TxNode{
   int64  id           = 1;    //自增di
   string txId         = 2;
   uint32 type         = 3;    //1-intput 2-output  3-intput|output
}
总结

这个项目的难点不在编码而是技术选型,当然还有调试。代码写完后经过漫长的同步,大概半个月才同步完成。 只有同步完成才能进行完整的功能测试,若果有数据的bug还得从头开始同步。需要注意的是这里只是设计了已经确认的区块,对于未确认的区块和内存池的交易要多带带考虑。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/24521.html

相关文章

  • 如何理解比特和区块链?

    摘要:比特币区块链无疑是当今业界的最热门的。目前,每个成功的矿工获得可能每年更换一次或通过比特币社区决策作为成功向区块链添加一块交易的奖励。填写其他详细信息,例如比特币金额和可选说明。 比特币区块链无疑是当今业界的最热门的。通过这篇博客,我将尽力向大家介绍加密货币比特币的概念,以及它如何创造我们称之为区块链的革命性技术。 这个问题经常引起混淆。这篇文章可以快速解释和清理这方面的混乱! 什么是...

    Kosmos 评论0 收藏0
  • 如何开发比特钱包应用程序

    摘要:创建比特币钱包需要一组优秀的程序员。如何使用流行的库构建自己的比特币钱包应用程序创建比特币钱包应用程序的一种方法是依赖现有工具。具有以下功能它允许开发人员使用密码加密创建比特币钱包应用程序。 尽管目前加密货币市场相当黯淡,但比特币和其他山寨币继续受欢迎。每天都有新的交易者加入市场,希望能够在下一个价格高涨时获利。 随着市场的突飞猛进,开发商也在获益。新交易者的首要任务是设置比特币钱包。...

    Cympros 评论0 收藏0
  • 如何开发比特钱包应用程序

    摘要:创建比特币钱包需要一组优秀的程序员。如何使用流行的库构建自己的比特币钱包应用程序创建比特币钱包应用程序的一种方法是依赖现有工具。具有以下功能它允许开发人员使用密码加密创建比特币钱包应用程序。 尽管目前加密货币市场相当黯淡,但比特币和其他山寨币继续受欢迎。每天都有新的交易者加入市场,希望能够在下一个价格高涨时获利。 随着市场的突飞猛进,开发商也在获益。新交易者的首要任务是设置比特币钱包。...

    crossea 评论0 收藏0
  • 比特钱包安全

    摘要:要点提醒确保比特币钱包安全的全部在于确保钱包私钥安全,好消息是,这个你可以采取措施。 本文是有关比特币相关的系列文章,发布于GIT-HUB,地址如下:https://github.com/junahan/JU... 比特币钱包安全概要 有关比特币钱包安全,可以简单的分为两类,一类是做为用户的你不可控制的安全问题,一类是做为用户的你可以控制的安全问题。之所以这样看似废话的区分,提醒你...

    付永刚 评论0 收藏0
  • 区块链学习之比特(六)

    摘要:侧链侧链协议允许资产在比特币区块链和其他区块链之间互转。实现了比特币区块链的扩展证明在比特币系统中验证交易时,涉及交易合法性检查双重花费检查脚本检查等。 比特币项目简介 比特币是基于区块链技术的一种数字货币实现,比特币网络是历史上首个经过大规模、长时间检查的数字货币系统 比特币网络在功能上具有如下特点: 去中心化: 意味着没有任何独立个体可以对网络中的交易进行破坏,任何交易请求都需要...

    xingpingz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<