HPB主网接入最佳实践之Java版

4次阅读

共计 9465 个字符,预计需要花费 24 分钟才能阅读完成。

1、开始准备

1.1 学习门槛

  • 熟悉 Java 的基本语法和使用
  • 熟悉 Java 的 IDE 工具基本使用(Eclipse,IDEA)
  • 熟悉 Git 版本管理的基本语法和使用
  • 熟悉 SpingBoot 开发(本 Demo 提供的是基于 Springboot 的源码)
  • 熟悉区块链的基本原理
  • HPB 主网如何介入请前往 https://www.hpb.io/client 了解

1.2 环境准备

  • JDK1.8 以上版本
  • Eclipse4.7 或者以上
  • Eclipse 安装了 Git 插件
  • Eclipse 安装了 Spring 插件
  • HPB 主网接入的 JAVA SDK 请前往这里地址下载:https://www.hpb.io/client
  • 因为是 maven 工程,会从网络中下载工程依赖的 jar 宝,所以需要机器处于联网状态

1.3 源码地址

https://github.com/loglos/web3-hpb-test.git

2、开始实践

2.1 通过 Eclipse Import 演示代码

  • 因为上传到 Github 的代码是不包括代码工程配置信息的,所以需要进行简单的调整。
  • 源码工程是基于 maven 的类型,可以右键工程代码,选择“configure/convert to maven projects”。
  • 转换成功后,系统就能识别为 maven 类型的工程了。
  • 提醒:转换为 maven 工程后,很多依赖的 jar 包都是通过 pom.xml 来配置管理的,同时如果本地没安装过 maven 的本地仓库,第一次会默认从远程的拉取依赖 jar 包,速度比较慢,如果工程报错,需要多尝试几次。

2.2 改变代码工程的属性

  • 因为上传到 Github 的代码是不包括代码工程配置信息的,所以需要进行简单的调整。
  • 源码工程是基于 maven 的类型,可以右键工程代码,选择“configure/convert to maven projects”。
  • 转换成功后,系统就能识别为 maven 类型的工程了。
  • 提醒:转换为 maven 工程后,很多依赖的 jar 包都是通过 pom.xml 来配置管理的,同时如果本地没安装过 maven 的本地仓库,第一次会默认从远程的拉取依赖 jar 包,速度比较慢,如果工程报错,需要多尝试几次。

2.3 源码关键配置信息说明
打开 maven 配置文件 pom.xml
<!–
其他的配置不需要修改,这里说明下,引用的事 HPB 主网的 JAVA 版本 SDK
–>

    <dependency>
        <groupId>io.hpb.web3</groupId>
        <artifactId>web3-hpb</artifactId>
        <version>1.0.0</version>
    </dependency>
    

打开 application.properties 文件,配置文件可以根据需要进行修改,也可以不进行修改。这里罗列了重要的几个配置属性进行说明。

指定工程发布后访问名称
spring.application.name=HpbWeb3Test

工程发布后的访问服务端口
server.port=9988
server.servlet.path=/
server.use-forward-headers=true
server.servlet.context-path=/HpbWeb3Test
server.servlet.application-display-name=hpb web3 test application
web3.admin-client=true
web3.httpTimeoutSeconds=600

指定的连接 HPB 主网的 RPC 网址,这里是主网正式网的开放的 RPC 地址
通过访问这个地址,可以进行通过 Java 操作 RPC 命令,直接和 HPB 主网进行交互。web3.client-address=http://pub.node.hpb.io/

打开 HpbWeb3Controller.java 文件,这里是本次演示的具体代码,这里对关键代码进行下说明。

// 注意这里,是引用了 HPB 主网提供的 Java SDK 包,里面封装了如何通过 RPC 方式与底层交互的方法
import io.hpb.web3.abi.datatypes.Address;
import io.hpb.web3.abi.datatypes.DynamicArray;
import io.hpb.web3.abi.datatypes.generated.Bytes32;
import io.hpb.web3.contract.HpbNodes;
import io.hpb.web3.crypto.Credentials;
import io.hpb.web3.crypto.RawTransaction;
import io.hpb.web3.crypto.WalletUtils;
import io.hpb.web3.protocol.admin.Admin;
import io.hpb.web3.protocol.core.DefaultBlockParameterName;
import io.hpb.web3.protocol.core.methods.response.HpbBlockNumber;
import io.hpb.web3.protocol.core.methods.response.HpbGetBalance;
import io.hpb.web3.protocol.core.methods.response.HpbGetTransactionCount;
import io.hpb.web3.protocol.core.methods.response.HpbGetTransactionReceipt;
import io.hpb.web3.protocol.core.methods.response.HpbSendTransaction;
import io.hpb.web3.protocol.core.methods.response.TransactionReceipt;
import io.hpb.web3.tuples.generated.Tuple4;
import io.hpb.web3.tx.ChainId;
import io.hpb.web3.tx.RawTransactionManager;
import io.hpb.web3.utils.Convert;
import io.hpb.web3.utils.Numeric;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/")
public class HpbWeb3Controller{
    
