English / 中文
Ontology Java SDK User Guide
Version 0.7.0
智能合约基本说明
- codeAddress是什么
codeAddress是智能合约的唯一标识。
- 如何获得codeAddress ?
InputStream is = new FileInputStream("IdContract.avm");
byte[] bys = new byte[is.available()];
is.read(bys);
is.close();
code = Helper.toHexString(bys);
System.out.println("Code:" + Helper.toHexString(bys));
System.out.println("CodeAddress:" + Helper.getCodeAddress(code, VmType.NEOVM.value()));
Note: 在获得codeAddress的时候,需要设置该合约需要运行在什么虚拟机上,目前支持的虚拟机是NEO和WASM。
- 调用智能合约invokeTransaction的过程,sdk中具体做了什么
//step1:构造交易
//需先将智能合约参数转换成vm可识别的opcode
Transaction tx = ontSdk.getSmartcodeTx().makeInvokeCodeTransaction(params, vmtype, fees);
//step2:对交易签名
ontSdk.signTx(tx, info1.address, password);
//step3:发送交易
ontSdk.getConnectMgr().sendRawTransaction(tx.toHexString());
- invoke时为什么要传入账号和密码
调用智能合约时需要用户签名,如果是预执行不需要签名,钱包中保存的是加密后的用户私钥,需要密码才能解密获取私钥。
- 查询资产操作时,智能合约预执行是怎么回事,如何使用?
如智能合约get相关操作,从智能合约存储空间里读取数据,无需走节点共识,只在该节点执行即可返回结果。发送交易时调用预执行接口。
String result = (String) sdk.getConnectMgr().sendRawTransactionPreExec(txHex);
智能合约部署和调用
Note:目前java-sdk支持neo和wasm智能合约部署和调用,NEO和WASM合约部署操作一样,调用略有不同,见下面详解:
部署智能合约Demo例子
InputStream is = new FileInputStream("/Users/sss/dev/ontologytest/IdContract/IdContract.avm");
byte[] bys = new byte[is.available()];
is.read(bys);
is.close();
code = Helper.toHexString(bys);
ontSdk.setCodeAddress(Helper.getCodeAddress(code,VmType.NEOVM.value()));
//部署合约
String txhash = ontSdk.getSmartcodeTx().makeDeployCodeTransaction(code, true, "name", "1.0", "1", "1", "1", VmType.NEOVM.value());
System.out.println("txhash:" + txhash);
//等待出块
Thread.sleep(6000);
DeployCodeTransaction t = (DeployCodeTransaction) ontSdk.getConnectMgr().getTransaction(txhash);
| 参数 | 字段 | 类型 | 描述 | 说明 | | —– | ——- | —— | ————- | ———– | | 输入参数 | codeHexStr| String | 合约code十六进制字符串 | 必选 | | | needStorage | Boolean | 是否需要存储 | 必选 | | | name | String | 名字 | 必选| | | codeVersion | String | 版本 | 必选 | | | author | String | 作者 | 必选 | | | email | String | emal | 必选 | | | desp | String | 描述信息 | 必选 | | | returnType | ContractParameterType | 合约返回的数据类型 | 必选 | | 输出参数 | txid | String | 交易编号 | 交易编号是64位字符串 |
智能合约调用
NEO智能合约调用
- 基本流程:
- 读取智能合约的abi文件;
- 构造调用智能合约函数;
- 构造交易;
- 交易签名(预执行不需要签名);
- 发送交易。
- 示例
//读取智能合约的abi文件
InputStream is = new FileInputStream("C:\\ZX\\NeoContract1.abi.json");
byte[] bys = new byte[is.available()];
is.read(bys);
is.close();
String abi = new String(bys);
//解析abi文件
AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class);
System.out.println("codeHash:"+abiinfo.getHash());
System.out.println("Entrypoint:"+abiinfo.getEntrypoint());
System.out.println("Functions:"+abiinfo.getFunctions());
System.out.println("Events"+abiinfo.getEvents());
//设置智能合约codeAddress
ontSdk.setCodeAddress(abiinfo.getHash());
//获取账号信息
Identity did = ontSdk.getWalletMgr().getIdentitys().get(0);
AccountInfo info = ontSdk.getWalletMgr().getAccountInfo(did.ontid,"passwordtest");
//构造智能合约函数
AbiFunction func = abiinfo.getFunction("AddAttribute");
System.out.println(func.getParameters());
func.setParamsValue(did.ontid.getBytes(),"key".getBytes(),"bytes".getBytes(),"values02".getBytes(),Helper.hexToBytes(info.pubkey));
System.out.println(func);
//调用智能合约,sendInvokeSmartCodeWithSign方法封装好了构造交易,签名交易,发送交易步骤
String hash = ontSdk.getSmartcodeTx().sendInvokeSmartCodeWithSign(did.ontid, "passwordtest", func, (byte) VmType.NEOVM.value()););
- AbiInfo结构(NEO合约调用的时候需要,WASM合约不需要)
public class AbiInfo {
public String hash;
public String entrypoint;
public List<AbiFunction> functions;
public List<AbiEvent> events;
}
public class AbiFunction {
public String name;
public String returntype;
public List<Parameter> parameters;
}
public class Parameter {
public String name;
public String type;
public String value;
}
WASM智能合约调用
- 基本流程:
- 构造调用合约中的方法需要的参数;
- 构造交易;
- 交易签名(如果是预执行不需要签名);
- 发送交易。
- 示例:
//设置要调用的合约地址codeAddress
ontSdk.getSmartcodeTx().setCodeAddress(codeAddress);
String funcName = "add";
//构造合约函数需要的参数
String params = ontSdk.getSmartcodeTx().buildWasmContractJsonParam(new Object[]{20,30});
//指定虚拟机类型构造交易
Transaction tx = ontSdk.getSmartcodeTx().makeInvokeCodeTransaction(ontSdk.getSmartcodeTx().getCodeAddress(),funcName,params.getBytes(),VmType.WASMVM.value(),new Fee[0]);
//发送交易
ontSdk.getConnectMgr().sendRawTransaction(tx.toHexString());
如果需要监控推送结果,可以了解下面章节。
智能合约执行过程推送
创建websocket线程,解析推送结果。
1. 设置websocket链接
//lock 全局变量,同步锁
public static Object lock = new Object();
//获得ont实例
String ip = "http://127.0.0.1";
String wsUrl = ip + ":" + "20335";
OntSdk wm = OntSdk.getInstance();
wm.setWesocket(wsUrl, lock);
wm.setDefaultConnect(wm.getWebSocket());
wm.openWalletFile("OntAssetDemo.json");
2. 启动websocket线程
//false 表示不打印回调函数信息
ontSdk.getWebSocket().startWebsocketThread(false);
3. 启动结果处理线程
Thread thread = new Thread(
new Runnable() {
@Override
public void run() {
waitResult(lock);
}
});
thread.start();
//将MsgQueue中的数据取出打印
public static void waitResult(Object lock) {
try {
synchronized (lock) {
while (true) {
lock.wait();
for (String e : MsgQueue.getResultSet()) {
System.out.println("RECV: " + e);
Result rt = JSON.parseObject(e, Result.class);
//TODO
MsgQueue.removeResult(e);
if (rt.Action.equals("getblockbyheight")) {
Block bb = Serializable.from(Helper.hexToBytes((String) rt.Result), Block.class);
//System.out.println(bb.json());
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
4. 每6秒发送一次心跳程序,维持socket链接
for (;;){
Map map = new HashMap();
if(i >0) {
map.put("SubscribeEvent", true);
map.put("SubscribeRawBlock", false);
}else{
map.put("SubscribeJsonBlock", false);
map.put("SubscribeRawBlock", true);
}
//System.out.println(map);
ontSdk.getWebSocket().setReqId(i);
ontSdk.getWebSocket().sendSubscribe(map);
Thread.sleep(6000);
}
5. 推送结果事例详解
以调用存证合约的put函数为例,
//存证合约abi.json文件部分内容如下
{
"hash":"0x27f5ae9dd51499e7ac4fe6a5cc44526aff909669",
"entrypoint":"Main",
"functions":
[
],
"events":
[
{
"name":"putRecord",
"parameters":
[
{
"name":"arg1",
"type":"String"
},
{
"name":"arg2",
"type":"ByteArray"
},
{
"name":"arg3",
"type":"ByteArray"
}
],
"returntype":"Void"
}
]
}
当调用put函数保存数据时,触发putRecord事件,websocket 推送的结果是{“putRecord”, “arg1”, “arg2”, “arg3”}的十六进制字符串
例子如下:
RECV: {"Action":"Log","Desc":"SUCCESS","Error":0,"Result":{"Message":"Put","TxHash":"8cb32f3a1817d88d8562fdc0097a0f9aa75a926625c6644dfc5417273ca7ed71","ContractAddress":"80f6bff7645a84298a1a52aa3745f84dba6615cf"},"Version":"1.0.0"}
RECV: {"Action":"Notify","Desc":"SUCCESS","Error":0,"Result":[{"States":["7075745265636f7264","507574","6b6579","7b2244617461223a7b22416c6772697468656d223a22534d32222c2248617368223a22222c2254657874223a2276616c75652d7465737431222c225369676e6174757265223a22227d2c2243416b6579223a22222c225365714e6f223a22222c2254696d657374616d70223a307d"],"TxHash":"8cb32f3a1817d88d8562fdc0097a0f9aa75a926625c6644dfc5417273ca7ed71","ContractAddress":"80f6bff7645a84298a1a52aa3745f84dba6615cf"}],"Version":"1.0.0"}