趣链HyperChain学习demo

趣链(hyperChain)

名词
QC QC(QuorumCert),NoxBFT算法中,主节点收到quorum(法定人数
)个节点对同一个提案的投票消息(带节点签名)后,将其合成一个QC证书
TC TC(TimeoutCert),NoxBFT算法中,节点收到quorum个节点超时消息(带节点签名)后,将其合成一个TC证书
quorum BFT算法中达成共识所需要的投票节点个数

架构
[img E2E68D50-52B6-462C-845D-EF1746984EBD]
PBFT
[img BA857096-884C-415A-9B75-48000458E6C3] 1.客户端Client将交易发送到区块链中的任意节点;
2.Replica节点接收到交易之后转发给Primary节点,Primary自身也能直接接收交易消息;
3.Primary会将收到的交易进行打包,生成batch进行验证,剔除其中的非法交易;
4.(三阶段第一阶段)Primary将验证通过的batch构造PrePrepare消息广播给其他节点,这里只广播批量交易的哈希值;
5.(三阶段第二阶段)Replica接收来自Primary的PrePrepare消息之后构造Prepare消息发送给其他Replica节点,表明该节点接收到来自主节点的PrePrepare消息并认可主节点的batch排序;
6.(三阶段第三阶段)Replica接收到2f个节点的Prepare消息之后对batch的消息进行合法性验证,验证通过之后向其他节点广播Commit消息,表示自己同意了Primary节点的验证结果;
7.Replica节点接收到2f+1个Commit之后执行batch中的交易并同主节点的执行结果进行验证,验证通过将会写入本地账本,并通过checkpoint检查点来进行结果校验的步骤,检查点规则可配置。
视图更换
Viewchange(视图更换)是指因原Primary节点失效而Replica节点参与新Primary节点选举的过程,该机制是保证整个共识算法健壮性的关键。 [img 59DD7CA9-6ED9-44B5-B2FA-DA546F7E75B0]
1.Replica节点检测到主节点有以上异常情况或者接收来自其他f+1个节点的ViewChange消息之后会向全网广播ViewChange消息;
2.当新主节点收到N-f个ViewChange消息时,会发送NewView消息;
3.Replica节点接收到NewView消息之后进行消息的验证和对比,验证View的切换信息相同之后正式更换ViewChange并打印FinishVC消息,从而完成整个ViewChange流程。
节点增删
Replica节点检测到主节点有以上异常情况或者接收来自其他f+1个节点的ViewChange消息之后会向全网广播ViewChange消息;
当新主节点收到N-f个ViewChange消息时,会发送NewView消息;
Replica节点接收到NewView消息之后进行消息的验证和对比,验证View的切换信息相同之后正式更换ViewChange并打印FinishVC消息,从而完成整个ViewChange流程。
[img 886118FA-01D5-4B6B-996A-90FF6BF63655]
1.首先,新的节点需要得到证书颁发机构颁发的证书,然后向联盟中的所有节点发送请求;
2.各个节点确认同意后会向联盟中的其他节点进行全网广播,当一个节点得到2f+1个同意加入的回复后会与新的节点建立连接;
3.随后,当新的节点和N-f(N为区块链联盟节点总数)个节点建立连接后就可以执行主动恢复算法,同步区块链联盟成员的最新状态;
4.随后,新节点再向主节点请求加入常规共识流程。最后,主节点确认过新节点的请求后会定义在哪个块号后需要改变节点总数N来共识(确保新节点的加入不会影响原有的共识,因为新节点的加入会导致全网共识N的改变,意味着f值可能改变)。
NoxBFT
基于HotStuff算法,实现了一种可扩展、高性能的新型的共识算法—NoxBFT。NoxBFT算法在保留原有RBFT算法高效性与鲁棒性的前提下,从三个方面实现了支持以千为数量级的大规模节点组网共识。首先,NoxBFT通过星型网络拓扑结构将网络复杂度将降低至n;其次,NoxBFT通过聚合签名实现了签名的快速验证,同时还支持动态扩展。
NoxBFT算法的共识流程主要是Proposal提案阶段与Vote投票阶段的循环:
[img 8CA83451-A590-4DD1-BD68-B4B02B333CCB]
1.Transaction&Broadcast:任意节点收到交易之后,首先将其存入到本地mempool中,随后将其广播给其他所有节点,收到广播的节点也会将其存入到各自的mempool中。每个节点在接收到交易后,都会进行交易的去重判断,剔除重复交易之后才能进入到节点的mempool中;
2.Proposal:当前轮次的主节点负责进行打包,从mempool中取出若干笔符合要求的交易打包成一个batch,并附带上一轮的QC封装成一个proposal,广播给其他节点;
3.Vote:所有的节点在监听到提案消息后,都会验证proposal的合法性(safety rules),验证通过后,首先检查该proposal中的QC证书(QuorumCert)是否达到了3-chain安全性提交规则(commit rules),达到后则直接提交区块,等待区块执行完成之后将其中的交易从mempool中移除(CommitTxs)。最后,节点会将投票(vote)信息发送至下一轮的主节点。需要注意的是,每个节点的投票中都会附带上节点签名; Proposal:下一轮的主节点收到quorum个vote后,聚合成一个QC,并开始下一轮打包,并重复步骤2与步骤3,一直到出现超时的情况。
超时轮换
当主节点由于网络原因或者其他因素导致从节点无法按期收到Proposal进行投票时,NoxBFT就会触发超时机制,通过Pacemaker活性模块让全网快速地进入到下一个round继续共识。
[img 8945397F-EDA4-4F8F-86E1-990CBCDE2CC5]
1.Transaction&Broadcast&Proposal:所有共识节点接收交易并且广播交易,当前的主节点正常的进行打包并广播proposal;
2.Round Timeout:由于网络原因,导致主节点proposal并没有及时地发送到从节点,因此从节点不会对本轮次进行投票;
3.Broadcast TimeoutMsg:所有节点都无法按期收到本轮的Proposal,导致超时,全网广播TimeoutVote消息,其中会附带上本节点当前所处的轮次号以及节点的签名;
4.Proposal:下一轮的主节点在一定时间内收到 quorum个TimeoutVote消息,构造成TC(Timeout cert),并从mempool中取出若干笔合法交易打包成batch,即可将TC与batch封装成一个新的提案proposal进行广播。
RAFT
与不限制共识成员的公链不同,联盟链中所有参与节点的身份都是已知的,每个节点有很高的可信度,故在某些可信度高的业务场景下可采用不容拜占庭节点的传统共识算法,基于此,平台同时支持Raft共识算法。
Raft共识机制中,节点共分为三种角色:

  • 领导者(Leader):接受客户端请求,并向从节点同步请求日志,当日志同步到大多数节点上后将提交日志,并广播给从节点。
  • 从节点(Follower):单向接收并持久化主节点同步的日志。
  • 候选节点(Candidate):主节点选举过程中的过渡角色,当从节点在规定的超时时间内没有收到主节点的任何消息,将转变为候选节点,并广播选举消息,且只有候选状态的节点才会接收选举投票的消息。候选节点有可能被选举为主节点,也有可能回退为从节点。
    在同一时刻,集群中只有一个Leader,负责生成日志数据(对应在区块链中即负责打包)并广播给Follower节点,为了保证共识的正确性和简单性,所有Follower节点只能单向接收从Leader发来的日志数据。
    Raft算法共识流程分为主节点选举和日志同步两步。将时间分为一个个的任期(term),每一个term以Leader选举开始。在成功选举Leader之后,Leader会在整个term内管理整个集群。如果Leader选举失败,该term就会因为没有Leader而结束。
    [img B07A99A5-C100-47EB-ACE9-A3FE6FEF78E7]
  • 领导人选举:Raft 使用心跳(heartbeat)触发Leader选举。当服务器启动时,Leader向所有Followers周期性发送heartbeat。如果Follower在选举超时时间内没有收到Leader的heartbeat,就会发起一次Leader选举。Follower将其当前term加一然后转换为Candidate。它首先给自己投票并且给集群中的其他服务器发送RequestVoteRPC。当赢得了多数的选票,成功当选为Leader后,它会重复开头的操作,即定期向所有Followers发送heartbeat维持其统治;
  • 日志同步:Leader选出后,就开始接收客户端的请求。Leader把请求作为日志条目(Log entries)加入到它的日志中,然后并行的向其他Follower节点发起AppendEntries RPC以复制该日志条目。当这条日志被复制到大多数服务器上,Leader将这条日志应用到它的状态机并向客户端返回执行结果。
    账本存储
    区块链本质上是一个分布式账本系统,因此区块链平台的账本设计至关重要。

