@@ -34,11 +34,11 @@ | |||||
<plugin> | <plugin> | ||||
<artifactId>maven-assembly-plugin</artifactId> | <artifactId>maven-assembly-plugin</artifactId> | ||||
<configuration> | <configuration> | ||||
<finalName>contract</finalName> | |||||
<finalName>transfer</finalName> | |||||
<appendAssemblyId>false</appendAssemblyId> | <appendAssemblyId>false</appendAssemblyId> | ||||
<archive> | <archive> | ||||
<manifest> | <manifest> | ||||
<mainClass>com.jd.blockchain.contract.ReadContractImpl</mainClass> | |||||
<mainClass>com.jd.blockchain.contract.TransferContractImpl</mainClass> | |||||
</manifest> | </manifest> | ||||
</archive> | </archive> | ||||
<descriptorRefs> | <descriptorRefs> | ||||
@@ -0,0 +1,17 @@ | |||||
package com.jd.blockchain.contract; | |||||
@Contract | |||||
public interface TransferContract { | |||||
@ContractEvent(name = "create") | |||||
String create(String address, String account, long money); | |||||
@ContractEvent(name = "transfer") | |||||
String transfer(String address, String from, String to, long money); | |||||
@ContractEvent(name = "read") | |||||
long read(String address, String account); | |||||
@ContractEvent(name = "readAll") | |||||
String readAll(String address, String account); | |||||
} |
@@ -0,0 +1,109 @@ | |||||
package com.jd.blockchain.contract; | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.KVDataVO; | |||||
import com.jd.blockchain.ledger.KVInfoVO; | |||||
public class TransferContractImpl implements EventProcessingAwire, TransferContract { | |||||
private ContractEventContext eventContext; | |||||
private HashDigest ledgerHash; | |||||
@Override | |||||
public String create(String address, String account, long money) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
// 肯定有返回值,但若不存在则返回version=-1 | |||||
if (kvDataEntries != null && kvDataEntries.length > 0) { | |||||
long currVersion = kvDataEntries[0].getVersion(); | |||||
if (currVersion > -1) { | |||||
throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account)); | |||||
} | |||||
eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L); | |||||
} else { | |||||
throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58())); | |||||
} | |||||
return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n", | |||||
address, account, money); | |||||
} | |||||
@Override | |||||
public String transfer(String address, String from, String to, long money) { | |||||
// 首先查询余额 | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); | |||||
if (kvDataEntries == null || kvDataEntries.length != 2) { | |||||
throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | |||||
} else { | |||||
// 判断from账号中钱数量是否足够 | |||||
long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | |||||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||||
if (kvDataEntry.getKey().equals(from)) { | |||||
fromMoney = (long) kvDataEntry.getValue(); | |||||
fromVersion = kvDataEntry.getVersion(); | |||||
} else { | |||||
toMoney = (long) kvDataEntry.getValue(); | |||||
toVersion = kvDataEntry.getVersion(); | |||||
} | |||||
} | |||||
if (fromMoney < money) { | |||||
throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from)); | |||||
} | |||||
long fromNewMoney = fromMoney - money; | |||||
long toNewMoney = toMoney + money; | |||||
// 重新设置 | |||||
eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion); | |||||
eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion); | |||||
} | |||||
return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money); | |||||
} | |||||
@Override | |||||
public long read(String address, String account) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
return -1; | |||||
} | |||||
return (long)kvDataEntries[0].getValue(); | |||||
} | |||||
@Override | |||||
public String readAll(String address, String account) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
// 获取最新的版本号 | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
return ""; | |||||
} | |||||
long newestVersion = kvDataEntries[0].getVersion(); | |||||
if (newestVersion == -1) { | |||||
return ""; | |||||
} | |||||
KVDataVO[] kvDataVOS = new KVDataVO[1]; | |||||
long[] versions = new long[(int)newestVersion + 1]; | |||||
for (int i = 0; i < versions.length; i++) { | |||||
versions[i] = i; | |||||
} | |||||
KVDataVO kvDataVO = new KVDataVO(account, versions); | |||||
kvDataVOS[0] = kvDataVO; | |||||
KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); | |||||
KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); | |||||
return JSON.toJSONString(allEntries); | |||||
} | |||||
@Override | |||||
public void beforeEvent(ContractEventContext eventContext) { | |||||
this.eventContext = eventContext; | |||||
this.ledgerHash = eventContext.getCurrentLedgerHash(); | |||||
} | |||||
@Override | |||||
public void postEvent(ContractEventContext eventContext, Exception error) { | |||||
} | |||||
} |
@@ -7,7 +7,7 @@ import com.jd.blockchain.consts.DataCodes; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) | @DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) | ||||
public interface DataAccountKVSetOperation extends Operation{ | |||||
public interface DataAccountKVSetOperation extends Operation { | |||||
@DataField(order=2, primitiveType=PrimitiveType.BYTES) | @DataField(order=2, primitiveType=PrimitiveType.BYTES) | ||||
Bytes getAccountAddress(); | Bytes getAccountAddress(); | ||||
@@ -106,9 +106,6 @@ public enum DataType { | |||||
ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)); | ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)); | ||||
@EnumField(type = PrimitiveType.INT8) | @EnumField(type = PrimitiveType.INT8) | ||||
public final byte CODE; | public final byte CODE; | ||||
@@ -8,6 +8,14 @@ public class KVDataVO { | |||||
private String key; | private String key; | ||||
private long[] version; | private long[] version; | ||||
public KVDataVO() { | |||||
} | |||||
public KVDataVO(String key, long[] version) { | |||||
this.key = key; | |||||
this.version = version; | |||||
} | |||||
public String getKey() { | public String getKey() { | ||||
return key; | return key; | ||||
} | } | ||||
@@ -8,6 +8,13 @@ package com.jd.blockchain.ledger; | |||||
public class KVInfoVO { | public class KVInfoVO { | ||||
private KVDataVO[] data; | private KVDataVO[] data; | ||||
public KVInfoVO() { | |||||
} | |||||
public KVInfoVO(KVDataVO[] data) { | |||||
this.data = data; | |||||
} | |||||
public KVDataVO[] getData() { | public KVDataVO[] getData() { | ||||
return data; | return data; | ||||
} | } | ||||
@@ -61,7 +61,7 @@ public class ContractInvocationProxy implements InvocationHandler { | |||||
((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); | ((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); | ||||
} | } | ||||
// 代理操作,返回值类型无法创建 | // 代理操作,返回值类型无法创建 | ||||
return null; | |||||
return returnResult(method.getReturnType()); | |||||
} | } | ||||
private byte[] serializeArgs(Object[] args) { | private byte[] serializeArgs(Object[] args) { | ||||
@@ -74,4 +74,36 @@ public class ContractInvocationProxy implements InvocationHandler { | |||||
} | } | ||||
return -1; | return -1; | ||||
} | } | ||||
private Object returnResult(Class<?> clazz) { | |||||
if (clazz.equals(Void.TYPE)) { | |||||
return null; | |||||
} | |||||
if (!clazz.isPrimitive()) { | |||||
// 非基本类型 | |||||
return null; | |||||
} else { | |||||
// 基本类型需要处理返回值,目前采用枚举遍历方式 | |||||
// 八种基本类型:int, double, float, long, short, boolean, byte, char, void | |||||
if (clazz.equals(int.class)) { | |||||
return 0; | |||||
} else if (clazz.equals(double.class)) { | |||||
return 0.0D; | |||||
} else if (clazz.equals(float.class)) { | |||||
return 0F; | |||||
} else if (clazz.equals(long.class)) { | |||||
return 0L; | |||||
} else if (clazz.equals(short.class)) { | |||||
return (short)0; | |||||
} else if (clazz.equals(boolean.class)) { | |||||
return Boolean.FALSE; | |||||
} else if (clazz.equals(byte.class)) { | |||||
return (byte)0; | |||||
} else if (clazz.equals(char.class)) { | |||||
return (char)0; | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
} | } |
@@ -60,6 +60,23 @@ public class ContractType { | |||||
public static ContractType resolve(Class<?> contractIntf) { | public static ContractType resolve(Class<?> contractIntf) { | ||||
// 如果是Class则首先获取其接口 | |||||
if (!contractIntf.isInterface()) { | |||||
Class<?> realIntf = null; | |||||
Class<?>[] interfaces = contractIntf.getInterfaces(); | |||||
for (Class<?> intf: interfaces) { | |||||
if (intf.isAnnotationPresent(Contract.class)) { | |||||
realIntf = intf; | |||||
break; | |||||
} | |||||
} | |||||
if (realIntf == null) { | |||||
throw new IllegalDataException(String.format( | |||||
"%s is not a Contract Type, because there is not @Contract !", contractIntf.getName())); | |||||
} | |||||
contractIntf = realIntf; | |||||
} | |||||
// 接口上必须有注解 | // 接口上必须有注解 | ||||
if (!contractIntf.isAnnotationPresent(Contract.class)) { | if (!contractIntf.isAnnotationPresent(Contract.class)) { | ||||
throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !"); | throw new IllegalDataException("It is not a Contract Type, because there is not @Contract !"); | ||||
@@ -1,46 +1,26 @@ | |||||
/** | /** | ||||
* Copyright: Copyright 2016-2020 JD.COM All Right Reserved | * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | ||||
* FileName: com.jd.blockchain.sdk.client.ClientOperationUtil | |||||
* FileName: com.jd.blockchain.sdk.client.ClientResolveUtil | |||||
* Author: shaozhuguang | * Author: shaozhuguang | ||||
* Department: Y事业部 | * Department: Y事业部 | ||||
* Date: 2019/3/27 下午4:12 | * Date: 2019/3/27 下午4:12 | ||||
* Description: | * Description: | ||||
*/ | */ | ||||
package com.jd.blockchain.sdk.client; | |||||
import java.lang.reflect.Field; | |||||
import org.apache.commons.codec.binary.Base64; | |||||
package com.jd.blockchain.sdk.converters; | |||||
import com.alibaba.fastjson.JSONArray; | import com.alibaba.fastjson.JSONArray; | ||||
import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||
import com.jd.blockchain.crypto.CryptoProvider; | import com.jd.blockchain.crypto.CryptoProvider; | ||||
import com.jd.blockchain.crypto.PubKey; | import com.jd.blockchain.crypto.PubKey; | ||||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||||
import com.jd.blockchain.ledger.BytesValue; | |||||
import com.jd.blockchain.ledger.BytesValueEntry; | |||||
import com.jd.blockchain.ledger.DataType; | |||||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||||
import com.jd.blockchain.ledger.CryptoSetting; | |||||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||||
import com.jd.blockchain.ledger.Operation; | |||||
import com.jd.blockchain.ledger.ParticipantNode; | |||||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||||
import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; | |||||
import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||||
import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||||
import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; | |||||
import com.jd.blockchain.transaction.KVData; | |||||
import com.jd.blockchain.transaction.LedgerInitOpTemplate; | |||||
import com.jd.blockchain.transaction.LedgerInitSettingData; | |||||
import com.jd.blockchain.transaction.UserRegisterOpTemplate; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.transaction.*; | |||||
import com.jd.blockchain.utils.Bytes; | import com.jd.blockchain.utils.Bytes; | ||||
import com.jd.blockchain.utils.codec.Base58Utils; | import com.jd.blockchain.utils.codec.Base58Utils; | ||||
import com.jd.blockchain.utils.codec.HexUtils; | import com.jd.blockchain.utils.codec.HexUtils; | ||||
import com.jd.blockchain.utils.io.BytesUtils; | import com.jd.blockchain.utils.io.BytesUtils; | ||||
import org.apache.commons.codec.binary.Base64; | |||||
import java.lang.reflect.Field; | |||||
/** | /** | ||||
* | * | ||||
@@ -49,7 +29,42 @@ import com.jd.blockchain.utils.io.BytesUtils; | |||||
* @since 1.0.0 | * @since 1.0.0 | ||||
*/ | */ | ||||
public class ClientOperationUtil { | |||||
public class ClientResolveUtil { | |||||
public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
return kvDataEntries; | |||||
} | |||||
KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||||
// kvDataEntries是代理对象,需要处理 | |||||
for (int i = 0; i < kvDataEntries.length; i++) { | |||||
KVDataEntry kvDataEntry = kvDataEntries[i]; | |||||
String key = kvDataEntry.getKey(); | |||||
long version = kvDataEntry.getVersion(); | |||||
DataType dataType = kvDataEntry.getType(); | |||||
KvData innerKvData = new KvData(key, version, dataType); | |||||
Object valueObj = kvDataEntry.getValue(); | |||||
switch (dataType) { | |||||
case NIL: | |||||
break; | |||||
case BYTES: | |||||
case TEXT: | |||||
case JSON: | |||||
innerKvData.setValue(valueObj.toString()); | |||||
break; | |||||
case INT32: | |||||
innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||||
break; | |||||
case INT64: | |||||
innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||||
break; | |||||
default: | |||||
throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||||
} | |||||
resolveKvDataEntries[i] = innerKvData; | |||||
} | |||||
return resolveKvDataEntries; | |||||
} | |||||
public static Operation read(Operation operation) { | public static Operation read(Operation operation) { | ||||
@@ -297,4 +312,65 @@ public class ClientOperationUtil { | |||||
this.id = id; | this.id = id; | ||||
} | } | ||||
} | } | ||||
public static class KvData implements KVDataEntry { | |||||
private String key; | |||||
private long version; | |||||
private DataType dataType; | |||||
private Object value; | |||||
public KvData() { | |||||
} | |||||
public KvData(String key, long version, DataType dataType) { | |||||
this(key, version, dataType, null); | |||||
} | |||||
public KvData(String key, long version, DataType dataType, Object value) { | |||||
this.key = key; | |||||
this.version = version; | |||||
this.dataType = dataType; | |||||
this.value = value; | |||||
} | |||||
public void setKey(String key) { | |||||
this.key = key; | |||||
} | |||||
public void setVersion(long version) { | |||||
this.version = version; | |||||
} | |||||
public void setDataType(DataType dataType) { | |||||
this.dataType = dataType; | |||||
} | |||||
public void setValue(Object value) { | |||||
this.value = value; | |||||
} | |||||
@Override | |||||
public String getKey() { | |||||
return key; | |||||
} | |||||
@Override | |||||
public long getVersion() { | |||||
return version; | |||||
} | |||||
@Override | |||||
public DataType getType() { | |||||
return dataType; | |||||
} | |||||
@Override | |||||
public Object getValue() { | |||||
return value; | |||||
} | |||||
} | |||||
} | } |
@@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.sdk.BlockchainEventHandle; | import com.jd.blockchain.sdk.BlockchainEventHandle; | ||||
import com.jd.blockchain.sdk.BlockchainEventListener; | import com.jd.blockchain.sdk.BlockchainEventListener; | ||||
import com.jd.blockchain.sdk.BlockchainService; | import com.jd.blockchain.sdk.BlockchainService; | ||||
import com.jd.blockchain.sdk.converters.ClientResolveUtil; | |||||
import com.jd.blockchain.transaction.BlockchainQueryService; | import com.jd.blockchain.transaction.BlockchainQueryService; | ||||
import com.jd.blockchain.transaction.TransactionService; | import com.jd.blockchain.transaction.TransactionService; | ||||
import com.jd.blockchain.transaction.TxTemplate; | import com.jd.blockchain.transaction.TxTemplate; | ||||
@@ -144,17 +145,20 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | ||||
return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); | |||||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys); | |||||
return ClientResolveUtil.read(kvDataEntries); | |||||
} | } | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | ||||
return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); | |||||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO); | |||||
return ClientResolveUtil.read(kvDataEntries); | |||||
} | } | ||||
@Override | @Override | ||||
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | ||||
return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); | |||||
KVDataEntry[] kvDataEntries = getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count); | |||||
return ClientResolveUtil.read(kvDataEntries); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -0,0 +1,385 @@ | |||||
///** | |||||
// * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||||
// * FileName: com.jd.blockchain.sdk.client.ClientResolveUtil | |||||
// * Author: shaozhuguang | |||||
// * Department: Y事业部 | |||||
// * Date: 2019/3/27 下午4:12 | |||||
// * Description: | |||||
// */ | |||||
//package com.jd.blockchain.sdk.client; | |||||
// | |||||
//import java.lang.reflect.Field; | |||||
// | |||||
//import com.jd.blockchain.ledger.*; | |||||
//import com.jd.blockchain.utils.io.ByteArray; | |||||
//import org.apache.commons.codec.binary.Base64; | |||||
// | |||||
//import com.alibaba.fastjson.JSONArray; | |||||
//import com.alibaba.fastjson.JSONObject; | |||||
//import com.jd.blockchain.crypto.CryptoProvider; | |||||
//import com.jd.blockchain.crypto.PubKey; | |||||
//import com.jd.blockchain.transaction.ContractCodeDeployOpTemplate; | |||||
//import com.jd.blockchain.transaction.ContractEventSendOpTemplate; | |||||
//import com.jd.blockchain.transaction.DataAccountKVSetOpTemplate; | |||||
//import com.jd.blockchain.transaction.DataAccountRegisterOpTemplate; | |||||
//import com.jd.blockchain.transaction.KVData; | |||||
//import com.jd.blockchain.transaction.LedgerInitOpTemplate; | |||||
//import com.jd.blockchain.transaction.LedgerInitSettingData; | |||||
//import com.jd.blockchain.transaction.UserRegisterOpTemplate; | |||||
//import com.jd.blockchain.utils.Bytes; | |||||
//import com.jd.blockchain.utils.codec.Base58Utils; | |||||
//import com.jd.blockchain.utils.codec.HexUtils; | |||||
//import com.jd.blockchain.utils.io.BytesUtils; | |||||
// | |||||
///** | |||||
// * | |||||
// * @author shaozhuguang | |||||
// * @create 2019/3/27 | |||||
// * @since 1.0.0 | |||||
// */ | |||||
// | |||||
//public class ClientResolveUtil { | |||||
// | |||||
// public static KVDataEntry[] read(KVDataEntry[] kvDataEntries) { | |||||
// if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
// return kvDataEntries; | |||||
// } | |||||
// KVDataEntry[] resolveKvDataEntries = new KVDataEntry[kvDataEntries.length]; | |||||
// // kvDataEntries是代理对象,需要处理 | |||||
// for (int i = 0; i < kvDataEntries.length; i++) { | |||||
// KVDataEntry kvDataEntry = kvDataEntries[i]; | |||||
// String key = kvDataEntry.getKey(); | |||||
// long version = kvDataEntry.getVersion(); | |||||
// DataType dataType = kvDataEntry.getType(); | |||||
// KvData innerKvData = new KvData(key, version, dataType); | |||||
// Object valueObj = kvDataEntry.getValue(); | |||||
// switch (dataType) { | |||||
// case NIL: | |||||
// break; | |||||
// case BYTES: | |||||
// case TEXT: | |||||
// case JSON: | |||||
// innerKvData.setValue(valueObj.toString()); | |||||
// break; | |||||
// case INT32: | |||||
// innerKvData.setValue(Integer.parseInt(valueObj.toString())); | |||||
// break; | |||||
// case INT64: | |||||
// innerKvData.setValue(Long.parseLong(valueObj.toString())); | |||||
// break; | |||||
// default: | |||||
// throw new IllegalStateException("Unsupported value type[" + dataType + "] to resolve!"); | |||||
// } | |||||
// resolveKvDataEntries[i] = innerKvData; | |||||
// } | |||||
// return resolveKvDataEntries; | |||||
// } | |||||
// | |||||
// public static Operation read(Operation operation) { | |||||
// | |||||
// try { | |||||
// // Class | |||||
// Class<?> clazz = operation.getClass(); | |||||
// Field field = clazz.getSuperclass().getDeclaredField("h"); | |||||
// field.setAccessible(true); | |||||
// Object object = field.get(operation); | |||||
// if (object instanceof JSONObject) { | |||||
// JSONObject jsonObject = (JSONObject) object; | |||||
// if (jsonObject.containsKey("accountID")) { | |||||
// return convertDataAccountRegisterOperation(jsonObject); | |||||
// } else if (jsonObject.containsKey("userID")) { | |||||
// return convertUserRegisterOperation(jsonObject); | |||||
// } else if (jsonObject.containsKey("contractID")) { | |||||
// return convertContractCodeDeployOperation(jsonObject); | |||||
// } else if (jsonObject.containsKey("writeSet")) { | |||||
// return convertDataAccountKVSetOperation(jsonObject); | |||||
// } else if (jsonObject.containsKey("initSetting")) { | |||||
// return convertLedgerInitOperation(jsonObject); | |||||
// } else if (jsonObject.containsKey("contractAddress")) { | |||||
// return convertContractEventSendOperation(jsonObject); | |||||
// } | |||||
// } | |||||
// } catch (Exception e) { | |||||
// throw new RuntimeException(e); | |||||
// } | |||||
// | |||||
// return null; | |||||
// } | |||||
// | |||||
// public static Object readValueByBytesValue(BytesValue bytesValue) { | |||||
// DataType dataType = bytesValue.getType(); | |||||
// Bytes saveVal = bytesValue.getValue(); | |||||
// Object showVal; | |||||
// switch (dataType) { | |||||
// case BYTES: | |||||
// // return hex | |||||
// showVal = HexUtils.encode(saveVal.toBytes()); | |||||
// break; | |||||
// case TEXT: | |||||
// case JSON: | |||||
// showVal = saveVal.toUTF8String(); | |||||
// break; | |||||
// case INT64: | |||||
// showVal = BytesUtils.toLong(saveVal.toBytes()); | |||||
// break; | |||||
// default: | |||||
// showVal = HexUtils.encode(saveVal.toBytes()); | |||||
// break; | |||||
// } | |||||
// return showVal; | |||||
// } | |||||
// | |||||
// public static DataAccountRegisterOperation convertDataAccountRegisterOperation(JSONObject jsonObject) { | |||||
// JSONObject account = jsonObject.getJSONObject("accountID"); | |||||
// return new DataAccountRegisterOpTemplate(blockchainIdentity(account)); | |||||
// } | |||||
// | |||||
// public static DataAccountKVSetOperation convertDataAccountKVSetOperation(JSONObject jsonObject) { | |||||
// // 写入集合处理 | |||||
// JSONArray writeSetObj = jsonObject.getJSONArray("writeSet"); | |||||
// JSONObject accountAddrObj = jsonObject.getJSONObject("accountAddress"); | |||||
// String addressBase58 = accountAddrObj.getString("value"); | |||||
// Bytes address = Bytes.fromBase58(addressBase58); | |||||
// | |||||
// DataAccountKVSetOpTemplate kvOperation = new DataAccountKVSetOpTemplate(address); | |||||
// for (int i = 0; i <writeSetObj.size(); i++) { | |||||
// JSONObject currWriteSetObj = writeSetObj.getJSONObject(i); | |||||
// long expectedVersion = currWriteSetObj.getLong("expectedVersion"); | |||||
// JSONObject valueObj = currWriteSetObj.getJSONObject("value"); | |||||
// String typeStr = valueObj.getString("type"); | |||||
// String realValBase58 = valueObj.getString("value"); | |||||
// String key = currWriteSetObj.getString("key"); | |||||
// DataType dataType = DataType.valueOf(typeStr); | |||||
// BytesValue bytesValue =BytesValueEntry.fromType(dataType, Base58Utils.decode(realValBase58)); | |||||
// KVData kvData = new KVData(key, bytesValue, expectedVersion); | |||||
// kvOperation.set(kvData); | |||||
// } | |||||
// | |||||
// return kvOperation; | |||||
// } | |||||
// | |||||
// public static LedgerInitOperation convertLedgerInitOperation(JSONObject jsonObject) { | |||||
// JSONObject legerInitObj = jsonObject.getJSONObject("initSetting"); | |||||
// LedgerInitSettingData ledgerInitSettingData = new LedgerInitSettingData(); | |||||
// String ledgerSeedStr = legerInitObj.getString("ledgerSeed"); | |||||
// | |||||
// // 种子需要做Base64转换 | |||||
// ledgerInitSettingData.setLedgerSeed(Base64.decodeBase64(BytesUtils.toBytes(ledgerSeedStr))); | |||||
// | |||||
// String consensusProvider = legerInitObj.getString("consensusProvider"); | |||||
// | |||||
// ledgerInitSettingData.setConsensusProvider(consensusProvider); | |||||
// | |||||
// JSONObject cryptoSettingObj = legerInitObj.getJSONObject("cryptoSetting"); | |||||
// boolean autoVerifyHash = cryptoSettingObj.getBoolean("autoVerifyHash"); | |||||
// short hashAlgorithm = cryptoSettingObj.getShort("hashAlgorithm"); | |||||
// | |||||
// CryptoConfig cryptoConfig = new CryptoConfig(); | |||||
// | |||||
// cryptoConfig.setAutoVerifyHash(autoVerifyHash); | |||||
// | |||||
// cryptoConfig.setHashAlgorithm(hashAlgorithm); | |||||
// | |||||
// ledgerInitSettingData.setCryptoSetting(cryptoConfig); | |||||
// | |||||
// | |||||
// JSONObject consensusSettingsObj = legerInitObj.getJSONObject("consensusSettings"); | |||||
// Bytes consensusSettings = Bytes.fromBase58(consensusSettingsObj.getString("value")); | |||||
// | |||||
// ledgerInitSettingData.setConsensusSettings(consensusSettings); | |||||
// | |||||
// JSONArray consensusParticipantsArray = legerInitObj.getJSONArray("consensusParticipants"); | |||||
// | |||||
// if (!consensusParticipantsArray.isEmpty()) { | |||||
// ParticipantNode[] participantNodes = new ParticipantNode[consensusParticipantsArray.size()]; | |||||
// for (int i = 0; i < consensusParticipantsArray.size(); i++) { | |||||
// JSONObject currConsensusParticipant = consensusParticipantsArray.getJSONObject(i); | |||||
// String addressBase58 = currConsensusParticipant.getString("address"); | |||||
// String name = currConsensusParticipant.getString("name"); | |||||
// int id = currConsensusParticipant.getInteger("id"); | |||||
// JSONObject pubKeyObj = currConsensusParticipant.getJSONObject("pubKey"); | |||||
// String pubKeyBase58 = pubKeyObj.getString("value"); | |||||
// // 生成ParticipantNode对象 | |||||
// ParticipantCertData participantCertData = new ParticipantCertData(id, addressBase58, name, new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes())); | |||||
// participantNodes[i] = participantCertData; | |||||
// } | |||||
// ledgerInitSettingData.setConsensusParticipants(participantNodes); | |||||
// } | |||||
// | |||||
// return new LedgerInitOpTemplate(ledgerInitSettingData); | |||||
// } | |||||
// | |||||
// public static UserRegisterOperation convertUserRegisterOperation(JSONObject jsonObject) { | |||||
// JSONObject user = jsonObject.getJSONObject("userID"); | |||||
// return new UserRegisterOpTemplate(blockchainIdentity(user)); | |||||
// } | |||||
// | |||||
// public static ContractCodeDeployOperation convertContractCodeDeployOperation(JSONObject jsonObject) { | |||||
// JSONObject contract = jsonObject.getJSONObject("contractID"); | |||||
// BlockchainIdentityData blockchainIdentity = blockchainIdentity(contract); | |||||
// | |||||
// String chainCodeStr = jsonObject.getString("chainCode"); | |||||
// ContractCodeDeployOpTemplate contractCodeDeployOpTemplate = new ContractCodeDeployOpTemplate(blockchainIdentity, BytesUtils.toBytes(chainCodeStr)); | |||||
// return contractCodeDeployOpTemplate; | |||||
// } | |||||
// | |||||
// public static ContractEventSendOperation convertContractEventSendOperation(JSONObject jsonObject) { | |||||
// JSONObject contractAddressObj = jsonObject.getJSONObject("contractAddress"); | |||||
// String contractAddress = contractAddressObj.getString("value"); | |||||
// String argsStr = jsonObject.getString("args"); | |||||
// String event = jsonObject.getString("event"); | |||||
// return new ContractEventSendOpTemplate(Bytes.fromBase58(contractAddress), event, BytesUtils.toBytes(argsStr)); | |||||
// } | |||||
// | |||||
// private static BlockchainIdentityData blockchainIdentity(JSONObject jsonObject) { | |||||
// JSONObject addressObj = jsonObject.getJSONObject("address"); | |||||
// // base58值 | |||||
// String addressBase58 = addressObj.getString("value"); | |||||
// Bytes address = Bytes.fromBase58(addressBase58); | |||||
// | |||||
// JSONObject pubKeyObj = jsonObject.getJSONObject("pubKey"); | |||||
// // base58值 | |||||
// String pubKeyBase58 = pubKeyObj.getString("value"); | |||||
// PubKey pubKey = new PubKey(Bytes.fromBase58(pubKeyBase58).toBytes()); | |||||
// | |||||
// // 生成对应的对象 | |||||
// return new BlockchainIdentityData(address, pubKey); | |||||
// } | |||||
// | |||||
// public static class CryptoConfig implements CryptoSetting { | |||||
// | |||||
// private short hashAlgorithm; | |||||
// | |||||
// private boolean autoVerifyHash; | |||||
// | |||||
// @Override | |||||
// public CryptoProvider[] getSupportedProviders() { | |||||
// return new CryptoProvider[0]; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public short getHashAlgorithm() { | |||||
// return hashAlgorithm; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public boolean getAutoVerifyHash() { | |||||
// return autoVerifyHash; | |||||
// } | |||||
// | |||||
// public void setHashAlgorithm(short hashAlgorithm) { | |||||
// this.hashAlgorithm = hashAlgorithm; | |||||
// } | |||||
// | |||||
// public void setAutoVerifyHash(boolean autoVerifyHash) { | |||||
// this.autoVerifyHash = autoVerifyHash; | |||||
// } | |||||
// } | |||||
// | |||||
// public static class ParticipantCertData implements ParticipantNode{ | |||||
// private int id; | |||||
// private String address; | |||||
// private String name; | |||||
// private PubKey pubKey; | |||||
// | |||||
// public ParticipantCertData() { | |||||
// } | |||||
// | |||||
// public ParticipantCertData(ParticipantNode participantNode) { | |||||
// this.address = participantNode.getAddress(); | |||||
// this.name = participantNode.getName(); | |||||
// this.pubKey = participantNode.getPubKey(); | |||||
// } | |||||
// | |||||
// public ParticipantCertData(int id, String address, String name, PubKey pubKey) { | |||||
// this.id = id; | |||||
// this.address = address; | |||||
// this.name = name; | |||||
// this.pubKey = pubKey; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public String getAddress() { | |||||
// return address; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public String getName() { | |||||
// return name; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public PubKey getPubKey() { | |||||
// return pubKey; | |||||
// } | |||||
// | |||||
// public int getId() { | |||||
// return id; | |||||
// } | |||||
// | |||||
// public void setId(int id) { | |||||
// this.id = id; | |||||
// } | |||||
// } | |||||
// | |||||
// public static class KvData implements KVDataEntry { | |||||
// | |||||
// private String key; | |||||
// | |||||
// private long version; | |||||
// | |||||
// private DataType dataType; | |||||
// | |||||
// private Object value; | |||||
// | |||||
// public KvData() { | |||||
// } | |||||
// | |||||
// public KvData(String key, long version, DataType dataType) { | |||||
// this(key, version, dataType, null); | |||||
// } | |||||
// | |||||
// public KvData(String key, long version, DataType dataType, Object value) { | |||||
// this.key = key; | |||||
// this.version = version; | |||||
// this.dataType = dataType; | |||||
// this.value = value; | |||||
// } | |||||
// | |||||
// public void setKey(String key) { | |||||
// this.key = key; | |||||
// } | |||||
// | |||||
// public void setVersion(long version) { | |||||
// this.version = version; | |||||
// } | |||||
// | |||||
// public void setDataType(DataType dataType) { | |||||
// this.dataType = dataType; | |||||
// } | |||||
// | |||||
// public void setValue(Object value) { | |||||
// this.value = value; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public String getKey() { | |||||
// return key; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public long getVersion() { | |||||
// return version; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public DataType getType() { | |||||
// return dataType; | |||||
// } | |||||
// | |||||
// @Override | |||||
// public Object getValue() { | |||||
// return value; | |||||
// } | |||||
// } | |||||
//} |
@@ -25,6 +25,11 @@ | |||||
<artifactId>tools-initializer</artifactId> | <artifactId>tools-initializer</artifactId> | ||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>contract-samples</artifactId> | |||||
<version>${project.version}</version> | |||||
</dependency> | |||||
</dependencies> | </dependencies> | ||||
<build> | <build> | ||||
@@ -0,0 +1,38 @@ | |||||
package com.jd.blockchain.sdk.samples; | |||||
import org.apache.commons.io.FileUtils; | |||||
import org.springframework.core.io.ClassPathResource; | |||||
import java.io.File; | |||||
public class SDKDemo_Constant { | |||||
public static final String GW_IPADDR = "127.0.0.1"; | |||||
public static final int GW_PORT = 11000; | |||||
public static final String[] PUB_KEYS = { | |||||
"3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", | |||||
"3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", | |||||
"3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", | |||||
"3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; | |||||
public static final String[] PRIV_KEYS = { | |||||
"177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", | |||||
"177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", | |||||
"177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", | |||||
"177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; | |||||
public static final String PASSWORD = "abc"; | |||||
public static final byte[] readChainCodes(String contractZip) { | |||||
// 构建合约的字节数组; | |||||
try { | |||||
ClassPathResource contractPath = new ClassPathResource(contractZip); | |||||
File contractFile = new File(contractPath.getURI()); | |||||
return FileUtils.readFileToByteArray(contractFile); | |||||
} catch (Exception e) { | |||||
throw new IllegalStateException(e); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,51 @@ | |||||
package com.jd.blockchain.sdk.samples; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
import com.jd.blockchain.ledger.PreparedTransaction; | |||||
import com.jd.blockchain.ledger.TransactionResponse; | |||||
import com.jd.blockchain.ledger.TransactionTemplate; | |||||
import com.jd.blockchain.sdk.BlockchainService; | |||||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
public abstract class SDK_Base_Demo { | |||||
protected BlockchainKeypair adminKey; | |||||
protected HashDigest ledgerHash; | |||||
protected BlockchainService blockchainService; | |||||
public SDK_Base_Demo() { | |||||
init(); | |||||
} | |||||
public void init() { | |||||
// 生成连接网关的账号 | |||||
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD); | |||||
PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); | |||||
adminKey = new BlockchainKeypair(pubKey, privKey); | |||||
// 连接网关 | |||||
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, | |||||
SDKDemo_Constant.GW_PORT, false, adminKey); | |||||
// 获取网关对应的Service处理类 | |||||
blockchainService = serviceFactory.getBlockchainService(); | |||||
HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); | |||||
// 获取当前账本Hash | |||||
ledgerHash = ledgerHashs[0]; | |||||
} | |||||
public TransactionResponse commit(TransactionTemplate txTpl) { | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
ptx.sign(adminKey); | |||||
return ptx.commit(); | |||||
} | |||||
} |
@@ -0,0 +1,164 @@ | |||||
package com.jd.blockchain.sdk.samples; | |||||
import com.jd.blockchain.contract.EventResult; | |||||
import com.jd.blockchain.contract.TransferContract; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.transaction.ContractEventExecutor; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; | |||||
public class SDK_Contract_Demo extends SDK_Base_Demo { | |||||
public static void main(String[] args) { | |||||
SDK_Contract_Demo demo = new SDK_Contract_Demo(); | |||||
demo.executeContract(); | |||||
} | |||||
public void executeContract() { | |||||
// 发布jar包 | |||||
// 定义交易模板 | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 将jar包转换为二进制数据 | |||||
byte[] contractCode = readChainCodes("transfer.jar"); | |||||
// 生成一个合约账号 | |||||
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); | |||||
// 生成发布合约操作 | |||||
txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); | |||||
// 生成预发布交易; | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
// 对交易进行签名 | |||||
ptx.sign(adminKey); | |||||
// 提交并等待共识返回; | |||||
TransactionResponse txResp = ptx.commit(); | |||||
// 获取合约地址 | |||||
Bytes contractAddress = contractDeployKey.getAddress(); | |||||
// 打印交易返回信息 | |||||
System.out.printf("Tx[%s] -> BlockHeight = %s, BlockHash = %s, isSuccess = %s, ExecutionState = %s \r\n", | |||||
txResp.getContentHash().toBase58(), txResp.getBlockHeight(), | |||||
txResp.getBlockHash().toBase58(), txResp.isSuccess(), | |||||
txResp.getExecutionState()); | |||||
// 打印合约地址 | |||||
System.out.printf("ContractAddress = %s \r\n", contractAddress.toBase58()); | |||||
// 注册一个数据账户 | |||||
BlockchainKeypair dataAccount = createDataAccount(); | |||||
// 获取数据账户地址 | |||||
String dataAddress = dataAccount.getAddress().toBase58(); | |||||
// 打印数据账户地址 | |||||
System.out.printf("DataAccountAddress = %s \r\n", dataAddress); | |||||
// 创建两个账号: | |||||
String account0 = "jd_zhangsan", account1 = "jd_lisi"; | |||||
long account0Money = 3000L, account1Money = 2000L; | |||||
// 创建两个账户 | |||||
// 使用KV操作创建一个账户 | |||||
System.out.println(create(dataAddress, account0, account0Money, false, null)); | |||||
// 使用合约创建一个账户 | |||||
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); | |||||
// 转账,使得双方钱达到一致 | |||||
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); | |||||
// 通过合约读取account0的当前信息 | |||||
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By Contract)\r\n", | |||||
dataAddress, account0, readByContract(dataAddress, account0, contractAddress)); | |||||
// 通过KV读取account1的当前信息 | |||||
System.out.printf("Read DataAccountAddress[%s] Account = %s 's money = %s (By KV Operation)\r\n", | |||||
dataAddress, account1, readByKvOperation(dataAddress, account1)); | |||||
// 通过合约读取account0的历史信息 | |||||
System.out.println(readAll(dataAddress, account0, contractAddress)); | |||||
// 通过合约读取account1的历史信息 | |||||
System.out.println(readAll(dataAddress, account1, contractAddress)); | |||||
} | |||||
private String readAll(String address, String account, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.readAll(address, account); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private long readByContract(String address, String account, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<Long> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.read(address, account); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private long readByKvOperation(String address, String account) { | |||||
KVDataEntry[] kvDataEntries = blockchainService.getDataEntries(ledgerHash, address, account); | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
throw new IllegalStateException(String.format("Ledger %s Service inner Error !!!", ledgerHash.toBase58())); | |||||
} | |||||
KVDataEntry kvDataEntry = kvDataEntries[0]; | |||||
if (kvDataEntry.getVersion() == -1) { | |||||
return 0L; | |||||
} | |||||
return (long) (kvDataEntry.getValue()); | |||||
} | |||||
private String transfer(String address, String from, String to, long money, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.transfer(address, from, to, money); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private BlockchainKeypair createDataAccount() { | |||||
// 首先注册一个数据账户 | |||||
BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
txTpl.dataAccounts().register(newDataAccount.getIdentity()); | |||||
commit(txTpl); | |||||
return newDataAccount; | |||||
} | |||||
private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
if (useContract) { | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.create(address, account, money); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} else { | |||||
// 通过KV创建 | |||||
txTpl.dataAccount(address).setInt64(account, money, -1); | |||||
TransactionResponse txResp = commit(txTpl); | |||||
return String.format("DataAccountAddress[%s] -> Create(By KV Operation) Account = %s and Money = %s Success!!! \r\n", | |||||
address, account, money); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,171 @@ | |||||
package test.com.jd.blockchain.sdk.test; | |||||
import com.jd.blockchain.contract.EventResult; | |||||
import com.jd.blockchain.contract.TransferContract; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.sdk.BlockchainService; | |||||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||||
import com.jd.blockchain.sdk.samples.SDKDemo_Constant; | |||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.transaction.ContractEventExecutor; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import static com.jd.blockchain.sdk.samples.SDKDemo_Constant.readChainCodes; | |||||
public class SDKDemo_Contract_Test { | |||||
private BlockchainKeypair adminKey; | |||||
private HashDigest ledgerHash; | |||||
private BlockchainService blockchainService; | |||||
@Before | |||||
public void init() { | |||||
// 生成连接网关的账号 | |||||
PrivKey privKey = KeyGenCommand.decodePrivKeyWithRawPassword(SDKDemo_Constant.PRIV_KEYS[0], SDKDemo_Constant.PASSWORD); | |||||
PubKey pubKey = KeyGenCommand.decodePubKey(SDKDemo_Constant.PUB_KEYS[0]); | |||||
adminKey = new BlockchainKeypair(pubKey, privKey); | |||||
// 连接网关 | |||||
GatewayServiceFactory serviceFactory = GatewayServiceFactory.connect(SDKDemo_Constant.GW_IPADDR, | |||||
SDKDemo_Constant.GW_PORT, false, adminKey); | |||||
blockchainService = serviceFactory.getBlockchainService(); | |||||
HashDigest[] ledgerHashs = blockchainService.getLedgerHashs(); | |||||
ledgerHash = ledgerHashs[0]; | |||||
} | |||||
@Test | |||||
public void testContract() { | |||||
// 发布jar包 | |||||
// 定义交易; | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
byte[] contractCode = readChainCodes("transfer.jar"); | |||||
// 生成一个合约账号 | |||||
BlockchainKeypair contractDeployKey = BlockchainKeyGenerator.getInstance().generate(); | |||||
txTpl.contracts().deploy(contractDeployKey.getIdentity(), contractCode); | |||||
// 签名; | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
ptx.sign(adminKey); | |||||
// 提交并等待共识返回; | |||||
TransactionResponse txResp = ptx.commit(); | |||||
System.out.println(txResp.isSuccess()); | |||||
// 首先注册一个数据账户 | |||||
BlockchainKeypair dataAccount = createDataAccount(); | |||||
String dataAddress = dataAccount.getAddress().toBase58(); | |||||
Bytes contractAddress = contractDeployKey.getAddress(); | |||||
// 创建两个账号: | |||||
String account0 = "jd_zhangsan", account1 = "jd_lisi"; | |||||
long account0Money = 3000L, account1Money = 2000L; | |||||
// 创建两个账户 | |||||
// 使用KV创建一个账户 | |||||
System.out.println(create(dataAddress, account0, account0Money, false, null)); | |||||
// 使用合约创建一个账户 | |||||
System.out.println(create(dataAddress, account1, account1Money, true, contractAddress)); | |||||
// 转账,使得双方钱达到一致 | |||||
System.out.println(transfer(dataAddress, account0, account1, 500L, contractAddress)); | |||||
// 读取当前结果 | |||||
System.out.println(read(dataAddress, account0, contractAddress)); | |||||
System.out.println(read(dataAddress, account1, contractAddress)); | |||||
// 读取账号历史信息 | |||||
System.out.println(readAll(dataAddress, account0, contractAddress)); | |||||
System.out.println(readAll(dataAddress, account1, contractAddress)); | |||||
} | |||||
private String readAll(String address, String account, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.readAll(address, account); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private long read(String address, String account, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<Long> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.read(address, account); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private String transfer(String address, String from, String to, long money, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.transfer(address, from, to, money); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} | |||||
private BlockchainKeypair createDataAccount() { | |||||
// 首先注册一个数据账户 | |||||
BlockchainKeypair newDataAccount = BlockchainKeyGenerator.getInstance().generate(); | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
txTpl.dataAccounts().register(newDataAccount.getIdentity()); | |||||
commit(txTpl); | |||||
return newDataAccount; | |||||
} | |||||
private String create(String address, String account, long money, boolean useContract, Bytes contractAddress) { | |||||
TransactionTemplate txTpl = blockchainService.newTransaction(ledgerHash); | |||||
if (useContract) { | |||||
// 使用合约创建 | |||||
TransferContract transferContract = txTpl.contract(contractAddress, TransferContract.class); | |||||
EventResult<String> eventResult = txTpl.result((ContractEventExecutor<TransferContract>) () -> { | |||||
transferContract.create(address, account, money); | |||||
return transferContract; | |||||
}); | |||||
commit(txTpl); | |||||
return eventResult.get(); | |||||
} else { | |||||
// 通过KV创建 | |||||
txTpl.dataAccount(address).setInt64(account, money, -1); | |||||
TransactionResponse txResp = commit(txTpl); | |||||
return account + money; | |||||
} | |||||
} | |||||
private TransactionResponse commit(TransactionTemplate txTpl) { | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
ptx.sign(adminKey); | |||||
return ptx.commit(); | |||||
} | |||||
} |
@@ -24,6 +24,7 @@ import java.util.Random; | |||||
import java.util.concurrent.CountDownLatch; | import java.util.concurrent.CountDownLatch; | ||||
import java.util.concurrent.atomic.AtomicLong; | import java.util.concurrent.atomic.AtomicLong; | ||||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||||
import com.jd.blockchain.contract.EventResult; | import com.jd.blockchain.contract.EventResult; | ||||
import com.jd.blockchain.contract.ReadContract; | import com.jd.blockchain.contract.ReadContract; | ||||
import com.jd.blockchain.ledger.*; | import com.jd.blockchain.ledger.*; | ||||
@@ -556,9 +557,13 @@ public class IntegrationBase { | |||||
// 再提交一个KV写入 | // 再提交一个KV写入 | ||||
String key1 = "JingDong", value1 = "www.jd.com"; | String key1 = "JingDong", value1 = "www.jd.com"; | ||||
String key2 = "JD", value2 = "JingDong"; | String key2 = "JD", value2 = "JingDong"; | ||||
String key3 = "Test", value3 = "OK"; | |||||
TransactionTemplate txKv = blockchainService.newTransaction(ledgerHash); | TransactionTemplate txKv = blockchainService.newTransaction(ledgerHash); | ||||
txKv.dataAccount(newDataAccount.getAddress()).setText(key1, value1, -1).setText(key2, value2, -1); | |||||
txKv.dataAccount(newDataAccount.getAddress()) | |||||
.setText(key1, value1, -1) | |||||
.setBytes(key2, Bytes.fromString(value2), -1) | |||||
.setBytes(key3, Bytes.fromString(value3).toBytes(), -1); | |||||
PreparedTransaction kvPtx = txKv.prepare(); | PreparedTransaction kvPtx = txKv.prepare(); | ||||
kvPtx.sign(adminKey); | kvPtx.sign(adminKey); | ||||
@@ -578,10 +583,7 @@ public class IntegrationBase { | |||||
ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | ReadContract readContract2 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | ||||
EventResult<String> read2 = txContract.result((ContractEventExecutor<ReadContract>) () -> { | |||||
readContract2.read(newDataAccount.getAddress().toBase58(), key2); | |||||
return readContract2; | |||||
}); | |||||
readContract2.read(newDataAccount.getAddress().toBase58(), key2); | |||||
ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | ReadContract readContract3 = txContract.contract(contractDeployKey.getAddress(), ReadContract.class); | ||||
@@ -601,14 +603,13 @@ public class IntegrationBase { | |||||
// 通过EventResult获取结果 | // 通过EventResult获取结果 | ||||
System.out.printf("readContract1.result = %s \r\n", read1.get()); | System.out.printf("readContract1.result = %s \r\n", read1.get()); | ||||
System.out.printf("readContract2.result = %s \r\n", read2.get()); | |||||
System.out.printf("readContract3.result = %s \r\n", read3.get()); | System.out.printf("readContract3.result = %s \r\n", read3.get()); | ||||
// 打印结果 | // 打印结果 | ||||
// for (OperationResult or : operationResults) { | |||||
// System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), or.getResult()); | |||||
// } | |||||
for (OperationResult or : operationResults) { | |||||
System.out.printf("操作[%s].Result = %s \r\n", or.getIndex(), ContractSerializeUtils.resolve(or.getResult())); | |||||
} | |||||
// | // | ||||
// // 验证结果 | // // 验证结果 | ||||
// assertNotNull(contractReturn); | // assertNotNull(contractReturn); | ||||