区块链学习

1.摘要Tendermint是跨链Cosmos项目的核心技术。本文主要介绍以下内容:(1)Tendermint的网络层级框架图(2)Tendermint模块组成及共识算法原理(3)Tendermint工作流程2.Tendermint概述Cosmos的开发团队Tendermint其实早在2014年就开始意识到了其不足,并持续专注于寻求不依赖挖矿等高电力消耗的共识机制,提供快速的交易处理能力,它们的目标是为全事件所有的区块链提供速度、安全和可扩展性。目前,Tendermint加入了微软Azure区块链即服务平台,也成为了以太坊区块链联盟成员之一,同时Tendermint也是跨链技术Cosmos的核心技术。两者大致的关系如下:图中可以轻松看出Cosmos就是在Tendermint基础上添加一些插件功能来实现的。2.1Tendermint的概念Tendermint的概念总结下有以下几点:(1)Tendermint是一个能够在不同机器上,安全一致复制应用的软件,其中安全性和一致性也是分布式账本的关键概念。(2)Tendermint具备拜占庭容错能力,是一种拜占庭容错共识算法。(3)Tendermint主要有两部分组成:1)TendermintCore:区块链共识引擎,负责节点之间数据传输以及拜占庭共识。2)ABCI:区块链应用程序接口(theApplicationBlockChainInterface),也是一个协议,支持任何语言的交易处理实现。总体来讲,Tendermint可以理解为一个模块化的区块链软件框架,支持开发者个性化定制自己的区块链,而又不需要考虑共识以及网络传输的实现。2.2Tendermint设计原则区块链是一个具备确定性的状态机,可以在不信任的节点之间进行状态复制,包括应用的状态和改变状态的交易。从架构的层面上,区块链可以简单分为三个概念层:(1)网络层(Networking):负责交易和数据传输和同步。(2)共识算法(Consensus):负责不同的验证节点处理完交易后,保证状态的一致,也就是将交易打包到区块中。(3)应用程序(Application):交易的真正执行者。大致框架如下:目前大部分的区块链实现都是采用上面的框架,实现成单一的程序,但是这就很容易出现两个问题:(1)代码复用困难,代码库的分支管理变得复杂。(2)限制了应用开发的语言。如何去规避这两个问题呢?Tendermint设计了自己的一套框架,其设计原则是易使用,易理解,高性能,适用于各种分布式应用。它的创新之处在于,将区块链应用(状态)与底层共识进行了分离,将共识引擎和P2P网络层封装组成TendermintCore。同时提供ABCI接口与应用层进行交互,应用逻辑可以用任何语言编写,应用做的事情实际上就是状态机控制。基于这种架构,应用的开发者可以方便地实现自己的区块链。Tendermint的框架总体来讲分为ABCIApplication以及TendermintCore两部分,两者通过ABCI连接。3.Tendermint核心模块3.1ABCIApplication开发者定制开发的区块链应用,开发语言不受限制,可以使用任何语言进行开发,但是必须实现为一个ABCIServer,即需要满足以下几点:(1)是一个SocketServer,需支持TSP或GRPC两种方式之一。(2)能够处理ABCIMessage。所有的ABCI消息类型都是通过protobuf来定义的,具体的消息格式可参考https://github.com/tendermint/abci/blob/master/types/types.proto(3)实现区块链应用接口(ABCI)。ABCI是Tendermint中定义的一套Application与TendermintCore之间交互的协议。详细定义如下(版本:0.10.3):ABCI接口可以分为三类:信息查询、交易校验以及共识相关处理。而TendermintCore作为ABCIClient在启动时,会与ABCIServer建立三个连接,分别用于这三类接口消息的处理。在TendermintCore与Application交互的所有消息类型中,有3种主要的消息类型:(1)CheckTx消息用于验证交易。TendermintCore中的mempool通过此消息校验交易的合法性,通过之后才会将交易广播给其它节点。(2)DeliverTx消息是应用的主要工作流程,通过此消息真正执行交易,包括验证交易、更新应用程序的状态。(3)Commit消息通知应用程序计算当前的事件状态,并存在下一区块头中。3.2TendermintCoreTendermint共识引擎,包含区块链需要大部分功能实现,主要有:共识算法:拜占庭POS算法。P2P:采用gossip算法,默认端口是46656。RPC:区块链对外接口,默认端口是46657。支持三种访问方式:URIoverHTTP、JSONRPCoverHTTP、JSONRPCoverwebsockets。详细的RPC接口定义列表可以参考https://tendermint.github.io/slate其它:交易缓存池、消息队列等。3.2.1共识算法Tendermint是一个易于理解的BFT共识协议。协议遵循一个简单的状态机,如下:协议中有两个角色:(1)验证人:协议中的角色或者节点,不同的验证者在投票过程中具备不同的权力(votepower)。(2)提议人:由验证人轮流产生。验证人轮流对交易的区块提议并对提议的区块投票。区块被提交到链上,且每个区块就是一个区块高度。但区块也有可能提交失败,这种情况下协议将选择下一个验证人在相同高度上提议一个新块,重新开始投票。从图中可以看到,成功提交一个区块,必须经过两阶段的投票,称为pre-vote和pre-commit。当超过2/3的验证人在同一轮提议中对同一个块进行了pre-commit投票,那么这个区块才会被提交。由于离线或者网络延迟等原因,可能造成提议人提议区块失败。这种情况在Tendermint中也是允许的,因为验证人会在进入下一轮提议之前等待一定时间,用于接收提议人提议的区块。假设少于三分之一的验证人是拜占庭节点,Tendermint能够保证验证人永远不会在同一高度重复提交区块而造成冲突。为了做到这一点,Tendermint引入了锁定机制,一旦验证人预投票了一个区块,那么该验证人就会被锁定在这个区块。然后:(1)该验证人必须在预提交的区块进行预投票。(2)当前一轮预提议和预投票没成功提交区块时,该验证人就会被解锁,然后进行对新块的下一轮预提交。可以看到,Tendermint共识算法和PBFT时非常相似的,可以说是PBFT的变种,那我们来比较一下:(1)相同点:1)同属BFT体系。2)抗1/3拜占庭节点攻击。3)三阶段提交,第一阶段广播交易(区块),后两阶段广播签名(确认)。4)两者都需要达到法定人数才能提交块。(2)不同点:1)Tendermint与PBFT的区别主要是在超过1/3节点为拜占庭节点的情况下。当拜占庭节点数量在验证者数量的1/3和2/3之间时,PBFT算法无法提供保证,使得攻击者可以将任意结果返回给客户端。而Tendermint共识模型认为必须超过2/3数量的precommit确认才能提交块。举个例子,如果1/2的验证者是拜占庭节点,Tendermint中这些拜占庭节点能够阻止区块的提交,但他们自己也无法提交恶意块。而在PBFT中拜占庭节点却是可以提交块给客户端。简单的说,就是比特币的网络存在分叉的可能,而Tendermint不会发生这种情况。2)另一个不同点在于拜占庭节点概念不同,PBFT指的是节点数,而Tendermint代表的是节点的权益数,也就是投票权力。3)最后一点,PBFT需要预设一组固定的验证人,而Tendermint是通过要求超过2/3法定人数的验证人员批准会员变更,从而支持验证人的动态变化。锁机制详解举个例子,有四个validator节点,A,B,C,D,在某个R轮,在propose阶段,(1)proposer节点广播出了新块blockX;(2)A的超时时间内没有收到这个新块,向外广播pre-votenil,B,C,D都收到了,向外广播pre-vote投给blockX;(3)现在四个节点进入了pre-commit阶段,A处于红色内圈,B,C,D处于蓝色外圈;(4)假设A由于自身网络不好,又没有在规定时间内收到超过2/3个对blockX的投票,于是只能发出pre-commitnil投票消息投给空块(5)D收到了B和C的pre-vote消息,加上自己的,就超过了2/3了,于是D在本机区块链里commit了blockX(6)假设此时B和C网络出现问题,收不到D在pre-commit消息,这是B和C只能看到2票投给了blockX,一票投给了空块,全部不足2/3,于是B和C都只能commit空块,高度不变,进人R+1轮,A也只能看到2票投给了blockX,一票投给了空块,也只能commit空块,高度不变,进人R+1轮;(7)在R+1轮,由于新换了一个proposer,提议了新的区块blockY,A,B,C三个个可能会在达成共识,提交blockY,于是在同样的高度,就有blockX和blockY两个块,产生了分叉?其实,Tendermint加上了锁的机制,具体就是,在第7步,即使proposer出了新块blockY,A,B,C只能被锁定在第6步他们的pre-commit块上,即A在第6步投给了空块,那么在第R+1轮,只能继续投给空块,B在第6步投给了blockX,那么在新一轮,永远只能投给blockX,C也是类似。这样在R+1轮,就会有1票投给空块,两票投给blockX,最终达成共识blockX,A,B,C三人都会commitblockX,与D一致,没有产生冲突。3.2.2P2P网络Tendermint的P2P网络协议借鉴了比特币的对等发现协议,更准确地说,Tendermint是采用了BTCD的P2P地址簿(AddressBook)机制。当连接建立后,新节点将自身的Address信息(包含IP、Port、ID等)发送给相邻节点,相邻节点接收到信息后加入到自己的地址薄,再将此条Address信息,转播给它的相邻节点。此外为了保证节点之间数据传输的安全性,Tendermint采用了基于Station-to-Station协议的认证加密方案,此协议是一种密钥协商方案,基于经典的DH算法,并提供相互密钥和实体认证。大致的流程如下:(1)每一个节点都必须生成一对ED25519密钥对作为自己的ID。(2)当两个节点建立起TCP连接时,两者都会生成一个临时的ED25519密钥对,并把临时公钥发给对方。(3)两个节点分别将自己的私钥和对方的临时公钥相乘,得到共享密钥。这个共享密钥对称加密密钥。(4)将两个临时公钥以一定规则进行排序,并将两个临时公钥拼接起来后使用Ripemd160进行哈希处理,后面填充4个0,这样可以得到一个24字节的随机数。(5)得到的随机数作为加密种子,但为了保证相同的随机数不会被相同的私钥使用两次,我们将随机数最后一个bit置为1,这样就得到了两个随机数,同时约定排序更高的公钥使用反转过的随机数来加密自己的消息,而另外一个用于解密对方节点的消息。(6)使用排序的临时公钥拼接起来,并进行SHA256哈希,得到一个挑战码。(7)每个节点都使用自己的私钥对挑战码进行签名,并将自己的公钥和签名发给其它节点校验。(8)校验通过之后,双方的认证就验证成功了。后续的通信就使用共享密钥和随机数进行加密,保护数据的安全。3.3应用示例Tendermint官方项目里内置了ABCIApplication的两个简单实现counter以及kvstore。这个两个Demo逻辑非常简单,运行起来也非常简单,以kvstore为例,只需要下面三条简单的指令就可以轻松的跑起来:tendermintinitabci-clikvstoretendermintnode复杂一点,假设想使用Tendermint实现一套类似Ethereum的应用,最终应该是这样:由TendermintCore负责交易和区块的共享以及共识处理,开发者只需将go-ethereum和ABCIServer集成一个ABCI应用。Ethermint项目就是Tendermint团队开发的一个类似应用,大家可以参考,遗憾的是目前Ethermint目前只支持低版本的abci和go-ethereum。4.Tendermint工作流程上图简单描述了Tenermint的工作流。大致为:(1)client通过RPC接口broadcast_tx_commit提交交易;(2)mempool调用ABCI接口CheckTx用于校验交易的有效性,比如交易序号、发送者余额等,同时订阅交易执行后的事件并等待监听。(3)共识从mempool中获取交易开始共识排序,打包区块,确定之后依次调用ABCI相关接口更新当前的事件状态,并触发事件。(4)最终将交易信息返回client。5.参考本文转载自《深度解析Tendermint,快速融入Cosmos生态》。更多Tendermint资料参考:(1)拜占庭共识Tendermint介绍及简单入门https://blog.csdn.net/niyuelin1990/article/details/80537329(2)Tendermint说明文档https://tendermint.readthedocs.io/en/master/(3)TendermintGIT地址https://github.com/tendermint/tendermint(4)深度解析Tendermint,快速融入Cosmos生态[质量高]https://zhuanlan.zhihu.com/p/38252058(5)区块链框架Tendermint入门教程https://hbliu.coding.me/2018/04/02/tendermint-introduction-1/(6)详解Tendermint共识算法https://www.odaily.com/post/5134145(7)分布式一致性协议介绍(Paxos、Raft)https://www.cnblogs.com/zhang-qc/p/8688258.html作者:笔名辉哥链接:https://www.jianshu.com/p/68fb29cd00de