趣链区块链平台(以下简称“平台”)的账本数据主要包含2个部分:

  • 区块数据:交易信息通过区块链这种链式结构进行存储,保证了用户交易的不可篡改以及可追溯性
  • 状态数据:采用账户模型维护区块链系统的状态,即图中state data部分
    [img 654AEF06-E990-41F0-AC30-C6B86DC6C954]
    数据结构
    区块链
    区块链是由包含交易信息的区块从后向前有序链接起来的数据结构。所有区块被从后向前有序地链接在这个链条里,每一个区块都指向其父区块。区块链经常被视为一个垂直的栈,第一个区块作为栈底的首区块,随后每个区块都被放置在其他区块之上。用栈形象化地表示区块依次链接这一概念后,我们便可以使用一些术语,例如,“高度”表示最新区块与首区块之间的距离,“顶部”或“顶端”表示最新添加的区块。
    合约状态
    与比特币系统采用UTXO模型不同,平台采用了账户模型来表示系统状态。当节点收到一笔“待执行”的交易后,会首先交由执行模块执行。执行交易结束后,会更改相关合约账户的状态,例如某用户A发起一笔交易调用已部署的合约B,使得合约B中的变量值b由0变为1,并持久化到合约状态中存储。每一笔交易的执行,即意味着合约账户状态的一次转移,也代表着系统账本的一次状态转移。因此,趣链区块链平台也可以被认为是一个状态转移系统。
    存储机制
    区块数据主要通过区块的形式进行串联,所有区块被从后向前有序地链接在一个链条里,每一个区块都指向其父区块;状态数据,其实是一系列的KV键值对,每次执行一笔交易,修改一系列状态变量,从底层来看,就是更新了一批KV对。区块数据的特征是不断追加不断增长,而状态数据往往是频繁更新不会持续增长。
    平台自主研发混合存储引擎机制,对于区块数据采用区块链专用存储引擎Filelog,对于KV型状态数据选用具备很高随机写顺序读性能的存储引擎LevelDB,以此实现区块数据与状态数据的分离,保证在系统数据量不断增大的情况下读写性能不受影响。此外,针对状态数据,平台还设计了多级缓存机制,从而实现状态数据高效存储。
    Filelog
    用来存储区块链场景中的区块数据、回执数据等等一类按照区块号严格递增的数据,因此filelog的基本操作仅包括read/write两种。
    blockFilelog、journal、receiptFilelog。其中blockFilelog用于存储区块数据,journal用于保存journal,receiptFilelog用于存储回执。这三类数据在filelog中的key均为对应的区块号。
    Filelog的特点:
  • 顺序写:每一条数据均与一个唯一的sequence number相绑定,且sequence number单调递增
  • 随机读:读取时每一个sequence number都有可能会被随机读到,不按照递增顺序
  • 数据可迁移:平台支持数据归档,即将历史数据从线上迁移到线下路径中
  • 对于连续型的块链数据, Filelog的读写性能都优于LevelDB,特别是数据的写入性能有了大幅提升
    levelDB
    LevelDB是Google开源的持久化KV单机数据库,具有很高的随机写,顺序读/写性能,但是随机读的性能很一般,适合应用在查询较少,而写很多的场景。
    目前平台中有四个levelDB数据库,其中consensusDB用于保存共识状态,mqDB和radarDB分别用于存储mq和radar服务执行过程中产生的一些信息,而certDB用于保存证书。
    LevelDB的特点:
  • 随机读写:key是无序的,交易执行过程中任何已有的或还不存在的数据都有可能会被访问到
  • key和value都是任意长度的字节数组
  • 可以创建数据的全景snapshot(快照),允许在快照中查数据
  • 支持批量操作以原子操作进行
    Multicache
    一个集读写缓存与底层数据库于一体的组件,提供统一的批量写入服务,可直接对接分布式LevelDB数据库.
    multicache有如下特点:
  • 在分配的内存空间范围内,multicache将写数据库的操作转化为写内存,实现效率提升
  • 在时间局部性强的应用中,multicache用于缓存写数据的内存空间可以很好的对读操作提供服务,提升读效率
  • 数据可回滚:一旦出现异常区块,平台的回滚机制要求这些数据库中的内容按区块号进行回滚
    网络通讯
    平台的P2P网络,主要采用传输层Transport与网络层Network解耦的方式,能够灵活应用其他传输协议,提高网络层的适用性和灵活性。
    通讯流程
    [img 285DF965-BC78-4239-B0AD-771E2A446D3F]
  • 网络传输层:用于身份认证密钥协商、协议版本协商、建立节点间加密通信连接
  • 逻辑网络层:用于维护子协议、子协议可以拥有自己的网络模块,不同子协议间的通信相互独立
    节点类型
  • 验证节点(VP,Validate Peer):VP节点是区块链网络中参与共识验证的节点,平台赋予VP节点绝对的投票权,并且拥有全量的数据
  • 非验证节点(NVP,Non-Validate Peer):NVP节点在区块链网络中不参与共识验证,仅参与账本记账,需要依附VP节点来保证与全网状态的最终一致性。同时平台赋予NVP节点完善的状态恢复机制,可以很好的为上层提供读写分离服务
  • 热备节点(CVP,Candidate VP):CVP节点是区块链网络中共识验证的节点的热备节点,它依附于VP节点存在,可动态替换该VP节点,且不影响整个网络
    转发策略
    支持全连接转发策略以及自发现转策略,两种转发策略针对不同的应用场景。
    [img 756E7AEB-563D-4AD8-AA25-C0120B22FE13]
  • 全连接转发策略:采取全连接双向通信的方式,节点统一配置、高效转发、并发能力强
  • 自发现转发策略:通过自适应路由进行网络自发现,并支持跨域转发,这样做会简化节点的网络配置同时动态调整,实现跨域通信
    智能合约
    智能合约是指内嵌于区块链上的自定义程序逻辑,广泛意义上的智能合约包含编程语言、编译器、虚拟机、事件、状态机、容错机制等。其中,对应用程序开发影响较大的是编程语言以及智能合约的执行引擎,即虚拟机。虚拟机作为沙箱被封装起来,整个执行环境都被完全隔离。虚拟机内部执行的智能合约不能接触网络、文件系统或者系统中的其他线程等系统资源。
    智能合约执行引擎
  • HyperEVM(EVM)是为了最大程度利用开源社区在智能合约技术和经验方面的积累,提高智能合约的重用性而深度重构EVM的虚拟机,并且完全兼容EVM上开发的智能合约。 HyperEVM在保持Solidity开发语言的兼容性基础上,对智能合约虚拟机进行性能优化,保持了以太坊虚拟机的沙盒安全模型,做了充分的容错机制,并进行系统级别的优化,结合环境隔离能够保证合约在有限时间内安全执行,在执行性能方面由逼近二进制原生代码的效率。z
  • HyperVM(HVM)是平台自研的首个完全基于Go语言实现的高性能Java智能合约执行引擎,在保证智能合约执行的安全性、确定性、可终止性的前提下,提供了一系列灵活应用模式、工具方法集,以满足复杂多样的业务场景需求,面向广泛的区块链开发人员提供更便捷、灵活、安全的区块链应用开发模式。
  • Built-in virtual machine(BVM)是用于处理内置合约的虚拟机类型。所谓内置合约,即是合约代码由开发人员预先写好,在平台启动时就直接创建对象加载,不需要用户手动部署的合约。由于嵌入系统中,内置合约的执行可以接近原生代码的执行速度。BVM的出现可以让开发者通过自定义内置合约,提供一些固定功能,以此实现多层级权限管理、联盟自治CAF等功能特性,更好地支撑上层业务开展。
    加密机制
    趣链区块链平台(以下简称“平台”)采用可插拔的全国密算法多级加密机制对于业务完整生命周期所涉及的数据、通信传输、物理连接等都进行了不同策略的加密,保障系统的安全性。具体采用散列算法、对称加密算法、随机比特生成器、传输层安全机制、密钥管理机制等密码学方式进行全链路安全防护。
    平台实现了密码算法国密化,现已支持SM2、SM3、SM4、SM9等国密标准算法。
    加密体系

