前面我们讲到 Basecoin 是一个基于 tendermint 的 ABCI 应用,同时它也是一个跨链应用。这节,我给大家介绍如何利用它在不同的账户之间发送交易,并试着探索下其中的技术内幕。
Install
墙外的用户直接运行:
1 | go get -u github.com/tendermint/basecoin/cmd/... |
像我们被困在墙内的用户怎么办呢,Basecoin 是用 glide 管理依赖包的,老司机都知道通过 glide miror set
来设置那些被墙包的镜像,具体请看我的另一篇 《我是如何管理goalng包的》。
安装好后,会有两个工具:
- basecoin 运行区块链节点
- basecli 轻客户端命令行
Generate some keys
首先,生成 2 组 key,一个用来接收初始分配的币,一个用来发送币。
1 | # WARNING: this will wipe out any existing info in the ~/.basecli dir |
生成 key 时会提示你输入密码,生成好后,查看已有的 key 列表:
1 | AllendeMacBook-Pro:~ $ basecli keys list |
你可以看到在目录下已经有 cool 和 friend 两组 key 了:
1 | AllendeMacBook-Pro:~ $ ls -l ~/.basecli/keys/ |
Initialize Basecoin
初始化 Basecoin 区块链:
1 | # WARNING: this will wipe out any existing info in the ~/.basecoin dir |
basecoin 会创建出运行区块链必须的文件,在 ~/.basecoin
目录下,有一个 validator(验证节点)和一个账户(cool)。
1 | AllendeMacBook-Pro:~ $ ls -l ~/.basecoin/ |
Start
准备就绪!现在,我们可以启动 Basecoin 区块链了:
1 | basecoin start |
你可以从控制台上看到,Basecoin 会每隔一秒出一个新块。
Initialize Light-Client
现在,Basecoin 区块链已经运行,我们可以初始化 basecli
了,它可以发送交易给 basecoin
,并查询 basecoin
区块链的状态。
打开一个新的命令行窗口:
1 | basecli init --node=tcp://localhost:46657 --genesis=$HOME/.basecoin/genesis.json |
通过提供 genesis 配置文件给 basecli,它会解析出区块链的 chainID 和 validator 集合,basecli 需要这些信息才能通过 basecoin 区块链的密码学验证逻辑。
注意:
--genesis
只有在 validator 集合没有变动的情况下才能生效,如果之前 validator 集合发生过更改,你需要通过其他方式来找到当前区块链的 validator 集合。
Send transactions
现在,我们可以发送交易了。
首先,来看下我们之前创建的两个账户的资产信息:
1 | ME=$(basecli keys get cool | awk '{print $2}') |
第一个账户显示出了它的资产信息,第二个账户显示账户不存在。让我们从第一个账户发点币给第二个账户:
1 | $ basecli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1 |
第二个账户现在有 1000 个 mycoin 了,我们可以从第二个账户发回 500 个给第一个账户:
1 | basecli tx send --name=friend --amount=500mycoin --to=$ME --sequence=1 |
如果我们发送的币超出发送者拥有的数量,毫无疑问,会报错:
1 | basecli tx send --name=friend --amount=500000mycoin --to=$ME --sequence=2 |
从上面例子都可以看出,每次发送交易时,需指定发送者名字 --name
,发送币及数量 --amount
,接收者名字 --to
以及本次交易的序列号 --sequence
(有序递增),区块链则返回本次交易 hash,我们可以根据这个 hash 查询到本次交易在区块链上的记录。
1 | basecli query tx 743D40A6EB009E18C162FA7DA98B57FBC324187E |
Accounts and Transactions
为了更好地理解 basecli 以及 basecoin 是如何工作的,我们需要先补点跟账户、交易相关的基础知识
Accounts
受以太坊的账户系统的启发,Basecoin 维护了一个账户系统,每个账户包含一个公钥、不同币种的资产信息以及一个严格递增的交易序列号。请注意:Basecoin 是一个多数字货币资产钱包,因此每个账户可以有许多种不同的 token。
1 | type Account struct { |
如果你想往区块链里添加更多的币种,只需要在区块链初始化前手动编辑 ~/.basecoin/genesis.json
。
账户被序列号保存在默克尔树中,键为 base/a/<address>
,其中<address>
是账户的地址。一般地,账户地址是一个 20 字节的公钥哈希(RIPEMD160
算法),当然,其他格式也支持。Basecoin 中用到的默克尔树是一个平衡二叉查找树,也称 IAVL
树。
Transactions
Basecoin 定义里一个简单的交易类型 SendTx
,它包含一个或多个输入和输出,允许 token 从一个账户转移到其他账户。
1 | type SendTx struct { |
注意到SendTx
还包含 Gas
和 Fee
字段,Gas 限制了每次交易最多允许执行的计算次数,Fee 指这比交易的交易费,validator 根据交易费大小对接收到的交易进行打包排序,这有点类似于比特币中手续费概念。
和以太坊中的 Gas、GasPrice 概念稍微有点不同,以太坊中的交易费
Fee = Gas x GasPrice
,在 Basecoin 中,Gas 和 Fee 是两个独立的概念。
只有在 Sequence == 0
的时候,PubKey
才是必选项。之后,它会存储在默克尔树该账户对应的 key 中,后续的交易只需要引用PubKey
对应的 Address
就可以指定发送者了。
最后,多个输入账户和多个输出账户可以让我们在一笔交易中就实现在不同账户间多个 token 的转移,当然,你必须保证”价值守恒”(输入=输出,交易费已经在 Fee 中指定)
,并且,每个输入都要有对应账户的私钥签名。
Conclusion
本章介绍了 basecoin 和 basecli 两个命令行工具及其基本用法,演示了如何启动一条 basecoin 区块链,怎样在账户间发送 token,并讨论了 basecoin 中账户和交易类型,下一章,我们将介绍 Basecoin 的插件系统,实现不同插件的扩展。