    // 输出日志
    private static Log log = LogFactory.getLog(HpbWeb3Controller.class);
    // 超时时间
    private final long WEB3J_TIMEOUT = 3;
    
    // 演示的 HPB 账号地址
    private final String contractAddr = "0x7be6aa25600feed355b79b6a4e14dcdb0bd529cb";
    
    // 设置账号的余额单位为 18GWEI
    private final BigInteger gasPrice = Convert.toWei("18", Convert.Unit.GWEI).toBigInteger();
    // 设置默认的 GasLimit
    private final BigInteger gasLimit = new BigInteger("95000000");
    
    
    @Autowired
    private Admin admin;
    @ApiOperation(value="通过根据交易 hash 查询交易收据",notes = "过根据交易 hash 查询交易收据"
            + "reqStrList [参数 1:交易 hash]")
    @PostMapping("/QueryByHash")
    public List<Object> QueryByHash(@RequestBody List<String> reqStrList)throws Exception{List<Object> list=new ArrayList<Object>();
        if(reqStrList!=null&&reqStrList.size()>0) {String transactionHash = reqStrList.get(0);
            
            // 初始化封装的 Java SDK 包里的方法; 通过初始化 HpbGetTransactionReceipt,可以获得指定账号的交易数据
            HpbGetTransactionReceipt receipt = admin.hpbGetTransactionReceipt(transactionHash).send();
            if(!receipt.hasError()) {TransactionReceipt transactionReceipt = receipt.getResult();
                if(transactionReceipt.isStatusOK()) {list.add(transactionReceipt);
                }
            }
        }
        return list;
    }
    
    
    @ApiOperation(value="获得当前区块号",notes = "获得当前区块号")
    @PostMapping("/getCurrentBlock")
    public List<Object> getCurrentBlock()throws Exception{List<Object> list=new ArrayList<Object>();
        
        // 初始化封装的 Java SDK 包里的方法; 通过 HpbBlockNumber 获取当前区块的对象内容
        HpbBlockNumber blockNumber = admin.hpbBlockNumber().sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
        list.add(blockNumber);
        return list;
    }
    @ApiOperation(value="获得当前账户的 Nonce",notes = "获得当前账户的 Nonce"
            + "reqStrList [参数 1:账户地址;")
    @PostMapping("/getCurrentNonce")
    public List<Object> getCurrentNonce(@RequestBody List<String> reqStrList)throws Exception{List<Object> list=new ArrayList<Object>();
        if(reqStrList!=null&&reqStrList.size()>0) {String address =reqStrList.get(0);
            
            // 初始化封装的 Java SDK 包里的方法; 通过 HpbGetTransactionCount 获取当前账号 Nonce
            //Nonce 是账户的随机数:在一个账户中的防止多重交易的用途。HpbGetTransactionCount transactionCount = admin.hpbGetTransactionCount(address, 
                    DefaultBlockParameterName.PENDING).sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
            BigInteger nonce = transactionCount.getTransactionCount();
            log.info(nonce);
            list.add(nonce);
        }
        return list;
    }
    
    
    
    @ApiOperation(value="获得当前账户的余额",notes = "获得当前账户的余额"
            + "reqStrList [参数 1:账户地址;]")
    @PostMapping("/getBalance")
    public List<Object> getBalance(@RequestBody List<String> reqStrList)throws Exception{List<Object> list=new ArrayList<Object>();
        if(reqStrList!=null&&reqStrList.size()>0) {String address =reqStrList.get(0);
            
            // 初始化封装的 Java SDK 包里的方法; 通过 HpbGetBalance 获取当前账号的余额。HpbGetBalance balance = admin.hpbGetBalance(address, DefaultBlockParameterName.LATEST).send();
            log.info(balance);
            list.add(balance);
        }
        return list;
    }
    
    
    
    @ApiOperation(value="发送交易",notes = "发送交易"
            + "reqStrList [参数 1:账户 keystore 地址; 参数 2:密码; 参数 3:接收账户地址; 参数 4:转账金额;]")
    @PostMapping("/sendTransaction")
    public List<Object> sendTransaction(@RequestBody List<String> reqStrList)throws Exception{List<Object> list=new ArrayList<Object>();
        if(reqStrList!=null&&reqStrList.size()>3) {
            // 获取指定账号的 keystore
            String keystore =reqStrList.get(0);
            
            // 获取用户输入发送交易的账号密码
            String password =reqStrList.get(1);
            
            // 加载私钥对象
            Credentials credentials = WalletUtils.loadCredentials(password, keystore);
            
            // 创建交易管理对象
            RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);
            
            // 获取 nonce
            HpbGetTransactionCount transactionCount = admin.hpbGetTransactionCount(credentials.getAddress(), 
                    DefaultBlockParameterName.PENDING).sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
            
            BigInteger nonce = transactionCount.getTransactionCount();
            
            // 获取目标地址
            String to =reqStrList.get(2);
            
            // 转账金额
            String value =reqStrList.get(3);
            
            // 创建交易对象
            RawTransaction rawTransaction = RawTransaction.createTransaction(
                    nonce,
                    gasPrice,
                    gasLimit,
                    to,
                    Convert.toWei(value, Convert.Unit.HPB).toBigInteger(),
                    "");
                
            // 签名并发送交易
            HpbSendTransaction transaction = transactionManager.signAndSend(rawTransaction);
            log.info(transaction.getTransactionHash());
            list.add(transaction);
        }
        return list;
    }
    
    
    
    @ApiOperation(value="调用 HpbNodes 智能合约",notes = "调用 HpbNodes 智能合约"
            + "reqStrList [参数 1:账户 keystore 地址; 参数 2:密码]")
    @PostMapping("/invokeHpbNodes")
    public List<Object> invokeHpbNodes(@RequestBody List<String> reqStrList)throws Exception{List<Object> list=new ArrayList<Object>();
        if(reqStrList!=null&&reqStrList.size()>1) {String keystore =reqStrList.get(0);
            String password =reqStrList.get(1);
            Credentials credentials = WalletUtils.loadCredentials(password, keystore);
            RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);
            HpbNodes hpbNodes = HpbNodes.load(contractAddr, admin, transactionManager, gasPrice, gasLimit);
            // 调用智能合约
            Tuple4<DynamicArray<Address>, DynamicArray<Bytes32>, DynamicArray<Bytes32>, DynamicArray<Bytes32>> send = 
                    hpbNodes.getAllHpbNodes().send();
            Bytes32 bytes32 = send.getValue2().getValue().get(1);
            log.info(Numeric.toHexStringNoPrefix(bytes32.getValue()));
            Bytes32 bytes321 = send.getValue3().getValue().get(1);
            log.info(Numeric.toHexStringNoPrefix(bytes321.getValue()));
            Bytes32 bytes322 = send.getValue3().getValue().get(1);
            log.info(Numeric.toHexStringNoPrefix(bytes322.getValue()));
            list.add(send);
        }
        return list;
    }
    
}