散列算法
哈希是一种散列函数,把任意长度的输入通过哈希算法,变换成固定长度的输出(哈希值),哈希值的空间通常远小于输入的空间,并且哈希函数具有不可逆性,根据哈希值无法反推输入原文的内容。
对称加密
对称加密主要应用于数据传输方面,以弥补非对称加密算法在效率上的不足。
平台在通信双方协商出一个机密共享密钥后,再基于对称加密算法保证节点间的密文传输,使得计算上破解传输内容的难度更高,从而保证平台消息传输的高安全性。
对称加密也称常规加密,私钥、或者单钥加密,一个完整的对称加密方案由五个部分组成:

  • 明文(plaintext):原始的消息或者数据,作为算法输入
  • 加密算法(encryption algorithm):加密算法对明文进行各种替换和转换
  • 秘密密钥(secret key):算法输入,算法进行替换和转换都依赖于秘密密钥
  • 密文(ciphertext):已被打乱的消息,作为加密算法的输出,取决于明文和秘密密钥(对于一个给定的消息,两个不同的秘密密钥会产成不同的密文
  • 解密算法(decryption algorithm):本质上是加密算法的逆运算。使用密文和秘密密钥产生原始明文

非对称加密
应用主要包含数字签名、密钥协商和公钥加密。
平台采用了SM2等非对称加密对交易进行签名,生成相应的国密证书以此来保证平台的身份安全。
在网络通信过程中,使用会话密钥对传输的信息进行加密,可以防止黑客窃听机密消息进行欺诈等行为。区块链平台通过实现SM2等非对称加密算法的密钥协商协议完成会话密钥的建立和网络中用户之间的相互认证,保证通信双方可以在不安全的公共媒体上创建共享的机密协议,而不必事先交换任何私有信息。
传输层安全
除了上述提到的密钥协商与密文传输以外,节点间还通过传输层安全TLS(TransportLayer Security)来保证通信安全。TLS 能够在传输层保障信息传输的安全性,是目前较为通用的网络传输实施标准,在几乎所有的网络安全传输中都采用了该技术,比如google、淘宝、百度、微信等。
传输层安全是Hyperchain默认开启的功能,采用TLSCA签发的证书进行安全通信,即在传输网络传输过程中需要验证传输层安全协议证书的安全性,验证通过即可以进行正常网络通信,反之则无法进行网络通信。目前TLSCert也已完全支持国密。
密钥管理
平台可以采用通过国家密码管理局认证的用户智能密码钥匙完成密钥管理功能。智能密码钥匙用于保管用户私钥和生成SM2签名。
随机比特生成器
平台采用硬件密码卡完成上述非对称加密算法中需要使用的随机数的生成。密码卡用于生成非对称加密算法中所需要的安全随机数和保管平台私钥。
数据归档
提供数据归档功能,将一部分旧的线上数据移到线下转存,以解决区块链数据的存储问题。
完整的数据归档过程包括:

  • filelog数据从线上到线下的迁移,包括:区块数据和区块对应的日志数据
  • leveldb数据从线上到线下的迁移包括,包括交易索引数据、交易回执数据以及非法交易数据
  • 新创建的数据,包括用于存储当前的世界状态的snapshot数据库,存储本次归档的manifest内容的snapshot.meta,以及存储本次archive过程中迁移数据统计结果的archive.meta
    此外,平台还通过Archive Reader组件支持归档数据的查阅及恢复。其中,恢复归档数据是归档的逆过程,将线下已经被归档出去的数据挪回线上。
    部署安装
    *Go的安装: *
    export GOPATH= H O M E / g o e x p o r t P A T H = HOME/go export PATH= HOME/goexportPATH=PATH: G O P A T H / b i n e x p o r t G O R O O T = / u s r / l o c a l / g o e x p o r t G O P A T H = GOPATH/bin export GOROOT=/usr/local/go export GOPATH= GOPATH/binexportGOROOT=/usr/local/goexportGOPATH=HOME/go
    export PATH= P A T H : PATH: PATH:GOPATH/bin:$GOROOT/bin
    安装智能合约编译器
    使用Solidity进行智能合约的编写。
    wget https://github.com/ethereum/solidity/releases/download/v0.4.13/solc-static-linux
    sudo cp solc-static-linux /usr/bin/solc
    sudo chmod +x /usr/bin/solc
    部署启动
    cd hyperchain-hyperchain-bec5b48c3/
    ./hyperchain

docker启动solo模式
docker pull hyperchaincn/solo:v2.0.0
docker run -d -p 8081:8081 hyperchaincn/solo:v2.0.0

java内容
resources中存放文件夹hvm-jar
Pom.xml中添加依赖:

<dependencies>
    <dependency>
        <groupId>cn.hyperchaingroupId>
        <artifactId>litesdkartifactId>
        <version>1.0.3version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>RELEASEversion>
    dependency>
dependencies>

java代码:

package cn.timechainer.hyperchainSDK.testSDK;

import cn.hyperchain.sdk.account.Account;
import cn.hyperchain.sdk.account.Algo;
import cn.hyperchain.sdk.common.utils.Decoder;
import cn.hyperchain.sdk.common.utils.FileUtil;
import cn.hyperchain.sdk.exception.RequestException;
import cn.hyperchain.sdk.provider.DefaultHttpProvider;
import cn.hyperchain.sdk.provider.ProviderManager;
import cn.hyperchain.sdk.request.Request;
import cn.hyperchain.sdk.response.ReceiptResponse;
import cn.hyperchain.sdk.response.TxHashResponse;
import cn.hyperchain.sdk.response.block.BlockNumberResponse;
import cn.hyperchain.sdk.response.block.BlockResponse;
import cn.hyperchain.sdk.response.node.NodeResponse;
import cn.hyperchain.sdk.response.node.NodeStateResponse;
import cn.hyperchain.sdk.response.tx.*;
import cn.hyperchain.sdk.service.*;
import cn.hyperchain.sdk.service.params.FilterParam;
import cn.hyperchain.sdk.service.params.MetaDataParam;
import cn.hyperchain.sdk.transaction.Transaction;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

class TestSDK {
     
    public static String DEFAULT_URL = "192.168.182.9:8081";
    public static final int nodeID1 = 1;    //传入nodeID可以有多个
    public static final String txHash = "0x6892cdc15f5c05606164a476caadd693e86df01c8c6fafea20c9a480d8fb2aea";    //传入nodeID可以有多个
    public static final String blockHash = "0x0fd3426a6b47a7d672c9785766eb6919d6268c2434674e4098d1e0e7dee2f315";
    public static final int index = 0;    //区块内的交易索引值
    public static final int blockNumber = 0x10;    //区块号
    public static final String from_block = "0x10";
    public static final String to_block = "0x60";
    public static final String address = "0x08deebc2c7db8a9166067f6bf8742f964973b2d0";
    public static final String txIndex = "0x60";



    public static void main(String[] args) throws IOException, RequestException {
     
        System.out.println("start HyperChain.");
        // create a provider:管理与节点的连接
        //Builder(readTimeout, writeTimeout, connectTimeout), setUrl.https(证书)
        DefaultHttpProvider defaultHttpProvider = new DefaultHttpProvider.Builder().setUrl(DEFAULT_URL).build();
        System.out.println("创建一个httpprovider");

        // 每个节点需要一个HttpProvider, Manager负责管理这些HttpProvider
        ProviderManager providerManager = ProviderManager.createManager(defaultHttpProvider);
        System.out.println("创建一个providerManager");
        //测试进行一笔交易
        TestSDK.startTxService(providerManager);

        //创建一个TxService原来获取交易信息
        TxService txService = ServiceManager.getTxService(providerManager);
        //测试txService
        TestSDK.transactionService(txService);

        //创建一个BlockService原来获取交易信息
        BlockService blockService = ServiceManager.getBlockService(providerManager);
        //测试blockService
        TestSDK.blockService(blockService);

       //创建一个NodeService原来获取节点信息
        NodeService nodeService = ServiceManager.getNodeService(providerManager);
        //测试blockService
        TestSDK.nodeService(nodeService);

        //创建一个MQService
        MQService mqService = ServiceManager.getMQService(providerManager);

    }

    private static void startTxService(ProviderManager providerManager) throws RequestException, IOException {
     
        System.out.println("开始进行交易");
        // 创建用户:先创建service,再创建accout
        AccountService accountService = ServiceManager.getAccountService(providerManager);
        Account account = accountService.genAccount(Algo.SMRAW); //ECRAW和SMRAM不需要设置passwd
        System.out.println("创建一个account");
        System.out.println(account);

        // 创建交易体:创建交易体时需要指定要部署的jar包(封装成流)。
        InputStream payload = FileUtil.readFileAsStream("hvm-jar/contractcollection-1.0-SNAPSHOT.jar");
        Transaction transaction = new Transaction.HVMBuilder(account.getAddress()).deploy(payload).build();
        System.out.println("创建一个交易实体");
        transaction.sign(accountService.fromAccountJson(account.toJson()));


        // 创建请求
        ContractService contractService = ServiceManager.getContractService(providerManager);
        Request<TxHashResponse> contractRequest = contractService.deploy(transaction);
        System.out.println("创建一个交易请求");

        //发送交易体
        ReceiptResponse receiptResponse = contractRequest.send().polling();
        System.out.println("发送交易请求,并获取交易响应凭证");
        System.out.println(receiptResponse);

        System.out.println("未解码的交易结果");
        System.out.println(receiptResponse.getRet());

        //解码交易响应凭证
        System.out.println("获取交易响应凭证解码结果");
        System.out.println(Decoder.decodeHVM(receiptResponse.getRet(), String.class));
    }

    public static void transactionService(TxService txService) throws RequestException {
     

        System.out.println("开始进行区块查询相关操作");

//        System.out.println(getTxResponseByTxHash(txService));
//        System.out.println(getTxResponseByBlockHash(txService));
//        System.out.println(getTxResponseDiscardTransactions(txService));
//        System.out.println(getTxResponseTransactionsCount(txService));
//        System.out.println(getTxResponseTransactionReceipt(txService));
//        System.out.println(getTxResponseBlockTxCountByHash(txService));
//        System.out.println(getTxResponseTransactionCountByContractAddr(txService));
//        System.out.println(getTxResponseBatchByHash(txService));
//        System.out.println(getTxResponseTxCountByTime(txService));
//        System.out.println(getTxResponseByFilter(txService));
        System.out.println(getTxResponseTxVersioin(txService));

    }

    public static String getTxResponseByTxHash(TxService txService) throws RequestException {
     
        System.out.println("创建通过交易Hash查询交易的请求:发送请求,并获取响应结果,最后输出");
        //设置是否隐私交易为false,输出结果与不加该参数一致
        Request<TxResponse> txResponse = txService.getTxByHash(txHash, false ,nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseBatchByHash(TxService txService) throws RequestException {
     
        System.out.println("根据区块hash获取区块交易数量");
        ArrayList<String> txHashList = new ArrayList<>();
        txHashList.add(txHash);
        // 还可以根据需要的数量进行查询getBlockTxCountByNumber
        Request<TxResponse> txResponse = txService.getBatchTxByHash(txHashList, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseByBlockHash(TxService txService) throws RequestException {
     
        System.out.println("创建通过区块Hash查询交易的请求:发送请求,并获取响应结果,最后输出");
        //设置是否隐私交易为false,输出结果与不加该参数一致
        Request<TxResponse> txResponse = txService.getTxByBlockHashAndIndex(blockHash , index, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseDiscardTransactions(TxService txService) throws RequestException {
     
        //可以按时间进行查询
        System.out.println("获取所有非法交易");
        Request<TxResponse> txResponse = txService.getDiscardTx(nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseTransactionsCount(TxService txService) throws RequestException {
     
        System.out.println("获取链上的所有交易量");
        Request<TxCountWithTSResponse> txResponse = txService.getTransactionsCount(nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseTransactionReceipt(TxService txService) throws RequestException {
     
        System.out.println("根据Tx hash获取交易回执信息");
        Request<ReceiptResponse> txResponse = txService.getTransactionReceipt(txHash, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseBlockTxCountByHash(TxService txService) throws RequestException {
     
        System.out.println("根据区块hash获取区块交易数量");
        // 还可以根据需要的数量进行查询getBlockTxCountByNumber
        Request<TxCountResponse> txResponse = txService.getBlockTxCountByHash(blockHash, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseTransactionCountByContractAddr(TxService txService) throws RequestException {
     
        System.out.println("根据合约地址查询区块间的交易数量");
        Request<TxResponse> txResponse = txService.getTransactionsCountByContractAddr(from_block, to_block, address, false, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseNextPageTransactions(TxService txService) throws RequestException {
     
        final String blkNumber = "100"; //从该区块开始计数
        final String txIndex = "0"; //起始交易在blkNumber号区块的位置偏移量
        final String minBlkNumber = "96"; //截止计数的最小区块号
        final String maxBlkNumber = "100"; //截止计数的最大区块号
        final String separated = "0"; //标示要跳过的交易条数, 用于跳页查询
        final String pageSize = "10"; //要返回的交易条数
        final boolean containCurrent = true; //true表示返回的结果中包括blkNumber区块中位置为txIndex的交易,如果该条交易不是合约地址为address的交易,则不算入。

        System.out.println("查询下一页交易");
        //查询上一页交易
        Request<TxResponse> txResponse = txService.getNextPageTransactions(blkNumber, txIndex, minBlkNumber, maxBlkNumber, separated, pageSize, containCurrent, address, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseTxCountByTime(TxService txService) throws RequestException {
     
        System.out.println("获取指定时间内的交易数量");
        final BigInteger startTime = new BigInteger("1609739137600000000");
        final BigInteger endTime = new BigInteger("1609739137733697845");
        // 还可以根据需要的数量进行查询getBlockTxCountByNumber
        Request<TxCountResponse> txResponse = txService.getTxsCountByTime(startTime, endTime, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseByFilter(TxService txService) throws RequestException {
     
        final int mode = 1; //0表示与filter完全稳和的与查询,1表示部分稳和的或查询
        final boolean detail = false; //是否显示查询细节
        MetaDataParam metaData = null;
        FilterParam filter = null;
        System.out.println("根据filter获取满足条件的交易");
        // 还可以根据需要的数量进行查询getBlockTxCountByNumber
        Request<TxLimitResponse> txResponse = txService.getTxsByFilter(mode, detail, metaData, filter, nodeID1);
        return txResponse.send().toString();
    }

    public static String getTxResponseTxVersioin(TxService txService) throws RequestException {
     
        System.out.println("获取平台当前的交易版本号");
        // 还可以根据需要的数量进行查询getBlockTxCountByNumber
        Request<TxVersionResponse> txResponse = txService.getTxVersion(nodeID1);
        return txResponse.send().toString();
    }

    private static void blockService(BlockService blockService) throws RequestException {
     
        System.out.println("开始进行block service相关操作");
//        System.out.println(getBlockResponseByBlockNumber(blockService));
//        System.out.println(getBlockResponseLatestBlock(blockService));
//        System.out.println(getBlockResponseChainHeight(blockService));
        System.out.println(getBlockResponseGenesisBlock(blockService));


    }

    private static String getBlockResponseByBlockNumber(BlockService blockService) throws RequestException {
     
        // 根据区块号进行批量查询:getBatchBlocksByNum(blockNumberList,...)
        System.out.println("根据区块号,获取结果");
        //还可以根据区块hash进行查询:getBlockByHash; 根据hash批量查询:getBatchBlockByHash(blockHashList,...)
        //还可以根据区块的区间进行查询 :getBlocks(from, to,...)
        final boolean isPlain = true; //默认为false,返回的数据包括区块内的交易
        Request<BlockResponse> blockResponse = blockService.getBlockByNum(from_block, isPlain, nodeID1);
        return blockResponse.send().toString();
    }

    private static String getBlockResponseLatestBlock(BlockService blockService) throws RequestException {
     
        System.out.println("获取最新区块的数据");
        Request<BlockResponse> blockResponse = blockService.getLatestBlock(nodeID1);
        return blockResponse.send().toString();
    }

    private static String getBlockResponseGenesisBlock(BlockService blockService) throws RequestException {
     
        System.out.println("查询最新的区块号,即链高");
        Request<BlockNumberResponse> blockResponse = blockService.getGenesisBlock(nodeID1);
        return blockResponse.send().toString();
    }

    private static void nodeService(NodeService nodeService) throws RequestException {
     
        System.out.println("开始进行node service相关操作");
        System.out.println(getNodeResponseNodes(nodeService));
        System.out.println(getNodeResponseNodeStates(nodeService));

    }

    private static List<NodeResponse.Node> getNodeResponseNodes(NodeService nodeService) throws RequestException {
     
        System.out.println("查询所有节点信息");
        Request<NodeResponse> nodeResponse = nodeService.getNodes(nodeID1);
        return nodeResponse.send().getResult();
    }

    private static List<NodeStateResponse.NodeState> getNodeResponseNodeStates(NodeService nodeService) throws RequestException {
     
        System.out.println("查询所有节点信息");
        Request<NodeStateResponse> nodeResponse = nodeService.getNodeStates(nodeID1);
        return nodeResponse.send().getResult();
    }
}

你可能感兴趣的:(趣链,区块链)