| @@ -96,7 +96,7 @@ public abstract class AbstractContractCode implements ContractCode { | |||
| eventContext.getEvent(), address.toString(), error.getMessage()), error); | |||
| } | |||
| BytesValue retnBytes = BytesValueEncoding.encode(retn, handleMethod.getReturnType()); | |||
| BytesValue retnBytes = BytesValueEncoding.encodeSingle(retn, handleMethod.getReturnType()); | |||
| return retnBytes; | |||
| } | |||
| @@ -39,7 +39,6 @@ | |||
| <version>${project.version}</version> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,24 +1,131 @@ | |||
| package com.jd.blockchain.ledger; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.ledger.resolver.*; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| public class BytesValueEncoding { | |||
| public static BytesValue encode(Object value, Class<?> type) { | |||
| throw new IllegalStateException("Not implemented!"); | |||
| private static final Map<Class<?>, BytesValueResolver> CLASS_RESOLVER_MAP = new ConcurrentHashMap<>(); | |||
| private static final Map<DataType, BytesValueResolver> DATA_TYPE_RESOLVER_MAP = new ConcurrentHashMap<>(); | |||
| static { | |||
| init(); | |||
| } | |||
| public static BytesValueList encode(Object[] values, Class<?>[] types) { | |||
| throw new IllegalStateException("Not implemented!"); | |||
| private static void init() { | |||
| BytesValueResolver[] resolvers = new BytesValueResolver[]{ | |||
| new BytesToBytesValueResolver(), | |||
| new IntegerToBytesValueResolver(), | |||
| new LongToBytesValueResolver(), | |||
| new ShortToBytesValueResolver(), | |||
| new StringToBytesValueResolver() | |||
| }; | |||
| for (BytesValueResolver currResolver : resolvers) { | |||
| // 填充classMAP | |||
| Class<?>[] supportClasses = currResolver.supportClasses(); | |||
| if (supportClasses != null && supportClasses.length > 0) { | |||
| for (Class<?> clazz : supportClasses) { | |||
| CLASS_RESOLVER_MAP.put(clazz, currResolver); | |||
| } | |||
| } | |||
| // 填充dataTypeMap | |||
| DataType[] supportDataTypes = currResolver.supportDataTypes(); | |||
| if (supportDataTypes != null && supportDataTypes.length > 0) { | |||
| for (DataType dataType : supportDataTypes) { | |||
| DATA_TYPE_RESOLVER_MAP.put(dataType, currResolver); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public static BytesValue encodeSingle(Object value, Class<?> type) { | |||
| if (type == null) { | |||
| type = value.getClass(); | |||
| } | |||
| if (type.isInterface()) { | |||
| // 判断是否含有DataContract注解 | |||
| if (!type.isAnnotationPresent(DataContract.class)) { | |||
| throw new IllegalStateException(String.format("Interface[%s] can not be serialize !!!", type.getName())); | |||
| } | |||
| // 将对象序列化 | |||
| byte[] serialBytes = BinaryProtocol.encode(value, type); | |||
| return BytesData.fromType(DataType.DATA_CONTRACT, serialBytes); | |||
| } | |||
| BytesValueResolver bytesValueResolver = CLASS_RESOLVER_MAP.get(type); | |||
| if (bytesValueResolver == null) { | |||
| throw new IllegalStateException(String.format("Class[%s] can not find encoder !!!", type.getName())); | |||
| } | |||
| return bytesValueResolver.encode(value, type); | |||
| } | |||
| public static BytesValueList encodeArray(Object[] values, Class<?>[] types) { | |||
| if (values == null || values.length == 0) { | |||
| return null; | |||
| } | |||
| if (types != null && types.length != values.length) { | |||
| throw new IllegalStateException("Types can be null, or types's length must be equal BytesValue[]'s !!!"); | |||
| } | |||
| BytesValueListData bytesValueListData = new BytesValueListData(); | |||
| for (int i = 0; i < values.length; i++) { | |||
| BytesValue bytesValue = encodeSingle(values[i], types == null ? null : types[i]); | |||
| bytesValueListData.add(bytesValue); | |||
| } | |||
| return bytesValueListData; | |||
| } | |||
| public static Object decode(BytesValue value) { | |||
| return decode(value, null); | |||
| } | |||
| public static Object decode(BytesValue value, Class<?> type) { | |||
| throw new IllegalStateException("Not implemented!"); | |||
| DataType dataType = value.getType(); | |||
| BytesValueResolver valueResolver = DATA_TYPE_RESOLVER_MAP.get(dataType); | |||
| if (valueResolver == null) { | |||
| throw new IllegalStateException(String.format("DataType[%s] can not find encoder !!!", dataType.name())); | |||
| } | |||
| return type == null ? valueResolver.decode(value) : valueResolver.decode(value, type); | |||
| } | |||
| public static Object[] decode(BytesValueList values, Class<?>[] types) { | |||
| throw new IllegalStateException("Not implemented!"); | |||
| BytesValue[] bytesValues = values.getValues(); | |||
| if (bytesValues == null || bytesValues.length == 0) { | |||
| return null; | |||
| } | |||
| // 允许types为null,此时每个BytesValue按照当前的对象来处理 | |||
| // 若types不为null,则types's长度必须和bytesValues一致 | |||
| if (types != null && types.length != bytesValues.length) { | |||
| throw new IllegalStateException("Types can be null, or types's length must be equal BytesValue[]'s !!!"); | |||
| } | |||
| Object[] resolveObjs = new Object[bytesValues.length]; | |||
| if (types == null) { | |||
| // 按照默认方式解析 | |||
| for (int i = 0; i < bytesValues.length; i++) { | |||
| BytesValue bytesValue = bytesValues[i]; | |||
| DataType dataType = bytesValue.getType(); | |||
| BytesValueResolver valueResolver = DATA_TYPE_RESOLVER_MAP.get(dataType); | |||
| if (valueResolver == null) { | |||
| throw new IllegalStateException(String.format("DataType[%s] can not find encoder !!!", dataType.name())); | |||
| } | |||
| resolveObjs[i] = valueResolver.decode(bytesValue); | |||
| } | |||
| return resolveObjs; | |||
| } | |||
| // 按照输入的Class进行解析 | |||
| for (int i = 0; i < bytesValues.length; i++) { | |||
| resolveObjs[i] = decode(bytesValues[i], types[i]); | |||
| } | |||
| return resolveObjs; | |||
| } | |||
| public static Object getDefaultValue(Class<?> type) { | |||
| @@ -54,7 +161,29 @@ public class BytesValueEncoding { | |||
| } | |||
| public static boolean supportType(Class<?> currParamType) { | |||
| // TODO Auto-generated method stub | |||
| return false; | |||
| if (currParamType.isInterface()) { | |||
| // 接口序列化必须实现DataContract注解 | |||
| if (!currParamType.isAnnotationPresent(DataContract.class)) { | |||
| throw new IllegalStateException(String.format("Interface[%s] can not be serialize !!!", currParamType.getName())); | |||
| } | |||
| return true; | |||
| } | |||
| return CLASS_RESOLVER_MAP.containsKey(currParamType); | |||
| } | |||
| public static class BytesValueListData implements BytesValueList { | |||
| private List<BytesValue> bytesValues = new ArrayList<>(); | |||
| public void add(BytesValue bytesValue) { | |||
| bytesValues.add(bytesValue); | |||
| } | |||
| @Override | |||
| public BytesValue[] getValues() { | |||
| BytesValue[] bytesValueArray = new BytesValue[bytesValues.size()]; | |||
| return bytesValues.toArray(bytesValueArray); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,54 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public abstract class AbstractBytesValueResolver implements BytesValueResolver { | |||
| protected boolean isSupport(Class<?> type) { | |||
| if (type == null) { | |||
| return false; | |||
| } | |||
| Class<?>[] supports = supportClasses(); | |||
| if (supports != null && supports.length > 0) { | |||
| for (Class<?> clazz : supports) { | |||
| if (type.equals(clazz)) { | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| protected boolean isSupport(DataType dataType) { | |||
| if (dataType == null) { | |||
| return false; | |||
| } | |||
| DataType[] supports = supportDataTypes(); | |||
| if (supports != null && supports.length > 0) { | |||
| for (DataType dt : supports) { | |||
| if (dataType.equals(dt)) { | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| @Override | |||
| public BytesValue encode(Object value) { | |||
| return encode(value, value.getClass()); | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value) { | |||
| DataType dataType = value.getType(); | |||
| if (!isSupport(dataType)) { | |||
| throw new IllegalStateException(String.format("Un-support encode DataType[%s] Object !!!", dataType.name())); | |||
| } | |||
| return decode(value.getValue()); | |||
| } | |||
| protected abstract Object decode(Bytes value); | |||
| } | |||
| @@ -0,0 +1,58 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import java.util.Set; | |||
| public class BytesToBytesValueResolver extends AbstractBytesValueResolver { | |||
| private final Class<?>[] supportClasses = {Bytes.class, byte[].class}; | |||
| private final DataType[] supportDataTypes = {DataType.BYTES}; | |||
| private final Set<Class<?>> convertClasses = initByteConvertSet(); | |||
| @Override | |||
| public BytesValue encode(Object value, Class<?> type) { | |||
| if (!isSupport(type)) { | |||
| throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
| } | |||
| if (type.equals(byte[].class)) { | |||
| return BytesData.fromBytes((byte[]) value); | |||
| } | |||
| return BytesData.fromBytes((Bytes) value); | |||
| } | |||
| @Override | |||
| public Class<?>[] supportClasses() { | |||
| return supportClasses; | |||
| } | |||
| @Override | |||
| public DataType[] supportDataTypes() { | |||
| return supportDataTypes; | |||
| } | |||
| @Override | |||
| protected Object decode(Bytes value) { | |||
| return value; | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value, Class<?> clazz) { | |||
| Bytes bytesVal = (Bytes) decode(value); | |||
| if (!convertClasses.contains(clazz)) { | |||
| throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); | |||
| } | |||
| if (clazz.equals(String.class)) { | |||
| return bytesVal.toUTF8String(); | |||
| } else if (clazz.equals(byte[].class)) { | |||
| return bytesVal.toBytes(); | |||
| } | |||
| return bytesVal; | |||
| } | |||
| } | |||
| @@ -0,0 +1,80 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import java.util.Arrays; | |||
| import java.util.HashSet; | |||
| import java.util.Set; | |||
| public interface BytesValueResolver { | |||
| /** | |||
| * Int相关的可转换Class集合 | |||
| */ | |||
| Class<?>[] supportIntConvertClasses = { | |||
| short.class, Short.class, int.class, Integer.class, long.class, Long.class}; | |||
| /** | |||
| * 字节数组(字符串)相关可转换的Class集合 | |||
| */ | |||
| Class<?>[] supportByteConvertClasses = { | |||
| String.class, Bytes.class, byte[].class}; | |||
| default Set<Class<?>> initIntConvertSet() { | |||
| return new HashSet<>(Arrays.asList(supportIntConvertClasses)); | |||
| } | |||
| default Set<Class<?>> initByteConvertSet() { | |||
| return new HashSet<>(Arrays.asList(supportByteConvertClasses)); | |||
| } | |||
| /** | |||
| * 将对象转换为BytesValue | |||
| * | |||
| * @param value | |||
| * @return | |||
| */ | |||
| BytesValue encode(Object value); | |||
| /** | |||
| * 将对象转换为BytesValue | |||
| * | |||
| * @param value | |||
| * @param type | |||
| * @return | |||
| */ | |||
| BytesValue encode(Object value, Class<?> type); | |||
| /** | |||
| * 当前解析器支持的Class列表 | |||
| * | |||
| * @return | |||
| */ | |||
| Class<?>[] supportClasses(); | |||
| /** | |||
| * 当前解析器支持的DataType列表 | |||
| * | |||
| * @return | |||
| */ | |||
| DataType[] supportDataTypes(); | |||
| /** | |||
| * 将BytesValue解析为对应的Object | |||
| * | |||
| * @param value | |||
| * @return | |||
| */ | |||
| Object decode(BytesValue value); | |||
| /** | |||
| * 将BytesValue转换为指定Class的Object | |||
| * | |||
| * @param value | |||
| * @param clazz | |||
| * @return | |||
| */ | |||
| Object decode(BytesValue value, Class<?> clazz); | |||
| } | |||
| @@ -0,0 +1,58 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import java.util.Set; | |||
| public class IntegerToBytesValueResolver extends AbstractBytesValueResolver { | |||
| private final Class<?>[] supportClasses = {Integer.class, int.class}; | |||
| private final DataType[] supportDataTypes = {DataType.INT32}; | |||
| private final Set<Class<?>> convertClasses = initIntConvertSet(); | |||
| @Override | |||
| public BytesValue encode(Object value, Class<?> type) { | |||
| if (!isSupport(type)) { | |||
| throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
| } | |||
| return BytesData.fromInt32((int) value); | |||
| } | |||
| @Override | |||
| public Class<?>[] supportClasses() { | |||
| return supportClasses; | |||
| } | |||
| @Override | |||
| public DataType[] supportDataTypes() { | |||
| return supportDataTypes; | |||
| } | |||
| @Override | |||
| protected Object decode(Bytes value) { | |||
| return BytesUtils.toInt(value.toBytes()); | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value, Class<?> clazz) { | |||
| // 支持转换为short、int、long | |||
| int intVal = (int)decode(value); | |||
| if (convertClasses.contains(clazz)) { | |||
| // 对于short和Short需要强制类型转换 | |||
| if (clazz.equals(short.class) || clazz.equals(Short.class)) { | |||
| return (short) intVal; | |||
| } else if (clazz.equals(long.class) || clazz.equals(Long.class)) { | |||
| return (long) intVal; | |||
| } | |||
| return intVal; | |||
| } else { | |||
| throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,58 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import java.util.Set; | |||
| public class LongToBytesValueResolver extends AbstractBytesValueResolver { | |||
| private final Class<?>[] supportClasses = {Long.class, long.class}; | |||
| private final DataType[] supportDataTypes = {DataType.INT64}; | |||
| private final Set<Class<?>> convertClasses = initIntConvertSet(); | |||
| @Override | |||
| public BytesValue encode(Object value, Class<?> type) { | |||
| if (!isSupport(type)) { | |||
| throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
| } | |||
| return BytesData.fromInt64((long)value); | |||
| } | |||
| @Override | |||
| public Class<?>[] supportClasses() { | |||
| return supportClasses; | |||
| } | |||
| @Override | |||
| public DataType[] supportDataTypes() { | |||
| return supportDataTypes; | |||
| } | |||
| @Override | |||
| protected Object decode(Bytes value) { | |||
| return BytesUtils.toLong(value.toBytes()); | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value, Class<?> clazz) { | |||
| // 支持转换为short、int、long | |||
| long longVal = (long)decode(value); | |||
| if (convertClasses.contains(clazz)) { | |||
| // 对于short和Short需要强制类型转换 | |||
| if (clazz.equals(short.class) || clazz.equals(Short.class)) { | |||
| return (short) longVal; | |||
| } else if (clazz.equals(int.class) || clazz.equals(Integer.class)) { | |||
| return (int) longVal; | |||
| } | |||
| return longVal; | |||
| } else { | |||
| throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,57 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import java.util.Set; | |||
| public class ShortToBytesValueResolver extends AbstractBytesValueResolver { | |||
| private final Class<?>[] supportClasses = {Short.class, short.class}; | |||
| private final DataType[] supportDataTypes = {DataType.INT16}; | |||
| private final Set<Class<?>> convertClasses = initIntConvertSet(); | |||
| @Override | |||
| public BytesValue encode(Object value, Class<?> type) { | |||
| if (!isSupport(type)) { | |||
| throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
| } | |||
| return BytesData.fromInt16((short)value); | |||
| } | |||
| @Override | |||
| public Class<?>[] supportClasses() { | |||
| return supportClasses; | |||
| } | |||
| @Override | |||
| public DataType[] supportDataTypes() { | |||
| return supportDataTypes; | |||
| } | |||
| @Override | |||
| protected Object decode(Bytes value) { | |||
| return BytesUtils.toShort(value.toBytes()); | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value, Class<?> clazz) { | |||
| // 支持转换为short、int、long,由short转int、long无需转换 | |||
| short shortVal = (short)decode(value); | |||
| if (convertClasses.contains(clazz)) { | |||
| if (clazz.equals(int.class) || clazz.equals(Integer.class)) { | |||
| return (int) shortVal; | |||
| } else if (clazz.equals(long.class) || clazz.equals(Long.class)) { | |||
| return (long) shortVal; | |||
| } | |||
| return shortVal; | |||
| } else { | |||
| throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| package com.jd.blockchain.ledger.resolver; | |||
| import com.jd.blockchain.ledger.BytesData; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.serialize.json.JSONSerializeUtils; | |||
| import java.util.Set; | |||
| public class StringToBytesValueResolver extends AbstractBytesValueResolver { | |||
| private final Class<?>[] supportClasses = {String.class}; | |||
| private final DataType[] supportDataTypes = {DataType.TEXT, DataType.XML, DataType.JSON}; | |||
| private final Set<Class<?>> convertClasses = initByteConvertSet(); | |||
| @Override | |||
| public BytesValue encode(Object value, Class<?> type) { | |||
| if (!isSupport(type)) { | |||
| throw new IllegalStateException(String.format("Un-support encode Class[%s] Object !!!", type.getName())); | |||
| } | |||
| // 类型判断 | |||
| String valString = (String)value; | |||
| if (JSONSerializeUtils.isJSON(valString)) { | |||
| return BytesData.fromJSON(valString); | |||
| } | |||
| // 暂不处理XML格式 | |||
| return BytesData.fromText(valString); | |||
| } | |||
| @Override | |||
| public Class<?>[] supportClasses() { | |||
| return supportClasses; | |||
| } | |||
| @Override | |||
| public DataType[] supportDataTypes() { | |||
| return supportDataTypes; | |||
| } | |||
| @Override | |||
| protected Object decode(Bytes value) { | |||
| return BytesUtils.toString(value.toBytes()); | |||
| } | |||
| @Override | |||
| public Object decode(BytesValue value, Class<?> clazz) { | |||
| // 支持三种类型对象返回,String.class,byte[].class,Bytes.class | |||
| String textValue = (String)decode(value); | |||
| if (!convertClasses.contains(clazz)) { | |||
| throw new IllegalStateException(String.format("Un-Support decode value to class[%s] !!!", clazz.getName())); | |||
| } | |||
| if (clazz.equals(byte[].class)) { | |||
| return BytesUtils.toBytes(textValue); | |||
| } else if (clazz.equals(Bytes.class)) { | |||
| return Bytes.fromString(textValue); | |||
| } | |||
| return textValue; | |||
| } | |||
| } | |||
| @@ -53,7 +53,7 @@ public class ContractInvocationHandler implements InvocationHandler { | |||
| } | |||
| // 序列化调用参数; | |||
| Class<?>[] argTypes = method.getParameterTypes(); | |||
| BytesValueList argBytes = BytesValueEncoding.encode(args, argTypes); | |||
| BytesValueList argBytes = BytesValueEncoding.encodeArray(args, argTypes); | |||
| // 定义合约调用操作; | |||
| ContractEventSendOpTemplate opTemplate = (ContractEventSendOpTemplate) sendOpBuilder.send(contractAddress, | |||
| @@ -0,0 +1,43 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.ledger.resolver.BytesToBytesValueResolver; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import static org.junit.Assert.*; | |||
| import org.junit.Test; | |||
| public class BytesToBytesValueResolverTest { | |||
| private BytesToBytesValueResolver resolver = new BytesToBytesValueResolver(); | |||
| @Test | |||
| public void test() { | |||
| String text = "www.jd.com"; | |||
| byte[] bytes = BytesUtils.toBytes(text); | |||
| Bytes bytesObj = Bytes.fromString(text); | |||
| BytesValue bytesValue = resolver.encode(bytes); | |||
| assertNotNull(bytesValue); | |||
| assertEquals(bytesValue.getType(), DataType.BYTES); | |||
| assertEquals(bytesObj, bytesValue.getValue()); | |||
| Bytes resolveBytesObj = (Bytes)resolver.decode(bytesValue); | |||
| assertEquals(bytesObj, resolveBytesObj); | |||
| byte[] resolveBytes = (byte[])resolver.decode(bytesValue, byte[].class); | |||
| assertArrayEquals(bytes, resolveBytes); | |||
| String resolveText = (String)resolver.decode(bytesValue, String.class); | |||
| assertEquals(text, resolveText); | |||
| } | |||
| } | |||
| @@ -0,0 +1,24 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.jd.blockchain.ledger.BytesValueEncoding; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import static org.junit.Assert.*; | |||
| import org.junit.Test; | |||
| public class BytesValueEncodingTest { | |||
| @Test | |||
| public void testSupport() { | |||
| assertTrue(BytesValueEncoding.supportType(byte[].class)); | |||
| assertTrue(BytesValueEncoding.supportType(int.class)); | |||
| assertTrue(BytesValueEncoding.supportType(Integer.class)); | |||
| assertTrue(BytesValueEncoding.supportType(short.class)); | |||
| assertTrue(BytesValueEncoding.supportType(Short.class)); | |||
| assertTrue(BytesValueEncoding.supportType(long.class)); | |||
| assertTrue(BytesValueEncoding.supportType(Long.class)); | |||
| assertTrue(BytesValueEncoding.supportType(String.class)); | |||
| assertTrue(BytesValueEncoding.supportType(Bytes.class)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,51 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.ledger.resolver.IntegerToBytesValueResolver; | |||
| import static org.junit.Assert.*; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import org.junit.Test; | |||
| public class IntegerToBytesValueResolverTest { | |||
| private IntegerToBytesValueResolver resolver = new IntegerToBytesValueResolver(); | |||
| @Test | |||
| public void test() { | |||
| int intVal = 1024; | |||
| BytesValue intBytesValue = resolver.encode(intVal); | |||
| BytesValue intBytesValue1 = resolver.encode(intVal, int.class); | |||
| BytesValue intBytesValue2 = resolver.encode(intVal, Integer.class); | |||
| assertEquals(intBytesValue.getValue(), intBytesValue1.getValue()); | |||
| assertEquals(intBytesValue.getValue(), intBytesValue2.getValue()); | |||
| Bytes intBytes = Bytes.fromInt(intVal); | |||
| assertEquals(intBytes, intBytesValue.getValue()); | |||
| assertEquals(intBytesValue.getType(), DataType.INT32); | |||
| int resolveInt = (int)resolver.decode(intBytesValue); | |||
| assertEquals(intVal, resolveInt); | |||
| short resolveShort = (short) resolver.decode(intBytesValue, short.class); | |||
| assertEquals(resolveShort, 1024); | |||
| Short resolveShortObj = (Short) resolver.decode(intBytesValue, Short.class); | |||
| assertEquals((short)resolveShortObj, resolveShort); | |||
| long resolveLong = (long) resolver.decode(intBytesValue, long.class); | |||
| assertEquals(resolveLong, 1024L); | |||
| Long resolveLongObj = (Long) resolver.decode(intBytesValue, Long.class); | |||
| assertEquals(resolveLong, (long) resolveLongObj); | |||
| } | |||
| } | |||
| @@ -0,0 +1,52 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.ledger.resolver.IntegerToBytesValueResolver; | |||
| import com.jd.blockchain.ledger.resolver.LongToBytesValueResolver; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertEquals; | |||
| public class LongToBytesValueResolverTest { | |||
| private LongToBytesValueResolver resolver = new LongToBytesValueResolver(); | |||
| @Test | |||
| public void test() { | |||
| long longVal = 65536L; | |||
| BytesValue longBytesValue = resolver.encode(longVal); | |||
| BytesValue longBytesValue1 = resolver.encode(longVal, long.class); | |||
| BytesValue longBytesValue2 = resolver.encode(longVal, Long.class); | |||
| assertEquals(longBytesValue.getValue(), longBytesValue1.getValue()); | |||
| assertEquals(longBytesValue.getValue(), longBytesValue2.getValue()); | |||
| Bytes longBytes = Bytes.fromLong(longVal); | |||
| assertEquals(longBytes, longBytesValue.getValue()); | |||
| assertEquals(longBytesValue.getType(), DataType.INT64); | |||
| long resolveLong = (long)resolver.decode(longBytesValue); | |||
| assertEquals(longVal, resolveLong); | |||
| short resolveShort = (short) resolver.decode(longBytesValue, short.class); | |||
| assertEquals(resolveShort, (short)65536); | |||
| Short resolveShortObj = (Short) resolver.decode(longBytesValue, Short.class); | |||
| assertEquals((short)resolveShortObj, resolveShort); | |||
| int resolveInt = (int) resolver.decode(longBytesValue, int.class); | |||
| assertEquals(resolveInt, 65536); | |||
| Integer resolveIntObj = (Integer) resolver.decode(longBytesValue, Integer.class); | |||
| assertEquals(resolveInt, (int) resolveIntObj); | |||
| } | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.ledger.resolver.ShortToBytesValueResolver; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertEquals; | |||
| public class ShortToBytesValueResolverTest { | |||
| private ShortToBytesValueResolver resolver = new ShortToBytesValueResolver(); | |||
| @Test | |||
| public void test() { | |||
| short shortVal = 64; | |||
| BytesValue shortBytesValue = resolver.encode(shortVal); | |||
| Bytes shortBytes = new Bytes(BytesUtils.toBytes(shortVal)); | |||
| assertEquals(shortBytes, shortBytesValue.getValue()); | |||
| assertEquals(shortBytesValue.getType(), DataType.INT16); | |||
| short resolveShort = (short)resolver.decode(shortBytesValue); | |||
| assertEquals(shortVal, resolveShort); | |||
| int resolveInt = (int) resolver.decode(shortBytesValue, int.class); | |||
| assertEquals(resolveInt, 64); | |||
| Integer resolveIntObj = (Integer) resolver.decode(shortBytesValue, Integer.class); | |||
| assertEquals((int)resolveIntObj, resolveShort); | |||
| long resolveLong = (long) resolver.decode(shortBytesValue, long.class); | |||
| assertEquals(resolveLong, 64L); | |||
| Long resolveLongObj = (Long) resolver.decode(shortBytesValue, Long.class); | |||
| assertEquals(resolveLong, (long) resolveLongObj); | |||
| } | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| package test.com.jd.blockchain.ledger.data; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.DataType; | |||
| import com.jd.blockchain.ledger.resolver.StringToBytesValueResolver; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import static org.junit.Assert.*; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import org.junit.Test; | |||
| public class StringToBytesValueResolverTest { | |||
| private StringToBytesValueResolver resolver = new StringToBytesValueResolver(); | |||
| @Test | |||
| public void testText() { | |||
| String textVal = "JDChain"; | |||
| BytesValue textBytesValue = resolver.encode(textVal); | |||
| assertEquals(Bytes.fromString(textVal), textBytesValue.getValue()); | |||
| assertEquals(textBytesValue.getType(), DataType.TEXT); | |||
| String resolveText = (String)resolver.decode(textBytesValue); | |||
| assertEquals(resolveText, textVal); | |||
| byte[] resolveBytes = (byte[]) resolver.decode(textBytesValue, byte[].class); | |||
| assertArrayEquals(resolveBytes, BytesUtils.toBytes(textVal)); | |||
| Bytes resolveBytesObj = (Bytes) resolver.decode(textBytesValue, Bytes.class); | |||
| assertEquals(resolveBytesObj, Bytes.fromString(textVal)); | |||
| } | |||
| @Test | |||
| public void testJson() { | |||
| Person person = new Person("zhangsan", 80); | |||
| String personJson = JSON.toJSONString(person); | |||
| BytesValue textBytesValue = resolver.encode(personJson); | |||
| assertEquals(Bytes.fromString(personJson), textBytesValue.getValue()); | |||
| assertEquals(textBytesValue.getType(), DataType.JSON); | |||
| } | |||
| public static class Person { | |||
| private String name; | |||
| private int age; | |||
| public Person() { | |||
| } | |||
| public Person(String name, int age) { | |||
| this.name = name; | |||
| this.age = age; | |||
| } | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| public void setName(String name) { | |||
| this.name = name; | |||
| } | |||
| public int getAge() { | |||
| return age; | |||
| } | |||
| public void setAge(int age) { | |||
| this.age = age; | |||
| } | |||
| } | |||
| } | |||
| @@ -31,348 +31,347 @@ import java.lang.reflect.Field; | |||
| 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 = BytesData.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, | |||
| BytesDataList.singleText(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; | |||
| } | |||
| } | |||
| 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 = BytesData.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, | |||
| BytesValueEncoding.encodeArray(new Object[]{argsStr}, null)); | |||
| } | |||
| 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; | |||
| } | |||
| } | |||
| } | |||
| @@ -17,8 +17,7 @@ import com.jd.blockchain.utils.Bytes; | |||
| 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(); | |||
| new SDK_Contract_Demo().executeContract(); | |||
| } | |||
| public void executeContract() { | |||
| @@ -42,7 +42,7 @@ public class CompositeConnectionFactory implements DbConnectionFactory { | |||
| connectionFactoryMap.put(dbPrefix, dbConnectionFactory); | |||
| } | |||
| } catch (Exception e) { | |||
| LOGGER.error("class:{%s} init error {%s}", clazz.getName(), e.getMessage()); | |||
| LOGGER.error("class:{} init error {}", clazz.getName(), e.getMessage()); | |||
| } | |||
| } | |||
| } | |||
| @@ -9,12 +9,7 @@ import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.contract.EventProcessingAware; | |||
| import com.jd.blockchain.contract.LedgerContext; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.BlockchainIdentity; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueList; | |||
| import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
| import com.jd.blockchain.ledger.Operation; | |||
| import com.jd.blockchain.ledger.TransactionRequest; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.ledger.core.LedgerDataSet; | |||
| import com.jd.blockchain.ledger.core.LedgerService; | |||
| import com.jd.blockchain.ledger.core.OperationHandle; | |||
| @@ -74,7 +69,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||
| } | |||
| // No return value; | |||
| return null; | |||
| return BytesValueEncoding.encodeSingle(result, null); | |||
| } | |||
| @Override | |||
| @@ -78,7 +78,7 @@ public class ContractProxy<T> implements InvocationHandler { | |||
| OperationResult opResult = operationResults[0]; | |||
| // 处理返回值 | |||
| return BytesValueEncoding.encode(opResult.getResult(), method.getReturnType()); | |||
| return BytesValueEncoding.encodeSingle(opResult.getResult(), method.getReturnType()); | |||
| } | |||
| private boolean isExecuteContractMethod(Method method) { | |||
| @@ -6,6 +6,7 @@ import java.io.InputStream; | |||
| import java.io.ObjectOutputStream; | |||
| import java.io.OutputStream; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.math.BigInteger; | |||
| import com.jd.blockchain.utils.IllegalDataException; | |||
| @@ -370,6 +371,10 @@ public class BytesUtils { | |||
| return value; | |||
| } | |||
| public static short toShort(byte[] bytes) { | |||
| return toShort(bytes, 0); | |||
| } | |||
| public static char toChar(byte[] bytes, int offset) { | |||
| char value = 0; | |||
| value = (char) ((value | (bytes[offset] & 0xFF)) << 8); | |||