tendermint(tm)是the cosmos network旗下的一个区块链项目。tm能安全且保持一致性地在多台机器之间复制应用程序。tm的共识算法基于节点不可信的设计,也就是允许拜占庭错误。tm主要分成两个部分。
一是一个区块链共识引擎(tendermint core)。他主要负责节点之间的数据同步有序传输,实现拜占庭共识机制。二是区块链应用接口(abci)。它是一种接口通讯协议,可以通过各种编程语言实现应用逻辑。应用逻辑和tm core通过abci实现了解耦。
下面简单介绍一下如何在windows环境下编译及使用tendermint。
下载源码及依赖
当然前提是已经配置好go环境和git,并且需要梯子,使用如下命令:
go get github.com/masterminds/glide
go get github.com/tendermint/tendermint/cmd/tendermint
执行时间比较长,耐心等待完成后,可以发现%gopath%目录和%gopeth%\src\github.com目录下多出许多东西
编译
有两种方式:
2.1
cd $gopath/src/github.com/tendermint/tendermint
glide install
go install 。/cmd/tendermint
这里作者遇到一个坑,执行glide install报错:[error] failed to find glide.yaml file in directory tree: cannot resolve parent of d:\
首先执行glide create,然后按照提示一步步操作,在执行glide install。
这时又遇到一个问题:[error] unable to export dependencies to vendor directory: error moving files: exit status 1. output: access is denied. 0 dir(s) moved.
网上查到资料,是因为glide版本造成的,修改到v0.12.3版本即可解决。
接下来重新glide install,新的问题出现了:error looking for crypto/ed25519: cannot detect vcs.这是由于国内访问golang.org被墙导致的,可以添加镜像文件解决:
glide mirror set https://golang.org/x/crypto https://github.com/golang/crypto
2.2
以上步骤很麻烦,不用怕,我们可以手动使用go build命令编译:
cd %gopath/src/github.com/tendermint/cmd/tendermint
go build
cd %gopath/src/github.com/tendermint/abci/cmd/abci-cli
go build
两次build之后,分别生成了tendermint.exe和abci-cli.exe,将这两个文件拷到%gopath/bin目录下
tendermint version
abci-cli version
以上两个命令如果有版本号输出,那么可以进入下一个步骤了。
运行官方的例子
官方的代码为我们展示了一个kvstore的例子,它的作用就是存储数据,类似与leveldb。
打开三个cmd窗口,cmd1,cmd2,cmd3
在cmd1中输入 abci-cli kvstore
可以看到程序在waiting for new connection.。.
接下来在cmd2输入 tendermint init,然后tendermint node
c:\users\ch》tendermint init
i[2019-08-04|18:28:48.105] found private validator module=main keyfile=\.tendermint\config\priv_validator_key.json statefile=\.tendermint\data\priv_validator_state.json
i[2019-08-04|18:28:48.113] found node key module=main path=\.tendermint\config\node_key.json
i[2019-08-04|18:28:48.118] found genesis file module=main path=\.tendermint\config\genesis.json
c:\users\ch》tendermint node
i[2019-08-04|18:28:57.497] version info module=main software=0.32.1 block=10 p2p=7
i[2019-08-04|18:28:57.514] starting node module=main impl=node
i[2019-08-04|18:28:57.528] started node module=main nodeinfo=“{protocolversion:{p2p:7 block:10 app:1} id_:fe807a7617494c46d38bc040801ab567cc330852 listenaddr:tcp://0.0.0.0:26656 network:test-chain-17uai5 version:0.32.1 channels:4020212223303800 moniker:caohuan other:{txindex:on rpcaddress:tcp://127.0.0.1:26657}}”
i[2019-08-04|18:28:58.539] executed block module=state height=1 validtxs=0 invalidtxs=0
i[2019-08-04|18:28:58.546] committed state module=state height=1 txs=0 apphash=0000000000000000
i[2019-08-04|18:28:59.552] executed block module=state height=2 validtxs=0 invalidtxs=0
i[2019-08-04|18:28:59.558] committed state module=state height=2 txs=0 apphash=0000000000000000
i[2019-08-04|18:29:00.573] executed block module=state height=3 validtxs=0 invalidtxs=0
i[2019-08-04|18:29:00.579] committed state module=state height=3 txs=0 apphash=0000000000000000
i[2019-08-04|18:29:01.592] executed block module=state height=4 validtxs=0 invalidtxs=0
i[2019-08-04|18:29:01.599] committed state module=state height=4 txs=0 apphash=0000000000000000
tendermint init是初始化tendermint服务,tendermint node则是启动服务
服务启动后,即开始出块,那是因为和cmd1启动的abci-cli建立了链接,如果想不要自动出空块,可以在启动的时候加上参数 tendermint node --consensus.create_empty_blocks=false
tendermint服务启动后,再看cmd1窗口:
c:\users\ch》abci-cli kvstore
i[2019-08-04|18:28:50.646] starting abciserver module=abci-server impl=abciserver
i[2019-08-04|18:28:50.693] waiting for new connection.。. module=abci-server
i[2019-08-04|18:28:57.473] accepted a new connection module=abci-server
i[2019-08-04|18:28:57.478] waiting for new connection.。. module=abci-server
i[2019-08-04|18:28:57.484] accepted a new connection module=abci-server
i[2019-08-04|18:28:57.488] waiting for new connection.。. module=abci-server
i[2019-08-04|18:28:57.492] accepted a new connection module=abci-server
i[2019-08-04|18:28:57.496] waiting for new connection.。. module=abci-server
能够发现这里建立了三个连接,这三个连接分别是:
info/query connection:用于查询服务通信
mempool connection:用于发送交易通信
consensus connection:用于共识通信
后面还会提到这三个连接的作用。
接下来可以开始测试了,在cmd3窗口输入 curl -s localhost:26657/broadcast_tx_commit?tx=\“author=caohuan\”
c:\users\ch》curl -s localhost:26657/broadcast_tx_commit?tx=\“author=caohuan\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“check_tx”: {
“gaswanted”: “1”
},
“deliver_tx”: {
“events”: [
{
“type”: “app”,
“attributes”: [
{
“key”: “y3jlyxrvcg==”,
“value”: “q29zbw9zagkgtmv0b3dva28=”
},
{
“key”: “a2v5”,
“value”: “yxv0ag9y”
}
]
}
]
},
“hash”: “b339c04b9163f0585b8db0703e2a107a9b21034b2f5d18bf9b66bdef5dd627e3”,
“height”: “168”
}
}
友情提示:这条命令在linux系统中是这么写的:curl -s ‘localhost:26657/broadcast_tx_commit?tx=“author=caohuan”’。windows环境中,少了单引号,多了转义的反斜杠。
现在查询一下这个操作有没有成功:curl -s localhost:26657/abci_query?data=\“author\”
c:\users\ch》curl -s localhost:26657/abci_query?data=\“author\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“response”: {
“log”: “exists”,
“key”: “yxv0ag9y”,
“value”: “y2fvahvhbg==”
}
}
}
查询出的这个value是base64编码的,可以使用在线工具转码,也可以在golang中自己实现一个转码,转码之后可以发现“y2fvahvhbg==”就是“caohuan”
除了使用curl命令以外,还可以使用浏览器,直接在地址栏输入 http://localhost:26657/abci_query?data=“author” 即可。
以上kvstore的例子就运行成功了,官方还有一个例子counter,这里就不详细展开介绍了,有兴趣的小伙伴可以去官方文档看一下。
简单分析一下
下面简单分析一下刚才经历了什么过程
首先开启abci-cli(cmd1)服务,然后开启tendermint(cmd2)服务,然后使用客户端client(cmd3)向tendermint发送交易,具体过程如下:
1,client产生了一条数据“author=caohuan”,要把这条数据发送到链上去
2,client发起请求:curl -s localhost:26657/broadcast_tx_commit?tx=\“author=caohuan\”
3,tendermint收到tx=“author=caohuan”的交易,发送给abci
4,abci接受到tx之后,调用checktx方法,验证这个tx是否符合交易规范。在/tendermint/abci/example/kvstore/kvstore.go可以看到代码,这里的checktx没有做任何事
6,tendermint把该tx存在内存池里,并把这条tx通转发给其他tendermint节点,所有节点对该交易进行两轮投票,prevote--》precommit--》commit,prevote超过三分之二同意之后进入precommit,再超过三分之二投票后进入commit(在该例中只有一个节点,所以没有经过共识)
7,tendermint共识完成之后进入commit阶段,再对abci发送请求:beginblock -》 delivertx * n次 --》 endblock --》 commit,即:新区快 --》 正在接受区块内容 * n条 --》 区块内容接受完了 --》 提交到区块链。这些方法在/tendermint/abci/example/kvstore/kvstore.go中都可以找得到
8,abci在commit之后会通知tendermint
9,区块链上多了一个区块记录着“author=caohuan”
现在在回过头来看一下刚才提到的三个连接包含哪些东西:
info/query connection:info,setoption,query
mempool connection:checktx
consensus connection:initchain,beginblock,delivertx,endblock,commit
这些接口是定义在/tendermint/abci/types/application.go中的,这些接口在协助完成了整个交易过程。
// info/query connection
info(requestinfo) responseinfo // return application info
setoption(requestsetoption) responsesetoption // set application option
query(requestquery) responsequery // query for state
// mempool connection
checktx(requestchecktx) responsechecktx // validate a tx for the mempool
// consensus connection
initchain(requestinitchain) responseinitchain // initialize blockchain with validators and other info from tendermintcore
beginblock(requestbeginblock) responsebeginblock // signals the beginning of a block
delivertx(requestdelivertx) responsedelivertx // deliver a tx for full processing
endblock(requestendblock) responseendblock // signals the end of a block, returns changes to the validator set
commit() responsecommit // commit the state and return the application merkle root hash
也就是说,如果我们想使用tendermint实现自己的一条链,就必须实现这些接口。
实现自己的一条链
接下来,我们尝试着实现自己的一条链,逻辑很简单:初始化xiaoming和dazhuang两个账户,余额各为100,由xiaoming向dazhuang转账。
代码:
func newcounterapplication(serial bool) *counterapplication {
fmt.println(“newcounterapplication进来了吗”)
return &counterapplication{accountmap: map[string]int{“xiaoming”: 100, “dazhuang”: 100}}
}
func (app *counterapplication) delivertx(req types.requestdelivertx) types.responsedelivertx {
fmt.println(“delivertx进来了吗”)
//xiaoming转给dazhuang
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(req.tx):], req.tx)
balance := int(binary.bigendian.uint64(tx8))
if app.accountmap[“xiaoming”] 《 balance {
return types.responsedelivertx{
code: code.codetypeencodingerror,
log: fmt.sprintf(“insufficient balance”)}
}
app.accountmap[“xiaoming”] -= balance
app.accountmap[“dazhuang”] += balance
return types.responsedelivertx{code: code.codetypeok}
}
func (app *counterapplication) checktx(req types.requestchecktx) types.responsechecktx {
fmt.println(“checktx进来了吗”)
//xiaoming转给dazhuang
tx8 := make([]byte, 8)
copy(tx8[len(tx8)-len(req.tx):], req.tx)
balance := int(binary.bigendian.uint64(tx8))
if app.accountmap[“xiaoming”] 《 balance {
return types.responsechecktx{
code: code.codetypeencodingerror,
log: fmt.sprintf(“insufficient balance”)}
}
fmt.println(“checktx ok”)
return types.responsechecktx{code: code.codetypeok}
}
func (app *counterapplication) commit() (resp types.responsecommit) {
fmt.println(“commit进来了吗”)
apphash := make([]byte, 8)
binary.putvarint(apphash, int64(len(app.accountmap))) //这里随便commit了一个hash
return types.responsecommit{data: apphash}
}
func (app *counterapplication) query(reqquery types.requestquery) types.responsequery {
fmt.println(“query进来了吗”)
name := string(reqquery.data)
amount, ok := app.accountmap[name]
if !ok {
return types.responsequery{log: fmt.sprintf(“invalid name %v”, reqquery.data)}
}
return types.responsequery{value: []byte(fmt.sprintf(“%v”, amount))}
}
先使用unsafe_reset_all参数启动一次tendermint,以清除之前的数据,然后启动tendermint和abci-cli开始测试
首先查询一下xiaoming和dazhuang的初始余额:
c:\users\ch》curl -s localhost:26657/abci_query?data=\“xiaoming\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“response”: {
“value”: “mtaw”
}
}
}
c:\users\ch》curl -s localhost:26657/abci_query?data=\“dazhuang\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“response”: {
“value”: “mtaw”
}
}
}
这里查询出来的结果还是base64编码的。
接下来转账:
c:\users\ch》curl localhost:26657/broadcast_tx_commit?tx=0x11
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“check_tx”: {},
“deliver_tx”: {},
“hash”: “4a64a107f0cb32536e5bce6c98c393db21cca7f4ea187ba8c4dca8b51d4ea80a”,
“height”: “3”
}
}
这里的0x11是16进制,换算成十进制就是17
再次查询余额:
c:\users\ch》curl -s localhost:26657/abci_query?data=\“xiaoming\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“response”: {
“value”: “odm=”
}
}
}
c:\users\ch》curl -s localhost:26657/abci_query?data=\“dazhuang\”
{
“jsonrpc”: “2.0”,
“id”: “”,
“result”: {
“response”: {
“value”: “mte3”
}
}
}
经过base64解码,odm=就是83,mte3就是117,测试成功!
Xilinx可编程逻辑器件设计与开发(基础篇)连载43:Spartan
欧拉iQ以自身的产品优势逆流而上 将促进整个行业的正向发展
台积电以5倍速扩产,在建及规划中的晶圆厂达12座
阻碍物联网行业发展的七大问题分析
如何采集pt100的电压
如何在windows上编译并使用区块链共识引擎tendermint
隔离单管 NSi6801x:高效能驱动解决方案的卓越之选
iPhone X产能充足,欲在单季度再创历史新高
采用固体电解质的色素增感型太阳能电池
WAIC2023圆满落幕!英码科技品牌备受行业青睐,助推人工智能创新发展
5G到底会改变什么?工信部直接颁发商用牌照的意义在哪?
小米长江产业基金投资泰凌微
年出鱼800万斤!珠海90后“沉迷”养叉尾,看他如何玩转500亩池塘?
7月19日快讯:3D打印火箭发动机/多晶硅初裁
基于FPGA芯片提供的图形化开发环境以加速嵌入式系统原型化详解
关于壁挂式直流充电桩设计
电子催眠器的设计原理
车载逆变器导热硅胶片选择时应该考虑哪些因素?
GTX1650显卡怎么样_GTX1650和1050哪个好
5G即将商用虚拟运营商正在步入2.0时代