区块链学习

区块链应用已经从单纯电子现金发展到去中心化投票等更多的领域,但是区块链这样的分布式系统的开发还存在一些困难的问题:安全、可靠性、敏捷度、以及一致性保证等等。Tendermint的目的就是致力于解决分布式系统开发中像公示算法这样的技术难点,而让Tendermint区块链应用开发者可以将关注点集中在业务逻辑上。如果希望快速掌握基于Tendermint的区块链开发,推荐汇智网的在线互动课程:Tendermint区块链开发详解,技术问题可以咨询课堂助教。Tendermint简介Tendermint萌芽于比特币、以太坊这样的加密货币,它的目标是提供一个比比特币的工作量证明(PoW)更加高效和安全的共识算法。简单地说,Tendermint是一个可供二次开发的软件包,可以在多台机器上安全、一致地实现应用状态的复制。Tendermint可以在不超过1/3的机器失效时依然正常工作,无论失效的原因是什么。Tendermint实现了拜占庭容错。任何正常工作的机器都会收到相同的交易日志,并分别推导出相同的状态Tendermint的特性如下图所示:Tendermint包含两个主要的组件:区块链共识引擎,即:Tendermint内核应用与区块链接口,即:ApplicationBlockChainInterfaceTendermint内核可以托管任意的应用状态,因此可以使用任何语言开发区块链软件:Haskell、GoLang、或者Rust都可以用来开发ABCI应用。其他区块链的一个问题是,它们都是单体设计思维的软件。以比特币为例,比特币的设计就是单体的,其区块链技术栈都包含在单一程序里,需要处理从P2P链接到交易广播、达成共识乃至检查账户余额的一切事情。单体应用通常不容易扩展、升级或再利用,而Tendermint则致力于将区块链技术栈的两个核心组件与其他部分解耦:共识引擎和P2P连接——事实上这也是开发区块链的最困难的两个技术环节——从而可以使用任何开发语言来开发ABCI应用。废话不多说了,让我们撸起袖子开干!Tendermint开发环境搭建与测试STEP1:下载Tendermint内核tendermint内核采用Go开发,有官方预编译程序,下载地址:TendermintCore。下载后直接解压,并将tendermint程序目录添加到环境变量PATH的设置里。STEP2:初始化Tendermint执行如下命令初始化Tendermint:~$tendermintinit应当可以在终端看到tendermint的输出信息:I[10–18|20:14:08.996]Generatedprivatevalidatormodule=mainpath=/Users/niharikasingh/.tendermint/config/priv_validator.jsonI[10–18|20:14:08.996]Generatednodekeymodule=mainpath=/Users/niharikasingh/.tendermint/config/node_key.jsonI[10–18|20:14:08.996]Generatedgenesisfilemodule=mainpath=/Users/niharikasingh/.tendermint/config/genesis.jsonSTEP3:启动Tendermint节点使用node子命令启动Tendermint节点:~$tendermintnode-proxy_app=kvstore-proxy_app运行标志用来指定一个内置的ABCI应用,例如kvstore是tendermint程序内置的键值对应用。你应该可以看到如下的tendermint程序输出:I[10–18|20:16:40.037]StartingmultiAppConnmodule=proxyimpl=multiAppConn...I[10–18|20:16:42.051]enterPropose:Ourturntoproposemodule=consensusheight=2round=0proposer=601302EBD1F8B4BCE9F99B219965F2796AB6BB10privValidator=”PrivValidator{601302EBD1F8B4BCE9F99B219965F2796AB6BB10LH:1,LR:0,LS:3}”I[10–18|20:16:42.055]Signedproposalmodule=consensusheight=2round=0proposal=”Proposal{2/01:48B45F4423A5(-1,:0:000000000000)F52DF1F111D8@2018–10–18T14:46:42.051967933Z}”I[10–18|20:16:42.056]Receivedproposalmodule=consensusproposal=”Proposal{2/01:48B45F4423A5(-1,STEP4:提交交易要提交一个交易,可以使用curl向Tendermint节点的RPC服务发出请求,例如:~$curlhttp://localhost:26657/broadcast_tx_commit?tx=\"niharika\"响应结果如下:{"jsonrpc":"2.0","id":"","result":{"check_tx":{"gasWanted":"1"},"deliver_tx":{"tags":[{"key":"YXBwLmNyZWF0b3I=","value":"amFl"},{"key":"YXBwLmtleQ==","value":"bmloYXJpa2E="}]},"hash":"EAAD936D3EDCCCF5DD214E02BB4065E5511CA5AC","height":"3533"}}注意结果中的value字段,例如bmloYXJpa2E,这其实是字符串niharika的base64编码。现在让我们查询一下:~$curl-s'localhost:26657/abci_query?data="niharika"'响应结果如下:{"jsonrpc":"2.0","id":"","result":{"response":{"log":"exists","index":"-1","key":"bmloYXJpa2E=","value":"bmloYXJpa2E="}}}很好,看起来我们的Tendermint内核与ABCI接口的工作一切正常!在本文中,我们成功安装并启动了tendermint内核,然后通过节点旳ABCI接口提交了一个交易来更新内置键值库应用的状态,最后通过ABCI接口查询了ABCI应用的状态。这就是基于Tendermint进行应用开发的核心模型:可以使用任何开发语言来代替curl完成这些操作,实现自己的ABCI应用!原文链接:Tendermint101-拥抱区块链的未来

区块链学习

Tendermint是什么?来自一段slack对话先来举个例子,Wordpress与ApacheWebServer,ApacheWebServer通过fastcgi与Wordpress进行交流。它们被组合到一个服务端的进程中,这个进程负责处理连接逻辑,比如控制流量和安全。Tendermint就像是分布式账本中的ApacheWebServer,它负责了像p2p网络,共识,交易广播等等之类的事情。对于应用任何商业性质的逻辑处理而言,Tendermint是透明的。而对Tendermint来说,这些逻辑处理也都只不过是二进制的字节而已。一旦网络中的验证人对一个块达成共识,并且想要提交这个块时,交易就会通过ABCI被推送到应用中,ABCI是一个网络套接字协议,它的作用就类似于在ApacheWebServer与Wordpress示例中的fastcgi.没有人知道谁会成为未来分布式账本中的Wordpress.另一种解释Tenermint是一个软件,用于在多台机器安全一致地复制一个应用。所谓安全,指的是即使有多达1/3的机器出现任意故障的情况下,Tendermint仍然能够正常工作。所谓一致,指的是每一个正常工作的机器都会有着同样的交易日志,计算相同的状态。安全一致的复制是分布式系统中一个至关重要的问题:从货币到选举,到基础设施规划,它在广泛应用的容错中承担了一个极其重要的角色。能够容忍机器以任何一种,甚至包括危害系统的方式发生故障,被称为拜占庭容错(BFT)。拜占庭理论已经有几十年的历史,但是很大程度上,直到最近像比特币,以太坊这样区块链技术的成功,它的软件实现才得以进一步发展。区块链技术只是以一种现代化的方式对BFT的再形式化,而且重点关注p2p网络和密码验证。区块链这个名词来源于交易的处理方式,通过区块的批量方式处理交易,每个块包含了前一个块的加密哈希,以此来形成一个链。实际上,区块链数据库真正地优化了BFT设计。Tendermint包含了两个主要的技术组件:一个区块链共识引擎和一个通用的应用程序接口。共识引擎,叫做TendermintCore,保证了每一台机器以相同的顺序记录同一笔交易。应用程序接口,叫做应用程序区块链接口(ABCI),保证了交易可以通过任何一种编程语言进行处理。与其他预先打包内置状态机(比如键值存储或者一个奇怪的脚本语言)的区块链和共识方案不同,开发者可以使用Tendermint实现应用的BFT状态机复制,而这些应用可以用任何语言编写,而且开发环境对开发者也十分友好。Tendermint的设计原则是易使用,易理解,高性能,对于各种分布式应用都十分有用。1.Tendermint与其他技术的比较大体上,Tendermint与两类软件很类似。第一类包含了分布式的键值存储,比如Zookeeper,etcd和consul,它们都使用了非拜占庭容错共识。第二类就是“区块链技术”,它既包括了像比特币和以太坊这样的加密货币,也包括了像HyperledgerBurrow这样的分布式账本设计。Zookeeper,etcd,consulZookeeper,etcd和consul都是在一个经典的非拜占庭容错共识算法上,实现了一个键值存储。Zookeeper使用了Paxos一个叫做ZookeeperAtomicBroadcast的版本,而etcd和consul则使用了更年轻,也更简单的Raft共识算法。一个典型的集群由3-5台机器构成,虽然可以承受1/2的机器发生问题,但是只要发生一次拜占庭故障,整个系统就可能被摧毁。它们每一个都提供了一个稍微有别于键值存储的实现,但是都将关注点放在提供分布式系统的基础服务上,比如动态配置,服务发现,锁定,领导人选取等等。Tendermint是一个本质上类似的软件,不过有两点关键不同:它是拜占庭容错的,这意味着它可以承受1/3机器发生任意形式的故障–包括黑客和恶意攻击。它并不像键值存储,是针对某一指定类型的应用。相反,它关注于任意的状态机复制,因此开发者可以量身打造适合自己的应用逻辑,从键值存储到加密货币到电子投票平台,甚至更多的应用都可适用。以上内容取自于consul.io和Hashicorpsites.Bitcoin,Ethereum,etc.在比特币和以太坊这样的传统加密货币下出现了Tendermint,它的目的在于提供一个比比特币的工作量证明更加有效和安全的共识算法。在早期,Tendermint内置了一个简单的货币来参与共识,用户必须向一个保证金账户中“绑定”一定数量的货币,如果他们表现不端,这些钱就会被收回–这一点使得Tendermint成为一个POS算法。自那时起,Tendermint就进化为一个能够承载任意应用状态的通用区块链共识引擎。这意味着它可以成为其他区块链软件共识引擎的一个即插即用的替代品。所以基于当前的以太坊代码库,无论是用何种语言,Rust,Go,Haskell,任何人都可以使用Tendermint共识运行一个ABCI应用。实际上,我们已经完成了这一点(ethermint)。此外,我们也计划为Bitcoin,ZCash,和其他确定性的应用完成同样的工作。另一个基于Tendermint构建的加密货币应用是Cosmos。Fabric,BurrowFabric采用了与Tendermint类似的方法,但是它更关注对状态的管理,并且要求所有的应用行为能够在多个docker容器,叫做“chaincode”的模块中运行。它使用了来自IBM(augmentedtohandlepotentiallynon-deterministicchaincode)的PBFT实现。通过扩展Tendermint来处理未来工作中存在的不确定性,在Tendermint中通过一个ABCI应用实现这个基于docker的行为是完全有可能的。Burrow是一个以太坊虚拟机和以太坊交易机制的实现,同时附带有名字注册,许可权和天然合约,可替代区块链API等额外特性。它使用Tendermint作为它的共识引擎,提供一个特殊的应用状态。2.什么是ABCI(应用区块链接口)区块链应用接口(ApplicationBlockChainInterface,ABCI)允许应用的拜占庭容错复制可以由任意一种编程语言编写。动机至今为止,所有的区块链“栈”(比如,比特币)都有着大一统的设计。这就是说,每个区块链栈都是一个单一的程序,这个程序处理了去中心化账本的所有事务。它还包括了P2P连接,交易的“内存池”广播,在最新块上的共识,账户余额,图灵完备的合约,用户级别的许可权等。在计算机科学中,使用大一统的架构,是一个典型的错误实践。这会使得代码重用变得困难,而且如果真的去这么做时,会导致代码库分支的维护变得十分复杂。尤其当代码设计并非模块化时,会产生难以维护的“意大利面条式代码”。大一统设计的另一个问题是,它限制了区块链栈的语言。比如在以太坊中,它支持一个图灵完备的字节码虚拟机,它限制你必须使用可以编译为那种类型字节码的语言。目前,它所支持的语言是Serpent和Solidity。相反,我们的方式是从特定区块链应用的应用状态细节中,将共识引擎和p2p层分离开来。我们通过将应用细节抽象为一个借口来实现这一点,这个接口被实现为一个socket协议。所以,我们就有了一个接口,应用区块链接口(ABCI),和它的主要实现,TendermintSocketProtocol(TSP,或Teaspoon)。ABCI介绍TendermintCore(“共识引擎”)通过一个满足ABCI标准的socket协议与应用进行交流。举个大家比较熟悉的例子,比特币。比特币是一个加密货币区块链,其中的每个节点维护了一个完全经过审计的UTXO数据库。如果有人想要在ABCI之上创建一个类似比特币的系统,TendermintCore将会负责:在节点间共享区块和交易建立交易(区块链)的标准/不可变顺序而应用将会负责:维护UTXO数据库验证交易的加密签名阻止花费尚未存在的交易允许客户端查询UTXO数据库Tendermint能够通过在应用过程和共识过程之间,提供一个非常简单的API(也就是ABCI)来分解区块链设计。ABCI包含了3个主要的消息类型,它们由core发送至应用,应用会对消息产生相应的回复。消息的详细说明在这里:ABCI消息类型。DeliverTx消息是应用的主要部分。链中的每笔交易都通过这个消息进行传送。应用需要基于当前状态,应用协议,和交易的加密证书上,去验证接收到DeliverTx消息的每笔交易,。一个经过验证的交易然后需要去更新应用状态–比如通过将绑定一个值到键值存储,或者通过更新UTXO数据库。CheckTx消息类似于DeliverTx,但是它仅用于验证交易。TendermintCore的内存池首先通过CheckTx检验一笔交易的有效性,并且只将有效交易中继到其他节点。比如,一个应用可能会检查在交易中不断增长的序列号,如果序列号过时,CheckTx就会返回一个错误。又或者,他们可能使用一个基于容量的系统,该系统需要对每笔交易重新更新容量。Commit消息用于计算当前应用状态的一个加密保证(cryptographiccommitment),这个加密保证会被放到下一个区块头。这有一些比较方便的属性。现在,更新状态时的不一致性会被认为是区块链的分支,分支会捕获所有的编程错误。这同样也简化了保障轻节点客户端安全的开发,因为Merkel-hash证明可以通过在区块哈希上的检查得到验证,区块链哈希由一个quorum签署。一个应用可能有多个ABCIsocket连接。TendermintCore给应用创建了三个ABCI连接:一个用于内存池广播时的交易验证,一个用于运行提交区块时的共识引擎,还有一个用于查询应用状态。很显然,在创建区块链时,应用的设计者需要非常小心地设计他们的消息处理,这个架构提供一个范例。下图阐释了通过ABCI的消息流:关于确定性的说明区块链交易处理的逻辑必须是确定性的。如果应用逻辑不确定,就无法在TendermintCore复制节点间达成共识。在以太坊上的Solidity是用于区块链应用一个非常好的语言选择,除了一些其他因素,它还是一个完全确定性的编程语言。但是,通过使用现有的一些语言,比如Java,C++,Python和Go也是可以创建确定性应用的。对通过避免非确定性来源创建确定性程序,游戏程序员和区块链开发者都已经很熟悉了,比如:随机数生成器(没有确定性的种子)线程上的竞争条件(或者避免多线程)系统时钟未初始化的内存(在像C或者C++这样的不安全语言)浮点数算法随机的语言特性(比如Go语言的map迭代)尽管程序员可以通过加倍小心来避免非确定性,但是给每个语言创建一个特殊的语法检查器或静态分析器,用它们来检查确定性也是有可能的。在未来,我们可能会与合作者一起创造出这样的工具。3.共识概览Tendermint是一个易于理解,大部分操作为异步的BFT共识协议。下图是一个简单的状态机,它展示了协议遵循的规则:协议中的参与者叫着“验证人”(validator)。他们轮流对交易区块进行提议,并对这些区块进行投票。区块会被提交到链上,每一个块占据一个“高度”(height)。提交块可能会失败,如果失败,协议就会开始下一轮的提交,并且一个新的验证人会继续提交那个高度的区块。要想成功提交一个块,需要有两个阶段的投票:“预投票”(pre-vote)和“预提交”(pre-commit)。在同一轮提交中,只有超过2/3的验证人对同一个块进行了预提交,这个块才能被提交到链上。上图右下角有一对夫妇在跳波卡舞,因为验证人做的事情就像是在跳波卡舞。当超过2/3的验证人对同一个块进行了预投票,我们就把它叫做一个“波卡”(polka)。每一个预提交都必须被同一轮中的一个波卡所证明。由于一些原因,验证人可能在提交一个块时失败:当前提议者可能离线了,或者网络非常慢。Tendermint允许他们证实一个验证人应该被跳过。在进行下一轮的投票前,验证人会等待一小段时间从提议者那里接收一个完整的提议块。这种对于超时的依赖,使得Tendermint成为了一个弱同步协议,而非一个异步协议。但是,协议的剩余部分都是异步的,只有在接收到超过2/3的验证人集合时,验证人才会采取下一步操作。Tendermint能够简化的一个原因就是它使用了同样的机制来提交一个块和跳过直接进入下一轮。基于不到1/3的验证人是拜占庭节点的前提,Tendermint保证了永远都不会违背其安全性–也就是说,验证人永远不会在同一高度提交冲突块。为了达到这一点,它引入了一些“锁定”(locking)的规则,这些规则对流程图中的路径进行了模块化。一旦一个验证人预提交了一个块,它就被“锁定”在了那个块上。然后,它必须为被锁定的那个块进行预投票只有在之后的轮中,有了那个块的一个波卡,它才能够解锁,并为一个新块进行预提交。权益在许多系统中,并非所有的验证人都在共识协议有着同样的“高度”(height)。因此,我们对1/3还是2/3的验证人并不十分感兴趣,而是关心在所有投票力量所占的比例,在个体验证人中,这些比例可能并不是均匀分布的。由于Tendermint可以复制任意的应用程序,定义一种货币,并用该货币来计算投票权力是完全有可能的。当使用货币决定投票权时,这个系统通常叫做权益证明(Proof-of-Stake)系统。通过应用逻辑,可以将验证人的货币持有强制绑定到一个押金账户中。如果他们被发现在共识协议中表现不端,这些钱就会被销毁。这就给协议的安全性增加了一个经济因素,能够让人们量化违反共识假设的成本,这个假设就是只有不到1/3的投票权来自拜占庭节点。CosmosNetwork的设计目的,是在实现了ABCI应用的加密货币中使用这个权益证明机制。原文:Tendermintintro

2020-4-14 1534 0
区块链学习

比特币使用椭圆曲线算法生成公钥和私钥,选择的是secp256k1曲线椭圆曲线加密(EllipticCurveCryptography)的缩写。该算法是基于椭圆曲线数学的一种公钥密码的算法,其安全性依赖于椭圆曲线离散对数问题的困难性。本文相关概念:1.数学上的椭圆曲线及相关概念2.密码学中的椭圆曲线3.椭圆曲线上的加密/解密4.椭圆曲线签名与验证签名一、数学上的椭圆曲线及相关概念1.1从平行线谈起平行线,永不相交。不过到了近代这个结论遭到了质疑。平行线会不会在很远很远的地方相交?事实上没有人见到过。所以“平行线,永不相交”只是假设(大家想想初中学习的平行公理,是没有证明的)。既然可以假设平行线永不相交,也可以假设平行线在很远很远的地方相交了。即平行线相交于无穷远点P∞(请大家闭上眼睛,想象一下那个无穷远点P∞,P∞是不是很虚幻,其实与其说数学锻炼人的抽象能力,还不如说是锻炼人的想象力)。给个图帮助理解一下:直线上出现P∞点,所带来的好处是所有的直线都相交了,且只有一个交点。这就把直线的平行与相交统一了。为与无穷远点相区别把原来平面上的点叫做平常点。以下是无穷远点的几个性质。▲直线L上的无穷远点只能有一个。(从定义可直接得出)▲平面上一组相互平行的直线有公共的无穷远点。(从定义可直接得出)▲平面上任何相交的两直线L1,L2有不同的无穷远点。(否则L1和L2有公共的无穷远点P,则L1和L2有两个交点A、P,故假设错误。)▲平面上全体无穷远点构成一条无穷远直线。(自己想象一下这条直线吧)▲平面上全体无穷远点与全体平常点构成射影平面。1.2射影平面坐标系射影平面坐标系是对普通平面直角坐标系(就是我们初中学到的那个笛卡儿平面直角坐标系)的扩展。我们知道普通平面直角坐标系没有为无穷远点设计坐标,不能表示无穷远点。为了表示无穷远点,产生了射影平面坐标系,当然射影平面坐标系同样能很好的表示旧有的平常点(数学也是“向下兼容”的)。我们对普通平面直角坐标系上的点A的坐标(x,y)做如下改造:令x=X/Z,y=Y/Z(Z≠0);则A点可以表示为(X:Y:Z)。变成了有三个参量的坐标点,这就对平面上的点建立了一个新的坐标体系。例1:求点(1,2)在新的坐标体系下的坐标。解:∵X/Z=1,Y/Z=2(Z≠0)∴X=Z,Y=2Z∴坐标为(Z:2Z:Z),Z≠0。即(1:2:1)(2:4:2)(1.2:2.4:1.2)等形如(Z:2Z:Z),Z≠0的坐标,都是(1,2)在新的坐标体系下的坐标。我们也可以得到直线的方程aX+bY+cZ=0(想想为什么?提示:普通平面直角坐标系下直线一般方程是ax+by+c=0)。新的坐标体系能够表示无穷远点么?那要让我们先想想无穷远点在哪里。根据上一节的知识,我们知道无穷远点是两条平行直线的交点。那么,如何求两条直线的交点坐标?这是初中的知识,就是将两条直线对应的方程联立求解。平行直线的方程是:aX+bY+c1Z=0;aX+bY+c2Z=0(c1≠c2);(为什么?提示:可以从斜率考虑,因为平行线斜率相同);将二方程联立,求解。有c2Z=c1Z=-(aX+bY),∵c1≠c2∴Z=0∴aX+bY=0;所以无穷远点就是这种形式(X:Y:0)表示。注意,平常点Z≠0,无穷远点Z=0,因此无穷远直线对应的方程是Z=0。例2:求平行线L1:X+2Y+3Z=0与L2:X+2Y+Z=0相交的无穷远点。解:因为L1∥L2所以有Z=0,X+2Y=0;所以坐标为(-2Y:Y:0),Y≠0。即(-2:1:0)(-4:2:0)(-2.4:1.2:0)等形如(-2Y:Y:0),Y≠0的坐标,都表示这个无穷远点。看来这个新的坐标体系能够表示射影平面上所有的点,我们就把这个能够表示射影平面上所有点的坐标体系叫做射影平面坐标系。1.3椭圆曲线上一节,我们建立了射影平面坐标系,这一节我们将在这个坐标系下建立椭圆曲线方程。因为我们知道,坐标中的曲线是可以用方程来表示的(比如:单位圆方程是x2+y2=1)。椭圆曲线是曲线,自然椭圆曲线也有方程。椭圆曲线的定义:一条椭圆曲线是在射影平面上满足方程---------------------------[1-1]的所有点的集合,且曲线上的每个点都是非奇异(或光滑)的。定义详解:▲[1-1]是Weierstrass方程(维尔斯特拉斯,KarlTheodorWilhelmWeierstrass,1815-1897),是一个齐次方程。▲椭圆曲线的形状,并不是椭圆的。只是因为椭圆曲线的描述方程,类似于计算一个椭圆周长的方程,故得名。我们来看看椭圆曲线是什么样的。▲所谓“非奇异”或“光滑”的,在数学中是指曲线上任意一点的偏导数Fx(x,y,z),Fy(x,y,z),Fz(x,y,z)不能同时为0。如果你没有学过高等数学,可以这样理解这个词,即满足方程的任意一点都存在切线。下面两个方程都不是椭圆曲线,尽管他们是方程[3-1]的形式。因为他们在(0:0:1)点处(即原点)没有切线。▲椭圆曲线上有一个无穷远点O∞(0:1:0),因为这个点满足方程[1-1]。知道了椭圆曲线上的无穷远点。我们就可以把椭圆曲线放到普通平面直角坐标系上了。因为普通平面直角坐标系只比射影平面坐标系少无穷远点。我们在普通平面直角坐标系上,求出椭圆曲线上所有平常点组成的曲线方程,再加上无穷远点O∞(0:1:0),不就构成椭圆曲线了么?我们设x=X/Z,y=Y/Z代入方程[1-1]得到:y2+a1xy+a3y=x3+a2x2+a4x+a6-------------------------[1-2]也就是说满足方程[1-2]的光滑曲线加上一个无穷远点O∞,组成了椭圆曲线。为了方便运算,表述,以及理解,今后论述椭圆曲线将主要使用[1-2]的形式。本节的最后,我们谈一下求椭圆曲线一点的切线斜率问题。由椭圆曲线的定义可以知道,椭圆曲线是光滑的,所以椭圆曲线上的平常点都有切线。而切线最重要的一个参数就是斜率k。例3:求椭圆曲线方程上,平常点A(x,y)的切线的斜率k。解:令F(x,y)=y2+a1xy+a3y-x3-a2x2-a4x-a6求偏导数Fx(x,y)=a1y-3x2-2a2x-a4Fy(x,y)=2y+a1x+a3则导数为:f'(x)=-Fx(x,y)/Fy(x,y)=-(a1y-3x2-2a2x-a4)/(2y+a1x+a3)=(3x2+2a2x+a4-a1y)/(2y+a1x+a3)所以-------------[1-3]看不懂解题过程没有关系,记住结论[1-3]就可以了。1.4椭圆曲线上的加法上一节,我们已经看到了椭圆曲线的图象,但点与点之间好象没有什么联系。我们能不能建立一个类似于在实数轴上加法的运算法则呢?天才的数学家找到了这一运算法则自从近世纪代数学引入了群、环、域的概念,使得代数运算达到了高度的统一。比如数学家总结了普通加法的主要特征,提出了加群(也叫交换群,或Abel(阿贝尔)群),在加群的眼中。实数的加法和椭圆曲线的上的加法没有什么区别。这也许就是数学抽象把:)。关于群以及加群的具体概念请参考近世代数方面的数学书。运算法则:任意取椭圆曲线上两点P、Q(若P、Q两点重合,则做P点的切线)做直线交于椭圆曲线的另一点R’,过R’做y轴的平行线交于R。我们规定P+Q=R。(如图)法则详解:▲这里的+不是实数中普通的加法,而是从普通加法中抽象出来的加法,他具备普通加法的一些性质,但具体的运算法则显然与普通加法不同。▲根据这个法则,可以知道椭圆曲线无穷远点O∞与椭圆曲线上一点P的连线交于P’,过P’作y轴的平行线交于P,所以有无穷远点O∞+P=P。这样,无穷远点O∞的作用与普通加法中零的作用相当(0+2=2),我们把无穷远点O∞称为零元。同时我们把P’称为P的负元(简称,负P;记作,-P)。(参见下图)▲根据这个法则,可以得到如下结论:如果椭圆曲线上的三个点A、B、C,处于同一条直线上,那么他们的和等于零元,即A+B+C=O∞同一直线上的三个点之和等于0.注:我们需要的只是三个点同线,与点的次序无关。这意味着,如果P、Q和R同线,那么P+(Q+R)=Q+(P+R)=R+(P+Q)=•••=0.这样,我们直观地证明了我们的“+”运算既满足结合律也满足交换律。▲k个相同的点P相加,我们记作kP。如下图:P+P+P=2P+P=3P。下面,我们利用P、Q点的坐标(x1,y1),(x2,y2),求出R=P+Q的坐标(x4,y4)。例4:求椭圆曲线方y2+a1xy+a3y=x3+a2x2+a4x+a6上,平常点P(x1,y1),Q(x2,y2)的和R(x4,y4)的坐标。解:(1)先求点-R(x3,y3)因为P,Q,-R三点共线,故设共线方程为y=kx+b,其中若P≠Q(P,Q两点不重合)则直线斜率k=(y1-y2)/(x1-x2)若P=Q(P,Q两点重合)则直线为椭圆曲线的切线,故由例3.1可知:k=(3x2+2a2x+a4-a1y)/(2y+a1x+a3)因此P,Q,-R三点的坐标值就是方程组:y2+a1xy+a3y=x3+a2x2+a4x+a6-----------------[1]y=(kx+b)-----------------[2]的解。将[2],代入[1]有(kx+b)2+a1x(kx+b)+a3(kx+b)=x3+a2x2+a4x+a6--------[3]对[3]化为一般方程,根据三次方程根与系数关系(当三次项系数为1时;-x1x2x3等于常数项系数,x1x2+x2x3+x3x1等于一次项系数,-(x1+x2+x3)等于二次项系数。)所以-(x1+x2+x3)=a2-ka1-k2x3=k2+ka1+a2+x1+x2;---------------------求出点-R的横坐标因为k=(y1-y3)/(x1-x3)故y3=y1-k(x1-x3);-------------------------------求出点-R的纵坐标(2)利用-R求R显然有x4=x3=k2+ka1+a2+x1+x2;------------求出点R的横坐标而y3y4为x=x4时方程y2+a1xy+a3y=x3+a2x2+a4x+a6的解化为一般方程y2+(a1x+a3)y-(x3+a2x2+a4x+a6)=0,根据二次方程根与系数关系得:-(a1x+a3)=y3+y4故y4=-y3-(a1x+a3)=k(x1-x4)-y1-(a1x4+a3);---------------求出点R的纵坐标即:x4=k2+ka1+a2+x1+x2;y4=k(x1-x4)-y1-a1x4-a3;本节的最后,提醒大家注意一点,以前提供的图像可能会给大家产生一种错觉,即椭圆曲线是关于x轴对称的。事实上,椭圆曲线并不一定关于x轴对称。如下图的y2-xy=x3+1二、密码学中的椭圆曲线我们现在基本上对椭圆曲线有了初步的认识,这是值得高兴的。但请大家注意,前面学到的椭圆曲线是连续的,并不适合用于加密;所以,我们必须把椭圆曲线变成离散的点,要把椭圆曲线定义在有限域上。让我们想一想,为什么椭圆曲线为什么连续?是因为椭圆曲线上点的坐标,是实数的(也就是说前面讲到的椭圆曲线是定义在实数域上的),实数是连续的,导致了曲线的连续。因此,我们要把椭圆曲线定义在有限域上(顾名思义,有限域是一种只有由有限个元素组成的域)。域的概念是从我们的有理数,实数的运算中抽象出来的,严格的定义请参考近世代数方面的数。简单的说,域中的元素同有理数一样,有自己得加法、乘法、除法、单位元(1),零元(0),并满足交换率、分配率。下面,我们给出一个有限域Fp,这个域只有有限个元素。Fp中只有p(p为素数)个元素0,1,2……p-2,p-1;Fp的加法(a+b)法则是a+b≡c(modp);即,(a+b)÷p的余数和c÷p的余数相同。Fp的乘法(a×b)法则是a×b≡c(modp);Fp的除法(a÷b)法则是a/b≡c(modp);即a×b-1≡c(modp);(b-1也是一个0到p-1之间的整数,但满足b×b-1≡1(modp))。Fp的单位元是1,零元是0。同时,并不是所有的椭圆曲线都适合加密。y2=x3+ax+b是一类可以用来加密的椭圆曲线,也是最为简单的一类。下面我们就把y2=x3+ax+b(modp)这条曲线定义在Fp上:选择两个满足下列条件的小于p(p为素数)的非负整数a、b4a3+27b2≠0 (modp)则满足下列方程的所有点(x,y),再加上无穷远点O∞,构成一条椭圆曲线。y2=x3+ax+b(modp)其中x,y∈[0,p-1]的整数,并将这条椭圆曲线记为Ep(a,b)。我们看一下y2=x3+x+1(mod23)的图像是不是觉得不可思议?椭圆曲线,怎么变成了这般模样,成了一个一个离散的点?椭圆曲线在不同的数域中会呈现出不同的样子,但其本质仍是一条椭圆曲线。举一个不太恰当的例子,好比是水,在常温下,是液体;到了零下,水就变成冰,成了固体;而温度上升到一百度,水又变成了水蒸气。但其本质仍是H2O。Fp上的椭圆曲线同样有加法,但已经不能给以几何意义的解释。不过,加法法则和实数域上的差不多,请读者自行对比。1.无穷远点O∞是零元,有O∞+O∞=O∞,O∞+P=P2.P(x,y)的负元是(x,-y),有P+(-P)=O∞3.P(x1,y1),Q(x2,y2)的和R(x3,y3)有如下关系:x3≡k2-x1-x2(modp)y3≡k(x1-x3)-y1(modp)其中若P=Q则k=(3x2+a)/2y1若P≠Q,则k=(y2-y1)/(x2-x1)例5:已知椭圆曲线已知E23(1,1)上两点P(3,10),Q(9,7),求(1)-P,(2)P+Q,(3)2P解:最后,我们讲一下椭圆曲线上点的阶。如果椭圆曲线上一点P,存在最小的正整数n,使得数乘nP=O∞,则将n称为P的阶,若n不存在,我们说P是无限阶的。事实上,在有限域上定义的椭圆曲线上所有的点的阶n都是存在的。计算可得27P=-P=(3,13)所以28P=O∞P的阶为28这些点做成了一个循环阿贝尔群,其中生成元为P,阶数为29。显然点的分布与顺序都是杂乱无章三、椭圆曲线上的加密/解密公开密钥算法总是要基于一个数学上的难题。比如RSA依据的是:给定两个素数p、q很容易相乘得到n,而对n进行因式分解却相对困难。那椭圆曲线上有什么难题呢?考虑如下等式:K=kG[其中K,G为Ep(a,b)上的点,k为小于n(n是点G的阶)的整数]不难发现,给定k和G,根据加法法则,计算K很容易;但给定K和G,求k就相对困难了。这就是椭圆曲线加密算法采用的难题。我们把点G称为基点(basepoint),k(k<n,n为基点g的阶)称为私有密钥(privtekey),k称为公开密钥(public=""key)。<=""p="">现在我们描述一个利用椭圆曲线进行加密通信的过程:1、用户A选定一条椭圆曲线Ep(a,b),并取椭圆曲线上一点,作为基点G。2、用户A选择一个私有密钥k,并生成公开密钥K=kG。3、用户A将Ep(a,b)和点K,G传给用户B。4、用户B接到信息后,将待传输的明文编码到Ep(a,b)上一点M(编码方法很多,这里不作讨论),并产生一个随机整数r(r<n)。5、用户B计算点C1=M+rK;C2=rG。6、用户B将C1、C2传给用户A。7、用户A接到信息后,计算C1-kC2,结果就是点M。因为C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M再对点M进行解码就可以得到明文。在这个加密通信中,如果有一个偷窥者H,他只能看到Ep(a,b)、K、G、C1、C2而通过K、G求k或通过C2、G求r都是相对困难的。因此,H无法得到A、B间传送的明文信息。总结:设私钥、公钥分别为k、K,即K=kG,其中G为G点。  公钥加密:  选择随机数r,将消息M生成密文C,该密文是一个点对,即:  C={rG,M+rK},其中K为公钥  私钥解密:  M+rK-k(rG)=M+r(kG)-k(rG)=M  其中k、K分别为私钥、公钥。ECC技术要求:密码学中,描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,G,n,h)。(p、a、b用来确定一条椭圆曲线,G为基点,n为点G的阶,h是椭圆曲线上所有点的个数m与n相除的整数部分)这几个参量取值的选择,直接影响了加密的安全性。参量值一般要求满足以下几个条件:1、p当然越大越安全,但越大,计算速度会变慢,200位左右可以满足一般安全要求;2、p≠n×h;3、pt≠1(modn),1≤t<20;4、4a3+27b2≠0(modp);5、n为素数;6、h≤4。四、椭圆曲线签名与验证签名  椭圆曲线签名算法,即ECDSA。设私钥、公钥分别为k、K,即K=kG,其中G为G点。私钥签名:1、选择随机数r,计算点rG(x,y)。2、根据随机数r、消息M的哈希h、私钥k,计算s=(h+kx)/r。3、将消息M、和签名{rG,s}发给接收方。公钥验证签名:1、接收方收到消息M、以及签名{rG=(x,y),s}。2、根据消息求哈希h。3、使用发送方公钥K计算:hG/s+xK/s,并与rG比较,如相等即验签成功。原理如下:hG/s+xK/s=hG/s+x(kG)/s=(h+xk)G/s=r(h+xk)G/(h+kx)=rG五、椭圆曲线在软件注册保护的应用我们知道将公开密钥算法作为软件注册算法的好处是Cracker很难通过跟踪验证算法得到注册机。下面,将简介一种利用Fp(a,b)椭圆曲线进行软件注册的方法。软件作者按如下方法制作注册机(也可称为签名过程)1、选择一条椭圆曲线Ep(a,b),和基点G;2、选择私有密钥k(k  3、产生一个随机整数r(r  4、将用户名和点R的坐标值x,y作为参数,计算SHA(SecureHashAlgorithm安全散列算法,类似于MD5)值,即Hash=SHA(username,x,y);5、计算sn≡r-Hash*k(modn)6、将sn和Hash作为用户名username的序列号软件验证过程如下:(软件中存有椭圆曲线Ep(a,b),和基点G,公开密钥K)1、从用户输入的序列号中,提取sn以及Hash;2、计算点R≡sn*G+Hash*K(modp),如果sn、Hash正确,其值等于软件作者签名过程中点R(x,y)的坐标,因为sn≡r-Hash*k(modn)所以sn*G+Hash*K=(r-Hash*k)*G+Hash*K=rG-Hash*kG+Hash*K=rG-Hash*K+Hash*K=rG=R;3、将用户名和点R的坐标值x,y作为参数,计算H=SHA(username,x,y);4、如果H=Hash则注册成功。如果H≠Hash,则注册失败(为什么?提示注意点R与Hash的关联性)。简单对比一下两个过程:作者签名用到了:椭圆曲线Ep(a,b),基点G,私有密钥k,及随机数r。软件验证用到了:椭圆曲线Ep(a,b),基点G,公开密钥K。Cracker要想制作注册机,只能通过软件中的Ep(a,b),点G,公开密钥K,并利用K=kG这个关系获得k后,才可以。而求k是很困难的。练习:下面也是一种常于软件保护的注册算法,请认真阅读,并试回答签名过程与验证过程都用到了那些参数,Cracker想制作注册机,应该如何做。软件作者按如下方法制作注册机(也可称为签名过程)1、选择一条椭圆曲线Ep(a,b),和基点G;2、选择私有密钥k(k  3、产生一个随机整数r(r  4、将用户名作为参数,计算Hash=SHA(username);5、计算x’=x(modn)6、计算sn≡(Hash+x’*k)/r(modn)7、将sn和x’作为用户名username的序列号软件验证过程如下:(软件中存有椭圆曲线Ep(a,b),和基点G,公开密钥K)1、从用户输入的序列号中,提取sn以及x’;2、将用户名作为参数,计算Hash=SHA(username);3、计算R=(Hash*G+x’*K)/sn,如果sn、Hash正确,其值等于软件作者签名过程中点R(x,y),因为sn≡(Hash+x’*k)/r(modn)所以(Hash*G+x’*K)/sn=(Hash*G+x’*K)/[(Hash+x’*k)/r]=(Hash*G+x’*K)/[(Hash*G+x’*k*G)/(rG)]=rG*[(Hash*G+x’*K)/(Hash*G+x’*K)]=rG=R(modp)4、v≡x(modn)5、如果v=x’则注册成功。如果v≠x’,则注册失败。

区块链学习

总是听到分叉币,今天来说说到底啥是分叉。分叉为什么叫分叉?因为Git中的Fork命令,在软件开发中的分叉指的是:在开源项目中如果有人Fork了一个项目(一个项目分叉为两个项目),然后开发者沿着这个Fork向另外一个不同的方向独立发展这个项目。那么区块链里为什么会产生分叉?假设在区块增长到2号的时候,此时软件升级了,增加了之前版本中不能识别的一些表结构,会怎么样?在传统的中心化软件体系中,由于数据存储都是集中的,版本管理也是集中的,如果是重大的升级,完全可以设置为若不更新到最新版就不能进行登录操作,从而确保用户使用的总是正确的版本。然而区块链先天是去中心的使用方式,一旦有新的软件版本发布后,并每个人都会去升级到新版本,这就可能导致如下图所示的问题:在2号区块生成的时候发布了新的版本,且新的版本增加了之前版本不能识别的数据结构,此时部分用户升级了新版,部分用户还没有升级,这些新旧版本的软件仍然在各自不停的挖矿、验证、打包区块,一段时间过后就会变成这样:这个就叫分叉。由于种种原因比特币协议发生改变,会有两个不同版本的比特币协议在同时使用,他们对其他区块的接受规则不同会导致区块链长期分叉,这两个不同的链都会被不同的网络认为是有效的。链分叉也导致网络分叉。先来说说硬分叉Apermanentdivergenceintheblockchain,commonlyoccurswhennon-upgradednodescan’tvalidateblockscreatedbyupgradednodesthatfollownewerconsensusrules.区块链的永久性分裂。当没有升级的节点不能验证已升级的节点基于新的共识协议所创建的区块时,硬分叉产生。硬分叉不向前兼容:这个定义该如何解读呢?看一下下图:HardFork硬分叉中,新的版本定义了新的规则,并且与旧版本不兼容。当协议发布后,并非所有节点都会选择升级;那些没有升级新协议的区块发布的交易将只能由运行旧版本软件的区块认证通过,而因此升级了新协议的区块发布的交易只能由运行新版本软件的区块认证通过;由于规则不兼容,因此矿工们工作在各自的最长链条上。于是产生了两条基于不同规则的、永远不会合并的区块链。顺便说一下历史上最大的硬分叉事件:TheDao被黑客攻击的事件。2016年6月区块链最大ICO项目TheDao遭黑客攻击,导致300多万以太币资产被分离出TheDAO资产池,当前相当于20亿美元。这时候V神站出来说,这个事情,我知道了,要不我们直接来个软分叉,重新算账。从块高度1760000开始把任何与TheDAO和childDAO相关的交易认做无效交易,不就解决了吗?然而,还是有人提出反对。他们认为这违反了区块链的不可篡改性以及智能合约的契约精神,哪怕TheDAO的钱被偷走了,但是只要数据被写在了区块上,就是不可篡改的,因此他们并不配合V神的分叉,依然使用老版本。就这样,软分叉最后生生搞成了一次硬分叉,V神的新ETH依然获得了大多数矿工和开发者的认可,但是还是有少数人坚持试用老节点,这时挖出来的币被称为ethereumclassic,也就是以太经典。这就是ETH和ETC。而分叉币中另一著名的则是BTC和BCC;BCC支持大区块(将区块大小提升至8M),不包含SegWit功能。再说说软分叉Asoftforkisachangetothebitcoinprotocolwhereinonlypreviouslyvalidblocks/transactionsaremadeinvalid.Sinceoldnodeswillrecognisethenewblocksasvalid,asoftforkisbackward-compatible.软分叉是对比特币协议的一次修改,只有先前有效验证的区块/交易将不再合规;由于旧节点依然可以验证新区块,软分叉被认为是向后兼容的。软分叉是向前兼容的:所有被新版本认为是合法的区块也会被以前旧版本认为是合法的。旧版本会接受新版本创建的区块。新版本和旧版本是兼容的。SoftFork软分叉也是对原有软件协议的修改。与硬分叉不同的是,新的软件版本所定义的新规则与旧版本兼容,但比旧版本更严格。当新版本发布时,升级了新软件版本的节点发布的区块可以被所有节点验证通过。而没有升级新版本的节点发布的区块只能在运行旧版本软件的节点上验证通过。此时,同样会产生两个区块链条,这种情况称为软分叉。当网络中的大多数节点选择部署新软件版本后(更精确的说法是大多数算力),新链条将产生更多的区块,工作在旧版本节点上的矿工们将会逐步升级软件并转移到新链条上来工作,这里有两方面原因。由于新链条成为最长链条,并且新链条上的区块被旧版本节点上的矿工们认可,所以他们会迁移到最长链上来。由于软分叉对于节点是无感知的,旧版本节点发布的新区块会被新版本节点“莫名其妙”的拒绝,这会敦促他们升级新软件版本。最终,并不会像硬分叉一样产生两个不相干的区块链,而是会产生一些临时性的分支。当然,只有当大多数算力支持软分叉时才会使新规则生效。总结来说硬分叉,是当比特币协议规则发生改变,旧节点拒绝接受由新节点创造的区块的情况。违反规则的区块将被忽视,矿工会按照他们的规则集,在他们最后见证的区块之后创建区块。软分叉,是当比特币协议规则发生改变,旧的节点并不会意识到规则是不同的,它们将遵循改变后的规则集,继续接受由新节点创造的区块。矿工们可能会在他们完全没有理解,或者验证过的区块上进行工作。协议一致性在区块链中,能够让区块链保证数据唯一性的前提是:所有矿工都遵从同样的机制。即如果所有矿工都使用同一套协议,则不会出现分叉。但是会有另一种情况导致短暂的“共存”:默认大家已经了解什么是挖矿了,在比特币中使用工作量证明,当有矿工第一个计算出所需的数字,就大喊一声“我的工作量证明成功了你们快来看呀”,这时经过验证之后所有的矿工都会把那一页抄写一份,贴在自己账本的最后一页,然后开始新的记账过程。但是会存在极小的概率下,有两个矿工同时计算出来,这该怎么办?由于网络的亲疏远近,不同的节点听到两个矿工喊“我解出来了”是有先后顺序的,一般大家会把先看到的区块复制过来,然后在这个区块后面开始新的挖矿工作,于是就出现了下面这种情况:这种情况就是短暂共存;要怎么解决呢?在以工作量证明为共识的区块链中,从分叉的区块开始,由于不同的矿工跟随了不同的区块,理论来说从分叉开始的两条链算力是有区别的,因此区块的增长速度也是不同的,在一段时间之后,总有一条链的长度会超过另一条,当矿工发现全网有一条更长的链时,他会放弃当前的链而把全网最长的链复制过来,在这条链的基础上继续挖矿工作,于是全网永远是只有一条最长的链为主链,分叉出来被放弃掉的链就会消失了。最终,只有一条链会被保留下来,成为真正有效的账本,其他都是无效的,所以整个区块链仍然是唯一的。

区块链学习

如果Layer1的关注点应该是状态而不是计算55,在设计Layer1区块链的时候,我们就需要先理解什么是区块链的状态。理解了状态是什么,我们才能理解状态爆炸是什么。状态区块链网络中的每一个全节点,在网络中运行一段时间之后都会在本地存储上留下一些数据,我们可以按照历史和现在把它们分为两类:历史-区块数据和交易数据都是历史,历史是从Genesis到达当前状态的路径。状态(即现在)-节点在处理完从Genesis到当前高度的所有区块和交易后形成的最终结果。状态随着区块的增加一直处于变化之中,交易是造成变化的原因。共识协议的作用是通过一系列的消息交换,保证每一个节点看到的当前状态是相同的,而实现这个目标的方式是保证每一个节点看到的历史是相同的。只要历史相同(即所有交易的排序相同),处理交易的方式相同(把交易放在相同的确定性虚拟机里面执行),最后看到的当前状态就是相同的。当我们说“区块链具有不可篡改性”的时候,指的是区块链历史不可篡改,相反,状态是一直在变化的。有趣的是,不同的区块链保存历史和状态的方式不同的,其中的差异使得不同的区块链形成了各自的特点。由于这篇文章讨论的话题是状态,而影响状态的历史数据主要是交易(而不是区块头),接下来的讨论历史的时候会侧重交易,忽略区块头。举个例子:Bitcoin的历史和状态Bitcoin的状态,指的是Bitcoin账本当前的样子。Bitcoin的状态是由一个个UTXO(尚未花费的交易输出)构成的,每个UTXO代表了一定数量的Bitcoin,每个UTXO上面写了一个名字(scriptPubkey),记录这个UTXO的所有者是谁。如果要做一个比喻的话,Bitcoin的当前状态是一个装满了金币的袋子,每个金币上刻着所有者的名字。Bitcoin的历史由一连串的交易构成,交易内部的主要结构是输入和输出。交易更改状态的方法是,把当前状态中包含的一些UTXO(交易输入引用的那些)标记为已花费,从UTXO集合中移出,然后把一些新的UTXO(这个交易的输出)添加到UTXO集合里面去。Screenshotfrom2019-03-2016-36-46.png1018×62862.1KB可以看出,Bitcoin交易的输出(TXO,TransactionOutput)正是上面说的UTXO,UTXO只不过是一种处于特殊阶段(尚未花费)的TXO。因为构成Bitcoin状态的组件(UTXO),同时也是构成交易的组件(TXO)。由此Bitcoin有一个奇妙的性质:任意时刻的状态都是历史的一个子集,历史和状态包含的数据类型是同一维度的。交易的历史(所有被打包的交易的集合,即所有产生过的TXO的集合)即状态的历史(每个区块对应的UTXO集合的集合,也是所有产生过的TXO的集合),Bitcoin的历史只包含交易。在Bitcoin网络中,每一个区块,每一个UTXO都要持续占用节点的存储空间。目前Bitcoin整个历史的大小(所有区块加起来的大小)大约是200G10,而状态的大小只有~3G(由~5000万个UTXO组成)10。Bitcoin通过对区块大小的限制很好的管理了历史的增长速度,由于其历史和状态之间的子集关系,状态数据大小必然远小于历史数据大小,因此状态增长也间接的受到区块大小的管理。再举个例子:Ethereum的历史和状态Ethereum的状态,也叫做“世界状态”,指的是Ethereum账本当前的样子。Ethereum的状态是由账户构成的一棵Merkle树(账户是叶子),账户里面不仅记录了余额(代表一定数量的ether),还有合约的数据(例如每一只加密猫的数据)。Ethereum的状态可以看作一个大账本,账本的第一列是名字,第二列是余额,第三列是合约数据。Ethereum的历史同样由交易构成,交易内部的主要结构是to-另一个账户,代表交易的发送对象value-交易携带的ether数量data-交易携带的任意信息交易更改状态的方法是,EVM找到交易发送的目标账户,根据交易的value计算目标账户的新余额;将交易携带的data作为参数传递给目标账户的智能合约,运行智能合约的逻辑,在运行中可能会修改任意账户的内部状态生成新的状态;构造新的叶子存放新的状态,更新状态Merkle树Screenshotfrom2019-03-2020-16-19.png1042×65840.1KB可以看出,Ethereum的历史和交易结构与Bitcoin相比有非常大的不同。Ethereum的状态是由账户构成的,而交易是由触发账户变动的信息构成,状态和交易中记录的是完全不同类型的数据,二者之间没有超集和子集的关系,历史和状态所包含的数据类型是两个维度的,交易历史大小与状态大小之间没有必然的联系。交易修改状态后,不仅会产生新的状态(图中实线框的叶子),而且会留下旧的状态(图中虚线框的叶子)成为历史状态,因此Ethereum的历史不仅仅包含交易,还包含历史状态。因为历史和状态属于不同的维度,Ethereum区块头中不仅仅包含交易的merkleroot,也需要显式包含状态的merkleroot。(思考题:EOS使用了类似Ethereum的账户模型,却没有在区块头中包含状态的MerkleTreeRoot,这是好还是不好?)Ethereum中每一个区块,每一个账户都会持续占用节点的存储空间。Ethereum节点在同步的时候有多种模式,在Archive模式下所有的历史和状态都会保存下来,其中历史包括历史交易和历史状态,所有数据加起来大小超过了2TB11;在Default模式下,历史状态会被裁剪掉,本地只保留历史交易和当前状态,所有数据加起来大约是170G6,其中交易历史大小是150G,当前状态大小是10G14。Ethereum中所有的开销管理都被统一到gas计费模型之下,交易的大小需要消耗对应的gas2,而每一条EVM指令消耗的gas,不仅考虑了计算开销,也将存储开销考虑在内1。通过每个区块的gaslimit,间接限制了历史和状态的增长速度。ps.常见的一个误解是,Ethereum的“区块链大小”已经超过1T了。从上面的分析我们可以看到,“区块链大小”是一个非常模糊的定义,如果把历史状态算进去,确实超过了,但是对于全节点来说,把历史状态删掉没有任何问题,因为只要有Genesis和交易历史,任意时刻的历史状态都可以重新被计算出来(不考虑计算需要的时间)。真正有意义的数据,是全节点必须的数据的大小,Bitcoin是200G,Ethereum是170G,两者是基本相同的,而且在平均配置的云主机上都能装下,因此人们观察到的Ethereum全节点减少2并不是由于存储增加导致的(根本原因是同步时的计算开销,这里不展开了)。考虑到Ethereum的历史长度(当前区块的timestamp减去genesis的timestamp)不到Bitcoin的一半,可以看出Ethereum的历史和状态大小增长更快。TheTragedyof(Storage)Commons:区块链版本的公地悲剧公地悲剧11所指的是这样一种情况,有限的共享资源在不受任何限制的使用下被人们过度消耗。区块链节点为保存历史和状态付出的存储,正是这样一种共享资源。区块链节点为处理交易所花费的资源有三种,CPU,存储和网络带宽。CPU和带宽都是每个区块会刷新的资源,我们可以认为每个区块间隔内都用同样多的CPU和带宽可供使用,上个区块消耗掉的CPU和带宽不会让下个区块可用的CPU和带宽变少。对于可刷新的资源,我们可以通过一次性支付的交易手续费来补偿节点(手续费与计算复杂度和交易大小的相关性可参考RFC0015Appendix4)。与CPU和带宽不同,存储是一种占用资源,在一个区块中被占用了的存储,除非使用者主动释放,否则无法在后面的区块中被其它使用者使用。节点需要为存储持续的付出成本,而使用者却不需要为存储持续的支付手续费(记住交易手续费只需要支付一次)。使用者只需要在往区块链写数据的时候支付一点点手续费,就可以永久使用一个可用性超过AmazonS3的存储,其无限大的永久存储成本需要区块链网络中的所有全节点来承担。Ethereum上由于各种DApp的存在,TheTragedyof(Storage)Commons相对更加严重。例如,在区块5700001(May30,2018)的时候,使用状态最多的5个合约8是:EtherDelta,5.09%IDEX,4.17%CryptoKitties,3.05%ENS,1.92%EOSSale,1.73%比较有趣的是最后一个,EOSSale。虽然EOS的众筹已经完成,EOS代币已经在EOS链上流转,EOS众筹的记录却永远留在了Ethereum的节点上,消耗Ethereum全节点的存储资源。可以看到,在缺乏管理的情况下,区块链的存储资源会被有意或者无意的滥用。在一个设计合理的经济模型中,使用者必须承担存储占用的成本,这个成本不仅仅与占用存储空间的大小成正比,还与占用时间的长度成正比。状态爆炸无论是历史还是状态数据都会占用存储资源。通过上面对Bitcoin和Ethereum的分析(其他区块链的状态模型基本都可以归纳为二者之一)可以看到,虽然它们对历史和状态的增长进行了管理,但是对历史和状态的总大小却没有任何控制,这些数据会持续的无休止的累积下去,使得运行全节点需要的存储资源越来越大,提高全节点的运行门槛,使网络的去中心化程度越来越低7,这是我们不愿意看到的。你也许会说,有没有可能硬件平均水平的提高会超过历史和状态的积累速度?我的回答是可能性很低:storage_growth.png1280×72021.3KB从这张图中我们可以看到,随着Ethereum网络的发展,状态数据累积的数量呈指数式的增长。Bitcoin的状态数据从0积累到3G,用了10年;Ethereum的状态数据从0积累到10G,用了4年;而这是在我们还没有解决Scalability问题,区块链仍然是小众技术的情况下的增长速度。当我们解决了scalability问题,区块链真正获得massadoption,DApp和用户数量都爆炸式增长的时候,区块链历史和状态数据会以什么速度累积呢?这就是状态爆炸问题,我们把它归类为post-scalabilityproblem,因为它在解决scalability问题之后会非常明显。我们最早是在做许可链场景落地8时注意到了这个问题,因为许可链的性能远高于公有链4,刚好处于post-scalability的阶段。(思考题:许可链怎么解决状态爆炸问题?)历史数据的累积相对容易处理,未来可以通过去中心化的Checkpoint或是零知识证明等技术来压缩,在那之前全节点甚至可以把历史直接丢掉,依然可以正常运行。状态数据的累积则麻烦许多,因为它是全节点运行必须的数据。不少区块链项目已经看到了这个问题,并提出了一些解决方案。EOSRAM是解决状态爆炸问题的一个有益尝试:RAM代表了超级节点服务器可用的内存资源,无论是账户、合约状态还是代码,都需要占用一定的RAM才能运行。RAM的设计也有很多问题,它需要通过内置的交易市场购买,不可转让,无法租用,将合约执行过程中的短期内存需求和合约状态的长期存储需求混在了一起,而且RAM的总量的设定没有确定的规则,更多取决于超级节点可以承受的硬件配置,而非共识空间的成本6。Ethereum社区也看到了这个问题并提出了StorageRent的方案4:要求使用者为存储资源的使用预支付一笔租金,占用存储资源会持续消耗这笔租金,占用时间越长,使用者需要支付的租金越多。StorageRent方案存在两个问题:1.预支付的租金终有一天会用完,这时候如何处理占用的状态?正是为解决这个问题,StorageRent需要诸如resurrection的机制来补充,增加了设计的复杂度,使智能合约的immutability大打折扣,也为使用体验带来了麻烦2;2.Ethereum的状态模型是一种共享状态的模型,而不是First-classState6。以ERC20Token为例,所有用户的资产记录都存放在单个ERC20合约的存储里面,在这种情况下,应该由谁来支付租金?解决状态爆炸问题也是NervosCKB的设计目标之一,为此CKB走了一条完全不同的、更为彻底的变革之路。

2019-10-31 2109 0