使用示例
本节以JAVASDK为例,给出使用Hyperchain构建区块链应用的demo。
准备工作
Java环境
如果您还没有搭建本地Java环境,请先下载安装JDK:下载,选择适合您平台的版本。
Java IDE
如果您还没有合适的Java IDE,请先下载安装,如IntelliJ IDEA:下载。
创建项目
如果您已经完成了准备工作,Java开发环境配置完毕,则开始创建项目。
1. 新建一个Maven项目
此处以groupId
和artifactId
是demo
为例。
2. 获取依赖
查看JAVASDK最新版本jar包:地址。
在项目中添加相关的依赖:
<dependency>
<groupId>cn.hyperchain.javasdk</groupId>
<artifactId>hyperchainsdk</artifactId>
<version>4.2.3</version>
</dependency>
// https://mvnrepository.com/artifact/cn.hyperchain.javasdk/hyperchainsdk
compile group: 'cn.hyperchain.javasdk', name: 'hyperchainsdk', version: '4.2.3'
// https://mvnrepository.com/artifact/cn.hyperchain.javasdk/hyperchainsdk
libraryDependencies += "cn.hyperchain.javasdk" % "hyperchainsdk" % "4.2.3"
// https://mvnrepository.com/artifact/cn.hyperchain.javasdk/hyperchainsdk
@Grapes(
@Grab(group='cn.hyperchain.javasdk', module='hyperchainsdk', version='4.2.3')
)
<dependency org="cn.hyperchain.javasdk" name="hyperchainsdk" rev="4.2.3"/>
完成以上步骤即可得到Hyperchain Java SDK进行使用。
3. 将certs文件夹添加到项目src/main/resources
中,供后续使用。
编写智能合约
Hyperchain目前支持使用Solidity语言和Java语言进行智能合约的开发,此处以Solidity为例。
下面是一个模拟银行的智能合约。本例中申明了银行相关的属性银行名bankName, 银行编号bankNum以及银行状态字段isInvalid等。除此之外,合约中还存储了一个adrress字段修饰的合约所有者地址,该地址用户判别合约调用者和合约的关系,理论上可以限制只有合约调用者才能够进行合约函数的编写。
contract SimulateBank{
address owner;
bytes32 bankName;
uint bankNum;
bool isInvalid;
mapping(address => uint) public accounts;
function SimulateBank( bytes32 _bankName,uint _bankNum,bool _isInvalid){
bankName = _bankName;
bankNum = _bankNum;
isInvalid = _isInvalid;
owner = msg.sender;
}
function issue(address addr,uint number) returns (bool){
if(msg.sender==owner){
accounts[addr] = accounts[addr] + number;
return true;
}
return false;
}
function transfer(address addr1,address addr2,uint amount) returns (bool){
if(accounts[addr1] >= amount){
accounts[addr1] = accounts[addr1] - amount;
accounts[addr2] = accounts[addr2] + amount;
return true;
}
return false;
}
function getAccountBalance(address addr) returns(uint){
return accounts[addr];
}
}
本例使用了一个map的结构进行用户及其资产的映射关系的维护,issue函数实现了用户存款的业务,transfer实现了简单的用户之间的资产转账的业务,而getAccountBalance函数实现了用户余额的查询功能。至此模拟银行合约的编写结束,接下来继续阐述如何对该合约进行编译、部署和调用。
本例中将SimulateBank.sol
添加到上面所建项目src/main/resources
中。
部署和调用合约
修改配置文件
在导入的jar包中有许多配置文件,请修改配置文件hpc.properties
,注意节点ip与端口是否正确。
#Hyperchain Nodes IP Ports
node = {"nodes":["localhost","localhost","localhost","localhost"]}
# JsonRpc connect port
jsonRpcPort = [8081, 8082, 8083, 8084]
# webSocket connect port
webSocketPort = [11011, 11012, 11013, 11014]
#Namespace
namespace = global
#重发次数
resendTime = 10
#第一次轮训时间间隔 unit /ms
firstPollingInterval = 100
#发送一次,第一次轮训的次数
firstPollingTimes = 10
#第二次轮训时间间隔 unit /ms
secondPollingInterval = 1000
#发送一次,第二次轮训的次数
secondPollingTimes = 10
#Send Tcert during the request or not
SendTcert = true
#if sendTcert is true , you should add follow path.
ecertPriPath = certs/sdkcert.priv
ecertPath = certs/sdkcert.cert
uniquePrivPath = certs/unique.priv
uniquePubPath = certs/unique.pub
#发送重新连接请求间隔(/ms)
reConnectTime = 10000
#Use Https
https = false
#If https is true, you shoule add follow properties
tlsca = certs/tls/tlsca.ca
tlspeerCert = certs/tls/tls_peer.cert
tlspeerPriv = certs/tls/tls_peer.priv
#CFCA开关
CFCA = false
下面是利用 JAVASDK 进行 SimulateBank 部署、调用的例子:
public class demo {
private static void log(String s) {
System.out.println("HyperchainAPITest ====== " + s);
}
public static void main(String[] args) throws Exception{
HyperchainAPI hyperchain = new HyperchainAPI();
//创建账户A
String accountJsonA = HyperchainAPI.newAccountRawSM2();
Account accountA = new Account(accountJsonA);
//创建账户B
String accountJsonB = HyperchainAPI.newAccountRawSM2();
Account accountB = new Account(accountJsonB);
//读取合约
String contract = Utils.readFile("SimulateBank.sol");
//编译合约
CompileReturn compile = hyperchain.compileContract(contract);
//获取bin
List<String> listBin = compile.getBin();
String bin = listBin.get(0);
//获取abi
List<String> listAbi = compile.getAbi();
String abi = listAbi.get(0);
//封装交易
Transaction transaction = new Transaction(accountA.getAddress(), bin, false);
//签名
transaction.signWithSM2(accountJsonA, "");
//部署合约
ReceiptReturn receiptReturn = hyperchain.deployContract(transaction);
//查询交易
int code = receiptReturn.getRawcode();
log("部署结果:" + code);
String contractAddress = receiptReturn.getContractAddress();
log("合约地址:" + contractAddress);
//调用合约(有参数)
FuncParamReal addr = new FuncParamReal("address", accountA.getAddress());
FuncParamReal number = new FuncParamReal("uint", "10000");
//方法编码
String payloadWithParams = FunctionEncode.encodeFunction("issue", addr, number);
//实例化调用合约
Transaction transactionWithParmas = new Transaction(accountA.getAddress(), contractAddress, payloadWithParams, false);
transactionWithParmas.signWithSM2(accountJsonA, "");
ReceiptReturn receiptReturnWithParams = hyperchain.invokeContract(transactionWithParmas);
//获取与解析返回值
String rawReturnWithParams;
rawReturnWithParams = receiptReturnWithParams.getRet();
String decodedResultWithParams = FunctionDecode.resultDecode("issue", abi, rawReturnWithParams);
log("调用issue:" + decodedResultWithParams);
//调用getAccountBalance方法查看余额
String payload2 = FunctionEncode.encodeFunction("getAccountBalance", addr);
Transaction transaction1 = new Transaction(accountB.getAddress(), contractAddress, payload2, false);
transaction1.signWithSM2(accountJsonB, "");
ReceiptReturn receiptReturn2 = hyperchain.invokeContract(transaction1);
String rawReturn2 = receiptReturn2.getRet();
String decodedResult = FunctionDecode.resultDecode("getAccountBalance", abi, rawReturn2);
log("调用getAccountBalance:" + decodedResult);
}
}
如上所示,首先需要实例化一个HyperchainAPI的实例,然后创建账户,接着使用该实例去进行合约的编译、部署和调用。合约编译之后只能返回一个交易哈希,需要通过该哈希去查询交易的结果,如部署合约中的拿到的交易回执中的合约地址。合约地址是调用合约的一个必须选项。此外在进行方法调用之前首先需要将需要调用的方法及其参数进行编码,最后通过invokeContract方法进行具体的合约调用。
在本例中,首先创建了A、B两个账户,先由A账户部署合约,并调用合约中的issue
方法,具体内容为“B账户发行了10000”,再由B账户调用合约中的getAccountBalance
方法查看自己账户中的余额。