跨链三部曲之:Basecoin Plugin

在前一节中,我们学习了如何使用 basecoin 启动区块链和 basecli 来发送交易,同时研究了 AccountSendTx 这两种基本类型。本节,我们将演示如何扩展 SendTx 以便让它支持另外一种交易类型:AppTx,这样就可以发送数据到一个自定义的插件 plugin。这里,我们来探索一个简单的 plugin:Counter

Example Plugin

basecoin 的设计使得实现一个用户自定义插件变得十分简单,Counter 插件是和 basecoin 区块链打包在一起的,因此,如果你已经安装了 baseocin,并且运行了 make install,你应该可以直接运行 Counter 区块链节点和它的客户端 countercli,它和我们之前的 basecli 用法十分相似。

除了 --name--amount是必选参数,Counter 交易由其他两个参数确定:boolean 类型的 valid,和 countfee 表示某种代币类型和数量。只有当 validtrueamount 数量大于 counterfee 时,该笔交易才是有效的。

跟之前 basecoin 区块链一样,类似的,counter 区块链也可以这样初始化:

1
2
3
4
5
6
7
8
9
10
# WARNING: this wipes out data - but counter is only for demos...
rm -rf ~/.counter
countercli reset_all

countercli keys new cool
countercli keys new friend

counter init $(countercli keys get cool | awk '{print $2}')

counter start

counter 的配置文件默认存放在 ~/.counter 目录,打开另一个命令行窗口, 初始化 countercli 并用 tx 的子命令 send 发送交易:

1
2
3
4
countercli init --node=tcp://localhost:46657 --genesis=$HOME/.counter/genesis.json

YOU=$(countercli keys get friend | awk '{print $2}')
countercli tx send --name=cool --amount=1000mycoin --to=$YOU --sequence=1

Counter 的 tx 还有另外一个子命令 counter,它会为这个 plugin 构造一个特殊的 AppTx:

1
2
countercli tx counter --name cool --amount=1mycoin --sequence=2
countercli tx counter --name cool --amount=1mycoin --sequence=3 --valid

第一笔交易不会被区块链接受,因为它没有指定 valid 参数,第二笔顺利发送,接下来我们可以查询这个 plugin:

1
countercli query counter

可以看到,我们这个自定义插件已经可以跑通,你应该看到 Counter 值为 1 代表当前 counter 的有效交易数量,如果再发送一笔交易:

1
2
countercli tx counter --name cool --amount=2mycoin --sequence=4 --valid --countfee=2mycoin
countercli query counter

再次查询,我们将看到 Counter 值会变为 2,这一次,我们指定了 countfee=2mycoin,它没有超出 --amount=2mycoin,因此,可以通过 counter 区块链的合法性验证。

记住,和 basecli 一样,每次查询, countercli 都会验证区块链返回的 proof,保证返回结果是最新且正确的。

AppTx

在实现我们自己的 plugin 之前,有必要先探究下 AppTx 和 basecoin 的 plugin 系统。

AppTxSendTx 相似,不同之处在于,SendTx 是从 inputs 发送交易到 outputs,而 AppTx 是从一个 input 发送交易到一个 plugin,当然,也可以附加其他数据 Data

1
2
3
4
5
6
7
type AppTx struct {
Gas int64 `json:"gas"`
Fee Coin `json:"fee"`
Input TxInput `json:"input"`
Name string `json:"type"` // Name of the plugin
Data []byte `json:"data"` // Data for the plugin to process
}

通过 plugin 的方式,AppTx 可以使 Basecoin 扩展为能够处理除了转账之外的其他交易。Name字段代表某个处理特殊交易的 plugin 名字,Data 代表 plugin 要处理的数据。

Plugins

一个 plugin,简单来说,它实现了 Plugin 接口中定义的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Plugin interface {

// Name of this plugin, should be short.
Name() string

// Run a transaction from ABCI DeliverTx
RunTx(store KVStore, ctx CallContext, txBytes []byte) (res abci.Result)

// Other ABCI message handlers
SetOption(store KVStore, key string, value string) (log string)
InitChain(store KVStore, vals []*abci.Validator)
BeginBlock(store KVStore, hash []byte, header *abci.Header)
EndBlock(store KVStore, height uint64) (res abci.ResponseEndBlock)
}

type CallContext struct {
CallerAddress []byte // Caller's Address (hash of PubKey)
CallerAccount *Account // Caller's Account, w/ fee & TxInputs deducted
Coins Coins // The coins that the caller wishes to spend, excluding fees
}

关键在于 RunTx 方法,AppTx 中的 Data 会赋值给 txBytes,Input 则用来填充 CallContext

注意到 RunTx 还接收一个 KVStore 类型参数 store,它抽象化了底层默克尔树对 account 数据的操作,这样 plugin 可以直接更新 Basecoin 节点里面的 account 信息,也可以存储其它信息用来来反馈区块链应用的最新状态。

通过 plugin 的方式,基于 Basecoin 的区块链应用可以得到很大扩展,甚至,可以实现类似于以太坊虚拟机那样的插件。这里 有些别人已经实现好的 plugin 例子。

Conclusion

本节我们演示了如何创建一个 plugin 来扩展现有 Basecoin 实现发送用户自定义交易到区块链,下一节,我们将介绍一个用于区块链跨链通信 IBC(Inter Blockchain Communication) 的插件。

hxzqlh wechat