@@ -34,11 +34,11 @@ | |||
<plugin> | |||
<artifactId>maven-assembly-plugin</artifactId> | |||
<configuration> | |||
<finalName>contract</finalName> | |||
<finalName>transfer</finalName> | |||
<appendAssemblyId>false</appendAssemblyId> | |||
<archive> | |||
<manifest> | |||
<mainClass>com.jd.blockchain.contract.ReadContractImpl</mainClass> | |||
<mainClass>com.jd.blockchain.contract.TransferContractImpl</mainClass> | |||
</manifest> | |||
</archive> | |||
<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; | |||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) | |||
public interface DataAccountKVSetOperation extends Operation{ | |||
public interface DataAccountKVSetOperation extends Operation { | |||
@DataField(order=2, primitiveType=PrimitiveType.BYTES) | |||
Bytes getAccountAddress(); | |||
@@ -106,9 +106,6 @@ public enum DataType { | |||
ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)); | |||
@EnumField(type = PrimitiveType.INT8) | |||
public final byte CODE; | |||
@@ -8,6 +8,14 @@ public class KVDataVO { | |||
private String key; | |||
private long[] version; | |||
public KVDataVO() { | |||
} | |||
public KVDataVO(String key, long[] version) { | |||
this.key = key; | |||
this.version = version; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
@@ -8,6 +8,13 @@ package com.jd.blockchain.ledger; | |||
public class KVInfoVO { | |||
private KVDataVO[] data; | |||
public KVInfoVO() { | |||
} | |||
public KVInfoVO(KVDataVO[] data) { | |||
this.data = data; | |||
} | |||
public KVDataVO[] getData() { | |||
return data; | |||
} | |||
@@ -61,7 +61,7 @@ public class ContractInvocationProxy implements InvocationHandler { | |||
((ContractEventSendOpTemplate) sendOperation).setEventAndArgs(event, argBytes); | |||
} | |||
// 代理操作,返回值类型无法创建 | |||
return null; | |||
return returnResult(method.getReturnType()); | |||
} | |||
private byte[] serializeArgs(Object[] args) { | |||
@@ -74,4 +74,36 @@ public class ContractInvocationProxy implements InvocationHandler { | |||
} | |||
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) { | |||
// 如果是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)) { | |||
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 | |||
* FileName: com.jd.blockchain.sdk.client.ClientOperationUtil | |||
* 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 org.apache.commons.codec.binary.Base64; | |||
package com.jd.blockchain.sdk.converters; | |||
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.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.codec.Base58Utils; | |||
import com.jd.blockchain.utils.codec.HexUtils; | |||
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 | |||
*/ | |||
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) { | |||
@@ -297,4 +312,65 @@ public class ClientOperationUtil { | |||
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.BlockchainEventListener; | |||
import com.jd.blockchain.sdk.BlockchainService; | |||
import com.jd.blockchain.sdk.converters.ClientResolveUtil; | |||
import com.jd.blockchain.transaction.BlockchainQueryService; | |||
import com.jd.blockchain.transaction.TransactionService; | |||
import com.jd.blockchain.transaction.TxTemplate; | |||
@@ -144,17 +145,20 @@ public abstract class BlockchainServiceProxy implements BlockchainService { | |||
@Override | |||
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 | |||
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 | |||
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 | |||
@@ -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> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>contract-samples</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
</dependencies> | |||
<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.atomic.AtomicLong; | |||
import com.jd.blockchain.contract.ContractSerializeUtils; | |||
import com.jd.blockchain.contract.EventResult; | |||
import com.jd.blockchain.contract.ReadContract; | |||
import com.jd.blockchain.ledger.*; | |||
@@ -556,9 +557,13 @@ public class IntegrationBase { | |||
// 再提交一个KV写入 | |||
String key1 = "JingDong", value1 = "www.jd.com"; | |||
String key2 = "JD", value2 = "JingDong"; | |||
String key3 = "Test", value3 = "OK"; | |||
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(); | |||
kvPtx.sign(adminKey); | |||
@@ -578,10 +583,7 @@ public class IntegrationBase { | |||
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); | |||
@@ -601,14 +603,13 @@ public class IntegrationBase { | |||
// 通过EventResult获取结果 | |||
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()); | |||
// 打印结果 | |||
// 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); | |||