使用示例

下文将以LiteSDK为例,教您如何使用Hyperchain构建一个区块链应用demo。

准备工作

Java环境

如果您还没有搭建本地Java环境,请先下载安装JDK:下载,选择适合您平台的版本。

Java IDE

如果您还没有合适的Java IDE,请先下载安装,如IntelliJ IDEA:下载

创建项目

如果您已经完成了准备工作,Java开发环境配置完毕,则开始创建项目。

1. 新建一个Maven项目

此处以groupIdartifactIddemo为例。

2. 获取依赖

  • 查看LiteSDK最新版本jar包:地址

  • 在项目中添加相关的依赖:

Maven

Gradle

STB

grape

Ivy

  1. <dependency> <groupId>cn.hyperchain</groupId> <artifactId>litesdk</artifactId> <version>1.0.0</version></dependency
  1. // https://mvnrepository.com/artifact/cn.hyperchain/litesdkcompile group: 'cn.hyperchain', name: 'litesdk', version: '1.0.0'
  1. // https://mvnrepository.com/artifact/cn.hyperchain/litesdklibraryDependencies += "cn.hyperchain" % "litesdk" % "1.0.0"
  1. // https://mvnrepository.com/artifact/cn.hyperchain/litesdk@Grapes( @Grab(group='cn.hyperchain', module='litesdk', version='1.0.0'))
  1. <dependency org="cn.hyperchain" name="litesdk" rev="1.0.0"/>

完成以上步骤即可得到LiteSDK进行使用。

3. 将certs文件夹添加到项目src/main/resources中,供后续使用。

编写合约

平台目前支持使用Java语言进行智能合约的开发,此处以HVM为例。

下面是一个模拟银行的智能合约。本例中申明了银行相关的属性银行名bankName, 银行编号bankNum以及银行状态字段isInvalid等。除此之外,合约中还存储了一个adrress字段修饰的合约所有者地址,该地址用户判别合约调用者和合约的关系,理论上可以限制只有合约调用者才能够进行合约函数的编写。

  1. //合约主体类SBank.java
  2. public class SBank extends BaseContract implements ISBank {
  3. //注解标记数据持久化
  4. @StoreField
  5. public HyperMap<String, Integer> accounts = new HyperMap<String, Integer>();
  6. public SBank() {
  7. }
  8. @Override
  9. public void onInit() {
  10. this.accounts.put("AAA", 1000000000);
  11. this.accounts.put("BBB", 1000000000);
  12. this.accounts.put("CCC", 1000000000);
  13. this.accounts.put("DDD", 1000000000);
  14. }
  15. @Override
  16. public boolean transfer(String from, String to, int value) {
  17. int fromBalance = this.accounts.get(from);
  18. int toBalance;
  19. if (!this.accounts.containsKey(from) || fromBalance < value) {
  20. return false;
  21. }
  22. // if to account not exist, create
  23. if (!this.accounts.containsKey(to)) {
  24. toBalance = 0;
  25. } else {
  26. toBalance = this.accounts.get(to);
  27. }
  28. // do transaction
  29. this.accounts.put(from, fromBalance - value);
  30. this.accounts.put(to, toBalance + value);
  31. return true;
  32. }
  33. @Override
  34. public boolean deposit(String from, int value) {
  35. // if to account not exist, create
  36. if (!this.accounts.containsKey(from)) {
  37. this.accounts.put(from, 0);
  38. }
  39. this.accounts.put(from, this.accounts.get(from) + value);
  40. return true;
  41. }
  42. }
  43. //ISBank.java
  44. public interface ISBank extends BaseContractInterface {
  45. boolean transfer(String from, String to, int val);
  46. boolean deposit(String from, int val);
  47. }
  48. //invoke bean: InvokeBank.java
  49. public class InvokeBank implements BaseInvoke<Boolean, ISBank> {
  50. public String from;
  51. public String to;
  52. public int value;
  53. // 必须有一个无参默认构造方法
  54. public InvokeBank() {
  55. }
  56. public InvokeBank(String from, String to, int value) {
  57. this.from = from;
  58. this.to = to;
  59. this.value = value;
  60. }
  61. @Override
  62. public Boolean invoke(ISBank obj) {
  63. boolean a = obj.transfer(from, to, value);
  64. return a;
  65. }
  66. }

本例使用了一个map的结构进行用户及其资产的映射关系的维护,deposit函数实现了用户存款的业务,transfer实现了简单的用户之间的资产转账的业务。至此模拟银行合约的编写结束,接下来继续阐述如何对该合约进行编译、部署和调用。

先将合约SBank.java、ISBank.java打成一个jar包,在pom.xml文件中需配置Main-Class为SBank.java(合约主体类),打好的jar包放到resources文件夹中(也可放入其他路径)。

部署调用合约

下面是利用 LiteSDK 进行 SBank 部署、调用的例子:

  1. public class TestSBank {
  2. //合约jar包路径
  3. String jarPath = "/Users/dong/IdeaProjects/hyperchain/contractRes/hvm-bench-test/hypermap/target/sbank.jar";
  4. String defaultURL = "localhost:8081";
  5. @Test
  6. public void testSBank() throws Exception {
  7. InputStream is = FileUtil.readFileAsStream(jarPath);
  8. DefaultHttpProvider defaultHttpProvider = new DefaultHttpProvider.Builder().setUrl(defaultURL).build();
  9. ProviderManager providerManager = ProviderManager.createManager(defaultHttpProvider);
  10. ContractService contractService = ServiceManager.getContractService(providerManager);
  11. AccountService accountService = ServiceManager.getAccountService(providerManager);
  12. Account account = accountService.genAccount(Algo.ECRAW);
  13. //部署合约
  14. Transaction transaction = new Transaction.HVMBuilder(account.getAddress()).deploy(is).build();
  15. transaction.sign(account);
  16. ReceiptResponse receiptResponse = contractService.deploy(transaction).send().polling();
  17. //获取合约地址
  18. String contractAddress = receiptResponse.getContractAddress();
  19. System.out.println("contract address: " + contractAddress);
  20. //调用合约
  21. Transaction transaction1 = new
  22. //创建指定invoke bean的交易
  23. Transaction.HVMBuilder(account.getAddress()).invoke(contractAddress, new InvokeBank("AAA", "BBB", 100)).build();
  24. transaction1.sign(account);
  25. ReceiptResponse receiptResponse1 = contractService.invoke(transaction1).send().polling();
  26. //对交易执行结果进行解码
  27. String decodeHVM = Decoder.decodeHVM(receiptResponse1.getRet(), String.class);
  28. System.out.println("decode: " + decodeHVM);
  29. }

如上所示,首先需要实例化一个HttpProvider的实例,然后创建账户,接着使用该实例去进行合约部署和调用。交易发送之后只能返回一个交易哈希,需要通过该哈希去查询交易的结果,如部署合约中的拿到的交易回执中的合约地址。合约地址和invoke bean是调用合约的一个必须选项。在进行方法调用之前首先需要将需要调用的invoke bean进行编码。

在本例中,执行的实际合约如下:

  1. 部署合约:在部署过程中创建了AAA、BBB、CCC、DDD四个账户,分别设置余额1000000000
  2. 调用合约:AAA账户向BBB账户中转入100,并返回成功或失败的状态