@@ -96,7 +96,7 @@ public abstract class AbstractContractCode implements ContractCode { | |||||
eventContext.getEvent(), address.toString(), error.getMessage()), error); | eventContext.getEvent(), address.toString(), error.getMessage()), error); | ||||
} | } | ||||
BytesValue retnBytes = BytesValueEncoding.encode(retn, handleMethod.getReturnType()); | |||||
BytesValue retnBytes = BytesValueEncoding.encodeSingle(retn, handleMethod.getReturnType()); | |||||
return retnBytes; | return retnBytes; | ||||
} | } | ||||
@@ -39,7 +39,6 @@ | |||||
<version>${project.version}</version> | <version>${project.version}</version> | ||||
<scope>test</scope> | <scope>test</scope> | ||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
</project> | </project> |
@@ -1,24 +1,131 @@ | |||||
package com.jd.blockchain.ledger; | 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 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) { | 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) { | 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) { | public static Object getDefaultValue(Class<?> type) { | ||||
@@ -54,7 +161,29 @@ public class BytesValueEncoding { | |||||
} | } | ||||
public static boolean supportType(Class<?> currParamType) { | 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(); | Class<?>[] argTypes = method.getParameterTypes(); | ||||
BytesValueList argBytes = BytesValueEncoding.encode(args, argTypes); | |||||
BytesValueList argBytes = BytesValueEncoding.encodeArray(args, argTypes); | |||||
// 定义合约调用操作; | // 定义合约调用操作; | ||||
ContractEventSendOpTemplate opTemplate = (ContractEventSendOpTemplate) sendOpBuilder.send(contractAddress, | 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 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 class SDK_Contract_Demo extends SDK_Base_Demo { | ||||
public static void main(String[] args) { | public static void main(String[] args) { | ||||
SDK_Contract_Demo demo = new SDK_Contract_Demo(); | |||||
demo.executeContract(); | |||||
new SDK_Contract_Demo().executeContract(); | |||||
} | } | ||||
public void executeContract() { | public void executeContract() { | ||||
@@ -42,7 +42,7 @@ public class CompositeConnectionFactory implements DbConnectionFactory { | |||||
connectionFactoryMap.put(dbPrefix, dbConnectionFactory); | connectionFactoryMap.put(dbPrefix, dbConnectionFactory); | ||||
} | } | ||||
} catch (Exception e) { | } 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.EventProcessingAware; | ||||
import com.jd.blockchain.contract.LedgerContext; | import com.jd.blockchain.contract.LedgerContext; | ||||
import com.jd.blockchain.crypto.HashDigest; | 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.LedgerDataSet; | ||||
import com.jd.blockchain.ledger.core.LedgerService; | import com.jd.blockchain.ledger.core.LedgerService; | ||||
import com.jd.blockchain.ledger.core.OperationHandle; | import com.jd.blockchain.ledger.core.OperationHandle; | ||||
@@ -74,7 +69,7 @@ public class MockerContractExeHandle implements OperationHandle { | |||||
} | } | ||||
// No return value; | // No return value; | ||||
return null; | |||||
return BytesValueEncoding.encodeSingle(result, null); | |||||
} | } | ||||
@Override | @Override | ||||
@@ -78,7 +78,7 @@ public class ContractProxy<T> implements InvocationHandler { | |||||
OperationResult opResult = operationResults[0]; | OperationResult opResult = operationResults[0]; | ||||
// 处理返回值 | // 处理返回值 | ||||
return BytesValueEncoding.encode(opResult.getResult(), method.getReturnType()); | |||||
return BytesValueEncoding.encodeSingle(opResult.getResult(), method.getReturnType()); | |||||
} | } | ||||
private boolean isExecuteContractMethod(Method method) { | private boolean isExecuteContractMethod(Method method) { | ||||
@@ -6,6 +6,7 @@ import java.io.InputStream; | |||||
import java.io.ObjectOutputStream; | import java.io.ObjectOutputStream; | ||||
import java.io.OutputStream; | import java.io.OutputStream; | ||||
import java.io.UnsupportedEncodingException; | import java.io.UnsupportedEncodingException; | ||||
import java.math.BigInteger; | |||||
import com.jd.blockchain.utils.IllegalDataException; | import com.jd.blockchain.utils.IllegalDataException; | ||||
@@ -370,6 +371,10 @@ public class BytesUtils { | |||||
return value; | return value; | ||||
} | } | ||||
public static short toShort(byte[] bytes) { | |||||
return toShort(bytes, 0); | |||||
} | |||||
public static char toChar(byte[] bytes, int offset) { | public static char toChar(byte[] bytes, int offset) { | ||||
char value = 0; | char value = 0; | ||||
value = (char) ((value | (bytes[offset] & 0xFF)) << 8); | value = (char) ((value | (bytes[offset] & 0xFF)) << 8); | ||||