2.4 运行程序和调试

2.4.1 发布程序

找到和选择好 Web3HpbTestApplication 类,右击”Run as /Spring Boot App” 启动成功后,系统会出现类似如下提示:
提示:

2019-01-09 10:49:18.538 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0     at org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:50)
 - Starting Web3HpbTestApplication on jason-hpbdeMBP with PID 46179 (/Users/hpb2017/git/web3-hpb-test/target/classes started by hpb2017 in /Users/hpb2017/git/web3-hpb-test)
2019-01-09 10:49:18.540 HpbWeb3Test [main] DEBUG io.hpb.web3.Web3HpbTestApplication Caller+0     at org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:53)
 - Running with Spring Boot v2.1.1.RELEASE, Spring v5.1.3.RELEASE
2019-01-09 10:49:18.542 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0     at org.springframework.boot.SpringApplication.logStartupProfileInfo(SpringApplication.java:675)
 - No active profile set, falling back to default profiles: default
2019-01-09 10:49:20.818 HpbWeb3Test [main] INFO  i.h.w.c.Web3AutoConfiguration Caller+0     at io.hpb.web3.configure.Web3AutoConfiguration.admin(Web3AutoConfiguration.java:51)
 - Building admin service for endpoint: http://pub.node.hpb.io/
2019-01-09 10:49:21.406 HpbWeb3Test [main] INFO  i.h.w.c.Web3AutoConfiguration Caller+0     at io.hpb.web3.configure.Web3AutoConfiguration.Web3(Web3AutoConfiguration.java:42)
 - Building service for endpoint: http://pub.node.hpb.io/
2019-01-09 10:49:22.057 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0     at org.springframework.boot.StartupInfoLogger.logStarted(StartupInfoLogger.java:59)
 - Started Web3HpbTestApplication in 3.943 seconds (JVM running for 5.429)

2.4.2 测试验证接口

Springboot 的接口可以通过自带的 swagger 插件进行访问和测试。打开本地访问地址:http://localhost:9988/HpbWeb3Test/swagger-ui.html#/ 会显示如目前系统开放的测试接口,然后选择点击“hpb-web-3-controller”,接入该接口的具体方法测试界面。点击“/getBalance”方法,点击“Try it out”开启编辑模式,输入你要查询余额的 HPB 地址;然后点击“Execute”开始执行。系统会显示执行的结果,注意这里获取的余额显示的是科学计数法。其他的接口可以依次根据接口的内容进行测试。

更多技术咨询

1. 如果你想了解更多关于 HPB 的技术信息,请访问我们的 GitHub WiKi:

HPB WiKi of GitHub

2. 如果你想获得更多 HPB 信息,请关注我们的官方网站:

HPB Website

正文完
 0