@@ -1,66 +1,66 @@ | |||
package com.jd.blockchain.binaryproto; | |||
/** | |||
* 键值操作的数据类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum PrimitiveType { | |||
/** | |||
* 空; | |||
*/ | |||
NIL(BaseType.NIL), | |||
/** | |||
* 布尔型; | |||
*/ | |||
BOOLEAN(BaseType.BOOLEAN), | |||
/** | |||
* 8位的整数: | |||
*/ | |||
INT8(BaseType.INT8), | |||
/** | |||
* 16位整数; | |||
*/ | |||
INT16(BaseType.INT16), | |||
/** | |||
* 32位整数; | |||
*/ | |||
INT32(BaseType.INT32), | |||
/** | |||
* 64位整数; | |||
*/ | |||
INT64(BaseType.INT64), | |||
/** | |||
* 文本; | |||
*/ | |||
TEXT(BaseType.TEXT), | |||
/** | |||
* 二进制数据; | |||
*/ | |||
BYTES(BaseType.BYTES); | |||
public final byte CODE; | |||
private PrimitiveType(byte code) { | |||
this.CODE = code; | |||
} | |||
public static PrimitiveType valueOf(byte code) { | |||
for (PrimitiveType dataType : PrimitiveType.values()) { | |||
if (dataType.CODE == code) { | |||
return dataType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Code[" + code + "] not suppported by PrimitiveType!"); | |||
} | |||
} | |||
package com.jd.blockchain.binaryproto; | |||
/** | |||
* 键值操作的数据类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum PrimitiveType { | |||
/** | |||
* 空; | |||
*/ | |||
NIL(BaseType.NIL), | |||
/** | |||
* 布尔型; | |||
*/ | |||
BOOLEAN(BaseType.BOOLEAN), | |||
/** | |||
* 8位的整数: | |||
*/ | |||
INT8(BaseType.INT8), | |||
/** | |||
* 16位整数; | |||
*/ | |||
INT16(BaseType.INT16), | |||
/** | |||
* 32位整数; | |||
*/ | |||
INT32(BaseType.INT32), | |||
/** | |||
* 64位整数; | |||
*/ | |||
INT64(BaseType.INT64), | |||
/** | |||
* 文本; | |||
*/ | |||
TEXT(BaseType.TEXT), | |||
/** | |||
* 二进制数据; | |||
*/ | |||
BYTES(BaseType.BYTES); | |||
public final byte CODE; | |||
private PrimitiveType(byte code) { | |||
this.CODE = code; | |||
} | |||
public static PrimitiveType valueOf(byte code) { | |||
for (PrimitiveType dataType : PrimitiveType.values()) { | |||
if (dataType.CODE == code) { | |||
return dataType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Code[" + code + "] not suppported by PrimitiveType!"); | |||
} | |||
} |
@@ -1,25 +1,25 @@ | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.PARAMETER }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ActionMessage { | |||
/** | |||
* 请求参数转换器; | |||
* <p> | |||
* 指定一个 {@link BinaryMessageConverter} 接口的实现类; | |||
* | |||
* @return | |||
*/ | |||
Class<?> converter(); | |||
} | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.PARAMETER }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ActionMessage { | |||
/** | |||
* 请求参数转换器; | |||
* <p> | |||
* 指定一个 {@link BinaryMessageConverter} 接口的实现类; | |||
* | |||
* @return | |||
*/ | |||
Class<?> converter(); | |||
} |
@@ -1,18 +1,18 @@ | |||
package com.jd.blockchain.consensus; | |||
public class ConsensusSecurityException extends Exception{ | |||
private static final long serialVersionUID = -164820276123627155L; | |||
public ConsensusSecurityException() { | |||
} | |||
public ConsensusSecurityException(String message) { | |||
super(message); | |||
} | |||
public ConsensusSecurityException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} | |||
package com.jd.blockchain.consensus; | |||
public class ConsensusSecurityException extends Exception{ | |||
private static final long serialVersionUID = -164820276123627155L; | |||
public ConsensusSecurityException() { | |||
} | |||
public ConsensusSecurityException(String message) { | |||
super(message); | |||
} | |||
public ConsensusSecurityException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -1,12 +1,12 @@ | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.TYPE }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ConsensusService { | |||
} | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.TYPE }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ConsensusService { | |||
} |
@@ -1,35 +1,35 @@ | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* 标识一个共识方法调用模式为“有序的消息调用”; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface OrderedAction { | |||
/** | |||
* 请求分组的索引器;<br> | |||
* | |||
* 指定一个 {@link GroupIndexer} 接口的实现类,用于根据请求消息列表来生成共识的分组ID; | |||
* @return | |||
*/ | |||
Class<?> groupIndexer() ; | |||
/** | |||
* 回复消息转换器; | |||
* <p> | |||
* 指定一个 {@link BinaryMessageConverter} 接口的实现类; | |||
* | |||
* @return | |||
*/ | |||
Class<?> responseConverter(); | |||
} | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* 标识一个共识方法调用模式为“有序的消息调用”; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface OrderedAction { | |||
/** | |||
* 请求分组的索引器;<br> | |||
* | |||
* 指定一个 {@link GroupIndexer} 接口的实现类,用于根据请求消息列表来生成共识的分组ID; | |||
* @return | |||
*/ | |||
Class<?> groupIndexer() ; | |||
/** | |||
* 回复消息转换器; | |||
* <p> | |||
* 指定一个 {@link BinaryMessageConverter} 接口的实现类; | |||
* | |||
* @return | |||
*/ | |||
Class<?> responseConverter(); | |||
} |
@@ -1,22 +1,22 @@ | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface UnorderedAction { | |||
/** | |||
* 请求分组的索引器;<br> | |||
* | |||
* 指定一个 {@link GroupIndexer} 接口的实现类,用于根据请求消息列表来生成共识的分组ID; | |||
* @return | |||
*/ | |||
Class<?> groupIndexer() ; | |||
} | |||
package com.jd.blockchain.consensus; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface UnorderedAction { | |||
/** | |||
* 请求分组的索引器;<br> | |||
* | |||
* 指定一个 {@link GroupIndexer} 接口的实现类,用于根据请求消息列表来生成共识的分组ID; | |||
* @return | |||
*/ | |||
Class<?> groupIndexer() ; | |||
} |
@@ -1,49 +1,49 @@ | |||
package com.jd.blockchain.consensus.action; | |||
public class ActionResponseData implements ActionResponse { | |||
private byte[] message; | |||
private boolean error = false; | |||
private String errorMessage; | |||
private String errorType; | |||
@Override | |||
public byte[] getMessage() { | |||
return message; | |||
} | |||
public void setMessage(byte[] message) { | |||
this.message = message; | |||
} | |||
@Override | |||
public boolean getError() { | |||
return error; | |||
} | |||
public void setError(boolean error) { | |||
this.error = error; | |||
} | |||
@Override | |||
public String getErrorMessage() { | |||
return errorMessage; | |||
} | |||
public void setErrorMessage(String errorMessage) { | |||
this.errorMessage = errorMessage; | |||
} | |||
@Override | |||
public String getErrorType() { | |||
return errorType; | |||
} | |||
public void setErrorType(String errorType) { | |||
this.errorType = errorType; | |||
} | |||
} | |||
package com.jd.blockchain.consensus.action; | |||
public class ActionResponseData implements ActionResponse { | |||
private byte[] message; | |||
private boolean error = false; | |||
private String errorMessage; | |||
private String errorType; | |||
@Override | |||
public byte[] getMessage() { | |||
return message; | |||
} | |||
public void setMessage(byte[] message) { | |||
this.message = message; | |||
} | |||
@Override | |||
public boolean getError() { | |||
return error; | |||
} | |||
public void setError(boolean error) { | |||
this.error = error; | |||
} | |||
@Override | |||
public String getErrorMessage() { | |||
return errorMessage; | |||
} | |||
public void setErrorMessage(String errorMessage) { | |||
this.errorMessage = errorMessage; | |||
} | |||
@Override | |||
public String getErrorType() { | |||
return errorType; | |||
} | |||
public void setErrorType(String errorType) { | |||
this.errorType = errorType; | |||
} | |||
} |
@@ -1,19 +1,19 @@ | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>jdchain-root</artifactId> | |||
<version>1.1.2.RELEASE</version> | |||
</parent> | |||
<artifactId>contract</artifactId> | |||
<packaging>pom</packaging> | |||
<modules> | |||
<module>contract-framework</module> | |||
<module>contract-jvm</module> | |||
<module>contract-maven-plugin</module> | |||
<module>contract-samples</module> | |||
</modules> | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>jdchain-root</artifactId> | |||
<version>1.1.2.RELEASE</version> | |||
</parent> | |||
<artifactId>contract</artifactId> | |||
<packaging>pom</packaging> | |||
<modules> | |||
<module>contract-framework</module> | |||
<module>contract-jvm</module> | |||
<module>contract-maven-plugin</module> | |||
<module>contract-samples</module> | |||
</modules> | |||
</project> |
@@ -1,65 +1,65 @@ | |||
package com.jd.blockchain.crypto; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Arrays; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesEncoding; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.NumberMask; | |||
import com.jd.blockchain.utils.security.RipeMD160Utils; | |||
import com.jd.blockchain.utils.security.ShaUtils; | |||
public class AddressEncoding { | |||
/** | |||
* 将区块链地址写入到输出流;<br> | |||
* | |||
* 现将地址按 Base58 解码为字节数组,并将字节数组以 {@link BytesEncoding} 的方式写入输出流;<br> | |||
* | |||
* 如果指定的地址为 null,则仅写入空字节数组;注:此种情况下,输出流并不是完全没有写入,而是实际上会被写入一个表示内容长度为 0 的头部字节;<br> | |||
* | |||
* @param address | |||
* 要写入的区块链地址; | |||
* @param out | |||
* 输出流; | |||
* @return 写入的地址的字节数;如果指定地址为 null,则返回值为写入的头部字节数;; | |||
*/ | |||
public static int writeAddress(Bytes address, OutputStream out) { | |||
return address.writeTo(out); | |||
} | |||
/** | |||
* 从流中读取区块链地址; | |||
* | |||
* @param in | |||
* @return | |||
* @throws IOException | |||
*/ | |||
public static Bytes readAddress(InputStream in) throws IOException { | |||
byte[] bytesAddress = BytesEncoding.read(NumberMask.TINY, in); | |||
if (bytesAddress.length == 0) { | |||
return null; | |||
} | |||
return new Bytes(bytesAddress); | |||
} | |||
/** | |||
* 从公钥生成地址; | |||
* | |||
* @param pubKey | |||
* @return | |||
*/ | |||
public static Bytes generateAddress(PubKey pubKey) { | |||
byte[] h1Bytes = ShaUtils.hash_256(pubKey.getRawKeyBytes()); | |||
byte[] h2Bytes = RipeMD160Utils.hash(h1Bytes); | |||
byte[] xBytes = BytesUtils.concat(new byte[] { AddressVersion.V1.CODE}, BytesUtils.toBytes(pubKey.getAlgorithm()), h2Bytes); | |||
byte[] checksum = Arrays.copyOf(ShaUtils.hash_256(ShaUtils.hash_256(xBytes)), 4); | |||
byte[] addressBytes = BytesUtils.concat(xBytes, checksum); | |||
return new Bytes(addressBytes); | |||
} | |||
} | |||
package com.jd.blockchain.crypto; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Arrays; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.BytesEncoding; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.NumberMask; | |||
import com.jd.blockchain.utils.security.RipeMD160Utils; | |||
import com.jd.blockchain.utils.security.ShaUtils; | |||
public class AddressEncoding { | |||
/** | |||
* 将区块链地址写入到输出流;<br> | |||
* | |||
* 现将地址按 Base58 解码为字节数组,并将字节数组以 {@link BytesEncoding} 的方式写入输出流;<br> | |||
* | |||
* 如果指定的地址为 null,则仅写入空字节数组;注:此种情况下,输出流并不是完全没有写入,而是实际上会被写入一个表示内容长度为 0 的头部字节;<br> | |||
* | |||
* @param address | |||
* 要写入的区块链地址; | |||
* @param out | |||
* 输出流; | |||
* @return 写入的地址的字节数;如果指定地址为 null,则返回值为写入的头部字节数;; | |||
*/ | |||
public static int writeAddress(Bytes address, OutputStream out) { | |||
return address.writeTo(out); | |||
} | |||
/** | |||
* 从流中读取区块链地址; | |||
* | |||
* @param in | |||
* @return | |||
* @throws IOException | |||
*/ | |||
public static Bytes readAddress(InputStream in) throws IOException { | |||
byte[] bytesAddress = BytesEncoding.read(NumberMask.TINY, in); | |||
if (bytesAddress.length == 0) { | |||
return null; | |||
} | |||
return new Bytes(bytesAddress); | |||
} | |||
/** | |||
* 从公钥生成地址; | |||
* | |||
* @param pubKey | |||
* @return | |||
*/ | |||
public static Bytes generateAddress(PubKey pubKey) { | |||
byte[] h1Bytes = ShaUtils.hash_256(pubKey.getRawKeyBytes()); | |||
byte[] h2Bytes = RipeMD160Utils.hash(h1Bytes); | |||
byte[] xBytes = BytesUtils.concat(new byte[] { AddressVersion.V1.CODE}, BytesUtils.toBytes(pubKey.getAlgorithm()), h2Bytes); | |||
byte[] checksum = Arrays.copyOf(ShaUtils.hash_256(ShaUtils.hash_256(xBytes)), 4); | |||
byte[] addressBytes = BytesUtils.concat(xBytes, checksum); | |||
return new Bytes(addressBytes); | |||
} | |||
} |
@@ -1,24 +1,24 @@ | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* The version of Blockchain Address generation rule; <br> | |||
* | |||
* | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum AddressVersion { | |||
V1((byte) 0x91); | |||
// Note: Implementor can only add new enum items, cann't remove or modify | |||
// existing enum items; | |||
public final byte CODE; | |||
AddressVersion(byte code) { | |||
CODE = code; | |||
} | |||
} | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* The version of Blockchain Address generation rule; <br> | |||
* | |||
* | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum AddressVersion { | |||
V1((byte) 0x91); | |||
// Note: Implementor can only add new enum items, cann't remove or modify | |||
// existing enum items; | |||
public final byte CODE; | |||
AddressVersion(byte code) { | |||
CODE = code; | |||
} | |||
} |
@@ -1,25 +1,25 @@ | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* 密钥; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface CryptoKey extends CryptoBytes { | |||
/** | |||
* 密钥的类型; | |||
* @return | |||
*/ | |||
CryptoKeyType getKeyType(); | |||
/** | |||
* 原始的密钥数据; | |||
* | |||
* @return | |||
*/ | |||
byte[] getRawKeyBytes(); | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* 密钥; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface CryptoKey extends CryptoBytes { | |||
/** | |||
* 密钥的类型; | |||
* @return | |||
*/ | |||
CryptoKeyType getKeyType(); | |||
/** | |||
* 原始的密钥数据; | |||
* | |||
* @return | |||
*/ | |||
byte[] getRawKeyBytes(); | |||
} |
@@ -1,29 +1,29 @@ | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* 私钥; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class PrivKey extends BaseCryptoKey { | |||
private static final long serialVersionUID = 6265440395252295646L; | |||
public PrivKey(short algorithm, byte[] rawCryptoBytes) { | |||
super(algorithm, rawCryptoBytes, CryptoKeyType.PRIVATE); | |||
} | |||
public PrivKey(CryptoAlgorithm algorithm, byte[] rawCryptoBytes) { | |||
super(algorithm, rawCryptoBytes, CryptoKeyType.PRIVATE); | |||
} | |||
public PrivKey(byte[] cryptoBytes) { | |||
super(cryptoBytes); | |||
} | |||
@Override | |||
public CryptoKeyType getKeyType() { | |||
return CryptoKeyType.PRIVATE; | |||
} | |||
package com.jd.blockchain.crypto; | |||
/** | |||
* 私钥; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class PrivKey extends BaseCryptoKey { | |||
private static final long serialVersionUID = 6265440395252295646L; | |||
public PrivKey(short algorithm, byte[] rawCryptoBytes) { | |||
super(algorithm, rawCryptoBytes, CryptoKeyType.PRIVATE); | |||
} | |||
public PrivKey(CryptoAlgorithm algorithm, byte[] rawCryptoBytes) { | |||
super(algorithm, rawCryptoBytes, CryptoKeyType.PRIVATE); | |||
} | |||
public PrivKey(byte[] cryptoBytes) { | |||
super(cryptoBytes); | |||
} | |||
@Override | |||
public CryptoKeyType getKeyType() { | |||
return CryptoKeyType.PRIVATE; | |||
} | |||
} |
@@ -1,14 +1,14 @@ | |||
package com.jd.blockchain.gateway; | |||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | |||
import org.springframework.context.annotation.ComponentScan; | |||
@EnableAutoConfiguration | |||
@EnableConfigurationProperties | |||
@SpringBootApplication | |||
@ComponentScan | |||
public class GatewayConfiguration { | |||
} | |||
package com.jd.blockchain.gateway; | |||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |||
import org.springframework.boot.autoconfigure.SpringBootApplication; | |||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | |||
import org.springframework.context.annotation.ComponentScan; | |||
@EnableAutoConfiguration | |||
@EnableConfigurationProperties | |||
@SpringBootApplication | |||
@ComponentScan | |||
public class GatewayConfiguration { | |||
} | |||
@@ -1,178 +1,178 @@ | |||
package com.jd.blockchain.gateway; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.context.ConfigurableApplicationContext; | |||
import org.springframework.core.io.ClassPathResource; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||
import com.jd.blockchain.utils.ArgumentSet; | |||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||
import com.jd.blockchain.utils.BaseConstant; | |||
import com.jd.blockchain.utils.ConsoleUtils; | |||
public class GatewayServerBooter { | |||
private static final String DEFAULT_GATEWAY_PROPS = "application-gw.properties"; | |||
// 当前参与方在初始化配置中的参与方列表的编号; | |||
private static final String HOST_ARG = "-c"; | |||
//sp;针对spring.config.location这个参数进行包装; | |||
private static final String SPRING_CF_LOCATION = BaseConstant.SPRING_CF_LOCATION; | |||
// 是否输出调试信息; | |||
private static final String DEBUG_OPT = "-debug"; | |||
public static void main(String[] args) { | |||
boolean debug = false; | |||
try { | |||
ArgumentSet arguments = ArgumentSet.resolve(args, ArgumentSet.setting().prefix(HOST_ARG, SPRING_CF_LOCATION).option(DEBUG_OPT)); | |||
debug = arguments.hasOption(DEBUG_OPT); | |||
ArgEntry argHost = arguments.getArg(HOST_ARG); | |||
String configFile = argHost == null ? null : argHost.getValue(); | |||
GatewayConfigProperties configProps; | |||
if (configFile == null) { | |||
ConsoleUtils.info("Load build-in default configuration ..."); | |||
ClassPathResource configResource = new ClassPathResource("gateway.conf"); | |||
try (InputStream in = configResource.getInputStream()) { | |||
configProps = GatewayConfigProperties.resolve(in); | |||
} | |||
} else { | |||
ConsoleUtils.info("Load configuration ..."); | |||
configProps = GatewayConfigProperties.resolve(argHost.getValue()); | |||
} | |||
//spring config location; | |||
String springConfigLocation=null; | |||
ArgumentSet.ArgEntry spConfigLocation = arguments.getArg(SPRING_CF_LOCATION); | |||
if (spConfigLocation != null) { | |||
springConfigLocation = spConfigLocation.getValue(); | |||
}else { | |||
//if no the config file, then should tip as follows. but it's not a good feeling, so we create it by inputStream; | |||
ConsoleUtils.info("no param:-sp, format: -sp /x/xx.properties, use the default application-gw.properties "); | |||
ClassPathResource configResource = new ClassPathResource(DEFAULT_GATEWAY_PROPS); | |||
InputStream in = configResource.getInputStream(); | |||
// 将文件写入至config目录下 | |||
String configPath = bootPath() + "config" + File.separator + DEFAULT_GATEWAY_PROPS; | |||
File targetFile = new File(configPath); | |||
// 先将原来文件删除再Copy | |||
if (targetFile.exists()) { | |||
FileUtils.forceDelete(targetFile); | |||
} | |||
FileUtils.copyInputStreamToFile(in, targetFile); | |||
springConfigLocation = "file:" + targetFile.getAbsolutePath(); | |||
} | |||
// 启动服务器; | |||
ConsoleUtils.info("Starting web server......"); | |||
GatewayServerBooter booter = new GatewayServerBooter(configProps,springConfigLocation); | |||
booter.start(); | |||
ConsoleUtils.info("Peer[%s] is connected success!", configProps.masterPeerAddress().toString()); | |||
} catch (Exception e) { | |||
ConsoleUtils.error("Error!! %s", e.getMessage()); | |||
if (debug) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
private volatile ConfigurableApplicationContext appCtx; | |||
private GatewayConfigProperties config; | |||
private AsymmetricKeypair defaultKeyPair; | |||
private String springConfigLocation; | |||
public GatewayServerBooter(GatewayConfigProperties config, String springConfigLocation) { | |||
this.config = config; | |||
this.springConfigLocation = springConfigLocation; | |||
String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | |||
if (base58Pwd == null || base58Pwd.length() == 0) { | |||
base58Pwd = KeyGenUtils.readPasswordString(); | |||
} | |||
// 加载密钥; | |||
PubKey pubKey = KeyGenUtils.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||
PrivKey privKey = null; | |||
String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | |||
if (base58PrivKey == null) { | |||
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | |||
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||
} else { | |||
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd); | |||
} | |||
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | |||
} | |||
public synchronized void start() { | |||
if (this.appCtx != null) { | |||
throw new IllegalStateException("Gateway server is running already."); | |||
} | |||
this.appCtx = startServer(config.http().getHost(), config.http().getPort(), springConfigLocation, | |||
config.http().getContextPath()); | |||
ConsoleUtils.info("\r\n\r\nStart connecting to peer ...."); | |||
BlockBrowserController blockBrowserController = appCtx.getBean(BlockBrowserController.class); | |||
blockBrowserController.setDataRetrievalUrl(config.dataRetrievalUrl()); | |||
blockBrowserController.setSchemaRetrievalUrl(config.getSchemaRetrievalUrl()); | |||
PeerConnector peerConnector = appCtx.getBean(PeerConnector.class); | |||
peerConnector.connect(config.masterPeerAddress(), defaultKeyPair, config.providerConfig().getProviders()); | |||
ConsoleUtils.info("Peer[%s] is connected success!", config.masterPeerAddress().toString()); | |||
} | |||
public synchronized void close() { | |||
if (this.appCtx == null) { | |||
return; | |||
} | |||
this.appCtx.close(); | |||
} | |||
private static ConfigurableApplicationContext startServer(String host, int port, String springConfigLocation, String contextPath) { | |||
List<String> argList = new ArrayList<String>(); | |||
argList.add(String.format("--server.address=%s", host)); | |||
argList.add(String.format("--server.port=%s", port)); | |||
if(springConfigLocation != null){ | |||
argList.add(String.format("--spring.config.location=%s", springConfigLocation)); | |||
} | |||
if (contextPath != null) { | |||
argList.add(String.format("--server.context-path=%s", contextPath)); | |||
} | |||
String[] args = argList.toArray(new String[argList.size()]); | |||
// 启动服务器; | |||
ConfigurableApplicationContext appCtx = SpringApplication.run(GatewayConfiguration.class, args); | |||
return appCtx; | |||
} | |||
private static String bootPath() throws Exception { | |||
URL url = GatewayServerBooter.class.getProtectionDomain().getCodeSource().getLocation(); | |||
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | |||
// 处理打包至SpringBoot问题 | |||
if (currPath.contains("!/")) { | |||
currPath = currPath.substring(5, currPath.indexOf("!/")); | |||
} | |||
if (currPath.endsWith(".jar")) { | |||
currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); | |||
} | |||
System.out.printf("Current Project Boot Path = %s \r\n", currPath); | |||
return new File(currPath).getParent() + File.separator; | |||
} | |||
package com.jd.blockchain.gateway; | |||
import java.io.File; | |||
import java.io.InputStream; | |||
import java.net.URL; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.commons.io.FileUtils; | |||
import org.springframework.boot.SpringApplication; | |||
import org.springframework.context.ConfigurableApplicationContext; | |||
import org.springframework.core.io.ClassPathResource; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.KeyGenUtils; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.gateway.web.BlockBrowserController; | |||
import com.jd.blockchain.utils.ArgumentSet; | |||
import com.jd.blockchain.utils.ArgumentSet.ArgEntry; | |||
import com.jd.blockchain.utils.BaseConstant; | |||
import com.jd.blockchain.utils.ConsoleUtils; | |||
public class GatewayServerBooter { | |||
private static final String DEFAULT_GATEWAY_PROPS = "application-gw.properties"; | |||
// 当前参与方在初始化配置中的参与方列表的编号; | |||
private static final String HOST_ARG = "-c"; | |||
//sp;针对spring.config.location这个参数进行包装; | |||
private static final String SPRING_CF_LOCATION = BaseConstant.SPRING_CF_LOCATION; | |||
// 是否输出调试信息; | |||
private static final String DEBUG_OPT = "-debug"; | |||
public static void main(String[] args) { | |||
boolean debug = false; | |||
try { | |||
ArgumentSet arguments = ArgumentSet.resolve(args, ArgumentSet.setting().prefix(HOST_ARG, SPRING_CF_LOCATION).option(DEBUG_OPT)); | |||
debug = arguments.hasOption(DEBUG_OPT); | |||
ArgEntry argHost = arguments.getArg(HOST_ARG); | |||
String configFile = argHost == null ? null : argHost.getValue(); | |||
GatewayConfigProperties configProps; | |||
if (configFile == null) { | |||
ConsoleUtils.info("Load build-in default configuration ..."); | |||
ClassPathResource configResource = new ClassPathResource("gateway.conf"); | |||
try (InputStream in = configResource.getInputStream()) { | |||
configProps = GatewayConfigProperties.resolve(in); | |||
} | |||
} else { | |||
ConsoleUtils.info("Load configuration ..."); | |||
configProps = GatewayConfigProperties.resolve(argHost.getValue()); | |||
} | |||
//spring config location; | |||
String springConfigLocation=null; | |||
ArgumentSet.ArgEntry spConfigLocation = arguments.getArg(SPRING_CF_LOCATION); | |||
if (spConfigLocation != null) { | |||
springConfigLocation = spConfigLocation.getValue(); | |||
}else { | |||
//if no the config file, then should tip as follows. but it's not a good feeling, so we create it by inputStream; | |||
ConsoleUtils.info("no param:-sp, format: -sp /x/xx.properties, use the default application-gw.properties "); | |||
ClassPathResource configResource = new ClassPathResource(DEFAULT_GATEWAY_PROPS); | |||
InputStream in = configResource.getInputStream(); | |||
// 将文件写入至config目录下 | |||
String configPath = bootPath() + "config" + File.separator + DEFAULT_GATEWAY_PROPS; | |||
File targetFile = new File(configPath); | |||
// 先将原来文件删除再Copy | |||
if (targetFile.exists()) { | |||
FileUtils.forceDelete(targetFile); | |||
} | |||
FileUtils.copyInputStreamToFile(in, targetFile); | |||
springConfigLocation = "file:" + targetFile.getAbsolutePath(); | |||
} | |||
// 启动服务器; | |||
ConsoleUtils.info("Starting web server......"); | |||
GatewayServerBooter booter = new GatewayServerBooter(configProps,springConfigLocation); | |||
booter.start(); | |||
ConsoleUtils.info("Peer[%s] is connected success!", configProps.masterPeerAddress().toString()); | |||
} catch (Exception e) { | |||
ConsoleUtils.error("Error!! %s", e.getMessage()); | |||
if (debug) { | |||
e.printStackTrace(); | |||
} | |||
} | |||
} | |||
private volatile ConfigurableApplicationContext appCtx; | |||
private GatewayConfigProperties config; | |||
private AsymmetricKeypair defaultKeyPair; | |||
private String springConfigLocation; | |||
public GatewayServerBooter(GatewayConfigProperties config, String springConfigLocation) { | |||
this.config = config; | |||
this.springConfigLocation = springConfigLocation; | |||
String base58Pwd = config.keys().getDefault().getPrivKeyPassword(); | |||
if (base58Pwd == null || base58Pwd.length() == 0) { | |||
base58Pwd = KeyGenUtils.readPasswordString(); | |||
} | |||
// 加载密钥; | |||
PubKey pubKey = KeyGenUtils.decodePubKey(config.keys().getDefault().getPubKeyValue()); | |||
PrivKey privKey = null; | |||
String base58PrivKey = config.keys().getDefault().getPrivKeyValue(); | |||
if (base58PrivKey == null) { | |||
//注:GatewayConfigProperties 确保了 PrivKeyValue 和 PrivKeyPath 必有其一; | |||
privKey = KeyGenUtils.readPrivKey(config.keys().getDefault().getPrivKeyPath(), base58Pwd); | |||
} else { | |||
privKey = KeyGenUtils.decodePrivKey(base58PrivKey, base58Pwd); | |||
} | |||
defaultKeyPair = new AsymmetricKeypair(pubKey, privKey); | |||
} | |||
public synchronized void start() { | |||
if (this.appCtx != null) { | |||
throw new IllegalStateException("Gateway server is running already."); | |||
} | |||
this.appCtx = startServer(config.http().getHost(), config.http().getPort(), springConfigLocation, | |||
config.http().getContextPath()); | |||
ConsoleUtils.info("\r\n\r\nStart connecting to peer ...."); | |||
BlockBrowserController blockBrowserController = appCtx.getBean(BlockBrowserController.class); | |||
blockBrowserController.setDataRetrievalUrl(config.dataRetrievalUrl()); | |||
blockBrowserController.setSchemaRetrievalUrl(config.getSchemaRetrievalUrl()); | |||
PeerConnector peerConnector = appCtx.getBean(PeerConnector.class); | |||
peerConnector.connect(config.masterPeerAddress(), defaultKeyPair, config.providerConfig().getProviders()); | |||
ConsoleUtils.info("Peer[%s] is connected success!", config.masterPeerAddress().toString()); | |||
} | |||
public synchronized void close() { | |||
if (this.appCtx == null) { | |||
return; | |||
} | |||
this.appCtx.close(); | |||
} | |||
private static ConfigurableApplicationContext startServer(String host, int port, String springConfigLocation, String contextPath) { | |||
List<String> argList = new ArrayList<String>(); | |||
argList.add(String.format("--server.address=%s", host)); | |||
argList.add(String.format("--server.port=%s", port)); | |||
if(springConfigLocation != null){ | |||
argList.add(String.format("--spring.config.location=%s", springConfigLocation)); | |||
} | |||
if (contextPath != null) { | |||
argList.add(String.format("--server.context-path=%s", contextPath)); | |||
} | |||
String[] args = argList.toArray(new String[argList.size()]); | |||
// 启动服务器; | |||
ConfigurableApplicationContext appCtx = SpringApplication.run(GatewayConfiguration.class, args); | |||
return appCtx; | |||
} | |||
private static String bootPath() throws Exception { | |||
URL url = GatewayServerBooter.class.getProtectionDomain().getCodeSource().getLocation(); | |||
String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8"); | |||
// 处理打包至SpringBoot问题 | |||
if (currPath.contains("!/")) { | |||
currPath = currPath.substring(5, currPath.indexOf("!/")); | |||
} | |||
if (currPath.endsWith(".jar")) { | |||
currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1); | |||
} | |||
System.out.printf("Current Project Boot Path = %s \r\n", currPath); | |||
return new File(currPath).getParent() + File.separator; | |||
} | |||
} |
@@ -1,17 +1,17 @@ | |||
package com.jd.blockchain.gateway.web; | |||
import org.springframework.context.annotation.Configuration; | |||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | |||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | |||
@Configuration | |||
@EnableWebSecurity | |||
public class GatewayWebSecurityConfigurer extends WebSecurityConfigurerAdapter { | |||
@Override | |||
protected void configure(HttpSecurity http) throws Exception { | |||
http.authorizeRequests().anyRequest().permitAll(); | |||
http.csrf().disable(); | |||
} | |||
} | |||
package com.jd.blockchain.gateway.web; | |||
import org.springframework.context.annotation.Configuration; | |||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | |||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | |||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | |||
@Configuration | |||
@EnableWebSecurity | |||
public class GatewayWebSecurityConfigurer extends WebSecurityConfigurerAdapter { | |||
@Override | |||
protected void configure(HttpSecurity http) throws Exception { | |||
http.authorizeRequests().anyRequest().permitAll(); | |||
http.csrf().disable(); | |||
} | |||
} |
@@ -1,31 +1,31 @@ | |||
#网关的HTTP服务地址; | |||
http.host=0.0.0.0 | |||
#网关的HTTP服务端口; | |||
http.port=8081 | |||
#网关的HTTP服务上下文路径,可选; | |||
#http.context-path= | |||
#共识节点的服务地址(与该网关节点连接的Peer节点的IP地址); | |||
peer.host=127.0.0.1 | |||
#共识节点的服务端口(与该网关节点连接的Peer节点的端口); | |||
peer.port=12000 | |||
#共识节点的服务是否启用安全证书; | |||
peer.secure=false | |||
#共识节点的服务提供解析器 | |||
#BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
#简单消息共识Provider:com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider | |||
peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
#数据检索服务对应URL,格式:http://{ip}:{port},例如:http://127.0.0.1:10001 | |||
#若该值不配置或配置不正确,则浏览器模糊查询部分无法正常显示 | |||
data.retrieval.url=http://127.0.0.1:10001 | |||
schema.retrieval.url=http://192.168.151.39:8082 | |||
#默认公钥的内容(Base58编码数据); | |||
keys.default.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 | |||
#默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; | |||
keys.default.privkey-path= | |||
#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; | |||
keys.default.privkey=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x | |||
#默认私钥的解码密码; | |||
#网关的HTTP服务地址; | |||
http.host=0.0.0.0 | |||
#网关的HTTP服务端口; | |||
http.port=8081 | |||
#网关的HTTP服务上下文路径,可选; | |||
#http.context-path= | |||
#共识节点的服务地址(与该网关节点连接的Peer节点的IP地址); | |||
peer.host=127.0.0.1 | |||
#共识节点的服务端口(与该网关节点连接的Peer节点的端口); | |||
peer.port=12000 | |||
#共识节点的服务是否启用安全证书; | |||
peer.secure=false | |||
#共识节点的服务提供解析器 | |||
#BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
#简单消息共识Provider:com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider | |||
peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider | |||
#数据检索服务对应URL,格式:http://{ip}:{port},例如:http://127.0.0.1:10001 | |||
#若该值不配置或配置不正确,则浏览器模糊查询部分无法正常显示 | |||
data.retrieval.url=http://127.0.0.1:10001 | |||
schema.retrieval.url=http://192.168.151.39:8082 | |||
#默认公钥的内容(Base58编码数据); | |||
keys.default.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9 | |||
#默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; | |||
keys.default.privkey-path= | |||
#默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; | |||
keys.default.privkey=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x | |||
#默认私钥的解码密码; | |||
keys.default.privkey-password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY |
@@ -1,31 +1,31 @@ | |||
package test.com.jd.blockchain.gateway.data; | |||
import java.lang.reflect.Type; | |||
import com.alibaba.fastjson.parser.DefaultJSONParser; | |||
import com.alibaba.fastjson.parser.JSONToken; | |||
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
public class HashDigestDeserializer implements ObjectDeserializer{ | |||
public static final HashDigestDeserializer INSTANCE = new HashDigestDeserializer(); | |||
@SuppressWarnings("unchecked") | |||
@Override | |||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { | |||
if (type instanceof Class && HashDigest.class.isAssignableFrom((Class<?>) type)) { | |||
String base58Str = parser.parseObject(String.class); | |||
byte[] hashBytes = Base58Utils.decode(base58Str); | |||
return (T) new HashDigest(hashBytes); | |||
} | |||
return (T) parser.parse(fieldName); | |||
} | |||
@Override | |||
public int getFastMatchToken() { | |||
return JSONToken.LBRACE; | |||
} | |||
} | |||
package test.com.jd.blockchain.gateway.data; | |||
import java.lang.reflect.Type; | |||
import com.alibaba.fastjson.parser.DefaultJSONParser; | |||
import com.alibaba.fastjson.parser.JSONToken; | |||
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.utils.codec.Base58Utils; | |||
public class HashDigestDeserializer implements ObjectDeserializer{ | |||
public static final HashDigestDeserializer INSTANCE = new HashDigestDeserializer(); | |||
@SuppressWarnings("unchecked") | |||
@Override | |||
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { | |||
if (type instanceof Class && HashDigest.class.isAssignableFrom((Class<?>) type)) { | |||
String base58Str = parser.parseObject(String.class); | |||
byte[] hashBytes = Base58Utils.decode(base58Str); | |||
return (T) new HashDigest(hashBytes); | |||
} | |||
return (T) parser.parse(fieldName); | |||
} | |||
@Override | |||
public int getFastMatchToken() { | |||
return JSONToken.LBRACE; | |||
} | |||
} |
@@ -1,27 +1,27 @@ | |||
package test.com.jd.blockchain.gateway.data; | |||
import java.io.IOException; | |||
import java.lang.reflect.Type; | |||
import com.alibaba.fastjson.serializer.JSONSerializer; | |||
import com.alibaba.fastjson.serializer.ObjectSerializer; | |||
import com.alibaba.fastjson.serializer.SerializeWriter; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public class HashDigestSerializer implements ObjectSerializer { | |||
public static HashDigestSerializer INSTANCE = new HashDigestSerializer(); | |||
@Override | |||
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) | |||
throws IOException { | |||
SerializeWriter out = serializer.out; | |||
if (object == null) { | |||
out.writeNull(); | |||
return; | |||
} | |||
HashDigest hash = (HashDigest) object; | |||
out.writeString(hash.toBase58()); | |||
} | |||
} | |||
package test.com.jd.blockchain.gateway.data; | |||
import java.io.IOException; | |||
import java.lang.reflect.Type; | |||
import com.alibaba.fastjson.serializer.JSONSerializer; | |||
import com.alibaba.fastjson.serializer.ObjectSerializer; | |||
import com.alibaba.fastjson.serializer.SerializeWriter; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
public class HashDigestSerializer implements ObjectSerializer { | |||
public static HashDigestSerializer INSTANCE = new HashDigestSerializer(); | |||
@Override | |||
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) | |||
throws IOException { | |||
SerializeWriter out = serializer.out; | |||
if (object == null) { | |||
out.writeNull(); | |||
return; | |||
} | |||
HashDigest hash = (HashDigest) object; | |||
out.writeString(hash.toBase58()); | |||
} | |||
} |
@@ -1,73 +1,73 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractAccount extends AccountDecorator implements ContractInfo { | |||
private static final String CONTRACT_INFO_PREFIX = "INFO" + LedgerConsts.KEY_SEPERATOR; | |||
private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; | |||
public ContractAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return getID().getPubKey(); | |||
} | |||
// public MerkleProof getChaincodeProof() { | |||
// return getHeaders().getProof(CHAIN_CODE_KEY); | |||
// } | |||
// | |||
// public MerkleProof getPropertyProof(Bytes key) { | |||
// return getHeaders().getProof(encodePropertyKey(key)); | |||
// } | |||
public long setChaincode(byte[] chaincode, long version) { | |||
TypedValue bytesValue = TypedValue.fromBytes(chaincode); | |||
return getHeaders().setValue(CHAIN_CODE_KEY, bytesValue, version); | |||
} | |||
public byte[] getChainCode() { | |||
return getHeaders().getValue(CHAIN_CODE_KEY).getBytes().toBytes(); | |||
} | |||
public byte[] getChainCode(long version) { | |||
return getHeaders().getValue(CHAIN_CODE_KEY, version).getBytes().toBytes(); | |||
} | |||
public long getChaincodeVersion() { | |||
return getHeaders().getVersion(CHAIN_CODE_KEY); | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
TypedValue bytesValue = TypedValue.fromText(value); | |||
return getHeaders().setValue(encodePropertyKey(key), bytesValue, version); | |||
} | |||
public String getProperty(String key) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key)); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
public String getProperty(String key, long version) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key), version); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
private String encodePropertyKey(String key) { | |||
return CONTRACT_INFO_PREFIX.concat(key); | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class ContractAccount extends AccountDecorator implements ContractInfo { | |||
private static final String CONTRACT_INFO_PREFIX = "INFO" + LedgerConsts.KEY_SEPERATOR; | |||
private static final String CHAIN_CODE_KEY = "CHAIN-CODE"; | |||
public ContractAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return getID().getPubKey(); | |||
} | |||
// public MerkleProof getChaincodeProof() { | |||
// return getHeaders().getProof(CHAIN_CODE_KEY); | |||
// } | |||
// | |||
// public MerkleProof getPropertyProof(Bytes key) { | |||
// return getHeaders().getProof(encodePropertyKey(key)); | |||
// } | |||
public long setChaincode(byte[] chaincode, long version) { | |||
TypedValue bytesValue = TypedValue.fromBytes(chaincode); | |||
return getHeaders().setValue(CHAIN_CODE_KEY, bytesValue, version); | |||
} | |||
public byte[] getChainCode() { | |||
return getHeaders().getValue(CHAIN_CODE_KEY).getBytes().toBytes(); | |||
} | |||
public byte[] getChainCode(long version) { | |||
return getHeaders().getValue(CHAIN_CODE_KEY, version).getBytes().toBytes(); | |||
} | |||
public long getChaincodeVersion() { | |||
return getHeaders().getVersion(CHAIN_CODE_KEY); | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
TypedValue bytesValue = TypedValue.fromText(value); | |||
return getHeaders().setValue(encodePropertyKey(key), bytesValue, version); | |||
} | |||
public String getProperty(String key) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key)); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
public String getProperty(String key, long version) { | |||
BytesValue bytesValue = getHeaders().getValue(encodePropertyKey(key), version); | |||
return TypedValue.wrap(bytesValue).stringValue(); | |||
} | |||
private String encodePropertyKey(String key) { | |||
return CONTRACT_INFO_PREFIX.concat(key); | |||
} | |||
} |
@@ -1,131 +1,131 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
/** | |||
* 返回合约总数; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return accountSet.getProof(address); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public ContractAccount getAccount(Bytes address) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
return new ContractAccount(accBase); | |||
} | |||
@Override | |||
public ContractAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
@Override | |||
public ContractAccount getAccount(Bytes address, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new ContractAccount(accBase); | |||
} | |||
/** | |||
* 部署一项新的合约链码; | |||
* | |||
* @param address 合约账户地址; | |||
* @param pubKey 合约账户公钥; | |||
* @param addressSignature 地址签名;合约账户的私钥对地址的签名; | |||
* @param chaincode 链码内容; | |||
* @return 合约账户; | |||
*/ | |||
public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { | |||
// TODO: 校验和记录合约地址签名; | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
contractAcc.setChaincode(chaincode, -1); | |||
return contractAcc; | |||
} | |||
/** | |||
* 更新指定账户的链码; | |||
* | |||
* @param address 合约账户地址; | |||
* @param chaincode 链码内容; | |||
* @param version 链码版本; | |||
* @return 返回链码的新版本号; | |||
*/ | |||
public long update(Bytes address, byte[] chaincode, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
return contractAcc.setChaincode(chaincode, version); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class ContractAccountSet implements Transactional, ContractAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public ContractAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public ContractAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
/** | |||
* 返回合约总数; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return accountSet.getProof(address); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public ContractAccount getAccount(Bytes address) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
return new ContractAccount(accBase); | |||
} | |||
@Override | |||
public ContractAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
@Override | |||
public ContractAccount getAccount(Bytes address, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new ContractAccount(accBase); | |||
} | |||
/** | |||
* 部署一项新的合约链码; | |||
* | |||
* @param address 合约账户地址; | |||
* @param pubKey 合约账户公钥; | |||
* @param addressSignature 地址签名;合约账户的私钥对地址的签名; | |||
* @param chaincode 链码内容; | |||
* @return 合约账户; | |||
*/ | |||
public ContractAccount deploy(Bytes address, PubKey pubKey, DigitalSignature addressSignature, byte[] chaincode) { | |||
// TODO: 校验和记录合约地址签名; | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
contractAcc.setChaincode(chaincode, -1); | |||
return contractAcc; | |||
} | |||
/** | |||
* 更新指定账户的链码; | |||
* | |||
* @param address 合约账户地址; | |||
* @param chaincode 链码内容; | |||
* @param version 链码版本; | |||
* @return 返回链码的新版本号; | |||
*/ | |||
public long update(Bytes address, byte[] chaincode, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
ContractAccount contractAcc = new ContractAccount(accBase); | |||
return contractAcc.setChaincode(chaincode, version); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
} |
@@ -1,234 +1,234 @@ | |||
package com.jd.blockchain.ledger.core; | |||
public class DataAccount extends AccountDecorator { | |||
public DataAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, BytesValue value, long version) { | |||
// return super.getDataset().setValue(key, value, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromText(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromBytes(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(String key) { | |||
// return baseAccount.getVersion(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(Bytes key) { | |||
// return baseAccount.getVersion(key); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key) { | |||
// return baseAccount.getValue(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key) { | |||
// return baseAccount.getValue(key); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key, long version) { | |||
// return baseAccount.getValue(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key, long version) { | |||
// return baseAccount.getValue(key, version); | |||
// } | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(String key, long version) { | |||
// return getDataEntry(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(Bytes key, long version) { | |||
// BytesValue value = baseAccount.getValue(key, version); | |||
// if (value == null) { | |||
// return new KVDataObject(key.toUTF8String(), -1, null); | |||
// }else { | |||
// return new KVDataObject(key.toUTF8String(), version, value); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * return the specified index's KVDataEntry; | |||
// * | |||
// * @param fromIndex | |||
// * @param count | |||
// * @return return null if not exist; | |||
// */ | |||
// | |||
// public KVDataEntry[] getDataEntries(int fromIndex, int count) { | |||
// if (count == 0 || getDataEntriesTotalCount() == 0) { | |||
// return null; | |||
// } | |||
// | |||
// if (count == -1 || count > getDataEntriesTotalCount()) { | |||
// fromIndex = 0; | |||
// count = (int)getDataEntriesTotalCount(); | |||
// } | |||
// | |||
// if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { | |||
// fromIndex = 0; | |||
// } | |||
// | |||
// KVDataEntry[] kvDataEntries = new KVDataEntry[count]; | |||
// byte[] value; | |||
// String key; | |||
// long ver; | |||
// for (int i = 0; i < count; i++) { | |||
// value = baseAccount.dataset.getValuesAtIndex(fromIndex); | |||
// key = baseAccount.dataset.getKeyAtIndex(fromIndex); | |||
// ver = baseAccount.dataset.getVersion(key); | |||
// BytesValue decodeData = BinaryProtocol.decode(value); | |||
// kvDataEntries[i] = new KVDataObject(key, ver, decodeData); | |||
// fromIndex++; | |||
// } | |||
// | |||
// return kvDataEntries; | |||
// } | |||
// | |||
// /** | |||
// * return the dataAccount's kv total count; | |||
// * | |||
// * @param | |||
// * @param | |||
// * @return return total count; | |||
// */ | |||
// public long getDataEntriesTotalCount() { | |||
// if(baseAccount == null){ | |||
// return 0; | |||
// } | |||
// return baseAccount.dataset.getDataCount(); | |||
// } | |||
package com.jd.blockchain.ledger.core; | |||
public class DataAccount extends AccountDecorator { | |||
public DataAccount(CompositeAccount mklAccount) { | |||
super(mklAccount); | |||
} | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, BytesValue value, long version) { | |||
// return super.getDataset().setValue(key, value, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, String value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromText(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Create or update the value associated the specified key if the version | |||
// * checking is passed.<br> | |||
// * | |||
// * The value of the key will be updated only if it's latest version equals the | |||
// * specified version argument. <br> | |||
// * If the key doesn't exist, the version checking will be ignored, and key will | |||
// * be created with a new sequence number as id. <br> | |||
// * It also could specify the version argument to -1 to ignore the version | |||
// * checking. | |||
// * <p> | |||
// * If updating is performed, the version of the key increase by 1. <br> | |||
// * If creating is performed, the version of the key initialize by 0. <br> | |||
// * | |||
// * @param key The key of data; | |||
// * @param value The value of data; | |||
// * @param version The expected version of the key. | |||
// * @return The new version of the key. <br> | |||
// * If the key is new created success, then return 0; <br> | |||
// * If the key is updated success, then return the new version;<br> | |||
// * If this operation fail by version checking or other reason, then | |||
// * return -1; | |||
// */ | |||
// public long setBytes(Bytes key, byte[] value, long version) { | |||
// BytesValue bytesValue = TypedValue.fromBytes(value); | |||
// return baseAccount.setValue(key, bytesValue, version); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(String key) { | |||
// return baseAccount.getVersion(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * Return the latest version entry associated the specified key; If the key | |||
// * doesn't exist, then return -1; | |||
// * | |||
// * @param key | |||
// * @return | |||
// */ | |||
// public long getDataVersion(Bytes key) { | |||
// return baseAccount.getVersion(key); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key) { | |||
// return baseAccount.getValue(Bytes.fromString(key)); | |||
// } | |||
// | |||
// /** | |||
// * return the latest version's value; | |||
// * | |||
// * @param key | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key) { | |||
// return baseAccount.getValue(key); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(String key, long version) { | |||
// return baseAccount.getValue(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * return the specified version's value; | |||
// * | |||
// * @param key | |||
// * @param version | |||
// * @return return null if not exist; | |||
// */ | |||
// public BytesValue getBytes(Bytes key, long version) { | |||
// return baseAccount.getValue(key, version); | |||
// } | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(String key, long version) { | |||
// return getDataEntry(Bytes.fromString(key), version); | |||
// } | |||
// | |||
// /** | |||
// * @param key | |||
// * @param version | |||
// * @return | |||
// */ | |||
// public KVDataEntry getDataEntry(Bytes key, long version) { | |||
// BytesValue value = baseAccount.getValue(key, version); | |||
// if (value == null) { | |||
// return new KVDataObject(key.toUTF8String(), -1, null); | |||
// }else { | |||
// return new KVDataObject(key.toUTF8String(), version, value); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * return the specified index's KVDataEntry; | |||
// * | |||
// * @param fromIndex | |||
// * @param count | |||
// * @return return null if not exist; | |||
// */ | |||
// | |||
// public KVDataEntry[] getDataEntries(int fromIndex, int count) { | |||
// if (count == 0 || getDataEntriesTotalCount() == 0) { | |||
// return null; | |||
// } | |||
// | |||
// if (count == -1 || count > getDataEntriesTotalCount()) { | |||
// fromIndex = 0; | |||
// count = (int)getDataEntriesTotalCount(); | |||
// } | |||
// | |||
// if (fromIndex < 0 || fromIndex > getDataEntriesTotalCount() - 1) { | |||
// fromIndex = 0; | |||
// } | |||
// | |||
// KVDataEntry[] kvDataEntries = new KVDataEntry[count]; | |||
// byte[] value; | |||
// String key; | |||
// long ver; | |||
// for (int i = 0; i < count; i++) { | |||
// value = baseAccount.dataset.getValuesAtIndex(fromIndex); | |||
// key = baseAccount.dataset.getKeyAtIndex(fromIndex); | |||
// ver = baseAccount.dataset.getVersion(key); | |||
// BytesValue decodeData = BinaryProtocol.decode(value); | |||
// kvDataEntries[i] = new KVDataObject(key, ver, decodeData); | |||
// fromIndex++; | |||
// } | |||
// | |||
// return kvDataEntries; | |||
// } | |||
// | |||
// /** | |||
// * return the dataAccount's kv total count; | |||
// * | |||
// * @param | |||
// * @param | |||
// * @return return total count; | |||
// */ | |||
// public long getDataEntriesTotalCount() { | |||
// if(baseAccount == null){ | |||
// return 0; | |||
// } | |||
// return baseAccount.dataset.getDataCount(); | |||
// } | |||
} |
@@ -1,113 +1,113 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class DataAccountSet implements Transactional, DataAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
/** | |||
* 返回账户的存在性证明; | |||
*/ | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return accountSet.getProof(address); | |||
} | |||
public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { | |||
// TODO: 未实现对地址签名的校验和记录; | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public DataAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
/** | |||
* 返回数据账户; <br> | |||
* 如果不存在,则返回 null; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public DataAccount getAccount(Bytes address) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
if (accBase == null) { | |||
return null; | |||
} | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public DataAccount getAccount(Bytes address, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class DataAccountSet implements Transactional, DataAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, accessPolicy); | |||
} | |||
public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(prefix), exStorage, verStorage, | |||
readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
/** | |||
* 返回账户的存在性证明; | |||
*/ | |||
@Override | |||
public MerkleProof getProof(Bytes address) { | |||
return accountSet.getProof(address); | |||
} | |||
public DataAccount register(Bytes address, PubKey pubKey, DigitalSignature addressSignature) { | |||
// TODO: 未实现对地址签名的校验和记录; | |||
CompositeAccount accBase = accountSet.register(address, pubKey); | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public DataAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
/** | |||
* 返回数据账户; <br> | |||
* 如果不存在,则返回 null; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public DataAccount getAccount(Bytes address) { | |||
CompositeAccount accBase = accountSet.getAccount(address); | |||
if (accBase == null) { | |||
return null; | |||
} | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public DataAccount getAccount(Bytes address, long version) { | |||
CompositeAccount accBase = accountSet.getAccount(address, version); | |||
return new DataAccount(accBase); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
} |
@@ -1,481 +1,481 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.ledger.LedgerAdminSettings; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerMetadata_V2; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.UserAuthorizationSettings; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class LedgerAdminDataset implements Transactional, LedgerAdminDataQuery, LedgerAdminSettings { | |||
static { | |||
DataContractRegistry.register(LedgerMetadata.class); | |||
DataContractRegistry.register(LedgerMetadata_V2.class); | |||
} | |||
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminDataset.class); | |||
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_SETTING_PREFIX = "SET" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String ROLE_PRIVILEGE_PREFIX = "RPV" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String USER_ROLE_PREFIX = "URO" + LedgerConsts.KEY_SEPERATOR; | |||
private final Bytes metaPrefix; | |||
private final Bytes settingPrefix; | |||
private LedgerMetadata_V2 origMetadata; | |||
private LedgerMetadataInfo metadata; | |||
/** | |||
* 原来的账本设置; | |||
* | |||
* <br> | |||
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效; | |||
*/ | |||
private LedgerSettings previousSettings; | |||
private HashDigest previousSettingHash; | |||
/** | |||
* 账本的参与节点; | |||
*/ | |||
private ParticipantDataset participants; | |||
/** | |||
* “角色-权限”数据集; | |||
*/ | |||
private RolePrivilegeDataset rolePrivileges; | |||
/** | |||
* “用户-角色”数据集; | |||
*/ | |||
private UserRoleDataset userRoles; | |||
/** | |||
* 账本参数配置; | |||
*/ | |||
private LedgerSettings settings; | |||
private ExPolicyKVStorage storage; | |||
private HashDigest adminDataHash; | |||
private boolean readonly; | |||
private boolean updated; | |||
public HashDigest getHash() { | |||
return adminDataHash; | |||
} | |||
public boolean isReadonly() { | |||
return readonly; | |||
} | |||
void setReadonly() { | |||
this.readonly = true; | |||
} | |||
public LedgerSettings getPreviousSetting() { | |||
return previousSettings; | |||
} | |||
@Override | |||
public RolePrivilegeSettings getRolePrivileges() { | |||
return rolePrivileges; | |||
} | |||
@Override | |||
public UserAuthorizationSettings getAuthorizations() { | |||
return userRoles; | |||
} | |||
@Override | |||
public LedgerAdminSettings getAdminInfo() { | |||
return this; | |||
} | |||
/** | |||
* 初始化账本的管理账户; | |||
* | |||
* <br> | |||
* | |||
* 只在新建账本时调用此方法; | |||
* | |||
* @param ledgerSeed | |||
* @param settings | |||
* @param partiList | |||
* @param exPolicyStorage | |||
* @param versioningStorage | |||
*/ | |||
public LedgerAdminDataset(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
ParticipantNode[] parties = initSetting.getConsensusParticipants(); | |||
if (parties.length == 0) { | |||
throw new LedgerException("No participant!"); | |||
} | |||
// 初始化元数据; | |||
this.metadata = new LedgerMetadataInfo(); | |||
this.metadata.setSeed(initSetting.getLedgerSeed()); | |||
// 新配置; | |||
this.settings = new LedgerConfiguration(initSetting.getConsensusProvider(), initSetting.getConsensusSettings(), | |||
initSetting.getCryptoSetting()); | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = null; | |||
this.adminDataHash = null; | |||
// 基于原配置初始化参与者列表; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(previousSettings.getCryptoSetting(), partiPrefix, exPolicyStorage, | |||
versioningStorage); | |||
for (ParticipantNode p : parties) { | |||
this.participants.addConsensusParticipant(p); | |||
} | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(this.settings.getCryptoSetting(), rolePrivilegePrefix, | |||
exPolicyStorage, versioningStorage); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(this.settings.getCryptoSetting(), userRolePrefix, exPolicyStorage, | |||
versioningStorage); | |||
// 初始化其它属性; | |||
this.storage = exPolicyStorage; | |||
this.readonly = false; | |||
} | |||
public LedgerAdminDataset(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage, | |||
VersioningKVStorage versioningKVStorage, boolean readonly) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
this.storage = kvStorage; | |||
this.readonly = readonly; | |||
this.origMetadata = loadAndVerifyMetadata(adminAccountHash); | |||
this.metadata = new LedgerMetadataInfo(origMetadata); | |||
this.settings = loadAndVerifySettings(metadata.getSettingsHash()); | |||
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储; | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = metadata.getSettingsHash(); | |||
this.adminDataHash = adminAccountHash; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(metadata.getParticipantsHash(), previousSettings.getCryptoSetting(), | |||
partiPrefix, kvStorage, versioningKVStorage, readonly); | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(metadata.getRolePrivilegesHash(), | |||
previousSettings.getCryptoSetting(), rolePrivilegePrefix, kvStorage, versioningKVStorage, readonly); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(metadata.getUserRolesHash(), previousSettings.getCryptoSetting(), | |||
userRolePrefix, kvStorage, versioningKVStorage, readonly); | |||
} | |||
private LedgerSettings loadAndVerifySettings(HashDigest settingsHash) { | |||
if (settingsHash == null) { | |||
return null; | |||
} | |||
Bytes key = encodeSettingsKey(settingsHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(settingsHash.getAlgorithm()); | |||
if (!hashFunc.verify(settingsHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger setting failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeSettings(bytes); | |||
} | |||
private LedgerSettings deserializeSettings(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeSetting(LedgerSettings setting) { | |||
return BinaryProtocol.encode(setting, LedgerSettings.class); | |||
} | |||
private LedgerMetadata_V2 loadAndVerifyMetadata(HashDigest adminAccountHash) { | |||
Bytes key = encodeMetadataKey(adminAccountHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm()); | |||
if (!hashFunc.verify(adminAccountHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger metadata failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeMetadata(bytes); | |||
} | |||
private Bytes encodeSettingsKey(HashDigest settingsHash) { | |||
return settingPrefix.concat(settingsHash); | |||
} | |||
private Bytes encodeMetadataKey(HashDigest metadataHash) { | |||
// return LEDGER_META_PREFIX + metadataHash; | |||
// return metaPrefix + metadataHash; | |||
return metaPrefix.concat(metadataHash); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata() | |||
*/ | |||
@Override | |||
public LedgerMetadata_V2 getMetadata() { | |||
return metadata; | |||
} | |||
// /** | |||
// * 返回原来的账本配置; | |||
// * | |||
// * <br> | |||
// * 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSettings)} 做出了新的更改; | |||
// * | |||
// * @return | |||
// */ | |||
// public LedgerSettings getPreviousSetting() { | |||
// return previousSettings; | |||
// } | |||
/** | |||
* 返回当前设置的账本配置; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public LedgerSettings getSettings() { | |||
return settings; | |||
} | |||
/** | |||
* 更新账本配置; | |||
* | |||
* @param ledgerSetting | |||
*/ | |||
public void setLedgerSetting(LedgerSettings ledgerSetting) { | |||
if (readonly) { | |||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||
} | |||
settings = ledgerSetting; | |||
updated = true; | |||
} | |||
@Override | |||
public long getParticipantCount() { | |||
return participants.getParticipantCount(); | |||
} | |||
@Override | |||
public ParticipantNode[] getParticipants() { | |||
return participants.getParticipants(); | |||
} | |||
@Override | |||
public ParticipantDataset getParticipantDataset() { | |||
return participants; | |||
} | |||
/** | |||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||
* | |||
* @param participant | |||
*/ | |||
public void addParticipant(ParticipantNode participant) { | |||
participants.addConsensusParticipant(participant); | |||
} | |||
/** | |||
* 更新参与方的状态参数; | |||
* | |||
* @param participant | |||
*/ | |||
public void updateParticipant(ParticipantNode participant) { | |||
participants.updateConsensusParticipant(participant); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return updated || participants.isUpdated() || rolePrivileges.isUpdated() || userRoles.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
// 计算并更新参与方集合的根哈希; | |||
participants.commit(); | |||
metadata.setParticipantsHash(participants.getRootHash()); | |||
// 计算并更新角色权限集合的根哈希; | |||
rolePrivileges.commit(); | |||
metadata.setRolePrivilegesHash(rolePrivileges.getRootHash()); | |||
// 计算并更新用户角色授权集合的根哈希; | |||
userRoles.commit(); | |||
metadata.setUserRolesHash(userRoles.getRootHash()); | |||
// 当前区块上下文的密码参数设置的哈希函数; | |||
HashFunction hashFunc = Crypto.getHashFunction(previousSettings.getCryptoSetting().getHashAlgorithm()); | |||
// 计算并更新参数配置的哈希; | |||
if (settings == null) { | |||
throw new LedgerException("Missing ledger settings!"); | |||
} | |||
byte[] settingsBytes = serializeSetting(settings); | |||
HashDigest settingsHash = hashFunc.hash(settingsBytes); | |||
metadata.setSettingsHash(settingsHash); | |||
if (previousSettingHash == null || !previousSettingHash.equals(settingsHash)) { | |||
Bytes settingsKey = encodeSettingsKey(settingsHash); | |||
boolean nx = storage.set(settingsKey, settingsBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = settingsHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
} | |||
// 基于之前的密码配置来计算元数据的哈希; | |||
byte[] metadataBytes = serializeMetadata(metadata); | |||
HashDigest metadataHash = hashFunc.hash(metadataBytes); | |||
if (adminDataHash == null || !adminDataHash.equals(metadataHash)) { | |||
// update modify; | |||
// String base58MetadataHash = metadataHash.toBase58(); | |||
// String metadataKey = encodeMetadataKey(base58MetadataHash); | |||
Bytes metadataKey = encodeMetadataKey(metadataHash); | |||
boolean nx = storage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = metadataHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
adminDataHash = metadataHash; | |||
} | |||
updated = false; | |||
} | |||
private LedgerMetadata_V2 deserializeMetadata(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeMetadata(LedgerMetadataInfo config) { | |||
return BinaryProtocol.encode(config, LedgerMetadata_V2.class); | |||
} | |||
@Override | |||
public void cancel() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
participants.cancel(); | |||
metadata =origMetadata == null ? new LedgerMetadataInfo() : new LedgerMetadataInfo(origMetadata); | |||
} | |||
public static class LedgerMetadataInfo implements LedgerMetadata_V2 { | |||
private byte[] seed; | |||
// private LedgerSetting setting; | |||
private HashDigest participantsHash; | |||
private HashDigest settingsHash; | |||
private HashDigest rolePrivilegesHash; | |||
private HashDigest userRolesHash; | |||
public LedgerMetadataInfo() { | |||
} | |||
public LedgerMetadataInfo(LedgerMetadata_V2 metadata) { | |||
this.seed = metadata.getSeed(); | |||
this.participantsHash = metadata.getParticipantsHash(); | |||
this.settingsHash = metadata.getSettingsHash(); | |||
this.rolePrivilegesHash = metadata.getRolePrivilegesHash(); | |||
this.userRolesHash = metadata.getUserRolesHash(); | |||
} | |||
@Override | |||
public byte[] getSeed() { | |||
return seed; | |||
} | |||
@Override | |||
public HashDigest getSettingsHash() { | |||
return settingsHash; | |||
} | |||
@Override | |||
public HashDigest getParticipantsHash() { | |||
return participantsHash; | |||
} | |||
@Override | |||
public HashDigest getRolePrivilegesHash() { | |||
return rolePrivilegesHash; | |||
} | |||
@Override | |||
public HashDigest getUserRolesHash() { | |||
return userRolesHash; | |||
} | |||
public void setSeed(byte[] seed) { | |||
this.seed = seed; | |||
} | |||
public void setSettingsHash(HashDigest settingHash) { | |||
this.settingsHash = settingHash; | |||
} | |||
public void setParticipantsHash(HashDigest participantsHash) { | |||
this.participantsHash = participantsHash; | |||
} | |||
public void setRolePrivilegesHash(HashDigest rolePrivilegesHash) { | |||
this.rolePrivilegesHash = rolePrivilegesHash; | |||
} | |||
public void setUserRolesHash(HashDigest userRolesHash) { | |||
this.userRolesHash = userRolesHash; | |||
} | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.HashFunction; | |||
import com.jd.blockchain.ledger.LedgerAdminSettings; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerMetadata_V2; | |||
import com.jd.blockchain.ledger.LedgerSettings; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.RolePrivilegeSettings; | |||
import com.jd.blockchain.ledger.UserAuthorizationSettings; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage.ExPolicy; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class LedgerAdminDataset implements Transactional, LedgerAdminDataQuery, LedgerAdminSettings { | |||
static { | |||
DataContractRegistry.register(LedgerMetadata.class); | |||
DataContractRegistry.register(LedgerMetadata_V2.class); | |||
} | |||
private static Logger LOGGER = LoggerFactory.getLogger(LedgerAdminDataset.class); | |||
public static final String LEDGER_META_PREFIX = "MTA" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_PARTICIPANT_PREFIX = "PAR" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String LEDGER_SETTING_PREFIX = "SET" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String ROLE_PRIVILEGE_PREFIX = "RPV" + LedgerConsts.KEY_SEPERATOR; | |||
public static final String USER_ROLE_PREFIX = "URO" + LedgerConsts.KEY_SEPERATOR; | |||
private final Bytes metaPrefix; | |||
private final Bytes settingPrefix; | |||
private LedgerMetadata_V2 origMetadata; | |||
private LedgerMetadataInfo metadata; | |||
/** | |||
* 原来的账本设置; | |||
* | |||
* <br> | |||
* 对 LedgerMetadata 修改的新配置不能立即生效,需要达成共识后,在下一次区块计算中才生效; | |||
*/ | |||
private LedgerSettings previousSettings; | |||
private HashDigest previousSettingHash; | |||
/** | |||
* 账本的参与节点; | |||
*/ | |||
private ParticipantDataset participants; | |||
/** | |||
* “角色-权限”数据集; | |||
*/ | |||
private RolePrivilegeDataset rolePrivileges; | |||
/** | |||
* “用户-角色”数据集; | |||
*/ | |||
private UserRoleDataset userRoles; | |||
/** | |||
* 账本参数配置; | |||
*/ | |||
private LedgerSettings settings; | |||
private ExPolicyKVStorage storage; | |||
private HashDigest adminDataHash; | |||
private boolean readonly; | |||
private boolean updated; | |||
public HashDigest getHash() { | |||
return adminDataHash; | |||
} | |||
public boolean isReadonly() { | |||
return readonly; | |||
} | |||
void setReadonly() { | |||
this.readonly = true; | |||
} | |||
public LedgerSettings getPreviousSetting() { | |||
return previousSettings; | |||
} | |||
@Override | |||
public RolePrivilegeSettings getRolePrivileges() { | |||
return rolePrivileges; | |||
} | |||
@Override | |||
public UserAuthorizationSettings getAuthorizations() { | |||
return userRoles; | |||
} | |||
@Override | |||
public LedgerAdminSettings getAdminInfo() { | |||
return this; | |||
} | |||
/** | |||
* 初始化账本的管理账户; | |||
* | |||
* <br> | |||
* | |||
* 只在新建账本时调用此方法; | |||
* | |||
* @param ledgerSeed | |||
* @param settings | |||
* @param partiList | |||
* @param exPolicyStorage | |||
* @param versioningStorage | |||
*/ | |||
public LedgerAdminDataset(LedgerInitSetting initSetting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
VersioningKVStorage versioningStorage) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
ParticipantNode[] parties = initSetting.getConsensusParticipants(); | |||
if (parties.length == 0) { | |||
throw new LedgerException("No participant!"); | |||
} | |||
// 初始化元数据; | |||
this.metadata = new LedgerMetadataInfo(); | |||
this.metadata.setSeed(initSetting.getLedgerSeed()); | |||
// 新配置; | |||
this.settings = new LedgerConfiguration(initSetting.getConsensusProvider(), initSetting.getConsensusSettings(), | |||
initSetting.getCryptoSetting()); | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = null; | |||
this.adminDataHash = null; | |||
// 基于原配置初始化参与者列表; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(previousSettings.getCryptoSetting(), partiPrefix, exPolicyStorage, | |||
versioningStorage); | |||
for (ParticipantNode p : parties) { | |||
this.participants.addConsensusParticipant(p); | |||
} | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(this.settings.getCryptoSetting(), rolePrivilegePrefix, | |||
exPolicyStorage, versioningStorage); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(this.settings.getCryptoSetting(), userRolePrefix, exPolicyStorage, | |||
versioningStorage); | |||
// 初始化其它属性; | |||
this.storage = exPolicyStorage; | |||
this.readonly = false; | |||
} | |||
public LedgerAdminDataset(HashDigest adminAccountHash, String keyPrefix, ExPolicyKVStorage kvStorage, | |||
VersioningKVStorage versioningKVStorage, boolean readonly) { | |||
this.metaPrefix = Bytes.fromString(keyPrefix + LEDGER_META_PREFIX); | |||
this.settingPrefix = Bytes.fromString(keyPrefix + LEDGER_SETTING_PREFIX); | |||
this.storage = kvStorage; | |||
this.readonly = readonly; | |||
this.origMetadata = loadAndVerifyMetadata(adminAccountHash); | |||
this.metadata = new LedgerMetadataInfo(origMetadata); | |||
this.settings = loadAndVerifySettings(metadata.getSettingsHash()); | |||
// 复制记录一份配置作为上一个区块的原始配置,该实例仅供读取,不做修改,也不会回写到存储; | |||
this.previousSettings = new LedgerConfiguration(settings); | |||
this.previousSettingHash = metadata.getSettingsHash(); | |||
this.adminDataHash = adminAccountHash; | |||
String partiPrefix = keyPrefix + LEDGER_PARTICIPANT_PREFIX; | |||
this.participants = new ParticipantDataset(metadata.getParticipantsHash(), previousSettings.getCryptoSetting(), | |||
partiPrefix, kvStorage, versioningKVStorage, readonly); | |||
String rolePrivilegePrefix = keyPrefix + ROLE_PRIVILEGE_PREFIX; | |||
this.rolePrivileges = new RolePrivilegeDataset(metadata.getRolePrivilegesHash(), | |||
previousSettings.getCryptoSetting(), rolePrivilegePrefix, kvStorage, versioningKVStorage, readonly); | |||
String userRolePrefix = keyPrefix + USER_ROLE_PREFIX; | |||
this.userRoles = new UserRoleDataset(metadata.getUserRolesHash(), previousSettings.getCryptoSetting(), | |||
userRolePrefix, kvStorage, versioningKVStorage, readonly); | |||
} | |||
private LedgerSettings loadAndVerifySettings(HashDigest settingsHash) { | |||
if (settingsHash == null) { | |||
return null; | |||
} | |||
Bytes key = encodeSettingsKey(settingsHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(settingsHash.getAlgorithm()); | |||
if (!hashFunc.verify(settingsHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger setting failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeSettings(bytes); | |||
} | |||
private LedgerSettings deserializeSettings(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeSetting(LedgerSettings setting) { | |||
return BinaryProtocol.encode(setting, LedgerSettings.class); | |||
} | |||
private LedgerMetadata_V2 loadAndVerifyMetadata(HashDigest adminAccountHash) { | |||
Bytes key = encodeMetadataKey(adminAccountHash); | |||
byte[] bytes = storage.get(key); | |||
HashFunction hashFunc = Crypto.getHashFunction(adminAccountHash.getAlgorithm()); | |||
if (!hashFunc.verify(adminAccountHash, bytes)) { | |||
String errorMsg = "Verification of the hash for ledger metadata failed! --[HASH=" + key + "]"; | |||
LOGGER.error(errorMsg); | |||
throw new LedgerException(errorMsg); | |||
} | |||
return deserializeMetadata(bytes); | |||
} | |||
private Bytes encodeSettingsKey(HashDigest settingsHash) { | |||
return settingPrefix.concat(settingsHash); | |||
} | |||
private Bytes encodeMetadataKey(HashDigest metadataHash) { | |||
// return LEDGER_META_PREFIX + metadataHash; | |||
// return metaPrefix + metadataHash; | |||
return metaPrefix.concat(metadataHash); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.core.LedgerAdministration#getMetadata() | |||
*/ | |||
@Override | |||
public LedgerMetadata_V2 getMetadata() { | |||
return metadata; | |||
} | |||
// /** | |||
// * 返回原来的账本配置; | |||
// * | |||
// * <br> | |||
// * 此方法总是返回从上一个区块加载的账本配置,即时调用 {@link #setLedgerSetting(LedgerSettings)} 做出了新的更改; | |||
// * | |||
// * @return | |||
// */ | |||
// public LedgerSettings getPreviousSetting() { | |||
// return previousSettings; | |||
// } | |||
/** | |||
* 返回当前设置的账本配置; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public LedgerSettings getSettings() { | |||
return settings; | |||
} | |||
/** | |||
* 更新账本配置; | |||
* | |||
* @param ledgerSetting | |||
*/ | |||
public void setLedgerSetting(LedgerSettings ledgerSetting) { | |||
if (readonly) { | |||
throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||
} | |||
settings = ledgerSetting; | |||
updated = true; | |||
} | |||
@Override | |||
public long getParticipantCount() { | |||
return participants.getParticipantCount(); | |||
} | |||
@Override | |||
public ParticipantNode[] getParticipants() { | |||
return participants.getParticipants(); | |||
} | |||
@Override | |||
public ParticipantDataset getParticipantDataset() { | |||
return participants; | |||
} | |||
/** | |||
* 加入新的参与方; 如果指定的参与方已经存在,则引发 LedgerException 异常; | |||
* | |||
* @param participant | |||
*/ | |||
public void addParticipant(ParticipantNode participant) { | |||
participants.addConsensusParticipant(participant); | |||
} | |||
/** | |||
* 更新参与方的状态参数; | |||
* | |||
* @param participant | |||
*/ | |||
public void updateParticipant(ParticipantNode participant) { | |||
participants.updateConsensusParticipant(participant); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return updated || participants.isUpdated() || rolePrivileges.isUpdated() || userRoles.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
// 计算并更新参与方集合的根哈希; | |||
participants.commit(); | |||
metadata.setParticipantsHash(participants.getRootHash()); | |||
// 计算并更新角色权限集合的根哈希; | |||
rolePrivileges.commit(); | |||
metadata.setRolePrivilegesHash(rolePrivileges.getRootHash()); | |||
// 计算并更新用户角色授权集合的根哈希; | |||
userRoles.commit(); | |||
metadata.setUserRolesHash(userRoles.getRootHash()); | |||
// 当前区块上下文的密码参数设置的哈希函数; | |||
HashFunction hashFunc = Crypto.getHashFunction(previousSettings.getCryptoSetting().getHashAlgorithm()); | |||
// 计算并更新参数配置的哈希; | |||
if (settings == null) { | |||
throw new LedgerException("Missing ledger settings!"); | |||
} | |||
byte[] settingsBytes = serializeSetting(settings); | |||
HashDigest settingsHash = hashFunc.hash(settingsBytes); | |||
metadata.setSettingsHash(settingsHash); | |||
if (previousSettingHash == null || !previousSettingHash.equals(settingsHash)) { | |||
Bytes settingsKey = encodeSettingsKey(settingsHash); | |||
boolean nx = storage.set(settingsKey, settingsBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = settingsHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
} | |||
// 基于之前的密码配置来计算元数据的哈希; | |||
byte[] metadataBytes = serializeMetadata(metadata); | |||
HashDigest metadataHash = hashFunc.hash(metadataBytes); | |||
if (adminDataHash == null || !adminDataHash.equals(metadataHash)) { | |||
// update modify; | |||
// String base58MetadataHash = metadataHash.toBase58(); | |||
// String metadataKey = encodeMetadataKey(base58MetadataHash); | |||
Bytes metadataKey = encodeMetadataKey(metadataHash); | |||
boolean nx = storage.set(metadataKey, metadataBytes, ExPolicy.NOT_EXISTING); | |||
if (!nx) { | |||
String base58MetadataHash = metadataHash.toBase58(); | |||
// 有可能发生了并发写入冲突,不同的节点都向同一个存储服务器上写入数据; | |||
String errMsg = "Ledger metadata already exist! --[MetadataHash=" + base58MetadataHash + "]"; | |||
LOGGER.warn(errMsg); | |||
throw new LedgerException(errMsg); | |||
} | |||
adminDataHash = metadataHash; | |||
} | |||
updated = false; | |||
} | |||
private LedgerMetadata_V2 deserializeMetadata(byte[] bytes) { | |||
return BinaryProtocol.decode(bytes); | |||
} | |||
private byte[] serializeMetadata(LedgerMetadataInfo config) { | |||
return BinaryProtocol.encode(config, LedgerMetadata_V2.class); | |||
} | |||
@Override | |||
public void cancel() { | |||
if (!isUpdated()) { | |||
return; | |||
} | |||
participants.cancel(); | |||
metadata =origMetadata == null ? new LedgerMetadataInfo() : new LedgerMetadataInfo(origMetadata); | |||
} | |||
public static class LedgerMetadataInfo implements LedgerMetadata_V2 { | |||
private byte[] seed; | |||
// private LedgerSetting setting; | |||
private HashDigest participantsHash; | |||
private HashDigest settingsHash; | |||
private HashDigest rolePrivilegesHash; | |||
private HashDigest userRolesHash; | |||
public LedgerMetadataInfo() { | |||
} | |||
public LedgerMetadataInfo(LedgerMetadata_V2 metadata) { | |||
this.seed = metadata.getSeed(); | |||
this.participantsHash = metadata.getParticipantsHash(); | |||
this.settingsHash = metadata.getSettingsHash(); | |||
this.rolePrivilegesHash = metadata.getRolePrivilegesHash(); | |||
this.userRolesHash = metadata.getUserRolesHash(); | |||
} | |||
@Override | |||
public byte[] getSeed() { | |||
return seed; | |||
} | |||
@Override | |||
public HashDigest getSettingsHash() { | |||
return settingsHash; | |||
} | |||
@Override | |||
public HashDigest getParticipantsHash() { | |||
return participantsHash; | |||
} | |||
@Override | |||
public HashDigest getRolePrivilegesHash() { | |||
return rolePrivilegesHash; | |||
} | |||
@Override | |||
public HashDigest getUserRolesHash() { | |||
return userRolesHash; | |||
} | |||
public void setSeed(byte[] seed) { | |||
this.seed = seed; | |||
} | |||
public void setSettingsHash(HashDigest settingHash) { | |||
this.settingsHash = settingHash; | |||
} | |||
public void setParticipantsHash(HashDigest participantsHash) { | |||
this.participantsHash = participantsHash; | |||
} | |||
public void setRolePrivilegesHash(HashDigest rolePrivilegesHash) { | |||
this.rolePrivilegesHash = rolePrivilegesHash; | |||
} | |||
public void setUserRolesHash(HashDigest userRolesHash) { | |||
this.userRolesHash = userRolesHash; | |||
} | |||
} | |||
} |
@@ -1,411 +1,411 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<CompositeAccount> { | |||
static { | |||
DataContractRegistry.register(MerkleSnapshot.class); | |||
DataContractRegistry.register(BlockchainIdentity.class); | |||
} | |||
private final Bytes keyPrefix; | |||
/** | |||
* 账户根哈希的数据集; | |||
*/ | |||
private MerkleDataSet merkleDataset; | |||
/** | |||
* The cache of latest version accounts, including accounts getting by querying | |||
* and by new regiestering ; | |||
* | |||
*/ | |||
// TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; | |||
private Map<Bytes, InnerMerkleAccount> latestAccountsCache = new HashMap<>(); | |||
private ExPolicyKVStorage baseExStorage; | |||
private VersioningKVStorage baseVerStorage; | |||
private CryptoSetting cryptoSetting; | |||
private volatile boolean updated; | |||
private AccountAccessPolicy accessPolicy; | |||
public boolean isReadonly() { | |||
return merkleDataset.isReadonly(); | |||
} | |||
void setReadonly() { | |||
merkleDataset.setReadonly(); | |||
} | |||
public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); | |||
} | |||
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
this.keyPrefix = keyPrefix; | |||
this.cryptoSetting = cryptoSetting; | |||
this.baseExStorage = exStorage; | |||
this.baseVerStorage = verStorage; | |||
this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, | |||
this.baseVerStorage, readonly); | |||
this.accessPolicy = accessPolicy; | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return merkleDataset.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return merkleDataset.getProof(key); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
DataEntry<Bytes, byte[]>[] results = merkleDataset.getLatestDataEntries(fromIndex, count); | |||
BlockchainIdentity[] ids = new BlockchainIdentity[results.length]; | |||
for (int i = 0; i < results.length; i++) { | |||
InnerMerkleAccount account = createAccount(results[i].getKey(), new HashDigest(results[i].getValue()), | |||
results[i].getVersion(), true); | |||
ids[i] = account.getID(); | |||
} | |||
return ids; | |||
} | |||
/** | |||
* 返回账户的总数量; | |||
* | |||
* @return | |||
*/ | |||
public long getTotal() { | |||
return merkleDataset.getDataCount(); | |||
} | |||
@Override | |||
public CompositeAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
/** | |||
* 返回最新版本的 Account; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public CompositeAccount getAccount(Bytes address) { | |||
return this.getAccount(address, -1); | |||
} | |||
/** | |||
* 账户是否存在;<br> | |||
* | |||
* 如果指定的账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 | |||
* {@link #commit()} 方法),此方法对该账户仍然返回 false; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
public boolean contains(Bytes address) { | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 无论是新注册未提交的,还是缓存已提交的账户实例,都认为是存在; | |||
return true; | |||
} | |||
long latestVersion = merkleDataset.getVersion(address); | |||
return latestVersion > -1; | |||
} | |||
/** | |||
* 返回指定账户的版本; <br> | |||
* 如果账户已经注册,则返回该账户的最新版本,值大于等于 0; <br> | |||
* 如果账户不存在,则返回 -1;<br> | |||
* 如果账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 {@link #commit()} | |||
* 方法),则返回 -1; <br> | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
public long getVersion(Bytes address) { | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 已注册尚未提交,也返回 -1; | |||
return acc.getVersion(); | |||
} | |||
return merkleDataset.getVersion(address); | |||
} | |||
/** | |||
* 返回指定版本的 Account; | |||
* | |||
* 只有最新版本的账户才能可写的,其它都是只读; | |||
* | |||
* @param address 账户地址; | |||
* @param version 账户版本;如果指定为 -1,则返回最新版本; | |||
* @return | |||
*/ | |||
public CompositeAccount getAccount(Bytes address, long version) { | |||
version = version < 0 ? -1 : version; | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null && version == -1) { | |||
return acc; | |||
} else if (acc != null && acc.getVersion() == version) { | |||
return acc; | |||
} | |||
long latestVersion = merkleDataset.getVersion(address); | |||
if (latestVersion < 0) { | |||
// Not exist; | |||
return null; | |||
} | |||
if (version > latestVersion) { | |||
return null; | |||
} | |||
// 如果是不存在的,或者刚刚新增未提交的账户,则前面一步查询到的 latestVersion 小于 0, 代码不会执行到此; | |||
if (acc != null && acc.getVersion() != latestVersion) { | |||
// 当执行到此处时,并且缓冲列表中缓存了最新的版本, | |||
// 如果当前缓存的最新账户的版本和刚刚从存储中检索得到的最新版本不一致,可能存在外部的并发更新,这超出了系统设计的逻辑; | |||
// TODO:如果是今后扩展至集群方案时,这种不一致的原因可能是由其它集群节点实例执行了更新,这种情况下,最好是放弃旧缓存,并重新加载和缓存最新版本; | |||
// by huanghaiquan at 2018-9-2 23:03:00; | |||
throw new IllegalStateException("The latest version in cache is not equals the latest version in storage! " | |||
+ "Mybe some asynchronzing updating are performed out of current server."); | |||
} | |||
// Now, be sure that "acc == null", so get account from storage; | |||
// Set readonly for the old version account; | |||
boolean readonly = (version > -1 && version < latestVersion) || isReadonly(); | |||
long qVersion = version == -1 ? latestVersion : version; | |||
// load account from storage; | |||
acc = loadAccount(address, readonly, qVersion); | |||
if (acc == null) { | |||
return null; | |||
} | |||
if (!readonly) { | |||
// cache the latest version witch enable reading and writing; | |||
// readonly version of account not necessary to be cached; | |||
latestAccountsCache.put(address, acc); | |||
} | |||
return acc; | |||
} | |||
public CompositeAccount register(Bytes address, PubKey pubKey) { | |||
return register(new BlockchainIdentityData(address, pubKey)); | |||
} | |||
/** | |||
* 注册一个新账户; <br> | |||
* | |||
* 如果账户已经存在,则会引发 {@link LedgerException} 异常; <br> | |||
* | |||
* 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; | |||
* | |||
* @param address 区块链地址; | |||
* @param pubKey 公钥; | |||
* @return 注册成功的账户对象; | |||
*/ | |||
public CompositeAccount register(BlockchainIdentity accountId) { | |||
if (isReadonly()) { | |||
throw new IllegalArgumentException("This AccountSet is readonly!"); | |||
} | |||
Bytes address = accountId.getAddress(); | |||
PubKey pubKey = accountId.getPubKey(); | |||
verifyAddressEncoding(address, pubKey); | |||
InnerMerkleAccount cachedAcc = latestAccountsCache.get(address); | |||
if (cachedAcc != null) { | |||
if (cachedAcc.getVersion() < 0) { | |||
// 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; | |||
return cachedAcc; | |||
} | |||
// 相同的账户已经存在; | |||
throw new LedgerException("The registering account already exist!"); | |||
} | |||
long version = merkleDataset.getVersion(address); | |||
if (version >= 0) { | |||
throw new LedgerException("The registering account already exist!"); | |||
} | |||
if (!accessPolicy.checkRegistering(address, pubKey)) { | |||
throw new LedgerException("Account Registering was rejected for the access policy!"); | |||
} | |||
Bytes prefix = keyPrefix.concat(address); | |||
InnerMerkleAccount acc = createInstance(accountId, cryptoSetting, prefix); | |||
latestAccountsCache.put(address, acc); | |||
updated = true; | |||
return acc; | |||
} | |||
private void verifyAddressEncoding(Bytes address, PubKey pubKey) { | |||
Bytes chAddress = AddressEncoding.generateAddress(pubKey); | |||
if (!chAddress.equals(address)) { | |||
throw new LedgerException("The registering Address mismatch the specified PubKey!"); | |||
} | |||
} | |||
private InnerMerkleAccount createInstance(BlockchainIdentity header, CryptoSetting cryptoSetting, Bytes keyPrefix) { | |||
return new InnerMerkleAccount(header, cryptoSetting, keyPrefix, baseExStorage, baseVerStorage); | |||
} | |||
/** | |||
* 加载指定版本的账户; | |||
* | |||
* @param address 账户地址; | |||
* @param readonly 是否只读; | |||
* @param version 账户的版本;大于等于 0 ; | |||
* @return | |||
*/ | |||
private InnerMerkleAccount loadAccount(Bytes address, boolean readonly, long version) { | |||
byte[] rootHashBytes = merkleDataset.getValue(address, version); | |||
if (rootHashBytes == null) { | |||
return null; | |||
} | |||
HashDigest rootHash = new HashDigest(rootHashBytes); | |||
return createAccount(address, rootHash, version, readonly); | |||
} | |||
private InnerMerkleAccount createAccount(Bytes address, HashDigest rootHash, long version, boolean readonly) { | |||
// prefix; | |||
Bytes prefix = keyPrefix.concat(address); | |||
return new InnerMerkleAccount(address, version, rootHash, cryptoSetting, prefix, baseExStorage, baseVerStorage, | |||
readonly); | |||
} | |||
// TODO:优化:区块链身份(地址+公钥)与其Merkle树根哈希分开独立存储; | |||
// 不必作为一个整块,避免状态数据写入时频繁重写公钥,尤其某些算法的公钥可能很大; | |||
/** | |||
* 保存账户的根哈希,返回账户的新版本; | |||
* | |||
* @param account | |||
* @return | |||
*/ | |||
private long saveAccount(InnerMerkleAccount account) { | |||
// 提交更改,更新哈希; | |||
account.commit(); | |||
return account.getVersion(); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return updated; | |||
} | |||
@Override | |||
public void commit() { | |||
if (!updated) { | |||
return; | |||
} | |||
try { | |||
for (InnerMerkleAccount acc : latestAccountsCache.values()) { | |||
// updated or new created; | |||
if (acc.isUpdated() || acc.getVersion() < 0) { | |||
saveAccount(acc); | |||
} | |||
} | |||
merkleDataset.commit(); | |||
} finally { | |||
updated = false; | |||
latestAccountsCache.clear(); | |||
} | |||
} | |||
@Override | |||
public void cancel() { | |||
if (!updated) { | |||
return; | |||
} | |||
Bytes[] addresses = new Bytes[latestAccountsCache.size()]; | |||
latestAccountsCache.keySet().toArray(addresses); | |||
for (Bytes address : addresses) { | |||
InnerMerkleAccount acc = latestAccountsCache.remove(address); | |||
// cancel; | |||
if (acc.isUpdated()) { | |||
acc.cancel(); | |||
} | |||
} | |||
updated = false; | |||
} | |||
/** | |||
* 内部实现的账户,监听和同步账户数据的变更; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private class InnerMerkleAccount extends MerkleAccount { | |||
private long version; | |||
public InnerMerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { | |||
super(accountID, cryptoSetting, keyPrefix, exStorage, verStorage); | |||
this.version = -1; | |||
} | |||
public InnerMerkleAccount(Bytes address, long version, HashDigest dataRootHash, CryptoSetting cryptoSetting, | |||
Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
super(address, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
this.version = version; | |||
} | |||
@Override | |||
protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { | |||
updated = true; | |||
} | |||
@Override | |||
protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { | |||
long newVersion = merkleDataset.setValue(this.getAddress(), newRootHash.toBytes(), version); | |||
if (newVersion < 0) { | |||
// Update fail; | |||
throw new LedgerException("Account updating fail! --[Address=" + this.getAddress() + "]"); | |||
} | |||
this.version = newVersion; | |||
} | |||
public long getVersion() { | |||
return version; | |||
} | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.BlockchainIdentityData; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.ledger.MerkleSnapshot; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.DataEntry; | |||
import com.jd.blockchain.utils.Transactional; | |||
public class MerkleAccountSet implements Transactional, MerkleProvable, AccountQuery<CompositeAccount> { | |||
static { | |||
DataContractRegistry.register(MerkleSnapshot.class); | |||
DataContractRegistry.register(BlockchainIdentity.class); | |||
} | |||
private final Bytes keyPrefix; | |||
/** | |||
* 账户根哈希的数据集; | |||
*/ | |||
private MerkleDataSet merkleDataset; | |||
/** | |||
* The cache of latest version accounts, including accounts getting by querying | |||
* and by new regiestering ; | |||
* | |||
*/ | |||
// TODO:未考虑大数据量时,由于缺少过期策略,会导致内存溢出的问题; | |||
private Map<Bytes, InnerMerkleAccount> latestAccountsCache = new HashMap<>(); | |||
private ExPolicyKVStorage baseExStorage; | |||
private VersioningKVStorage baseVerStorage; | |||
private CryptoSetting cryptoSetting; | |||
private volatile boolean updated; | |||
private AccountAccessPolicy accessPolicy; | |||
public boolean isReadonly() { | |||
return merkleDataset.isReadonly(); | |||
} | |||
void setReadonly() { | |||
merkleDataset.setReadonly(); | |||
} | |||
public MerkleAccountSet(CryptoSetting cryptoSetting, Bytes keyPrefix, ExPolicyKVStorage exStorage, | |||
VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { | |||
this(null, cryptoSetting, keyPrefix, exStorage, verStorage, false, accessPolicy); | |||
} | |||
public MerkleAccountSet(HashDigest rootHash, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
this.keyPrefix = keyPrefix; | |||
this.cryptoSetting = cryptoSetting; | |||
this.baseExStorage = exStorage; | |||
this.baseVerStorage = verStorage; | |||
this.merkleDataset = new MerkleDataSet(rootHash, cryptoSetting, keyPrefix, this.baseExStorage, | |||
this.baseVerStorage, readonly); | |||
this.accessPolicy = accessPolicy; | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return merkleDataset.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return merkleDataset.getProof(key); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
DataEntry<Bytes, byte[]>[] results = merkleDataset.getLatestDataEntries(fromIndex, count); | |||
BlockchainIdentity[] ids = new BlockchainIdentity[results.length]; | |||
for (int i = 0; i < results.length; i++) { | |||
InnerMerkleAccount account = createAccount(results[i].getKey(), new HashDigest(results[i].getValue()), | |||
results[i].getVersion(), true); | |||
ids[i] = account.getID(); | |||
} | |||
return ids; | |||
} | |||
/** | |||
* 返回账户的总数量; | |||
* | |||
* @return | |||
*/ | |||
public long getTotal() { | |||
return merkleDataset.getDataCount(); | |||
} | |||
@Override | |||
public CompositeAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
/** | |||
* 返回最新版本的 Account; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
@Override | |||
public CompositeAccount getAccount(Bytes address) { | |||
return this.getAccount(address, -1); | |||
} | |||
/** | |||
* 账户是否存在;<br> | |||
* | |||
* 如果指定的账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 | |||
* {@link #commit()} 方法),此方法对该账户仍然返回 false; | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
public boolean contains(Bytes address) { | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 无论是新注册未提交的,还是缓存已提交的账户实例,都认为是存在; | |||
return true; | |||
} | |||
long latestVersion = merkleDataset.getVersion(address); | |||
return latestVersion > -1; | |||
} | |||
/** | |||
* 返回指定账户的版本; <br> | |||
* 如果账户已经注册,则返回该账户的最新版本,值大于等于 0; <br> | |||
* 如果账户不存在,则返回 -1;<br> | |||
* 如果账户已经注册(通过 {@link #register(String, PubKey)} 方法),但尚未提交(通过 {@link #commit()} | |||
* 方法),则返回 -1; <br> | |||
* | |||
* @param address | |||
* @return | |||
*/ | |||
public long getVersion(Bytes address) { | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null) { | |||
// 已注册尚未提交,也返回 -1; | |||
return acc.getVersion(); | |||
} | |||
return merkleDataset.getVersion(address); | |||
} | |||
/** | |||
* 返回指定版本的 Account; | |||
* | |||
* 只有最新版本的账户才能可写的,其它都是只读; | |||
* | |||
* @param address 账户地址; | |||
* @param version 账户版本;如果指定为 -1,则返回最新版本; | |||
* @return | |||
*/ | |||
public CompositeAccount getAccount(Bytes address, long version) { | |||
version = version < 0 ? -1 : version; | |||
InnerMerkleAccount acc = latestAccountsCache.get(address); | |||
if (acc != null && version == -1) { | |||
return acc; | |||
} else if (acc != null && acc.getVersion() == version) { | |||
return acc; | |||
} | |||
long latestVersion = merkleDataset.getVersion(address); | |||
if (latestVersion < 0) { | |||
// Not exist; | |||
return null; | |||
} | |||
if (version > latestVersion) { | |||
return null; | |||
} | |||
// 如果是不存在的,或者刚刚新增未提交的账户,则前面一步查询到的 latestVersion 小于 0, 代码不会执行到此; | |||
if (acc != null && acc.getVersion() != latestVersion) { | |||
// 当执行到此处时,并且缓冲列表中缓存了最新的版本, | |||
// 如果当前缓存的最新账户的版本和刚刚从存储中检索得到的最新版本不一致,可能存在外部的并发更新,这超出了系统设计的逻辑; | |||
// TODO:如果是今后扩展至集群方案时,这种不一致的原因可能是由其它集群节点实例执行了更新,这种情况下,最好是放弃旧缓存,并重新加载和缓存最新版本; | |||
// by huanghaiquan at 2018-9-2 23:03:00; | |||
throw new IllegalStateException("The latest version in cache is not equals the latest version in storage! " | |||
+ "Mybe some asynchronzing updating are performed out of current server."); | |||
} | |||
// Now, be sure that "acc == null", so get account from storage; | |||
// Set readonly for the old version account; | |||
boolean readonly = (version > -1 && version < latestVersion) || isReadonly(); | |||
long qVersion = version == -1 ? latestVersion : version; | |||
// load account from storage; | |||
acc = loadAccount(address, readonly, qVersion); | |||
if (acc == null) { | |||
return null; | |||
} | |||
if (!readonly) { | |||
// cache the latest version witch enable reading and writing; | |||
// readonly version of account not necessary to be cached; | |||
latestAccountsCache.put(address, acc); | |||
} | |||
return acc; | |||
} | |||
public CompositeAccount register(Bytes address, PubKey pubKey) { | |||
return register(new BlockchainIdentityData(address, pubKey)); | |||
} | |||
/** | |||
* 注册一个新账户; <br> | |||
* | |||
* 如果账户已经存在,则会引发 {@link LedgerException} 异常; <br> | |||
* | |||
* 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; | |||
* | |||
* @param address 区块链地址; | |||
* @param pubKey 公钥; | |||
* @return 注册成功的账户对象; | |||
*/ | |||
public CompositeAccount register(BlockchainIdentity accountId) { | |||
if (isReadonly()) { | |||
throw new IllegalArgumentException("This AccountSet is readonly!"); | |||
} | |||
Bytes address = accountId.getAddress(); | |||
PubKey pubKey = accountId.getPubKey(); | |||
verifyAddressEncoding(address, pubKey); | |||
InnerMerkleAccount cachedAcc = latestAccountsCache.get(address); | |||
if (cachedAcc != null) { | |||
if (cachedAcc.getVersion() < 0) { | |||
// 同一个新账户已经注册,但尚未提交,所以重复注册不会引起任何变化; | |||
return cachedAcc; | |||
} | |||
// 相同的账户已经存在; | |||
throw new LedgerException("The registering account already exist!"); | |||
} | |||
long version = merkleDataset.getVersion(address); | |||
if (version >= 0) { | |||
throw new LedgerException("The registering account already exist!"); | |||
} | |||
if (!accessPolicy.checkRegistering(address, pubKey)) { | |||
throw new LedgerException("Account Registering was rejected for the access policy!"); | |||
} | |||
Bytes prefix = keyPrefix.concat(address); | |||
InnerMerkleAccount acc = createInstance(accountId, cryptoSetting, prefix); | |||
latestAccountsCache.put(address, acc); | |||
updated = true; | |||
return acc; | |||
} | |||
private void verifyAddressEncoding(Bytes address, PubKey pubKey) { | |||
Bytes chAddress = AddressEncoding.generateAddress(pubKey); | |||
if (!chAddress.equals(address)) { | |||
throw new LedgerException("The registering Address mismatch the specified PubKey!"); | |||
} | |||
} | |||
private InnerMerkleAccount createInstance(BlockchainIdentity header, CryptoSetting cryptoSetting, Bytes keyPrefix) { | |||
return new InnerMerkleAccount(header, cryptoSetting, keyPrefix, baseExStorage, baseVerStorage); | |||
} | |||
/** | |||
* 加载指定版本的账户; | |||
* | |||
* @param address 账户地址; | |||
* @param readonly 是否只读; | |||
* @param version 账户的版本;大于等于 0 ; | |||
* @return | |||
*/ | |||
private InnerMerkleAccount loadAccount(Bytes address, boolean readonly, long version) { | |||
byte[] rootHashBytes = merkleDataset.getValue(address, version); | |||
if (rootHashBytes == null) { | |||
return null; | |||
} | |||
HashDigest rootHash = new HashDigest(rootHashBytes); | |||
return createAccount(address, rootHash, version, readonly); | |||
} | |||
private InnerMerkleAccount createAccount(Bytes address, HashDigest rootHash, long version, boolean readonly) { | |||
// prefix; | |||
Bytes prefix = keyPrefix.concat(address); | |||
return new InnerMerkleAccount(address, version, rootHash, cryptoSetting, prefix, baseExStorage, baseVerStorage, | |||
readonly); | |||
} | |||
// TODO:优化:区块链身份(地址+公钥)与其Merkle树根哈希分开独立存储; | |||
// 不必作为一个整块,避免状态数据写入时频繁重写公钥,尤其某些算法的公钥可能很大; | |||
/** | |||
* 保存账户的根哈希,返回账户的新版本; | |||
* | |||
* @param account | |||
* @return | |||
*/ | |||
private long saveAccount(InnerMerkleAccount account) { | |||
// 提交更改,更新哈希; | |||
account.commit(); | |||
return account.getVersion(); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return updated; | |||
} | |||
@Override | |||
public void commit() { | |||
if (!updated) { | |||
return; | |||
} | |||
try { | |||
for (InnerMerkleAccount acc : latestAccountsCache.values()) { | |||
// updated or new created; | |||
if (acc.isUpdated() || acc.getVersion() < 0) { | |||
saveAccount(acc); | |||
} | |||
} | |||
merkleDataset.commit(); | |||
} finally { | |||
updated = false; | |||
latestAccountsCache.clear(); | |||
} | |||
} | |||
@Override | |||
public void cancel() { | |||
if (!updated) { | |||
return; | |||
} | |||
Bytes[] addresses = new Bytes[latestAccountsCache.size()]; | |||
latestAccountsCache.keySet().toArray(addresses); | |||
for (Bytes address : addresses) { | |||
InnerMerkleAccount acc = latestAccountsCache.remove(address); | |||
// cancel; | |||
if (acc.isUpdated()) { | |||
acc.cancel(); | |||
} | |||
} | |||
updated = false; | |||
} | |||
/** | |||
* 内部实现的账户,监听和同步账户数据的变更; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private class InnerMerkleAccount extends MerkleAccount { | |||
private long version; | |||
public InnerMerkleAccount(BlockchainIdentity accountID, CryptoSetting cryptoSetting, Bytes keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage) { | |||
super(accountID, cryptoSetting, keyPrefix, exStorage, verStorage); | |||
this.version = -1; | |||
} | |||
public InnerMerkleAccount(Bytes address, long version, HashDigest dataRootHash, CryptoSetting cryptoSetting, | |||
Bytes keyPrefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly) { | |||
super(address, dataRootHash, cryptoSetting, keyPrefix, exStorage, verStorage, readonly); | |||
this.version = version; | |||
} | |||
@Override | |||
protected void onUpdated(String key, TypedValue value, long expectedVersion, long newVersion) { | |||
updated = true; | |||
} | |||
@Override | |||
protected void onCommited(HashDigest previousRootHash, HashDigest newRootHash) { | |||
long newVersion = merkleDataset.setValue(this.getAddress(), newRootHash.toBytes(), version); | |||
if (newVersion < 0) { | |||
// Update fail; | |||
throw new LedgerException("Account updating fail! --[Address=" + this.getAddress() + "]"); | |||
} | |||
this.version = newVersion; | |||
} | |||
public long getVersion() { | |||
return version; | |||
} | |||
} | |||
} |
@@ -1,11 +1,11 @@ | |||
package com.jd.blockchain.ledger.core; | |||
public class Node { | |||
public Node(){ | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
public class Node { | |||
public Node(){ | |||
} | |||
} |
@@ -1,73 +1,73 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.ledger.ParticipantNodeState; | |||
/** | |||
* 参与方证书数据对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class ParticipantCertData implements ParticipantNode { | |||
private int id; | |||
private Bytes address; | |||
private String name; | |||
private PubKey pubKey; | |||
private ParticipantNodeState participantNodeState; | |||
public ParticipantCertData() { | |||
} | |||
public ParticipantCertData(ParticipantNode participantNode) { | |||
this.id = participantNode.getId(); | |||
this.address = participantNode.getAddress(); | |||
this.name = participantNode.getName(); | |||
this.pubKey = participantNode.getPubKey(); | |||
this.participantNodeState = participantNode.getParticipantNodeState(); | |||
} | |||
public ParticipantCertData(Bytes address, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
this.participantNodeState = participantNodeState; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
@Override | |||
public int getId() { | |||
return id; | |||
} | |||
public void setId(int id) { | |||
this.id = id; | |||
} | |||
@Override | |||
public ParticipantNodeState getParticipantNodeState() { | |||
return participantNodeState; | |||
} | |||
public void setParticipantNodeState(ParticipantNodeState participantNodeState) { | |||
this.participantNodeState = participantNodeState; | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.ledger.ParticipantNodeState; | |||
/** | |||
* 参与方证书数据对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class ParticipantCertData implements ParticipantNode { | |||
private int id; | |||
private Bytes address; | |||
private String name; | |||
private PubKey pubKey; | |||
private ParticipantNodeState participantNodeState; | |||
public ParticipantCertData() { | |||
} | |||
public ParticipantCertData(ParticipantNode participantNode) { | |||
this.id = participantNode.getId(); | |||
this.address = participantNode.getAddress(); | |||
this.name = participantNode.getName(); | |||
this.pubKey = participantNode.getPubKey(); | |||
this.participantNodeState = participantNode.getParticipantNodeState(); | |||
} | |||
public ParticipantCertData(Bytes address, String name, PubKey pubKey, ParticipantNodeState participantNodeState) { | |||
this.address = address; | |||
this.name = name; | |||
this.pubKey = pubKey; | |||
this.participantNodeState = participantNodeState; | |||
} | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
@Override | |||
public String getName() { | |||
return name; | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
@Override | |||
public int getId() { | |||
return id; | |||
} | |||
public void setId(int id) { | |||
this.id = id; | |||
} | |||
@Override | |||
public ParticipantNodeState getParticipantNodeState() { | |||
return participantNodeState; | |||
} | |||
public void setParticipantNodeState(ParticipantNodeState participantNodeState) { | |||
this.participantNodeState = participantNodeState; | |||
} | |||
} |
@@ -1,22 +1,22 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
/** | |||
* @author hhq | |||
* @version 1.0 | |||
* @created 14-6��-2018 12:13:33 | |||
*/ | |||
public class Peer extends Node { | |||
public ParticipantNode m_Participant; | |||
public Peer(){ | |||
} | |||
public void finalize() throws Throwable { | |||
super.finalize(); | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
/** | |||
* @author hhq | |||
* @version 1.0 | |||
* @created 14-6��-2018 12:13:33 | |||
*/ | |||
public class Peer extends Node { | |||
public ParticipantNode m_Participant; | |||
public Peer(){ | |||
} | |||
public void finalize() throws Throwable { | |||
super.finalize(); | |||
} | |||
} |
@@ -1,85 +1,85 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 用户账户; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccount extends AccountDecorator implements UserInfo { // implements UserInfo { | |||
private static final String USER_INFO_PREFIX = "PROP" + LedgerConsts.KEY_SEPERATOR; | |||
private static final String DATA_PUB_KEY = "DATA-PUBKEY"; | |||
public UserAccount(CompositeAccount baseAccount) { | |||
super(baseAccount); | |||
} | |||
private PubKey dataPubKey; | |||
@Override | |||
public Bytes getAddress() { | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return getID().getPubKey(); | |||
} | |||
@Override | |||
public PubKey getDataPubKey() { | |||
if (dataPubKey == null) { | |||
BytesValue pkBytes = getHeaders().getValue(DATA_PUB_KEY); | |||
if (pkBytes == null) { | |||
return null; | |||
} | |||
dataPubKey = new PubKey(pkBytes.getBytes().toBytes()); | |||
} | |||
return dataPubKey; | |||
} | |||
public void setDataPubKey(PubKey pubKey) { | |||
long version = getHeaders().getVersion(DATA_PUB_KEY); | |||
setDataPubKey(pubKey, version); | |||
} | |||
public void setDataPubKey(PubKey pubKey, long version) { | |||
TypedValue value = TypedValue.fromPubKey(dataPubKey); | |||
long newVersion = getHeaders().setValue(DATA_PUB_KEY, value, version); | |||
if (newVersion > -1) { | |||
dataPubKey = pubKey; | |||
} else { | |||
throw new LedgerException("Data public key was updated failed!"); | |||
} | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
return getHeaders().setValue(encodePropertyKey(key), TypedValue.fromText(value), version); | |||
} | |||
public String getProperty(String key) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key)); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
public String getProperty(String key, long version) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key), version); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
private String encodePropertyKey(String key) { | |||
return USER_INFO_PREFIX+key; | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 用户账户; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccount extends AccountDecorator implements UserInfo { // implements UserInfo { | |||
private static final String USER_INFO_PREFIX = "PROP" + LedgerConsts.KEY_SEPERATOR; | |||
private static final String DATA_PUB_KEY = "DATA-PUBKEY"; | |||
public UserAccount(CompositeAccount baseAccount) { | |||
super(baseAccount); | |||
} | |||
private PubKey dataPubKey; | |||
@Override | |||
public Bytes getAddress() { | |||
return getID().getAddress(); | |||
} | |||
@Override | |||
public PubKey getPubKey() { | |||
return getID().getPubKey(); | |||
} | |||
@Override | |||
public PubKey getDataPubKey() { | |||
if (dataPubKey == null) { | |||
BytesValue pkBytes = getHeaders().getValue(DATA_PUB_KEY); | |||
if (pkBytes == null) { | |||
return null; | |||
} | |||
dataPubKey = new PubKey(pkBytes.getBytes().toBytes()); | |||
} | |||
return dataPubKey; | |||
} | |||
public void setDataPubKey(PubKey pubKey) { | |||
long version = getHeaders().getVersion(DATA_PUB_KEY); | |||
setDataPubKey(pubKey, version); | |||
} | |||
public void setDataPubKey(PubKey pubKey, long version) { | |||
TypedValue value = TypedValue.fromPubKey(dataPubKey); | |||
long newVersion = getHeaders().setValue(DATA_PUB_KEY, value, version); | |||
if (newVersion > -1) { | |||
dataPubKey = pubKey; | |||
} else { | |||
throw new LedgerException("Data public key was updated failed!"); | |||
} | |||
} | |||
public long setProperty(String key, String value, long version) { | |||
return getHeaders().setValue(encodePropertyKey(key), TypedValue.fromText(value), version); | |||
} | |||
public String getProperty(String key) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key)); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
public String getProperty(String key, long version) { | |||
BytesValue value = getHeaders().getValue(encodePropertyKey(key), version); | |||
return value == null ? null : value.getBytes().toUTF8String(); | |||
} | |||
private String encodePropertyKey(String key) { | |||
return USER_INFO_PREFIX+key; | |||
} | |||
} |
@@ -1,121 +1,121 @@ | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccountSet implements Transactional, UserAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public UserAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage simpleStorage, | |||
VersioningKVStorage versioningStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(keyPrefix), simpleStorage, versioningStorage, | |||
accessPolicy); | |||
} | |||
public UserAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(keyPrefix), exStorage, | |||
verStorage, readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
/** | |||
* 返回用户总数; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return accountSet.getProof(key); | |||
} | |||
@Override | |||
public UserAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
@Override | |||
public UserAccount getAccount(Bytes address) { | |||
CompositeAccount baseAccount = accountSet.getAccount(address); | |||
return new UserAccount(baseAccount); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public UserAccount getAccount(Bytes address, long version) { | |||
CompositeAccount baseAccount = accountSet.getAccount(address, version); | |||
return new UserAccount(baseAccount); | |||
} | |||
/** | |||
* 注册一个新用户; <br> | |||
* | |||
* 如果用户已经存在,则会引发 {@link LedgerException} 异常; <br> | |||
* | |||
* 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; | |||
* | |||
* @param address 区块链地址; | |||
* @param pubKey 公钥; | |||
* @return 注册成功的用户对象; | |||
*/ | |||
public UserAccount register(Bytes address, PubKey pubKey) { | |||
CompositeAccount baseAccount = accountSet.register(address, pubKey); | |||
return new UserAccount(baseAccount); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
package com.jd.blockchain.ledger.core; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.CryptoSetting; | |||
import com.jd.blockchain.ledger.LedgerException; | |||
import com.jd.blockchain.ledger.MerkleProof; | |||
import com.jd.blockchain.storage.service.ExPolicyKVStorage; | |||
import com.jd.blockchain.storage.service.VersioningKVStorage; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.Transactional; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class UserAccountSet implements Transactional, UserAccountQuery { | |||
private MerkleAccountSet accountSet; | |||
public UserAccountSet(CryptoSetting cryptoSetting, String keyPrefix, ExPolicyKVStorage simpleStorage, | |||
VersioningKVStorage versioningStorage, AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(cryptoSetting, Bytes.fromString(keyPrefix), simpleStorage, versioningStorage, | |||
accessPolicy); | |||
} | |||
public UserAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String keyPrefix, | |||
ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, boolean readonly, | |||
AccountAccessPolicy accessPolicy) { | |||
accountSet = new MerkleAccountSet(dataRootHash, cryptoSetting, Bytes.fromString(keyPrefix), exStorage, | |||
verStorage, readonly, accessPolicy); | |||
} | |||
@Override | |||
public BlockchainIdentity[] getHeaders(int fromIndex, int count) { | |||
return accountSet.getHeaders(fromIndex, count); | |||
} | |||
/** | |||
* 返回用户总数; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
public long getTotal() { | |||
return accountSet.getTotal(); | |||
} | |||
public boolean isReadonly() { | |||
return accountSet.isReadonly(); | |||
} | |||
void setReadonly() { | |||
accountSet.setReadonly(); | |||
} | |||
@Override | |||
public HashDigest getRootHash() { | |||
return accountSet.getRootHash(); | |||
} | |||
@Override | |||
public MerkleProof getProof(Bytes key) { | |||
return accountSet.getProof(key); | |||
} | |||
@Override | |||
public UserAccount getAccount(String address) { | |||
return getAccount(Bytes.fromBase58(address)); | |||
} | |||
@Override | |||
public UserAccount getAccount(Bytes address) { | |||
CompositeAccount baseAccount = accountSet.getAccount(address); | |||
return new UserAccount(baseAccount); | |||
} | |||
@Override | |||
public boolean contains(Bytes address) { | |||
return accountSet.contains(address); | |||
} | |||
@Override | |||
public UserAccount getAccount(Bytes address, long version) { | |||
CompositeAccount baseAccount = accountSet.getAccount(address, version); | |||
return new UserAccount(baseAccount); | |||
} | |||
/** | |||
* 注册一个新用户; <br> | |||
* | |||
* 如果用户已经存在,则会引发 {@link LedgerException} 异常; <br> | |||
* | |||
* 如果指定的地址和公钥不匹配,则会引发 {@link LedgerException} 异常; | |||
* | |||
* @param address 区块链地址; | |||
* @param pubKey 公钥; | |||
* @return 注册成功的用户对象; | |||
*/ | |||
public UserAccount register(Bytes address, PubKey pubKey) { | |||
CompositeAccount baseAccount = accountSet.register(address, pubKey); | |||
return new UserAccount(baseAccount); | |||
} | |||
@Override | |||
public boolean isUpdated() { | |||
return accountSet.isUpdated(); | |||
} | |||
@Override | |||
public void commit() { | |||
accountSet.commit(); | |||
} | |||
@Override | |||
public void cancel() { | |||
accountSet.cancel(); | |||
} | |||
} |
@@ -1,43 +1,43 @@ | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>ledger</artifactId> | |||
<version>1.1.2.RELEASE</version> | |||
</parent> | |||
<artifactId>ledger-model</artifactId> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>utils-common</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>utils-web</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>binary-proto</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>crypto-framework</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>crypto-classic</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
</dependencies> | |||
<project xmlns="http://maven.apache.org/POM/4.0.0" | |||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||
<modelVersion>4.0.0</modelVersion> | |||
<parent> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>ledger</artifactId> | |||
<version>1.1.2.RELEASE</version> | |||
</parent> | |||
<artifactId>ledger-model</artifactId> | |||
<dependencies> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>utils-common</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>utils-web</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>binary-proto</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>crypto-framework</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
<dependency> | |||
<groupId>com.jd.blockchain</groupId> | |||
<artifactId>crypto-classic</artifactId> | |||
<version>${project.version}</version> | |||
</dependency> | |||
</dependencies> | |||
</project> |
@@ -1,14 +1,14 @@ | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.TYPE }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface Contract { | |||
String name() default ""; | |||
} | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.TYPE }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface Contract { | |||
String name() default ""; | |||
} |
@@ -1,14 +1,14 @@ | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ContractEvent { | |||
String name() default ""; | |||
} | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface ContractEvent { | |||
String name() default ""; | |||
} |
@@ -1,15 +1,15 @@ | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface EventHandle { | |||
} | |||
package com.jd.blockchain.contract; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.RetentionPolicy; | |||
import java.lang.annotation.Target; | |||
@Target({ ElementType.METHOD }) | |||
@Retention(RetentionPolicy.RUNTIME) | |||
public @interface EventHandle { | |||
} |
@@ -1,33 +1,33 @@ | |||
package com.jd.blockchain.ledger; | |||
public class BlockRollbackException extends LedgerException { | |||
private static final long serialVersionUID = 3583192000738807503L; | |||
private TransactionState state; | |||
public BlockRollbackException(String message) { | |||
this(TransactionState.SYSTEM_ERROR, message); | |||
} | |||
public BlockRollbackException(TransactionState state, String message) { | |||
super(message); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public BlockRollbackException(String message, Throwable cause) { | |||
this(TransactionState.SYSTEM_ERROR, message, cause); | |||
} | |||
public BlockRollbackException(TransactionState state, String message, Throwable cause) { | |||
super(message, cause); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public TransactionState getState() { | |||
return state; | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
public class BlockRollbackException extends LedgerException { | |||
private static final long serialVersionUID = 3583192000738807503L; | |||
private TransactionState state; | |||
public BlockRollbackException(String message) { | |||
this(TransactionState.SYSTEM_ERROR, message); | |||
} | |||
public BlockRollbackException(TransactionState state, String message) { | |||
super(message); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public BlockRollbackException(String message, Throwable cause) { | |||
this(TransactionState.SYSTEM_ERROR, message, cause); | |||
} | |||
public BlockRollbackException(TransactionState state, String message, Throwable cause) { | |||
super(message, cause); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public TransactionState getState() { | |||
return state; | |||
} | |||
} |
@@ -1,83 +1,83 @@ | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 区块链事件类型;<p> | |||
* | |||
* 每一种事件类型都包含一个事件码;<p> | |||
* | |||
* 在一次事件消息中,可以包含多种事件,而且事件之间具有嵌套关系;<br> | |||
* | |||
* 例如:<p> | |||
* | |||
* 一个区块生成事件 {@link #BLOCK_GENERATED} 含了交易提交事件 | |||
* {@link #TRANSACTION_COMMITED};<p> | |||
* | |||
* 交易提交事件 {@link #TRANSACTION_COMMITED} 必然包含账户更新事件 {@link #ACCOUNT_UPDATED};<p> | |||
* | |||
* 更进一步,账户更新事件 {@link #ACCOUNT_UPDATED} 也必然包含了权限更新事件 | |||
* {@link #PRIVILEGE_UPDATED}、负载数据更新事件 {@link #PAYLOAD_UPDATED} | |||
* 、合约脚本更新事件{@link #SCRIPT_UPDATED} 、合约脚本执行事件{@link #SCRIPT_INVOKED} 这4种事件中的一种或者多种事件;<p> | |||
* | |||
* 这种嵌套关系,表现在事件的编码中是子事件码的比特位中包含了上级事件码; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum BlockchainEventType { | |||
/** | |||
* 生成新区块;<br> | |||
* | |||
* 事件码:1 (0x01) | |||
* | |||
*/ | |||
BLOCK_GENERATED(1), | |||
/** | |||
* 成功提交新交易;<br> | |||
* | |||
* 事件码:3 (0x03) | |||
*/ | |||
TRANSACTION_COMMITED(3), | |||
/** | |||
* 账户的版本已更新;<br> | |||
* | |||
* 事件码:259 (0x103) | |||
*/ | |||
ACCOUNT_UPDATED(259), | |||
/** | |||
* 账户权限已被更新;<br> | |||
* | |||
* 事件码:65795 (0x10103) | |||
*/ | |||
PRIVILEGE_UPDATED(65795), | |||
/** | |||
* 账户负载数据已被更新;<br> | |||
* | |||
* 事件码:131331 (0x20103) | |||
*/ | |||
PAYLOAD_UPDATED(131331), | |||
/** | |||
* 合约脚本已被更新;<br> | |||
* | |||
* 事件码:262403 (0x40103) | |||
*/ | |||
SCRIPT_UPDATED(262403), | |||
/** | |||
* 合约脚本已被调用;<br> | |||
* | |||
* 事件码:524547 (0x80103) | |||
*/ | |||
SCRIPT_INVOKED(524547); | |||
public final int CODE; | |||
private BlockchainEventType(int code) { | |||
this.CODE = code; | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 区块链事件类型;<p> | |||
* | |||
* 每一种事件类型都包含一个事件码;<p> | |||
* | |||
* 在一次事件消息中,可以包含多种事件,而且事件之间具有嵌套关系;<br> | |||
* | |||
* 例如:<p> | |||
* | |||
* 一个区块生成事件 {@link #BLOCK_GENERATED} 含了交易提交事件 | |||
* {@link #TRANSACTION_COMMITED};<p> | |||
* | |||
* 交易提交事件 {@link #TRANSACTION_COMMITED} 必然包含账户更新事件 {@link #ACCOUNT_UPDATED};<p> | |||
* | |||
* 更进一步,账户更新事件 {@link #ACCOUNT_UPDATED} 也必然包含了权限更新事件 | |||
* {@link #PRIVILEGE_UPDATED}、负载数据更新事件 {@link #PAYLOAD_UPDATED} | |||
* 、合约脚本更新事件{@link #SCRIPT_UPDATED} 、合约脚本执行事件{@link #SCRIPT_INVOKED} 这4种事件中的一种或者多种事件;<p> | |||
* | |||
* 这种嵌套关系,表现在事件的编码中是子事件码的比特位中包含了上级事件码; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum BlockchainEventType { | |||
/** | |||
* 生成新区块;<br> | |||
* | |||
* 事件码:1 (0x01) | |||
* | |||
*/ | |||
BLOCK_GENERATED(1), | |||
/** | |||
* 成功提交新交易;<br> | |||
* | |||
* 事件码:3 (0x03) | |||
*/ | |||
TRANSACTION_COMMITED(3), | |||
/** | |||
* 账户的版本已更新;<br> | |||
* | |||
* 事件码:259 (0x103) | |||
*/ | |||
ACCOUNT_UPDATED(259), | |||
/** | |||
* 账户权限已被更新;<br> | |||
* | |||
* 事件码:65795 (0x10103) | |||
*/ | |||
PRIVILEGE_UPDATED(65795), | |||
/** | |||
* 账户负载数据已被更新;<br> | |||
* | |||
* 事件码:131331 (0x20103) | |||
*/ | |||
PAYLOAD_UPDATED(131331), | |||
/** | |||
* 合约脚本已被更新;<br> | |||
* | |||
* 事件码:262403 (0x40103) | |||
*/ | |||
SCRIPT_UPDATED(262403), | |||
/** | |||
* 合约脚本已被调用;<br> | |||
* | |||
* 事件码:524547 (0x80103) | |||
*/ | |||
SCRIPT_INVOKED(524547); | |||
public final int CODE; | |||
private BlockchainEventType(int code) { | |||
this.CODE = code; | |||
} | |||
} |
@@ -1,216 +1,216 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.Externalizable; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.ObjectInput; | |||
import java.io.ObjectOutput; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
import com.jd.blockchain.utils.io.BytesEncoding; | |||
import com.jd.blockchain.utils.io.BytesReader; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.BytesWriter; | |||
import com.jd.blockchain.utils.io.RuntimeIOException; | |||
/** | |||
* 区块链身份; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainIdentityData implements BytesWriter, BytesReader, Externalizable, BlockchainIdentity { | |||
private Bytes address; | |||
private PubKey pubKey; | |||
private BlockchainIdentityData() { | |||
} | |||
public BlockchainIdentityData(PubKey pubKey) { | |||
this.pubKey = pubKey; | |||
this.address = AddressEncoding.generateAddress(pubKey); | |||
} | |||
public BlockchainIdentityData(CryptoAlgorithm algorithm, ByteArray pubKeyBytes) { | |||
this.pubKey = new PubKey(algorithm, pubKeyBytes.bytes()); | |||
this.address = AddressEncoding.generateAddress(pubKey); | |||
} | |||
public BlockchainIdentityData(Bytes address, PubKey pubKey) { | |||
if (!verifyAddress(address, pubKey)) { | |||
throw new IllegalArgumentException("Blockchain address is mismatch with the pub-key!"); | |||
} | |||
this.address = address; | |||
this.pubKey = pubKey; | |||
} | |||
public static boolean verifyAddress(Bytes address, PubKey pubKey) { | |||
Bytes addr = AddressEncoding.generateAddress(pubKey); | |||
return addr.equals(address); | |||
} | |||
@Override | |||
public void resolvFrom(InputStream in) throws IOException { | |||
Bytes addr = AddressEncoding.readAddress(in); | |||
byte[] value = BytesEncoding.readInShort(in); | |||
PubKey pk = new PubKey(value); | |||
this.address = addr; | |||
this.pubKey = pk; | |||
} | |||
@Override | |||
public void writeTo(OutputStream out) throws IOException { | |||
AddressEncoding.writeAddress(address, out); | |||
BytesEncoding.writeInShort(pubKey.toBytes(), out); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.BlockchainIdentity#getAddress() | |||
*/ | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.BlockchainIdentity#getPubKey() | |||
*/ | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
public static BlockchainIdentity resolveFrom(ByteArray bytes) { | |||
try { | |||
BlockchainIdentityData id = new BlockchainIdentityData(); | |||
id.resolvFrom(bytes.asInputStream()); | |||
return id; | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public static ByteArray toBytes(List<BlockchainIdentityData> identities) { | |||
try { | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
BytesUtils.writeInt(identities.size(), out); | |||
for (BlockchainIdentityData identity : identities) { | |||
identity.writeTo(out); | |||
} | |||
return ByteArray.wrap(out.toByteArray()); | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public static List<BlockchainIdentityData> resolveIdentitiesFrom(ByteArray bytes) { | |||
try { | |||
InputStream in = bytes.asInputStream(); | |||
int identitiesLen = BytesUtils.readInt(in); | |||
List<BlockchainIdentityData> identities = new ArrayList<>(); | |||
for (int i = 0; i < identitiesLen; i++) { | |||
BlockchainIdentityData id = new BlockchainIdentityData(); | |||
id.resolvFrom(in); | |||
identities.add(id); | |||
} | |||
return identities; | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public ByteArray toBytes() { | |||
try { | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
writeTo(out); | |||
return ByteArray.wrap(out.toByteArray()); | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
@Override | |||
public int hashCode() { | |||
return address.hashCode(); | |||
} | |||
@Override | |||
public boolean equals(Object other) { | |||
if (this == other) { | |||
return true; | |||
} | |||
if (!(other instanceof BlockchainIdentityData)) { | |||
return false; | |||
} | |||
BlockchainIdentity identity = (BlockchainIdentity) other; | |||
if (!getAddress().equals(identity.getAddress())) { | |||
return false; | |||
} | |||
return pubKey.equals(identity.getPubKey()); | |||
} | |||
/** | |||
* The object implements the writeExternal method to save its contents by | |||
* calling the methods of DataOutput for its primitive values or calling the | |||
* writeObject method of ObjectOutput for objects, strings, and arrays. | |||
* | |||
* @param out | |||
* the stream to write the object to | |||
* @throws IOException | |||
* Includes any I/O exceptions that may occur | |||
* @serialData Overriding methods should use this tag to describe the data | |||
* layout of this Externalizable object. List the sequence of | |||
* element types and, if possible, relate the element to a | |||
* public/protected field and/or method of this Externalizable | |||
* class. | |||
*/ | |||
@Override | |||
public void writeExternal(ObjectOutput out) throws IOException { | |||
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||
writeTo(os); | |||
byte[] bts = os.toByteArray(); | |||
out.writeInt(bts.length); | |||
out.write(bts); | |||
} | |||
/** | |||
* The object implements the readExternal method to restore its contents by | |||
* calling the methods of DataInput for primitive types and readObject for | |||
* objects, strings and arrays. The readExternal method must read the values in | |||
* the same sequence and with the same types as were written by writeExternal. | |||
* | |||
* @param in | |||
* the stream to read data from in order to restore the object | |||
* @throws IOException | |||
* if I/O errors occur | |||
* @throws ClassNotFoundException | |||
* If the class for an object being restored cannot be found. | |||
*/ | |||
@Override | |||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |||
int len = in.readInt(); | |||
byte[] bts = new byte[len]; | |||
in.readFully(bts); | |||
this.resolvFrom(new ByteArrayInputStream(bts)); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.Externalizable; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.ObjectInput; | |||
import java.io.ObjectOutput; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
import com.jd.blockchain.utils.io.BytesEncoding; | |||
import com.jd.blockchain.utils.io.BytesReader; | |||
import com.jd.blockchain.utils.io.BytesUtils; | |||
import com.jd.blockchain.utils.io.BytesWriter; | |||
import com.jd.blockchain.utils.io.RuntimeIOException; | |||
/** | |||
* 区块链身份; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainIdentityData implements BytesWriter, BytesReader, Externalizable, BlockchainIdentity { | |||
private Bytes address; | |||
private PubKey pubKey; | |||
private BlockchainIdentityData() { | |||
} | |||
public BlockchainIdentityData(PubKey pubKey) { | |||
this.pubKey = pubKey; | |||
this.address = AddressEncoding.generateAddress(pubKey); | |||
} | |||
public BlockchainIdentityData(CryptoAlgorithm algorithm, ByteArray pubKeyBytes) { | |||
this.pubKey = new PubKey(algorithm, pubKeyBytes.bytes()); | |||
this.address = AddressEncoding.generateAddress(pubKey); | |||
} | |||
public BlockchainIdentityData(Bytes address, PubKey pubKey) { | |||
if (!verifyAddress(address, pubKey)) { | |||
throw new IllegalArgumentException("Blockchain address is mismatch with the pub-key!"); | |||
} | |||
this.address = address; | |||
this.pubKey = pubKey; | |||
} | |||
public static boolean verifyAddress(Bytes address, PubKey pubKey) { | |||
Bytes addr = AddressEncoding.generateAddress(pubKey); | |||
return addr.equals(address); | |||
} | |||
@Override | |||
public void resolvFrom(InputStream in) throws IOException { | |||
Bytes addr = AddressEncoding.readAddress(in); | |||
byte[] value = BytesEncoding.readInShort(in); | |||
PubKey pk = new PubKey(value); | |||
this.address = addr; | |||
this.pubKey = pk; | |||
} | |||
@Override | |||
public void writeTo(OutputStream out) throws IOException { | |||
AddressEncoding.writeAddress(address, out); | |||
BytesEncoding.writeInShort(pubKey.toBytes(), out); | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.BlockchainIdentity#getAddress() | |||
*/ | |||
@Override | |||
public Bytes getAddress() { | |||
return address; | |||
} | |||
/* | |||
* (non-Javadoc) | |||
* | |||
* @see com.jd.blockchain.ledger.BlockchainIdentity#getPubKey() | |||
*/ | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
public static BlockchainIdentity resolveFrom(ByteArray bytes) { | |||
try { | |||
BlockchainIdentityData id = new BlockchainIdentityData(); | |||
id.resolvFrom(bytes.asInputStream()); | |||
return id; | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public static ByteArray toBytes(List<BlockchainIdentityData> identities) { | |||
try { | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
BytesUtils.writeInt(identities.size(), out); | |||
for (BlockchainIdentityData identity : identities) { | |||
identity.writeTo(out); | |||
} | |||
return ByteArray.wrap(out.toByteArray()); | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public static List<BlockchainIdentityData> resolveIdentitiesFrom(ByteArray bytes) { | |||
try { | |||
InputStream in = bytes.asInputStream(); | |||
int identitiesLen = BytesUtils.readInt(in); | |||
List<BlockchainIdentityData> identities = new ArrayList<>(); | |||
for (int i = 0; i < identitiesLen; i++) { | |||
BlockchainIdentityData id = new BlockchainIdentityData(); | |||
id.resolvFrom(in); | |||
identities.add(id); | |||
} | |||
return identities; | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
public ByteArray toBytes() { | |||
try { | |||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
writeTo(out); | |||
return ByteArray.wrap(out.toByteArray()); | |||
} catch (IOException e) { | |||
throw new RuntimeIOException(e.getMessage(), e); | |||
} | |||
} | |||
@Override | |||
public int hashCode() { | |||
return address.hashCode(); | |||
} | |||
@Override | |||
public boolean equals(Object other) { | |||
if (this == other) { | |||
return true; | |||
} | |||
if (!(other instanceof BlockchainIdentityData)) { | |||
return false; | |||
} | |||
BlockchainIdentity identity = (BlockchainIdentity) other; | |||
if (!getAddress().equals(identity.getAddress())) { | |||
return false; | |||
} | |||
return pubKey.equals(identity.getPubKey()); | |||
} | |||
/** | |||
* The object implements the writeExternal method to save its contents by | |||
* calling the methods of DataOutput for its primitive values or calling the | |||
* writeObject method of ObjectOutput for objects, strings, and arrays. | |||
* | |||
* @param out | |||
* the stream to write the object to | |||
* @throws IOException | |||
* Includes any I/O exceptions that may occur | |||
* @serialData Overriding methods should use this tag to describe the data | |||
* layout of this Externalizable object. List the sequence of | |||
* element types and, if possible, relate the element to a | |||
* public/protected field and/or method of this Externalizable | |||
* class. | |||
*/ | |||
@Override | |||
public void writeExternal(ObjectOutput out) throws IOException { | |||
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||
writeTo(os); | |||
byte[] bts = os.toByteArray(); | |||
out.writeInt(bts.length); | |||
out.write(bts); | |||
} | |||
/** | |||
* The object implements the readExternal method to restore its contents by | |||
* calling the methods of DataInput for primitive types and readObject for | |||
* objects, strings and arrays. The readExternal method must read the values in | |||
* the same sequence and with the same types as were written by writeExternal. | |||
* | |||
* @param in | |||
* the stream to read data from in order to restore the object | |||
* @throws IOException | |||
* if I/O errors occur | |||
* @throws ClassNotFoundException | |||
* If the class for an object being restored cannot be found. | |||
*/ | |||
@Override | |||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |||
int len = in.readInt(); | |||
byte[] bts = new byte[len]; | |||
in.readFully(bts); | |||
this.resolvFrom(new ByteArrayInputStream(bts)); | |||
} | |||
} |
@@ -1,40 +1,40 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.SignatureFunction; | |||
/** | |||
* 区块链密钥生成器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainKeyGenerator { | |||
public static final String DEFAULT_ALGORITHM = "ED25519"; | |||
private BlockchainKeyGenerator() { | |||
} | |||
public static BlockchainKeyGenerator getInstance() { | |||
return new BlockchainKeyGenerator(); | |||
} | |||
public BlockchainKeypair generate() { | |||
return generate(DEFAULT_ALGORITHM); | |||
} | |||
public BlockchainKeypair generate(String algorithmName) { | |||
CryptoAlgorithm algorithm = Crypto.getAlgorithm(algorithmName); | |||
return generate(algorithm); | |||
} | |||
public BlockchainKeypair generate(CryptoAlgorithm signatureAlgorithm) { | |||
SignatureFunction signFunc = Crypto.getSignatureFunction(signatureAlgorithm); | |||
AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(); | |||
return new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.CryptoAlgorithm; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.SignatureFunction; | |||
/** | |||
* 区块链密钥生成器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainKeyGenerator { | |||
public static final String DEFAULT_ALGORITHM = "ED25519"; | |||
private BlockchainKeyGenerator() { | |||
} | |||
public static BlockchainKeyGenerator getInstance() { | |||
return new BlockchainKeyGenerator(); | |||
} | |||
public BlockchainKeypair generate() { | |||
return generate(DEFAULT_ALGORITHM); | |||
} | |||
public BlockchainKeypair generate(String algorithmName) { | |||
CryptoAlgorithm algorithm = Crypto.getAlgorithm(algorithmName); | |||
return generate(algorithm); | |||
} | |||
public BlockchainKeypair generate(CryptoAlgorithm signatureAlgorithm) { | |||
SignatureFunction signFunc = Crypto.getSignatureFunction(signatureAlgorithm); | |||
AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(); | |||
return new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey()); | |||
} | |||
} |
@@ -1,46 +1,46 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 区块链密钥对; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainKeypair extends AsymmetricKeypair { | |||
private BlockchainIdentity id; | |||
// public BlockchainKeyPair(CryptoAlgorithm algorithm, ByteArray pubKeyBytes, ByteArray privKeyBytes) { | |||
// this.id = new BlockchainIdentity(algorithm, pubKeyBytes); | |||
// privKey = new PrivKey(algorithm, privKeyBytes.bytes()); | |||
// } | |||
public BlockchainKeypair(String address, PubKey pubKey, PrivKey privKey) { | |||
super(pubKey, privKey); | |||
if (pubKey.getAlgorithm() != privKey.getAlgorithm()) { | |||
throw new IllegalArgumentException("The PublicKey's algorithm is different from the PrivateKey's!"); | |||
} | |||
this.id = new BlockchainIdentityData(Bytes.fromBase58(address), pubKey); | |||
} | |||
public BlockchainKeypair(PubKey pubKey, PrivKey privKey) { | |||
super(pubKey, privKey); | |||
if (pubKey.getAlgorithm() != privKey.getAlgorithm()) { | |||
throw new IllegalArgumentException("The PublicKey's algorithm is different from the PrivateKey's!"); | |||
} | |||
this.id = new BlockchainIdentityData(pubKey); | |||
} | |||
public Bytes getAddress() { | |||
return id.getAddress(); | |||
} | |||
public BlockchainIdentity getIdentity() { | |||
return id; | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.PrivKey; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 区块链密钥对; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainKeypair extends AsymmetricKeypair { | |||
private BlockchainIdentity id; | |||
// public BlockchainKeyPair(CryptoAlgorithm algorithm, ByteArray pubKeyBytes, ByteArray privKeyBytes) { | |||
// this.id = new BlockchainIdentity(algorithm, pubKeyBytes); | |||
// privKey = new PrivKey(algorithm, privKeyBytes.bytes()); | |||
// } | |||
public BlockchainKeypair(String address, PubKey pubKey, PrivKey privKey) { | |||
super(pubKey, privKey); | |||
if (pubKey.getAlgorithm() != privKey.getAlgorithm()) { | |||
throw new IllegalArgumentException("The PublicKey's algorithm is different from the PrivateKey's!"); | |||
} | |||
this.id = new BlockchainIdentityData(Bytes.fromBase58(address), pubKey); | |||
} | |||
public BlockchainKeypair(PubKey pubKey, PrivKey privKey) { | |||
super(pubKey, privKey); | |||
if (pubKey.getAlgorithm() != privKey.getAlgorithm()) { | |||
throw new IllegalArgumentException("The PublicKey's algorithm is different from the PrivateKey's!"); | |||
} | |||
this.id = new BlockchainIdentityData(pubKey); | |||
} | |||
public Bytes getAddress() { | |||
return id.getAddress(); | |||
} | |||
public BlockchainIdentity getIdentity() { | |||
return id; | |||
} | |||
} |
@@ -1,23 +1,23 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import com.jd.blockchain.ledger.data.AccountUpdateOperationBuilder; | |||
// | |||
///** | |||
// * 合约代码部署操作; | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
//public interface CodeDeployOperation extends AccountUpdateOperationBuilder { | |||
// | |||
// /** | |||
// * 修改脚本; | |||
// * | |||
// * @param code | |||
// * 合约代码; | |||
// * @param codeVersion | |||
// * 预期的当前的代码的版本;如果指定为 -1,则不进行版本检查; | |||
// */ | |||
// void set(BlockchainIdentity id, String code, long codeVersion); | |||
// | |||
//} | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import com.jd.blockchain.ledger.data.AccountUpdateOperationBuilder; | |||
// | |||
///** | |||
// * 合约代码部署操作; | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
//public interface CodeDeployOperation extends AccountUpdateOperationBuilder { | |||
// | |||
// /** | |||
// * 修改脚本; | |||
// * | |||
// * @param code | |||
// * 合约代码; | |||
// * @param codeVersion | |||
// * 预期的当前的代码的版本;如果指定为 -1,则不进行版本检查; | |||
// */ | |||
// void set(BlockchainIdentity id, String code, long codeVersion); | |||
// | |||
//} |
@@ -1,31 +1,31 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_CONTRACT_DEPLOY) | |||
public interface ContractCodeDeployOperation extends Operation { | |||
@DataField(order=2, refContract = true) | |||
BlockchainIdentity getContractID(); | |||
@DataField(order=3, primitiveType=PrimitiveType.BYTES) | |||
byte[] getChainCode(); | |||
/** | |||
* 地址签名; | |||
* | |||
* <br> | |||
* 这是合约账户身份 ({@link #getContractID()}) 使用对应的私钥对地址做出的签名; | |||
* <br> | |||
* 在注册时将校验此签名与账户地址、公钥是否相匹配,以此保证只有私钥的持有者才能注册相应的合约账户,确保合约账户的唯一性; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=4, refContract = true) | |||
DigitalSignature getAddressSignature(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_CONTRACT_DEPLOY) | |||
public interface ContractCodeDeployOperation extends Operation { | |||
@DataField(order=2, refContract = true) | |||
BlockchainIdentity getContractID(); | |||
@DataField(order=3, primitiveType=PrimitiveType.BYTES) | |||
byte[] getChainCode(); | |||
/** | |||
* 地址签名; | |||
* | |||
* <br> | |||
* 这是合约账户身份 ({@link #getContractID()}) 使用对应的私钥对地址做出的签名; | |||
* <br> | |||
* 在注册时将校验此签名与账户地址、公钥是否相匹配,以此保证只有私钥的持有者才能注册相应的合约账户,确保合约账户的唯一性; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=4, refContract = true) | |||
DigitalSignature getAddressSignature(); | |||
} |
@@ -1,32 +1,32 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.utils.Bytes; | |||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) | |||
public interface DataAccountKVSetOperation extends Operation { | |||
@DataField(order=2, primitiveType=PrimitiveType.BYTES) | |||
Bytes getAccountAddress(); | |||
@DataField(order=3, list=true, refContract=true) | |||
KVWriteEntry[] getWriteSet(); | |||
@DataContract(code=DataCodes.TX_OP_DATA_ACC_SET_KV) | |||
public static interface KVWriteEntry{ | |||
@DataField(order=1, primitiveType=PrimitiveType.TEXT) | |||
String getKey(); | |||
@DataField(order=2, refContract = true) | |||
BytesValue getValue(); | |||
@DataField(order=3, primitiveType=PrimitiveType.INT64) | |||
long getExpectedVersion(); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.utils.Bytes; | |||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_SET) | |||
public interface DataAccountKVSetOperation extends Operation { | |||
@DataField(order=2, primitiveType=PrimitiveType.BYTES) | |||
Bytes getAccountAddress(); | |||
@DataField(order=3, list=true, refContract=true) | |||
KVWriteEntry[] getWriteSet(); | |||
@DataContract(code=DataCodes.TX_OP_DATA_ACC_SET_KV) | |||
public static interface KVWriteEntry{ | |||
@DataField(order=1, primitiveType=PrimitiveType.TEXT) | |||
String getKey(); | |||
@DataField(order=2, refContract = true) | |||
BytesValue getValue(); | |||
@DataField(order=3, primitiveType=PrimitiveType.INT64) | |||
long getExpectedVersion(); | |||
} | |||
} |
@@ -1,26 +1,26 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_REG) | |||
public interface DataAccountRegisterOperation extends Operation { | |||
@DataField(order=1, refContract = true) | |||
BlockchainIdentity getAccountID(); | |||
/** | |||
* 地址签名; | |||
* | |||
* <br> | |||
* 这是账户身份 ({@link #getAccountID()}) 使用对应的私钥对地址做出的签名; | |||
* <br> | |||
* 在注册时将校验此签名与账户地址、公钥是否相匹配,以此保证只有私钥的持有者才能注册数据账户,确保数据账户的唯一性; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=2, refContract = true) | |||
DigitalSignature getAddressSignature(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_DATA_ACC_REG) | |||
public interface DataAccountRegisterOperation extends Operation { | |||
@DataField(order=1, refContract = true) | |||
BlockchainIdentity getAccountID(); | |||
/** | |||
* 地址签名; | |||
* | |||
* <br> | |||
* 这是账户身份 ({@link #getAccountID()}) 使用对应的私钥对地址做出的签名; | |||
* <br> | |||
* 在注册时将校验此签名与账户地址、公钥是否相匹配,以此保证只有私钥的持有者才能注册数据账户,确保数据账户的唯一性; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=2, refContract = true) | |||
DigitalSignature getAddressSignature(); | |||
} |
@@ -1,185 +1,185 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.BaseType; | |||
import com.jd.blockchain.binaryproto.EnumContract; | |||
import com.jd.blockchain.binaryproto.EnumField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 键值操作的数据类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@EnumContract(code = DataCodes.ENUM_TYPE_BYTES_VALUE_TYPE) | |||
public enum DataType { | |||
/** | |||
* 空; | |||
*/ | |||
NIL(PrimitiveType.NIL.CODE), | |||
/** | |||
* 布尔型; | |||
*/ | |||
BOOLEAN(PrimitiveType.BOOLEAN.CODE), | |||
/** | |||
* 数值型: | |||
*/ | |||
INT8(PrimitiveType.INT8.CODE), | |||
INT16(PrimitiveType.INT16.CODE), | |||
INT32(PrimitiveType.INT32.CODE), | |||
INT64(PrimitiveType.INT64.CODE), | |||
/** | |||
* 文本数据; | |||
*/ | |||
TEXT(PrimitiveType.TEXT.CODE), | |||
/** | |||
* 二进制数据; | |||
*/ | |||
BYTES(PrimitiveType.BYTES.CODE), | |||
/** | |||
* 时间戳; | |||
*/ | |||
TIMESTAMP((byte) (BaseType.INTEGER | 0x08)), | |||
/** | |||
* 文本数据; | |||
*/ | |||
JSON((byte) (BaseType.TEXT | 0x01)), | |||
/** | |||
* 文本数据; | |||
*/ | |||
XML((byte) (BaseType.TEXT | 0x02)), | |||
/** | |||
* 大整数; | |||
*/ | |||
BIG_INT((byte) (BaseType.BYTES | 0x01)), | |||
/** | |||
* 图片; | |||
*/ | |||
IMG((byte) (BaseType.BYTES | 0x02)), | |||
/** | |||
* 视频; | |||
*/ | |||
VIDEO((byte) (BaseType.BYTES | 0x03)), | |||
/** | |||
* 位置坐标; | |||
*/ | |||
LOCATION((byte) (BaseType.BYTES | 0x04)), | |||
/** | |||
* 公钥; | |||
*/ | |||
PUB_KEY((byte) (BaseType.BYTES | 0x05)), | |||
/** | |||
* 签名摘要; | |||
*/ | |||
SIGNATURE_DIGEST((byte) (BaseType.BYTES | 0x06)), | |||
/** | |||
* 哈希摘要; | |||
*/ | |||
HASH_DIGEST((byte) (BaseType.BYTES | 0x07)), | |||
/** | |||
* 加密数据; | |||
*/ | |||
ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)), | |||
/** | |||
* DataContract 数据; | |||
*/ | |||
DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); | |||
public static final boolean BOOLEAN_DEFAULT_VALUE = false; | |||
public static final byte INT8_DEFAULT_VALUE = 0; | |||
public static final short INT16_DEFAULT_VALUE = 0; | |||
public static final int INT32_DEFAULT_VALUE = 0; | |||
public static final long INT64_DEFAULT_VALUE = 0; | |||
@EnumField(type = PrimitiveType.INT8) | |||
public final byte CODE; | |||
private DataType(byte code) { | |||
this.CODE = code; | |||
} | |||
/** | |||
* 是否表示“文本类型”或“文本衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isText() { | |||
return BaseType.TEXT == (BaseType.TEXT & CODE); | |||
} | |||
/** | |||
* 是否表示“字节类型”或“字节衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBytes() { | |||
return BaseType.BYTES == (BaseType.BYTES & CODE); | |||
} | |||
/** | |||
* 是否表示“整数类型”或“整数衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isInteger() { | |||
return BaseType.INTEGER == (BaseType.INTEGER & CODE); | |||
} | |||
/** | |||
* 是否表示“布尔类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBoolean() { | |||
return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE); | |||
} | |||
/** | |||
* 是否表示“扩展类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isExt() { | |||
return BaseType.EXT == (BaseType.EXT & CODE); | |||
} | |||
public static DataType valueOf(byte code) { | |||
for (DataType dataType : DataType.values()) { | |||
if (dataType.CODE == code) { | |||
return dataType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Code [" + code + "] not supported by BytesValueType enum!"); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.BaseType; | |||
import com.jd.blockchain.binaryproto.EnumContract; | |||
import com.jd.blockchain.binaryproto.EnumField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 键值操作的数据类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@EnumContract(code = DataCodes.ENUM_TYPE_BYTES_VALUE_TYPE) | |||
public enum DataType { | |||
/** | |||
* 空; | |||
*/ | |||
NIL(PrimitiveType.NIL.CODE), | |||
/** | |||
* 布尔型; | |||
*/ | |||
BOOLEAN(PrimitiveType.BOOLEAN.CODE), | |||
/** | |||
* 数值型: | |||
*/ | |||
INT8(PrimitiveType.INT8.CODE), | |||
INT16(PrimitiveType.INT16.CODE), | |||
INT32(PrimitiveType.INT32.CODE), | |||
INT64(PrimitiveType.INT64.CODE), | |||
/** | |||
* 文本数据; | |||
*/ | |||
TEXT(PrimitiveType.TEXT.CODE), | |||
/** | |||
* 二进制数据; | |||
*/ | |||
BYTES(PrimitiveType.BYTES.CODE), | |||
/** | |||
* 时间戳; | |||
*/ | |||
TIMESTAMP((byte) (BaseType.INTEGER | 0x08)), | |||
/** | |||
* 文本数据; | |||
*/ | |||
JSON((byte) (BaseType.TEXT | 0x01)), | |||
/** | |||
* 文本数据; | |||
*/ | |||
XML((byte) (BaseType.TEXT | 0x02)), | |||
/** | |||
* 大整数; | |||
*/ | |||
BIG_INT((byte) (BaseType.BYTES | 0x01)), | |||
/** | |||
* 图片; | |||
*/ | |||
IMG((byte) (BaseType.BYTES | 0x02)), | |||
/** | |||
* 视频; | |||
*/ | |||
VIDEO((byte) (BaseType.BYTES | 0x03)), | |||
/** | |||
* 位置坐标; | |||
*/ | |||
LOCATION((byte) (BaseType.BYTES | 0x04)), | |||
/** | |||
* 公钥; | |||
*/ | |||
PUB_KEY((byte) (BaseType.BYTES | 0x05)), | |||
/** | |||
* 签名摘要; | |||
*/ | |||
SIGNATURE_DIGEST((byte) (BaseType.BYTES | 0x06)), | |||
/** | |||
* 哈希摘要; | |||
*/ | |||
HASH_DIGEST((byte) (BaseType.BYTES | 0x07)), | |||
/** | |||
* 加密数据; | |||
*/ | |||
ENCRYPTED_DATA((byte) (BaseType.BYTES | 0x08)), | |||
/** | |||
* DataContract 数据; | |||
*/ | |||
DATA_CONTRACT((byte) (BaseType.EXT | 0x01)); | |||
public static final boolean BOOLEAN_DEFAULT_VALUE = false; | |||
public static final byte INT8_DEFAULT_VALUE = 0; | |||
public static final short INT16_DEFAULT_VALUE = 0; | |||
public static final int INT32_DEFAULT_VALUE = 0; | |||
public static final long INT64_DEFAULT_VALUE = 0; | |||
@EnumField(type = PrimitiveType.INT8) | |||
public final byte CODE; | |||
private DataType(byte code) { | |||
this.CODE = code; | |||
} | |||
/** | |||
* 是否表示“文本类型”或“文本衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isText() { | |||
return BaseType.TEXT == (BaseType.TEXT & CODE); | |||
} | |||
/** | |||
* 是否表示“字节类型”或“字节衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBytes() { | |||
return BaseType.BYTES == (BaseType.BYTES & CODE); | |||
} | |||
/** | |||
* 是否表示“整数类型”或“整数衍生类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isInteger() { | |||
return BaseType.INTEGER == (BaseType.INTEGER & CODE); | |||
} | |||
/** | |||
* 是否表示“布尔类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isBoolean() { | |||
return BaseType.BOOLEAN == (BaseType.BOOLEAN & CODE); | |||
} | |||
/** | |||
* 是否表示“扩展类型”; | |||
* | |||
* @return | |||
*/ | |||
public boolean isExt() { | |||
return BaseType.EXT == (BaseType.EXT & CODE); | |||
} | |||
public static DataType valueOf(byte code) { | |||
for (DataType dataType : DataType.values()) { | |||
if (dataType.CODE == code) { | |||
return dataType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Code [" + code + "] not supported by BytesValueType enum!"); | |||
} | |||
} |
@@ -1,27 +1,27 @@ | |||
package com.jd.blockchain.ledger; | |||
public class DataVersionConflictException extends LedgerException { | |||
private static final long serialVersionUID = 3583192000738807503L; | |||
private TransactionState state; | |||
public DataVersionConflictException() { | |||
this(TransactionState.DATA_VERSION_CONFLICT, null); | |||
} | |||
public DataVersionConflictException(String message) { | |||
this(TransactionState.DATA_VERSION_CONFLICT, message); | |||
} | |||
private DataVersionConflictException(TransactionState state, String message) { | |||
super(message); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public TransactionState getState() { | |||
return state; | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
public class DataVersionConflictException extends LedgerException { | |||
private static final long serialVersionUID = 3583192000738807503L; | |||
private TransactionState state; | |||
public DataVersionConflictException() { | |||
this(TransactionState.DATA_VERSION_CONFLICT, null); | |||
} | |||
public DataVersionConflictException(String message) { | |||
this(TransactionState.DATA_VERSION_CONFLICT, message); | |||
} | |||
private DataVersionConflictException(TransactionState state, String message) { | |||
super(message); | |||
assert TransactionState.SUCCESS != state; | |||
this.state = state; | |||
} | |||
public TransactionState getState() { | |||
return state; | |||
} | |||
} |
@@ -1,15 +1,15 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 数字签名; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code= DataCodes.DIGITALSIGNATURE) | |||
public interface DigitalSignature extends DigitalSignatureBody { | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 数字签名; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code= DataCodes.DIGITALSIGNATURE) | |||
public interface DigitalSignature extends DigitalSignatureBody { | |||
} |
@@ -1,30 +1,30 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
@DataContract(code= DataCodes.REQUEST_ENDPOINT) | |||
public interface EndpointRequest { | |||
@DataField(order=1, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getHash(); | |||
/** | |||
* 交易内容; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=2, refContract=true) | |||
TransactionContent getTransactionContent(); | |||
/** | |||
* 终端用户的签名列表; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=3, list=true, refContract=true) | |||
DigitalSignature[] getEndpointSignatures(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
@DataContract(code= DataCodes.REQUEST_ENDPOINT) | |||
public interface EndpointRequest { | |||
@DataField(order=1, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getHash(); | |||
/** | |||
* 交易内容; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=2, refContract=true) | |||
TransactionContent getTransactionContent(); | |||
/** | |||
* 终端用户的签名列表; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=3, list=true, refContract=true) | |||
DigitalSignature[] getEndpointSignatures(); | |||
} |
@@ -1,46 +1,46 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
///** | |||
// * Hash 算法的代码常量; | |||
// * | |||
// * @author zhaoming9 | |||
// * | |||
// */ | |||
//public enum HashAlgorithm { | |||
// | |||
// RIPE160((byte) 1), | |||
// | |||
// SHA256((byte) 2), | |||
// | |||
// SM3((byte) 4); | |||
// | |||
// public final byte CODE; | |||
// | |||
// private HashAlgorithm(byte algorithm) { | |||
// CODE = algorithm; | |||
// } | |||
// | |||
// public byte getAlgorithm() { | |||
// return CODE; | |||
// } | |||
// | |||
// public static HashAlgorithm valueOf(byte algorithm) { | |||
// for (HashAlgorithm hashAlgorithm : HashAlgorithm.values()) { | |||
// if (hashAlgorithm.CODE == algorithm) { | |||
// return hashAlgorithm; | |||
// } | |||
// } | |||
// throw new IllegalArgumentException("Unsupported hash algorithm [" + algorithm + "]!"); | |||
// } | |||
// | |||
// public static void checkHashAlgorithm(HashAlgorithm algorithm) { | |||
// switch (algorithm) { | |||
// case RIPE160: | |||
// break; | |||
// case SHA256: | |||
// break; | |||
// default: | |||
// throw new IllegalArgumentException("Unsupported hash algorithm [" + algorithm + "]!"); | |||
// } | |||
// } | |||
//} | |||
//package com.jd.blockchain.ledger; | |||
// | |||
///** | |||
// * Hash 算法的代码常量; | |||
// * | |||
// * @author zhaoming9 | |||
// * | |||
// */ | |||
//public enum HashAlgorithm { | |||
// | |||
// RIPE160((byte) 1), | |||
// | |||
// SHA256((byte) 2), | |||
// | |||
// SM3((byte) 4); | |||
// | |||
// public final byte CODE; | |||
// | |||
// private HashAlgorithm(byte algorithm) { | |||
// CODE = algorithm; | |||
// } | |||
// | |||
// public byte getAlgorithm() { | |||
// return CODE; | |||
// } | |||
// | |||
// public static HashAlgorithm valueOf(byte algorithm) { | |||
// for (HashAlgorithm hashAlgorithm : HashAlgorithm.values()) { | |||
// if (hashAlgorithm.CODE == algorithm) { | |||
// return hashAlgorithm; | |||
// } | |||
// } | |||
// throw new IllegalArgumentException("Unsupported hash algorithm [" + algorithm + "]!"); | |||
// } | |||
// | |||
// public static void checkHashAlgorithm(HashAlgorithm algorithm) { | |||
// switch (algorithm) { | |||
// case RIPE160: | |||
// break; | |||
// case SHA256: | |||
// break; | |||
// default: | |||
// throw new IllegalArgumentException("Unsupported hash algorithm [" + algorithm + "]!"); | |||
// } | |||
// } | |||
//} |
@@ -1,37 +1,37 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* HashObject 表示以“哈希值”作为唯一标识的对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code= DataCodes.HASH_OBJECT) | |||
public interface HashObject { | |||
/** | |||
* 哈希值; | |||
* | |||
* @return | |||
*/ | |||
//no need annotation | |||
HashDigest getHash(); | |||
// /** | |||
// * 哈希算法; | |||
// * | |||
// * @return | |||
// */ | |||
// HashAlgorithm getHashAlgorithm(); | |||
// /** | |||
// * 进行哈希运算的数据; | |||
// * @return | |||
// */ | |||
// ByteArray getHashData(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* HashObject 表示以“哈希值”作为唯一标识的对象; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code= DataCodes.HASH_OBJECT) | |||
public interface HashObject { | |||
/** | |||
* 哈希值; | |||
* | |||
* @return | |||
*/ | |||
//no need annotation | |||
HashDigest getHash(); | |||
// /** | |||
// * 哈希算法; | |||
// * | |||
// * @return | |||
// */ | |||
// HashAlgorithm getHashAlgorithm(); | |||
// /** | |||
// * 进行哈希运算的数据; | |||
// * @return | |||
// */ | |||
// ByteArray getHashData(); | |||
} |
@@ -1,59 +1,59 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import my.utils.io.ByteArray; | |||
// | |||
//import java.io.Serializable; | |||
// | |||
///** | |||
// * Ledger 账本;<br> | |||
// * | |||
// * 账本只是一个逻辑上的对象,它是对一条区块的hash链的归纳抽象,而在存储上并没有具体的存在形式,而是具体化为由一个特定的创世区块作为开端的区块 hash | |||
// * 链;<br> | |||
// * | |||
// * 账本的唯一标识也是其创世区块(GenisisBlock)的 hash;<br> | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
//public interface Ledger extends Serializable { | |||
// | |||
// /** | |||
// * 账本的 hash; <br> | |||
// * | |||
// * 同时也是账本的唯一,等同于其创世区块(GenisisBlock)的 hash {@link GenesisBlock#getBlockHash()}; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getLedgerHash(); | |||
// | |||
// /** | |||
// * 账本结构版本;<br> | |||
// * | |||
// * 等同于 {@link Block#getLedgerVersion()}; | |||
// * | |||
// * @return | |||
// */ | |||
// long getLedgerVersion(); | |||
// | |||
// /** | |||
// * 由随机数构成的该账本的创世序列; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getGenesisKey(); | |||
// | |||
// /** | |||
// * 当前最新区块的 hash; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getBlockHash(); | |||
// | |||
// /** | |||
// * 账本的区块高度; | |||
// * | |||
// * @return | |||
// */ | |||
// long getBlockHeight(); | |||
// | |||
//} | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import my.utils.io.ByteArray; | |||
// | |||
//import java.io.Serializable; | |||
// | |||
///** | |||
// * Ledger 账本;<br> | |||
// * | |||
// * 账本只是一个逻辑上的对象,它是对一条区块的hash链的归纳抽象,而在存储上并没有具体的存在形式,而是具体化为由一个特定的创世区块作为开端的区块 hash | |||
// * 链;<br> | |||
// * | |||
// * 账本的唯一标识也是其创世区块(GenisisBlock)的 hash;<br> | |||
// * | |||
// * @author huanghaiquan | |||
// * | |||
// */ | |||
//public interface Ledger extends Serializable { | |||
// | |||
// /** | |||
// * 账本的 hash; <br> | |||
// * | |||
// * 同时也是账本的唯一,等同于其创世区块(GenisisBlock)的 hash {@link GenesisBlock#getBlockHash()}; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getLedgerHash(); | |||
// | |||
// /** | |||
// * 账本结构版本;<br> | |||
// * | |||
// * 等同于 {@link Block#getLedgerVersion()}; | |||
// * | |||
// * @return | |||
// */ | |||
// long getLedgerVersion(); | |||
// | |||
// /** | |||
// * 由随机数构成的该账本的创世序列; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getGenesisKey(); | |||
// | |||
// /** | |||
// * 当前最新区块的 hash; | |||
// * | |||
// * @return | |||
// */ | |||
// ByteArray getBlockHash(); | |||
// | |||
// /** | |||
// * 账本的区块高度; | |||
// * | |||
// * @return | |||
// */ | |||
// long getBlockHeight(); | |||
// | |||
//} |
@@ -1,323 +1,323 @@ | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import com.jd.blockchain.ledger.data.HashEncoding; | |||
// | |||
//import my.utils.io.ByteArray; | |||
//import my.utils.io.BytesEncoding; | |||
//import my.utils.io.BytesReader; | |||
//import my.utils.io.BytesUtils; | |||
//import my.utils.io.BytesWriter; | |||
//import my.utils.io.NumberMask; | |||
// | |||
//import java.io.IOException; | |||
//import java.io.InputStream; | |||
//import java.io.OutputStream; | |||
//import java.util.Objects; | |||
// | |||
///** | |||
// * Ledger 实现 | |||
// * | |||
// * @author zhaoming9 | |||
// */ | |||
//public class LedgerImpl implements Ledger, BytesWriter, BytesReader { | |||
// | |||
// private HashAlgorithm ledgerHashAlgorithm = HashAlgorithm.SHA256; // 账本hash算法 | |||
// private ByteArray ledgerHash = ByteArray.EMPTY; // 账本hash | |||
// | |||
// private long blockHeight = 0; // 账本当前高度 | |||
// private long blockVersion = 0; // 账本当前版本 | |||
// | |||
// private HashAlgorithm currentBlockHashAlgorithm = HashAlgorithm.SHA256; // 账本当前区块hash算法 | |||
// private ByteArray currentBlockHash = ByteArray.EMPTY; // 账本当前区块hash | |||
// | |||
// private HashAlgorithm previousBlockHashAlgorithm = HashAlgorithm.SHA256; // 账本前一区块hash算法 | |||
// private ByteArray previousBlockHash = ByteArray.EMPTY; // 账本前一区块hash | |||
// | |||
// private ByteArray accountRoot = ByteArray.EMPTY; // account mpt root hash | |||
// private long accountCount; // 账户数量 | |||
// private long txTotalCount; // 交易数量 | |||
// | |||
// private ByteArray genesisKey=ByteArray.EMPTY; // 创世块随机序列 | |||
// | |||
// public LedgerImpl() { | |||
// } | |||
// | |||
// /** | |||
// * 初始化一个新的账本; | |||
// * @param genesisKey | |||
// */ | |||
// public LedgerImpl(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// /** | |||
// * @param ledgerHashAlgorithm | |||
// * @param ledgerHash | |||
// * @param height | |||
// * @param version | |||
// * @param currentBlockHashAlgorithm | |||
// * @param currentBlockHash | |||
// * @param previousBlockHashAlgorithm | |||
// * @param previousBlockHash | |||
// * @param accountRoot | |||
// * @param accountCount | |||
// * @param txTotalCount | |||
// * @param genesisKey | |||
// */ | |||
// private LedgerImpl(HashAlgorithm ledgerHashAlgorithm, ByteArray ledgerHash, long height, long version, | |||
// HashAlgorithm currentBlockHashAlgorithm, ByteArray currentBlockHash, | |||
// HashAlgorithm previousBlockHashAlgorithm, ByteArray previousBlockHash, | |||
// ByteArray accountRoot, long accountCount, long txTotalCount, ByteArray genesisKey) { | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// this.ledgerHash = ledgerHash; | |||
// this.blockHeight = height; | |||
// this.blockVersion = version; | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// this.currentBlockHash = currentBlockHash; | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// this.previousBlockHash = previousBlockHash; | |||
// this.accountRoot = accountRoot; | |||
// this.accountCount = accountCount; | |||
// this.txTotalCount = txTotalCount; | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public LedgerImpl(ByteArray ledgerHash, long blockHeight, long blockVersion, ByteArray currentBlockHash, | |||
// ByteArray previousBlockHash, ByteArray accountRoot, long accountCount, long txTotalCount, ByteArray genesisKey) { | |||
// this(HashAlgorithm.SHA256, ledgerHash, blockHeight, blockVersion, HashAlgorithm.SHA256, currentBlockHash, | |||
// HashAlgorithm.SHA256, previousBlockHash, accountRoot, accountCount, txTotalCount, genesisKey); | |||
// } | |||
// | |||
// public LedgerImpl(LedgerImpl ledger) { | |||
// this(ledger.getLedgerHashAlgorithm(), ledger.getLedgerHash(), ledger.getBlockHeight(), ledger.getBlockVersion(), | |||
// ledger.getCurrentBlockHashAlgorithm(), ledger.getCurrentBlockHash(), | |||
// ledger.getPreviousBlockHashAlgorithm(), ledger.getPreviousBlockHash(), | |||
// ledger.getAccountRoot(), ledger.getAccountCount(), ledger.getTxTotalCount(),ledger.getGenesisKey()); | |||
// } | |||
// | |||
// public LedgerImpl nextLedger(ByteArray nextBlockHash, ByteArray accountRoot, long newAccountCnt, long newTxCnt) { | |||
// LedgerImpl nextLedger = new LedgerImpl(this); | |||
// nextLedger.blockHeight+=1; | |||
// nextLedger.previousBlockHash = nextLedger.currentBlockHash; | |||
// nextLedger.currentBlockHash = nextBlockHash; | |||
// nextLedger.accountRoot = accountRoot; | |||
// nextLedger.accountCount += newAccountCnt; | |||
// nextLedger.txTotalCount += newTxCnt; | |||
// | |||
// return nextLedger; | |||
// } | |||
// | |||
// /** | |||
// * 账本的 hash; <br> | |||
// * <p> | |||
// * 同时也是账本的唯一,等同于其创世区块(GenisisBlock)的 hash | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getLedgerHash() { | |||
// return ledgerHash; | |||
// } | |||
// | |||
// /** | |||
// * 由随机数构成的该账本的创世序列; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getGenesisKey() { | |||
// return genesisKey; | |||
// } | |||
// | |||
// /** | |||
// * 当前最新区块的 hash; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getBlockHash() { | |||
// return currentBlockHash; | |||
// } | |||
// | |||
// public HashAlgorithm getBlockHashAlgorithm() { | |||
// return currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// /** | |||
// * 账本的区块高度; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public long getBlockHeight() { | |||
// return blockHeight; | |||
// } | |||
// | |||
// @Override | |||
// public void resolvFrom(InputStream in) throws IOException { | |||
// HashAlgorithm ledgerHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(ledgerHashAlgorithm); | |||
// ByteArray ledgerHash = HashEncoding.read(in); | |||
// | |||
// long height = BytesUtils.readLong(in); | |||
// long version = BytesUtils.readLong(in); | |||
// | |||
// HashAlgorithm currentBlockHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(currentBlockHashAlgorithm); | |||
// ByteArray currentBlockHash = HashEncoding.read(in); | |||
// | |||
// HashAlgorithm previousBlockHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(previousBlockHashAlgorithm); | |||
// ByteArray previousBlockHash = HashEncoding.read(in); | |||
// | |||
// ByteArray accountHash = HashEncoding.read(in); | |||
// long accountCount = BytesUtils.readLong(in); | |||
// long txTotalCount = BytesUtils.readLong(in); | |||
// ByteArray key = BytesEncoding.readAsByteArray(NumberMask.SHORT, in); | |||
// | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// this.ledgerHash = ledgerHash; | |||
// this.blockHeight = height; | |||
// this.blockVersion = version; | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// this.currentBlockHash = currentBlockHash; | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// this.previousBlockHash = previousBlockHash; | |||
// this.accountRoot = accountHash; | |||
// this.accountCount = accountCount; | |||
// this.txTotalCount = txTotalCount; | |||
// this.genesisKey = key; | |||
// } | |||
// | |||
// @Override | |||
// public void writeTo(OutputStream out) throws IOException { | |||
// BytesUtils.writeByte(ledgerHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(ledgerHash, out); | |||
// | |||
// BytesUtils.writeLong(blockHeight, out); | |||
// BytesUtils.writeLong(blockVersion, out); | |||
// | |||
// BytesUtils.writeByte(currentBlockHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(currentBlockHash, out); | |||
// | |||
// BytesUtils.writeByte(previousBlockHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(previousBlockHash, out); | |||
// | |||
// HashEncoding.write(accountRoot, out); | |||
// BytesUtils.writeLong(accountCount, out); | |||
// BytesUtils.writeLong(txTotalCount, out); | |||
// BytesEncoding.write(genesisKey, NumberMask.SHORT, out); | |||
// } | |||
// | |||
// public HashAlgorithm getLedgerHashAlgorithm() { | |||
// return ledgerHashAlgorithm; | |||
// } | |||
// | |||
// public void setLedgerHashAlgorithm(HashAlgorithm ledgerHashAlgorithm) { | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// } | |||
// | |||
// public void setLedgerHash(ByteArray ledgerHash) { | |||
// this.ledgerHash = ledgerHash; | |||
// } | |||
// | |||
// public void setBlockHeight(long blockHeight) { | |||
// this.blockHeight = blockHeight; | |||
// } | |||
// | |||
// public HashAlgorithm getCurrentBlockHashAlgorithm() { | |||
// return currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// public void setCurrentBlockHashAlgorithm(HashAlgorithm currentBlockHashAlgorithm) { | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// public long getBlockVersion() { | |||
// return blockVersion; | |||
// } | |||
// | |||
// public void setBlockVersion(long blockVersion) { | |||
// this.blockVersion = blockVersion; | |||
// } | |||
// | |||
// public void setGenesisKey(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public ByteArray getCurrentBlockHash() { | |||
// return currentBlockHash; | |||
// } | |||
// | |||
// public void setCurrentBlockHash(ByteArray currentBlockHash) { | |||
// this.currentBlockHash = currentBlockHash; | |||
// } | |||
// | |||
// public HashAlgorithm getPreviousBlockHashAlgorithm() { | |||
// return previousBlockHashAlgorithm; | |||
// } | |||
// | |||
// public void setPreviousBlockHashAlgorithm(HashAlgorithm previousBlockHashAlgorithm) { | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// } | |||
// | |||
// public ByteArray getAccountRoot() { | |||
// return accountRoot; | |||
// } | |||
// | |||
// public void setAccountRoot(ByteArray accountRoot) { | |||
// this.accountRoot = accountRoot; | |||
// } | |||
// | |||
// public long getAccountCount() { | |||
// return accountCount; | |||
// } | |||
// | |||
// public void setAccountCount(long accountCount) { | |||
// this.accountCount = accountCount; | |||
// } | |||
// | |||
// public long getTxTotalCount() { | |||
// return txTotalCount; | |||
// } | |||
// | |||
// public void setTxTotalCount(long txTotalCount) { | |||
// this.txTotalCount = txTotalCount; | |||
// } | |||
// | |||
// public ByteArray getPreviousBlockHash() { | |||
// return previousBlockHash; | |||
// } | |||
// | |||
// public void setPreviousBlockHash(ByteArray previousBlockHash) { | |||
// this.previousBlockHash = previousBlockHash; | |||
// } | |||
// | |||
// @Override | |||
// public boolean equals(Object o) { | |||
// if (this == o) return true; | |||
// if (!(o instanceof LedgerImpl)) return false; | |||
// LedgerImpl ledger = (LedgerImpl) o; | |||
// return getBlockHeight() == ledger.getBlockHeight() && | |||
// getBlockVersion() == ledger.getBlockVersion() && | |||
// getLedgerHashAlgorithm() == ledger.getLedgerHashAlgorithm() && | |||
// Objects.equals(getLedgerHash(), ledger.getLedgerHash()) && | |||
// getCurrentBlockHashAlgorithm() == ledger.getCurrentBlockHashAlgorithm() && | |||
// Objects.equals(getCurrentBlockHash(), ledger.getCurrentBlockHash()) && | |||
// getPreviousBlockHashAlgorithm() == ledger.getPreviousBlockHashAlgorithm() && | |||
// Objects.equals(getPreviousBlockHash(), ledger.getPreviousBlockHash()) && | |||
// Objects.equals(getGenesisKey(), ledger.getGenesisKey()); | |||
// } | |||
// | |||
// @Override | |||
// public int hashCode() { | |||
// | |||
// return Objects.hash(getLedgerHashAlgorithm(), getLedgerHash(), getBlockHeight(), getBlockVersion(), getCurrentBlockHashAlgorithm(), getCurrentBlockHash(), getPreviousBlockHashAlgorithm(), getPreviousBlockHash(), getGenesisKey()); | |||
// } | |||
// | |||
// @Override | |||
// public long getLedgerVersion() { | |||
// // TODO Auto-generated method stub | |||
// return 0; | |||
// } | |||
//} | |||
//package com.jd.blockchain.ledger; | |||
// | |||
//import com.jd.blockchain.ledger.data.HashEncoding; | |||
// | |||
//import my.utils.io.ByteArray; | |||
//import my.utils.io.BytesEncoding; | |||
//import my.utils.io.BytesReader; | |||
//import my.utils.io.BytesUtils; | |||
//import my.utils.io.BytesWriter; | |||
//import my.utils.io.NumberMask; | |||
// | |||
//import java.io.IOException; | |||
//import java.io.InputStream; | |||
//import java.io.OutputStream; | |||
//import java.util.Objects; | |||
// | |||
///** | |||
// * Ledger 实现 | |||
// * | |||
// * @author zhaoming9 | |||
// */ | |||
//public class LedgerImpl implements Ledger, BytesWriter, BytesReader { | |||
// | |||
// private HashAlgorithm ledgerHashAlgorithm = HashAlgorithm.SHA256; // 账本hash算法 | |||
// private ByteArray ledgerHash = ByteArray.EMPTY; // 账本hash | |||
// | |||
// private long blockHeight = 0; // 账本当前高度 | |||
// private long blockVersion = 0; // 账本当前版本 | |||
// | |||
// private HashAlgorithm currentBlockHashAlgorithm = HashAlgorithm.SHA256; // 账本当前区块hash算法 | |||
// private ByteArray currentBlockHash = ByteArray.EMPTY; // 账本当前区块hash | |||
// | |||
// private HashAlgorithm previousBlockHashAlgorithm = HashAlgorithm.SHA256; // 账本前一区块hash算法 | |||
// private ByteArray previousBlockHash = ByteArray.EMPTY; // 账本前一区块hash | |||
// | |||
// private ByteArray accountRoot = ByteArray.EMPTY; // account mpt root hash | |||
// private long accountCount; // 账户数量 | |||
// private long txTotalCount; // 交易数量 | |||
// | |||
// private ByteArray genesisKey=ByteArray.EMPTY; // 创世块随机序列 | |||
// | |||
// public LedgerImpl() { | |||
// } | |||
// | |||
// /** | |||
// * 初始化一个新的账本; | |||
// * @param genesisKey | |||
// */ | |||
// public LedgerImpl(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// /** | |||
// * @param ledgerHashAlgorithm | |||
// * @param ledgerHash | |||
// * @param height | |||
// * @param version | |||
// * @param currentBlockHashAlgorithm | |||
// * @param currentBlockHash | |||
// * @param previousBlockHashAlgorithm | |||
// * @param previousBlockHash | |||
// * @param accountRoot | |||
// * @param accountCount | |||
// * @param txTotalCount | |||
// * @param genesisKey | |||
// */ | |||
// private LedgerImpl(HashAlgorithm ledgerHashAlgorithm, ByteArray ledgerHash, long height, long version, | |||
// HashAlgorithm currentBlockHashAlgorithm, ByteArray currentBlockHash, | |||
// HashAlgorithm previousBlockHashAlgorithm, ByteArray previousBlockHash, | |||
// ByteArray accountRoot, long accountCount, long txTotalCount, ByteArray genesisKey) { | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// this.ledgerHash = ledgerHash; | |||
// this.blockHeight = height; | |||
// this.blockVersion = version; | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// this.currentBlockHash = currentBlockHash; | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// this.previousBlockHash = previousBlockHash; | |||
// this.accountRoot = accountRoot; | |||
// this.accountCount = accountCount; | |||
// this.txTotalCount = txTotalCount; | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public LedgerImpl(ByteArray ledgerHash, long blockHeight, long blockVersion, ByteArray currentBlockHash, | |||
// ByteArray previousBlockHash, ByteArray accountRoot, long accountCount, long txTotalCount, ByteArray genesisKey) { | |||
// this(HashAlgorithm.SHA256, ledgerHash, blockHeight, blockVersion, HashAlgorithm.SHA256, currentBlockHash, | |||
// HashAlgorithm.SHA256, previousBlockHash, accountRoot, accountCount, txTotalCount, genesisKey); | |||
// } | |||
// | |||
// public LedgerImpl(LedgerImpl ledger) { | |||
// this(ledger.getLedgerHashAlgorithm(), ledger.getLedgerHash(), ledger.getBlockHeight(), ledger.getBlockVersion(), | |||
// ledger.getCurrentBlockHashAlgorithm(), ledger.getCurrentBlockHash(), | |||
// ledger.getPreviousBlockHashAlgorithm(), ledger.getPreviousBlockHash(), | |||
// ledger.getAccountRoot(), ledger.getAccountCount(), ledger.getTxTotalCount(),ledger.getGenesisKey()); | |||
// } | |||
// | |||
// public LedgerImpl nextLedger(ByteArray nextBlockHash, ByteArray accountRoot, long newAccountCnt, long newTxCnt) { | |||
// LedgerImpl nextLedger = new LedgerImpl(this); | |||
// nextLedger.blockHeight+=1; | |||
// nextLedger.previousBlockHash = nextLedger.currentBlockHash; | |||
// nextLedger.currentBlockHash = nextBlockHash; | |||
// nextLedger.accountRoot = accountRoot; | |||
// nextLedger.accountCount += newAccountCnt; | |||
// nextLedger.txTotalCount += newTxCnt; | |||
// | |||
// return nextLedger; | |||
// } | |||
// | |||
// /** | |||
// * 账本的 hash; <br> | |||
// * <p> | |||
// * 同时也是账本的唯一,等同于其创世区块(GenisisBlock)的 hash | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getLedgerHash() { | |||
// return ledgerHash; | |||
// } | |||
// | |||
// /** | |||
// * 由随机数构成的该账本的创世序列; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getGenesisKey() { | |||
// return genesisKey; | |||
// } | |||
// | |||
// /** | |||
// * 当前最新区块的 hash; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public ByteArray getBlockHash() { | |||
// return currentBlockHash; | |||
// } | |||
// | |||
// public HashAlgorithm getBlockHashAlgorithm() { | |||
// return currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// /** | |||
// * 账本的区块高度; | |||
// * | |||
// * @return | |||
// */ | |||
// @Override | |||
// public long getBlockHeight() { | |||
// return blockHeight; | |||
// } | |||
// | |||
// @Override | |||
// public void resolvFrom(InputStream in) throws IOException { | |||
// HashAlgorithm ledgerHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(ledgerHashAlgorithm); | |||
// ByteArray ledgerHash = HashEncoding.read(in); | |||
// | |||
// long height = BytesUtils.readLong(in); | |||
// long version = BytesUtils.readLong(in); | |||
// | |||
// HashAlgorithm currentBlockHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(currentBlockHashAlgorithm); | |||
// ByteArray currentBlockHash = HashEncoding.read(in); | |||
// | |||
// HashAlgorithm previousBlockHashAlgorithm = HashAlgorithm.valueOf(BytesUtils.readByte(in)); | |||
// HashAlgorithm.checkHashAlgorithm(previousBlockHashAlgorithm); | |||
// ByteArray previousBlockHash = HashEncoding.read(in); | |||
// | |||
// ByteArray accountHash = HashEncoding.read(in); | |||
// long accountCount = BytesUtils.readLong(in); | |||
// long txTotalCount = BytesUtils.readLong(in); | |||
// ByteArray key = BytesEncoding.readAsByteArray(NumberMask.SHORT, in); | |||
// | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// this.ledgerHash = ledgerHash; | |||
// this.blockHeight = height; | |||
// this.blockVersion = version; | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// this.currentBlockHash = currentBlockHash; | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// this.previousBlockHash = previousBlockHash; | |||
// this.accountRoot = accountHash; | |||
// this.accountCount = accountCount; | |||
// this.txTotalCount = txTotalCount; | |||
// this.genesisKey = key; | |||
// } | |||
// | |||
// @Override | |||
// public void writeTo(OutputStream out) throws IOException { | |||
// BytesUtils.writeByte(ledgerHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(ledgerHash, out); | |||
// | |||
// BytesUtils.writeLong(blockHeight, out); | |||
// BytesUtils.writeLong(blockVersion, out); | |||
// | |||
// BytesUtils.writeByte(currentBlockHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(currentBlockHash, out); | |||
// | |||
// BytesUtils.writeByte(previousBlockHashAlgorithm.getAlgorithm(), out); | |||
// HashEncoding.write(previousBlockHash, out); | |||
// | |||
// HashEncoding.write(accountRoot, out); | |||
// BytesUtils.writeLong(accountCount, out); | |||
// BytesUtils.writeLong(txTotalCount, out); | |||
// BytesEncoding.write(genesisKey, NumberMask.SHORT, out); | |||
// } | |||
// | |||
// public HashAlgorithm getLedgerHashAlgorithm() { | |||
// return ledgerHashAlgorithm; | |||
// } | |||
// | |||
// public void setLedgerHashAlgorithm(HashAlgorithm ledgerHashAlgorithm) { | |||
// this.ledgerHashAlgorithm = ledgerHashAlgorithm; | |||
// } | |||
// | |||
// public void setLedgerHash(ByteArray ledgerHash) { | |||
// this.ledgerHash = ledgerHash; | |||
// } | |||
// | |||
// public void setBlockHeight(long blockHeight) { | |||
// this.blockHeight = blockHeight; | |||
// } | |||
// | |||
// public HashAlgorithm getCurrentBlockHashAlgorithm() { | |||
// return currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// public void setCurrentBlockHashAlgorithm(HashAlgorithm currentBlockHashAlgorithm) { | |||
// this.currentBlockHashAlgorithm = currentBlockHashAlgorithm; | |||
// } | |||
// | |||
// public long getBlockVersion() { | |||
// return blockVersion; | |||
// } | |||
// | |||
// public void setBlockVersion(long blockVersion) { | |||
// this.blockVersion = blockVersion; | |||
// } | |||
// | |||
// public void setGenesisKey(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public ByteArray getCurrentBlockHash() { | |||
// return currentBlockHash; | |||
// } | |||
// | |||
// public void setCurrentBlockHash(ByteArray currentBlockHash) { | |||
// this.currentBlockHash = currentBlockHash; | |||
// } | |||
// | |||
// public HashAlgorithm getPreviousBlockHashAlgorithm() { | |||
// return previousBlockHashAlgorithm; | |||
// } | |||
// | |||
// public void setPreviousBlockHashAlgorithm(HashAlgorithm previousBlockHashAlgorithm) { | |||
// this.previousBlockHashAlgorithm = previousBlockHashAlgorithm; | |||
// } | |||
// | |||
// public ByteArray getAccountRoot() { | |||
// return accountRoot; | |||
// } | |||
// | |||
// public void setAccountRoot(ByteArray accountRoot) { | |||
// this.accountRoot = accountRoot; | |||
// } | |||
// | |||
// public long getAccountCount() { | |||
// return accountCount; | |||
// } | |||
// | |||
// public void setAccountCount(long accountCount) { | |||
// this.accountCount = accountCount; | |||
// } | |||
// | |||
// public long getTxTotalCount() { | |||
// return txTotalCount; | |||
// } | |||
// | |||
// public void setTxTotalCount(long txTotalCount) { | |||
// this.txTotalCount = txTotalCount; | |||
// } | |||
// | |||
// public ByteArray getPreviousBlockHash() { | |||
// return previousBlockHash; | |||
// } | |||
// | |||
// public void setPreviousBlockHash(ByteArray previousBlockHash) { | |||
// this.previousBlockHash = previousBlockHash; | |||
// } | |||
// | |||
// @Override | |||
// public boolean equals(Object o) { | |||
// if (this == o) return true; | |||
// if (!(o instanceof LedgerImpl)) return false; | |||
// LedgerImpl ledger = (LedgerImpl) o; | |||
// return getBlockHeight() == ledger.getBlockHeight() && | |||
// getBlockVersion() == ledger.getBlockVersion() && | |||
// getLedgerHashAlgorithm() == ledger.getLedgerHashAlgorithm() && | |||
// Objects.equals(getLedgerHash(), ledger.getLedgerHash()) && | |||
// getCurrentBlockHashAlgorithm() == ledger.getCurrentBlockHashAlgorithm() && | |||
// Objects.equals(getCurrentBlockHash(), ledger.getCurrentBlockHash()) && | |||
// getPreviousBlockHashAlgorithm() == ledger.getPreviousBlockHashAlgorithm() && | |||
// Objects.equals(getPreviousBlockHash(), ledger.getPreviousBlockHash()) && | |||
// Objects.equals(getGenesisKey(), ledger.getGenesisKey()); | |||
// } | |||
// | |||
// @Override | |||
// public int hashCode() { | |||
// | |||
// return Objects.hash(getLedgerHashAlgorithm(), getLedgerHash(), getBlockHeight(), getBlockVersion(), getCurrentBlockHashAlgorithm(), getCurrentBlockHash(), getPreviousBlockHashAlgorithm(), getPreviousBlockHash(), getGenesisKey()); | |||
// } | |||
// | |||
// @Override | |||
// public long getLedgerVersion() { | |||
// // TODO Auto-generated method stub | |||
// return 0; | |||
// } | |||
//} |
@@ -1,13 +1,13 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_LEDGER_INIT) | |||
public interface LedgerInitOperation extends Operation{ | |||
@DataField(order=1, refContract=true) | |||
LedgerInitSetting getInitSetting(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code= DataCodes.TX_OP_LEDGER_INIT) | |||
public interface LedgerInitOperation extends Operation{ | |||
@DataField(order=1, refContract=true) | |||
LedgerInitSetting getInitSetting(); | |||
} |
@@ -1,67 +1,67 @@ | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 魔数表; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class MagicNumber { | |||
/** | |||
* JD区块链系统标识的高位,即小写字母 j 的 ASCII; | |||
* | |||
*/ | |||
public static final byte JD_HIGH = 0x6A; | |||
/** | |||
* JD区块链系统标识的低位, 即小写字母 d 的 ASCII; | |||
*/ | |||
public static final byte JD_LOW = 0x64; | |||
/** | |||
* 创世区块标识; | |||
*/ | |||
public static final byte GENESIS_BLOCK = 0x00; | |||
/** | |||
* 子区块标识; | |||
* | |||
* 注:“子区块”是除了“创世区块”之外其它的区块; | |||
*/ | |||
public static final byte CHILD_BLOCK = 0x01; | |||
/** | |||
* 交易内容标识; | |||
*/ | |||
public static final byte TX_CONTENT = 0x10; | |||
/** | |||
* 交易请求标识; | |||
*/ | |||
public static final byte TX_REQUEST = 0x11; | |||
/** | |||
* 交易持久标识; | |||
*/ | |||
public static final byte TX_PERSISTENCE = 0x12; | |||
/** | |||
* 数字签名标识; | |||
*/ | |||
public static final byte SIGNATURE = 0x20; | |||
// /** | |||
// * 公钥标识; | |||
// */ | |||
// public static final byte PUB_KEY = 0x21; | |||
// | |||
// /** | |||
// * 私钥标识; | |||
// */ | |||
// public static final byte PRIV_KEY = 0x22; | |||
} | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 魔数表; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class MagicNumber { | |||
/** | |||
* JD区块链系统标识的高位,即小写字母 j 的 ASCII; | |||
* | |||
*/ | |||
public static final byte JD_HIGH = 0x6A; | |||
/** | |||
* JD区块链系统标识的低位, 即小写字母 d 的 ASCII; | |||
*/ | |||
public static final byte JD_LOW = 0x64; | |||
/** | |||
* 创世区块标识; | |||
*/ | |||
public static final byte GENESIS_BLOCK = 0x00; | |||
/** | |||
* 子区块标识; | |||
* | |||
* 注:“子区块”是除了“创世区块”之外其它的区块; | |||
*/ | |||
public static final byte CHILD_BLOCK = 0x01; | |||
/** | |||
* 交易内容标识; | |||
*/ | |||
public static final byte TX_CONTENT = 0x10; | |||
/** | |||
* 交易请求标识; | |||
*/ | |||
public static final byte TX_REQUEST = 0x11; | |||
/** | |||
* 交易持久标识; | |||
*/ | |||
public static final byte TX_PERSISTENCE = 0x12; | |||
/** | |||
* 数字签名标识; | |||
*/ | |||
public static final byte SIGNATURE = 0x20; | |||
// /** | |||
// * 公钥标识; | |||
// */ | |||
// public static final byte PUB_KEY = 0x21; | |||
// | |||
// /** | |||
// * 私钥标识; | |||
// */ | |||
// public static final byte PRIV_KEY = 0x22; | |||
} |
@@ -1,22 +1,22 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code = DataCodes.REQUEST_NODE) | |||
public interface NodeRequest extends EndpointRequest { | |||
/** | |||
* 接入交易的节点的签名;<br> | |||
* | |||
* 注:能够提交交易的节点可以是共识节点或网关节点; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=1, list=true, refContract=true) | |||
DigitalSignature[] getNodeSignatures(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code = DataCodes.REQUEST_NODE) | |||
public interface NodeRequest extends EndpointRequest { | |||
/** | |||
* 接入交易的节点的签名;<br> | |||
* | |||
* 注:能够提交交易的节点可以是共识节点或网关节点; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=1, list=true, refContract=true) | |||
DigitalSignature[] getNodeSignatures(); | |||
} |
@@ -1,27 +1,27 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
/** | |||
* 操作参数; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface OperationArgument { | |||
/** | |||
* 参数类型; <br> | |||
* | |||
* @return | |||
*/ | |||
byte getKey(); | |||
/** | |||
* 参数值; | |||
* | |||
* @return | |||
*/ | |||
ByteArray getValue(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.utils.io.ByteArray; | |||
/** | |||
* 操作参数; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface OperationArgument { | |||
/** | |||
* 参数类型; <br> | |||
* | |||
* @return | |||
*/ | |||
byte getKey(); | |||
/** | |||
* 参数值; | |||
* | |||
* @return | |||
*/ | |||
ByteArray getValue(); | |||
} |
@@ -1,68 +1,68 @@ | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 权限类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum PermissionType { | |||
/** | |||
* 账户权限配置; | |||
*/ | |||
SET_PRIVILEGE(1), | |||
/** | |||
* 注册参与方; | |||
*/ | |||
REG_PARTICIPANT(2), | |||
/** | |||
* 配置账本;包括除了{@link #SET_PRIVILEGE}、 {@link #REG_PARTICIPANT} 之外的其它账本设置,例如:设置密码参数、共识参数等; | |||
*/ | |||
CONFIG_LEDGER(4), | |||
/** | |||
* 用户注册; | |||
*/ | |||
REG_USER(8), | |||
/** | |||
* 注册数据账户; | |||
*/ | |||
REG_DATA_ACCOUNT(16), | |||
/** | |||
* 部署新的合约代码; | |||
*/ | |||
DEPLOY_CONTRACT(32), | |||
/** | |||
* 写入用户信息; | |||
*/ | |||
SET_USER(1024), | |||
/** | |||
* 写入数据; | |||
*/ | |||
SET_DATA(2048), | |||
/** | |||
* 写入数据; | |||
*/ | |||
INVOKE_CONTRACT(4096), | |||
/** | |||
* 升级合约代码; | |||
*/ | |||
UPDATE_CONTRACT(8192); | |||
public final int CODE; | |||
private PermissionType(int code) { | |||
this.CODE = code; | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 权限类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum PermissionType { | |||
/** | |||
* 账户权限配置; | |||
*/ | |||
SET_PRIVILEGE(1), | |||
/** | |||
* 注册参与方; | |||
*/ | |||
REG_PARTICIPANT(2), | |||
/** | |||
* 配置账本;包括除了{@link #SET_PRIVILEGE}、 {@link #REG_PARTICIPANT} 之外的其它账本设置,例如:设置密码参数、共识参数等; | |||
*/ | |||
CONFIG_LEDGER(4), | |||
/** | |||
* 用户注册; | |||
*/ | |||
REG_USER(8), | |||
/** | |||
* 注册数据账户; | |||
*/ | |||
REG_DATA_ACCOUNT(16), | |||
/** | |||
* 部署新的合约代码; | |||
*/ | |||
DEPLOY_CONTRACT(32), | |||
/** | |||
* 写入用户信息; | |||
*/ | |||
SET_USER(1024), | |||
/** | |||
* 写入数据; | |||
*/ | |||
SET_DATA(2048), | |||
/** | |||
* 写入数据; | |||
*/ | |||
INVOKE_CONTRACT(4096), | |||
/** | |||
* 升级合约代码; | |||
*/ | |||
UPDATE_CONTRACT(8192); | |||
public final int CODE; | |||
private PermissionType(int code) { | |||
this.CODE = code; | |||
} | |||
} |
@@ -1,39 +1,39 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 角色配置操作; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_OP_ROLE_CONFIGURE) | |||
public interface RolesConfigureOperation extends Operation { | |||
@DataField(order = 2, refContract = true, list = true) | |||
RolePrivilegeEntry[] getRoles(); | |||
@DataContract(code = DataCodes.TX_OP_ROLE_CONFIGURE_ENTRY) | |||
public static interface RolePrivilegeEntry { | |||
@DataField(order = 1, primitiveType = PrimitiveType.TEXT) | |||
String getRoleName(); | |||
@DataField(order = 2, refEnum = true, list = true) | |||
LedgerPermission[] getEnableLedgerPermissions(); | |||
@DataField(order = 3, refEnum = true, list = true) | |||
LedgerPermission[] getDisableLedgerPermissions(); | |||
@DataField(order = 4, refEnum = true, list = true) | |||
TransactionPermission[] getEnableTransactionPermissions(); | |||
@DataField(order = 5, refEnum = true, list = true) | |||
TransactionPermission[] getDisableTransactionPermissions(); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* 角色配置操作; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_OP_ROLE_CONFIGURE) | |||
public interface RolesConfigureOperation extends Operation { | |||
@DataField(order = 2, refContract = true, list = true) | |||
RolePrivilegeEntry[] getRoles(); | |||
@DataContract(code = DataCodes.TX_OP_ROLE_CONFIGURE_ENTRY) | |||
public static interface RolePrivilegeEntry { | |||
@DataField(order = 1, primitiveType = PrimitiveType.TEXT) | |||
String getRoleName(); | |||
@DataField(order = 2, refEnum = true, list = true) | |||
LedgerPermission[] getEnableLedgerPermissions(); | |||
@DataField(order = 3, refEnum = true, list = true) | |||
LedgerPermission[] getDisableLedgerPermissions(); | |||
@DataField(order = 4, refEnum = true, list = true) | |||
TransactionPermission[] getEnableTransactionPermissions(); | |||
@DataField(order = 5, refEnum = true, list = true) | |||
TransactionPermission[] getDisableTransactionPermissions(); | |||
} | |||
} |
@@ -1,21 +1,21 @@ | |||
package com.jd.blockchain.ledger; | |||
public interface SignatureInfo { | |||
/** | |||
* 签署账户的地址; | |||
* | |||
* @return | |||
*/ | |||
String getAddress(); | |||
/** | |||
* 签名的摘要; | |||
* | |||
* 注:采用Base64编码; | |||
* | |||
* @return | |||
*/ | |||
String getDigest(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
public interface SignatureInfo { | |||
/** | |||
* 签署账户的地址; | |||
* | |||
* @return | |||
*/ | |||
String getAddress(); | |||
/** | |||
* 签名的摘要; | |||
* | |||
* 注:采用Base64编码; | |||
* | |||
* @return | |||
*/ | |||
String getDigest(); | |||
} |
@@ -1,37 +1,37 @@ | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 状态操作类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum StateOpType { | |||
/** | |||
* 设置状态值; | |||
*/ | |||
SET((byte) 1), | |||
/** | |||
* 移除状态值; | |||
*/ | |||
REMOVE((byte) 0); | |||
public final byte CODE; | |||
private StateOpType(byte code) { | |||
this.CODE = code; | |||
} | |||
public static StateOpType valueOf(byte code) { | |||
for (StateOpType opType : StateOpType.values()) { | |||
if (opType.CODE == code) { | |||
return opType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Unsupported code[" + code + "] of StateOpType!"); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
/** | |||
* 状态操作类型; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public enum StateOpType { | |||
/** | |||
* 设置状态值; | |||
*/ | |||
SET((byte) 1), | |||
/** | |||
* 移除状态值; | |||
*/ | |||
REMOVE((byte) 0); | |||
public final byte CODE; | |||
private StateOpType(byte code) { | |||
this.CODE = code; | |||
} | |||
public static StateOpType valueOf(byte code) { | |||
for (StateOpType opType : StateOpType.values()) { | |||
if (opType.CODE == code) { | |||
return opType; | |||
} | |||
} | |||
throw new IllegalArgumentException("Unsupported code[" + code + "] of StateOpType!"); | |||
} | |||
} |
@@ -1,54 +1,54 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* Transaction 区块链交易,是被原子执行的操作集合; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX) | |||
public interface Transaction extends NodeRequest, HashObject { | |||
/** | |||
* 交易 Hash; | |||
* | |||
* 这是包含交易内容、签名列表、交易结果的完整性 hash; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
@Override | |||
HashDigest getHash(); | |||
/** | |||
* 交易被包含的区块高度; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, primitiveType = PrimitiveType.INT64) | |||
long getBlockHeight(); | |||
/** | |||
* 交易的执行结果; | |||
* | |||
* 值为枚举值 {@link TransactionState#CODE} 之一; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, refEnum = true) | |||
TransactionState getExecutionState(); | |||
/** | |||
* 交易的返回结果 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=4, list = true, refContract=true) | |||
OperationResult[] getOperationResults(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* Transaction 区块链交易,是被原子执行的操作集合; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX) | |||
public interface Transaction extends NodeRequest, HashObject { | |||
/** | |||
* 交易 Hash; | |||
* | |||
* 这是包含交易内容、签名列表、交易结果的完整性 hash; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
@Override | |||
HashDigest getHash(); | |||
/** | |||
* 交易被包含的区块高度; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, primitiveType = PrimitiveType.INT64) | |||
long getBlockHeight(); | |||
/** | |||
* 交易的执行结果; | |||
* | |||
* 值为枚举值 {@link TransactionState#CODE} 之一; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, refEnum = true) | |||
TransactionState getExecutionState(); | |||
/** | |||
* 交易的返回结果 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=4, list = true, refContract=true) | |||
OperationResult[] getOperationResults(); | |||
} |
@@ -1,51 +1,51 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.transaction.ClientOperator; | |||
import com.jd.blockchain.transaction.LedgerInitOperator; | |||
/** | |||
* 区块链交易模板; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionBuilder extends ClientOperator, LedgerInitOperator { | |||
HashDigest getLedgerHash(); | |||
/** | |||
* 基于当前的系统时间完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作;<br> | |||
* | |||
* @return | |||
*/ | |||
TransactionRequestBuilder prepareRequest(); | |||
/** | |||
* 生成交易内容; | |||
* | |||
* @return | |||
*/ | |||
TransactionContent prepareContent(); | |||
/** | |||
* 基于当前的系统时间完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作; | |||
* | |||
* @param time 交易时间戳; | |||
* @return | |||
*/ | |||
TransactionRequestBuilder prepareRequest(long time); | |||
/** | |||
* 生成交易内容; | |||
* | |||
* @param time 交易时间戳; | |||
* @return | |||
*/ | |||
TransactionContent prepareContent(long time); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.transaction.ClientOperator; | |||
import com.jd.blockchain.transaction.LedgerInitOperator; | |||
/** | |||
* 区块链交易模板; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionBuilder extends ClientOperator, LedgerInitOperator { | |||
HashDigest getLedgerHash(); | |||
/** | |||
* 基于当前的系统时间完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作;<br> | |||
* | |||
* @return | |||
*/ | |||
TransactionRequestBuilder prepareRequest(); | |||
/** | |||
* 生成交易内容; | |||
* | |||
* @return | |||
*/ | |||
TransactionContent prepareContent(); | |||
/** | |||
* 基于当前的系统时间完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作; | |||
* | |||
* @param time 交易时间戳; | |||
* @return | |||
*/ | |||
TransactionRequestBuilder prepareRequest(long time); | |||
/** | |||
* 生成交易内容; | |||
* | |||
* @param time 交易时间戳; | |||
* @return | |||
*/ | |||
TransactionContent prepareContent(long time); | |||
} |
@@ -1,81 +1,81 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* 已就绪的交易; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionRequestBuilder extends HashObject { | |||
/** | |||
* 交易内容的 Hash; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
HashDigest getHash(); | |||
/** | |||
* 交易数据内容; <br> | |||
* | |||
* <br> | |||
* 如果需要对交易进行外部签名,可以将此数据块发送到外部进行签名; | |||
* | |||
* @return | |||
*/ | |||
TransactionContent getTransactionContent(); | |||
/** | |||
* 对交易进行签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param privKey | |||
* 签名账户的私钥; | |||
* @return | |||
*/ | |||
DigitalSignature signAsEndpoint(AsymmetricKeypair keyPair); | |||
/** | |||
* 对交易进行签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param privKey | |||
* 签名账户的私钥; | |||
* @return | |||
*/ | |||
DigitalSignature signAsNode(AsymmetricKeypair keyPair); | |||
/** | |||
* 加入签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param digest | |||
* Base64格式的签名摘要; | |||
* @return | |||
*/ | |||
void addEndpointSignature(DigitalSignature... signature); | |||
/** | |||
* 加入签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param digest | |||
* Base64格式的签名摘要; | |||
* @return | |||
*/ | |||
void addNodeSignature(DigitalSignature... signatures); | |||
/** | |||
* 生成交易请求; | |||
* | |||
*/ | |||
TransactionRequest buildRequest(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* 已就绪的交易; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionRequestBuilder extends HashObject { | |||
/** | |||
* 交易内容的 Hash; | |||
* | |||
* @return | |||
*/ | |||
@Override | |||
HashDigest getHash(); | |||
/** | |||
* 交易数据内容; <br> | |||
* | |||
* <br> | |||
* 如果需要对交易进行外部签名,可以将此数据块发送到外部进行签名; | |||
* | |||
* @return | |||
*/ | |||
TransactionContent getTransactionContent(); | |||
/** | |||
* 对交易进行签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param privKey | |||
* 签名账户的私钥; | |||
* @return | |||
*/ | |||
DigitalSignature signAsEndpoint(AsymmetricKeypair keyPair); | |||
/** | |||
* 对交易进行签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param privKey | |||
* 签名账户的私钥; | |||
* @return | |||
*/ | |||
DigitalSignature signAsNode(AsymmetricKeypair keyPair); | |||
/** | |||
* 加入签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param digest | |||
* Base64格式的签名摘要; | |||
* @return | |||
*/ | |||
void addEndpointSignature(DigitalSignature... signature); | |||
/** | |||
* 加入签名; | |||
* | |||
* @param address | |||
* 签名账户的地址; | |||
* @param digest | |||
* Base64格式的签名摘要; | |||
* @return | |||
*/ | |||
void addNodeSignature(DigitalSignature... signatures); | |||
/** | |||
* 生成交易请求; | |||
* | |||
*/ | |||
TransactionRequest buildRequest(); | |||
} |
@@ -1,68 +1,68 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* 交易请求 {@link TransactionRequest} 的回复; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_RESPONSE) | |||
public interface TransactionResponse { | |||
/** | |||
* 交易原始内容的哈希; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getContentHash(); | |||
/** | |||
* 执行状态; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, refEnum = true) | |||
TransactionState getExecutionState(); | |||
/** | |||
* 交易被纳入的区块哈希; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getBlockHash(); | |||
/** | |||
* 交易被纳入的区块高度; | |||
* | |||
* <p> | |||
* 如果未生成区块,则返回 -1; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 4, primitiveType = PrimitiveType.INT64) | |||
long getBlockHeight(); | |||
/** | |||
* 交易是否执行成功 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 5, primitiveType = PrimitiveType.BOOLEAN) | |||
boolean isSuccess(); | |||
/** | |||
* 合约返回值 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=6, list=true, refContract = true) | |||
OperationResult[] getOperationResults(); | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
/** | |||
* 交易请求 {@link TransactionRequest} 的回复; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_RESPONSE) | |||
public interface TransactionResponse { | |||
/** | |||
* 交易原始内容的哈希; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getContentHash(); | |||
/** | |||
* 执行状态; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, refEnum = true) | |||
TransactionState getExecutionState(); | |||
/** | |||
* 交易被纳入的区块哈希; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, primitiveType = PrimitiveType.BYTES) | |||
HashDigest getBlockHash(); | |||
/** | |||
* 交易被纳入的区块高度; | |||
* | |||
* <p> | |||
* 如果未生成区块,则返回 -1; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 4, primitiveType = PrimitiveType.INT64) | |||
long getBlockHeight(); | |||
/** | |||
* 交易是否执行成功 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 5, primitiveType = PrimitiveType.BOOLEAN) | |||
boolean isSuccess(); | |||
/** | |||
* 合约返回值 | |||
* | |||
* @return | |||
*/ | |||
@DataField(order=6, list=true, refContract = true) | |||
OperationResult[] getOperationResults(); | |||
} |
@@ -1,16 +1,16 @@ | |||
package com.jd.blockchain.ledger; | |||
public class TransactionRollbackException extends RuntimeException { | |||
private static final long serialVersionUID = -1223140447229570029L; | |||
public TransactionRollbackException(String message) { | |||
super(message); | |||
} | |||
public TransactionRollbackException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
public class TransactionRollbackException extends RuntimeException { | |||
private static final long serialVersionUID = -1223140447229570029L; | |||
public TransactionRollbackException(String message) { | |||
super(message); | |||
} | |||
public TransactionRollbackException(String message, Throwable cause) { | |||
super(message, cause); | |||
} | |||
} |
@@ -1,27 +1,27 @@ | |||
package com.jd.blockchain.ledger; | |||
import java.io.Closeable; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.transaction.ClientOperator; | |||
/** | |||
* 区块链交易模板; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionTemplate extends ClientOperator, Closeable { | |||
HashDigest getLedgerHash(); | |||
/** | |||
* 完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作; | |||
* | |||
* @return | |||
*/ | |||
PreparedTransaction prepare(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import java.io.Closeable; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.transaction.ClientOperator; | |||
/** | |||
* 区块链交易模板; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface TransactionTemplate extends ClientOperator, Closeable { | |||
HashDigest getLedgerHash(); | |||
/** | |||
* 完成交易定义,并生成就绪的交易数据; <br> | |||
* | |||
* 注:调用此方法后,不能再向当前对象加入更多的操作; | |||
* | |||
* @return | |||
*/ | |||
PreparedTransaction prepare(); | |||
} |
@@ -1,57 +1,57 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 角色配置操作; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_OP_USER_ROLES_AUTHORIZE) | |||
public interface UserAuthorizeOperation extends Operation { | |||
@DataField(order = 2, refContract = true, list = true) | |||
UserRolesEntry[] getUserRolesAuthorizations(); | |||
@DataContract(code = DataCodes.TX_OP_USER_ROLE_AUTHORIZE_ENTRY) | |||
public static interface UserRolesEntry { | |||
/** | |||
* 用户地址; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 0, primitiveType = PrimitiveType.BYTES, list = true) | |||
Bytes[] getUserAddresses(); | |||
/** | |||
* 要更新的多角色权限策略; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, refEnum = true) | |||
RolesPolicy getPolicy(); | |||
/** | |||
* 授权的角色清单; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, primitiveType = PrimitiveType.TEXT, list = true) | |||
String[] getAuthorizedRoles(); | |||
/** | |||
* 取消授权的角色清单; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 4, primitiveType = PrimitiveType.TEXT, list = true) | |||
String[] getUnauthorizedRoles(); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.binaryproto.PrimitiveType; | |||
import com.jd.blockchain.consts.DataCodes; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 角色配置操作; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code = DataCodes.TX_OP_USER_ROLES_AUTHORIZE) | |||
public interface UserAuthorizeOperation extends Operation { | |||
@DataField(order = 2, refContract = true, list = true) | |||
UserRolesEntry[] getUserRolesAuthorizations(); | |||
@DataContract(code = DataCodes.TX_OP_USER_ROLE_AUTHORIZE_ENTRY) | |||
public static interface UserRolesEntry { | |||
/** | |||
* 用户地址; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 0, primitiveType = PrimitiveType.BYTES, list = true) | |||
Bytes[] getUserAddresses(); | |||
/** | |||
* 要更新的多角色权限策略; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 2, refEnum = true) | |||
RolesPolicy getPolicy(); | |||
/** | |||
* 授权的角色清单; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 3, primitiveType = PrimitiveType.TEXT, list = true) | |||
String[] getAuthorizedRoles(); | |||
/** | |||
* 取消授权的角色清单; | |||
* | |||
* @return | |||
*/ | |||
@DataField(order = 4, primitiveType = PrimitiveType.TEXT, list = true) | |||
String[] getUnauthorizedRoles(); | |||
} | |||
} |
@@ -1,29 +1,29 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code=DataCodes.TX_OP_USER_INFO_SET) | |||
public interface UserInfoSetOperation extends Operation { | |||
String getUserAddress(); | |||
KVEntry[] getPropertiesWriteSet(); | |||
@DataContract(code=DataCodes.TX_OP_USER_INFO_SET_KV) | |||
public static interface KVEntry{ | |||
String getKey(); | |||
String getValue(); | |||
long getExpectedVersion(); | |||
} | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.consts.DataCodes; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
@DataContract(code=DataCodes.TX_OP_USER_INFO_SET) | |||
public interface UserInfoSetOperation extends Operation { | |||
String getUserAddress(); | |||
KVEntry[] getPropertiesWriteSet(); | |||
@DataContract(code=DataCodes.TX_OP_USER_INFO_SET_KV) | |||
public static interface KVEntry{ | |||
String getKey(); | |||
String getValue(); | |||
long getExpectedVersion(); | |||
} | |||
} |
@@ -1,13 +1,13 @@ | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code = DataCodes.TX_OP_USER_REG) | |||
public interface UserRegisterOperation extends Operation { | |||
@DataField(order = 2, refContract = true) | |||
BlockchainIdentity getUserID(); | |||
} | |||
package com.jd.blockchain.ledger; | |||
import com.jd.blockchain.binaryproto.DataContract; | |||
import com.jd.blockchain.binaryproto.DataField; | |||
import com.jd.blockchain.consts.DataCodes; | |||
@DataContract(code = DataCodes.TX_OP_USER_REG) | |||
public interface UserRegisterOperation extends Operation { | |||
@DataField(order = 2, refContract = true) | |||
BlockchainIdentity getUserID(); | |||
} |
@@ -1,26 +1,26 @@ | |||
package com.jd.blockchain.setting; | |||
/** | |||
* 网关接入设置; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class GatewayIncomingSetting { | |||
private LedgerIncomingSetting[] ledgers; | |||
/** | |||
* 所有账本的接入设置; | |||
* | |||
* @return | |||
*/ | |||
public LedgerIncomingSetting[] getLedgers() { | |||
return ledgers; | |||
} | |||
public void setLedgers(LedgerIncomingSetting[] ledgerSettings) { | |||
this.ledgers = ledgerSettings; | |||
} | |||
} | |||
package com.jd.blockchain.setting; | |||
/** | |||
* 网关接入设置; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class GatewayIncomingSetting { | |||
private LedgerIncomingSetting[] ledgers; | |||
/** | |||
* 所有账本的接入设置; | |||
* | |||
* @return | |||
*/ | |||
public LedgerIncomingSetting[] getLedgers() { | |||
return ledgers; | |||
} | |||
public void setLedgers(LedgerIncomingSetting[] ledgerSettings) { | |||
this.ledgers = ledgerSettings; | |||
} | |||
} |
@@ -1,358 +1,358 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.utils.Bytes; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.net.NetworkAddress; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainOperationFactory implements ClientOperator, LedgerInitOperator { | |||
private static final SecurityOperationBuilderImpl SECURITY_OP_BUILDER = new SecurityOperationBuilderImpl(); | |||
private static final LedgerInitOperationBuilderImpl LEDGER_INIT_OP_BUILDER = new LedgerInitOperationBuilderImpl(); | |||
private static final UserRegisterOperationBuilderImpl USER_REG_OP_BUILDER = new UserRegisterOperationBuilderImpl(); | |||
private static final DataAccountRegisterOperationBuilderImpl DATA_ACC_REG_OP_BUILDER = new DataAccountRegisterOperationBuilderImpl(); | |||
private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl(); | |||
// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); | |||
private SecurityOperationBuilderFilter securityOpBuilder = new SecurityOperationBuilderFilter(); | |||
private static final ParticipantRegisterOperationBuilderImpl PARTICIPANT_REG_OP_BUILDER = new ParticipantRegisterOperationBuilderImpl(); | |||
private static final ParticipantStateUpdateOperationBuilderImpl PARTICIPANT_STATE_UPDATE_OP_BUILDER = new ParticipantStateUpdateOperationBuilderImpl(); | |||
private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); | |||
private UserRegisterOperationBuilder userRegOpBuilder = new UserRegisterOperationBuilderFilter(); | |||
private DataAccountRegisterOperationBuilder dataAccRegOpBuilder = new DataAccountRegisterOperationBuilderFilter(); | |||
private ContractCodeDeployOperationBuilder contractCodeDeployOpBuilder = new ContractCodeDeployOperationBuilderFilter(); | |||
private ContractEventSendOperationBuilder contractEventSendOpBuilder = new ContractEventSendOperationBuilderFilter(); | |||
private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder(); | |||
private ParticipantRegisterOperationBuilder participantRegOpBuilder = new ParticipantRegisterOperationBuilderFilter(); | |||
private ParticipantStateUpdateOperationBuilder participantStateModifyOpBuilder = new ParticipantStateUpdateOperationBuilderFilter(); | |||
// TODO: 暂时只支持单线程情形,未考虑多线程; | |||
private List<Operation> operationList = new ArrayList<>(); | |||
@Override | |||
public LedgerInitOperationBuilder ledgers() { | |||
return ledgerInitOpBuilder; | |||
} | |||
@Override | |||
public SecurityOperationBuilder security() { | |||
return securityOpBuilder; | |||
} | |||
@Override | |||
public UserRegisterOperationBuilder users() { | |||
return userRegOpBuilder; | |||
} | |||
@Override | |||
public DataAccountRegisterOperationBuilder dataAccounts() { | |||
return dataAccRegOpBuilder; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
return new DataAccountKVSetOperationBuilderFilter(Bytes.fromBase58(accountAddress)); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
return new DataAccountKVSetOperationBuilderFilter(accountAddress); | |||
} | |||
@Override | |||
public ContractCodeDeployOperationBuilder contracts() { | |||
return contractCodeDeployOpBuilder; | |||
} | |||
public ContractEventSendOperationBuilder contractEvents() { | |||
return contractEventSendOpBuilder; | |||
} | |||
@Override | |||
public ParticipantRegisterOperationBuilder participants() {return participantRegOpBuilder;} | |||
@Override | |||
public ParticipantStateUpdateOperationBuilder states() {return participantStateModifyOpBuilder;} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | |||
} | |||
/** | |||
* 返回已经定义的操作列表; | |||
* | |||
* @return | |||
*/ | |||
public Collection<Operation> getOperations() { | |||
return operationList; | |||
} | |||
/** | |||
* 返回与操作列表对应的返回值处理器; | |||
* | |||
* @return | |||
*/ | |||
public Collection<OperationResultHandle> getReturnValuetHandlers() { | |||
List<OperationResultHandle> resultHandlers = new ArrayList<OperationResultHandle>(); | |||
int index = 0; | |||
for (Operation op : operationList) { | |||
if (op instanceof ContractEventSendOperation) { | |||
// 操作具有返回值,创建对应的结果处理器; | |||
ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; | |||
ContractInvocation invocation = opTemp.getInvocation(); | |||
OperationResultHandle retnHandler; | |||
if (invocation == null) { | |||
retnHandler = new NullOperationReturnValueHandler(index); | |||
} else { | |||
invocation.setOperationIndex(index); | |||
retnHandler = invocation; | |||
} | |||
resultHandlers.add(retnHandler); | |||
} | |||
index++; | |||
} | |||
return resultHandlers; | |||
} | |||
public void clear() { | |||
operationList.clear(); | |||
} | |||
// --------------------------------- 内部类型 ----------------------------------- | |||
private class LedgerInitOperationBuilderFilter implements LedgerInitOperationBuilder { | |||
@Override | |||
public LedgerInitOperation create(LedgerInitSetting initSetting) { | |||
LedgerInitOperation op = LEDGER_INIT_OP_BUILDER.create(initSetting); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class UserRegisterOperationBuilderFilter implements UserRegisterOperationBuilder { | |||
@Override | |||
public UserRegisterOperation register(BlockchainIdentity userID) { | |||
UserRegisterOperation op = USER_REG_OP_BUILDER.register(userID); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class SecurityOperationBuilderFilter implements SecurityOperationBuilder { | |||
@Override | |||
public RolesConfigurer roles() { | |||
RolesConfigurer rolesConfigurer = SECURITY_OP_BUILDER.roles(); | |||
operationList.add(rolesConfigurer.getOperation()); | |||
return rolesConfigurer; | |||
} | |||
@Override | |||
public UserAuthorizer authorziations() { | |||
UserAuthorizer userAuthorizer = SECURITY_OP_BUILDER.authorziations(); | |||
operationList.add(userAuthorizer.getOperation()); | |||
return userAuthorizer; | |||
} | |||
} | |||
private class DataAccountRegisterOperationBuilderFilter implements DataAccountRegisterOperationBuilder { | |||
@Override | |||
public DataAccountRegisterOperation register(BlockchainIdentity accountID) { | |||
DataAccountRegisterOperation op = DATA_ACC_REG_OP_BUILDER.register(accountID); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { | |||
private DataAccountKVSetOperationBuilder innerBuilder; | |||
private DataAccountKVSetOperation op; | |||
public DataAccountKVSetOperationBuilderFilter(Bytes accountAddress) { | |||
innerBuilder = new DataAccountKVSetOperationBuilderImpl(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperation getOperation() { | |||
return innerBuilder.getOperation(); | |||
} | |||
private void addOperation() { | |||
if (op == null) { | |||
op = innerBuilder.getOperation(); | |||
operationList.add(op); | |||
} | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
innerBuilder.setText(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
innerBuilder.setInt64(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
innerBuilder.setBytes(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
innerBuilder.setBytes(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
innerBuilder.setImage(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
innerBuilder.setJSON(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
innerBuilder.setXML(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
innerBuilder.setTimestamp(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
} | |||
private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder { | |||
@Override | |||
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { | |||
ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ParticipantRegisterOperationBuilderFilter implements ParticipantRegisterOperationBuilder { | |||
@Override | |||
public ParticipantRegisterOperation register(String participantName, BlockchainIdentity participantIdentity, NetworkAddress networkAddress) { | |||
ParticipantRegisterOperation op = PARTICIPANT_REG_OP_BUILDER.register(participantName, participantIdentity, networkAddress); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ParticipantStateUpdateOperationBuilderFilter implements ParticipantStateUpdateOperationBuilder { | |||
@Override | |||
public ParticipantStateUpdateOperation update(BlockchainIdentity blockchainIdentity, NetworkAddress networkAddress, ParticipantNodeState participantNodeState) { | |||
ParticipantStateUpdateOperation op = PARTICIPANT_STATE_UPDATE_OP_BUILDER.update(blockchainIdentity, networkAddress, participantNodeState); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { | |||
@Override | |||
public ContractEventSendOperation send(String address, String event, BytesValueList args) { | |||
return send(Bytes.fromBase58(address), event, args); | |||
} | |||
@Override | |||
public synchronized ContractEventSendOperation send(Bytes address, String event, BytesValueList args) { | |||
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
/** | |||
* 不做任何操作的返回值处理器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private static class NullOperationReturnValueHandler implements OperationResultHandle { | |||
private int operationIndex; | |||
public NullOperationReturnValueHandler(int operationIndex) { | |||
this.operationIndex = operationIndex; | |||
} | |||
@Override | |||
public int getOperationIndex() { | |||
return operationIndex; | |||
} | |||
@Override | |||
public Object complete(BytesValue bytesValue) { | |||
return null; | |||
} | |||
@Override | |||
public void complete(Throwable error) { | |||
} | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.utils.Bytes; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.ledger.*; | |||
import com.jd.blockchain.utils.Bytes; | |||
import com.jd.blockchain.utils.net.NetworkAddress; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class BlockchainOperationFactory implements ClientOperator, LedgerInitOperator { | |||
private static final SecurityOperationBuilderImpl SECURITY_OP_BUILDER = new SecurityOperationBuilderImpl(); | |||
private static final LedgerInitOperationBuilderImpl LEDGER_INIT_OP_BUILDER = new LedgerInitOperationBuilderImpl(); | |||
private static final UserRegisterOperationBuilderImpl USER_REG_OP_BUILDER = new UserRegisterOperationBuilderImpl(); | |||
private static final DataAccountRegisterOperationBuilderImpl DATA_ACC_REG_OP_BUILDER = new DataAccountRegisterOperationBuilderImpl(); | |||
private static final ContractCodeDeployOperationBuilderImpl CONTRACT_CODE_DEPLOY_OP_BUILDER = new ContractCodeDeployOperationBuilderImpl(); | |||
// private static final ContractEventSendOperationBuilderImpl CONTRACT_EVENT_SEND_OP_BUILDER = new ContractEventSendOperationBuilderImpl(); | |||
private SecurityOperationBuilderFilter securityOpBuilder = new SecurityOperationBuilderFilter(); | |||
private static final ParticipantRegisterOperationBuilderImpl PARTICIPANT_REG_OP_BUILDER = new ParticipantRegisterOperationBuilderImpl(); | |||
private static final ParticipantStateUpdateOperationBuilderImpl PARTICIPANT_STATE_UPDATE_OP_BUILDER = new ParticipantStateUpdateOperationBuilderImpl(); | |||
private LedgerInitOperationBuilder ledgerInitOpBuilder = new LedgerInitOperationBuilderFilter(); | |||
private UserRegisterOperationBuilder userRegOpBuilder = new UserRegisterOperationBuilderFilter(); | |||
private DataAccountRegisterOperationBuilder dataAccRegOpBuilder = new DataAccountRegisterOperationBuilderFilter(); | |||
private ContractCodeDeployOperationBuilder contractCodeDeployOpBuilder = new ContractCodeDeployOperationBuilderFilter(); | |||
private ContractEventSendOperationBuilder contractEventSendOpBuilder = new ContractEventSendOperationBuilderFilter(); | |||
private ContractInvocationProxyBuilder contractInvoProxyBuilder = new ContractInvocationProxyBuilder(); | |||
private ParticipantRegisterOperationBuilder participantRegOpBuilder = new ParticipantRegisterOperationBuilderFilter(); | |||
private ParticipantStateUpdateOperationBuilder participantStateModifyOpBuilder = new ParticipantStateUpdateOperationBuilderFilter(); | |||
// TODO: 暂时只支持单线程情形,未考虑多线程; | |||
private List<Operation> operationList = new ArrayList<>(); | |||
@Override | |||
public LedgerInitOperationBuilder ledgers() { | |||
return ledgerInitOpBuilder; | |||
} | |||
@Override | |||
public SecurityOperationBuilder security() { | |||
return securityOpBuilder; | |||
} | |||
@Override | |||
public UserRegisterOperationBuilder users() { | |||
return userRegOpBuilder; | |||
} | |||
@Override | |||
public DataAccountRegisterOperationBuilder dataAccounts() { | |||
return dataAccRegOpBuilder; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
return new DataAccountKVSetOperationBuilderFilter(Bytes.fromBase58(accountAddress)); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
return new DataAccountKVSetOperationBuilderFilter(accountAddress); | |||
} | |||
@Override | |||
public ContractCodeDeployOperationBuilder contracts() { | |||
return contractCodeDeployOpBuilder; | |||
} | |||
public ContractEventSendOperationBuilder contractEvents() { | |||
return contractEventSendOpBuilder; | |||
} | |||
@Override | |||
public ParticipantRegisterOperationBuilder participants() {return participantRegOpBuilder;} | |||
@Override | |||
public ParticipantStateUpdateOperationBuilder states() {return participantStateModifyOpBuilder;} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
return contractInvoProxyBuilder.create(address, contractIntf, contractEventSendOpBuilder); | |||
} | |||
/** | |||
* 返回已经定义的操作列表; | |||
* | |||
* @return | |||
*/ | |||
public Collection<Operation> getOperations() { | |||
return operationList; | |||
} | |||
/** | |||
* 返回与操作列表对应的返回值处理器; | |||
* | |||
* @return | |||
*/ | |||
public Collection<OperationResultHandle> getReturnValuetHandlers() { | |||
List<OperationResultHandle> resultHandlers = new ArrayList<OperationResultHandle>(); | |||
int index = 0; | |||
for (Operation op : operationList) { | |||
if (op instanceof ContractEventSendOperation) { | |||
// 操作具有返回值,创建对应的结果处理器; | |||
ContractEventSendOpTemplate opTemp = (ContractEventSendOpTemplate) op; | |||
ContractInvocation invocation = opTemp.getInvocation(); | |||
OperationResultHandle retnHandler; | |||
if (invocation == null) { | |||
retnHandler = new NullOperationReturnValueHandler(index); | |||
} else { | |||
invocation.setOperationIndex(index); | |||
retnHandler = invocation; | |||
} | |||
resultHandlers.add(retnHandler); | |||
} | |||
index++; | |||
} | |||
return resultHandlers; | |||
} | |||
public void clear() { | |||
operationList.clear(); | |||
} | |||
// --------------------------------- 内部类型 ----------------------------------- | |||
private class LedgerInitOperationBuilderFilter implements LedgerInitOperationBuilder { | |||
@Override | |||
public LedgerInitOperation create(LedgerInitSetting initSetting) { | |||
LedgerInitOperation op = LEDGER_INIT_OP_BUILDER.create(initSetting); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class UserRegisterOperationBuilderFilter implements UserRegisterOperationBuilder { | |||
@Override | |||
public UserRegisterOperation register(BlockchainIdentity userID) { | |||
UserRegisterOperation op = USER_REG_OP_BUILDER.register(userID); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class SecurityOperationBuilderFilter implements SecurityOperationBuilder { | |||
@Override | |||
public RolesConfigurer roles() { | |||
RolesConfigurer rolesConfigurer = SECURITY_OP_BUILDER.roles(); | |||
operationList.add(rolesConfigurer.getOperation()); | |||
return rolesConfigurer; | |||
} | |||
@Override | |||
public UserAuthorizer authorziations() { | |||
UserAuthorizer userAuthorizer = SECURITY_OP_BUILDER.authorziations(); | |||
operationList.add(userAuthorizer.getOperation()); | |||
return userAuthorizer; | |||
} | |||
} | |||
private class DataAccountRegisterOperationBuilderFilter implements DataAccountRegisterOperationBuilder { | |||
@Override | |||
public DataAccountRegisterOperation register(BlockchainIdentity accountID) { | |||
DataAccountRegisterOperation op = DATA_ACC_REG_OP_BUILDER.register(accountID); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class DataAccountKVSetOperationBuilderFilter implements DataAccountKVSetOperationBuilder { | |||
private DataAccountKVSetOperationBuilder innerBuilder; | |||
private DataAccountKVSetOperation op; | |||
public DataAccountKVSetOperationBuilderFilter(Bytes accountAddress) { | |||
innerBuilder = new DataAccountKVSetOperationBuilderImpl(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperation getOperation() { | |||
return innerBuilder.getOperation(); | |||
} | |||
private void addOperation() { | |||
if (op == null) { | |||
op = innerBuilder.getOperation(); | |||
operationList.add(op); | |||
} | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
innerBuilder.setText(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
innerBuilder.setInt64(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
innerBuilder.setBytes(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
innerBuilder.setBytes(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
innerBuilder.setImage(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
innerBuilder.setJSON(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
innerBuilder.setXML(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
innerBuilder.setTimestamp(key, value, expVersion); | |||
addOperation(); | |||
return this; | |||
} | |||
} | |||
private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder { | |||
@Override | |||
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { | |||
ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ParticipantRegisterOperationBuilderFilter implements ParticipantRegisterOperationBuilder { | |||
@Override | |||
public ParticipantRegisterOperation register(String participantName, BlockchainIdentity participantIdentity, NetworkAddress networkAddress) { | |||
ParticipantRegisterOperation op = PARTICIPANT_REG_OP_BUILDER.register(participantName, participantIdentity, networkAddress); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ParticipantStateUpdateOperationBuilderFilter implements ParticipantStateUpdateOperationBuilder { | |||
@Override | |||
public ParticipantStateUpdateOperation update(BlockchainIdentity blockchainIdentity, NetworkAddress networkAddress, ParticipantNodeState participantNodeState) { | |||
ParticipantStateUpdateOperation op = PARTICIPANT_STATE_UPDATE_OP_BUILDER.update(blockchainIdentity, networkAddress, participantNodeState); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
private class ContractEventSendOperationBuilderFilter implements ContractEventSendOperationBuilder { | |||
@Override | |||
public ContractEventSendOperation send(String address, String event, BytesValueList args) { | |||
return send(Bytes.fromBase58(address), event, args); | |||
} | |||
@Override | |||
public synchronized ContractEventSendOperation send(Bytes address, String event, BytesValueList args) { | |||
ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); | |||
operationList.add(op); | |||
return op; | |||
} | |||
} | |||
/** | |||
* 不做任何操作的返回值处理器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
private static class NullOperationReturnValueHandler implements OperationResultHandle { | |||
private int operationIndex; | |||
public NullOperationReturnValueHandler(int operationIndex) { | |||
this.operationIndex = operationIndex; | |||
} | |||
@Override | |||
public int getOperationIndex() { | |||
return operationIndex; | |||
} | |||
@Override | |||
public Object complete(BytesValue bytesValue) { | |||
return null; | |||
} | |||
@Override | |||
public void complete(Throwable error) { | |||
} | |||
} | |||
} |
@@ -1,330 +1,330 @@ | |||
package com.jd.blockchain.transaction; | |||
import org.springframework.cglib.core.Block; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.Transaction; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
/** | |||
* 区块链查询器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface BlockchainQueryService { | |||
/** | |||
* 返回所有的账本的 hash 列表;<br> | |||
* | |||
* 注:账本的 hash 既是该账本的创世区块的 hash; | |||
* | |||
* @return 账本 hash 的集合; | |||
*/ | |||
HashDigest[] getLedgerHashs(); | |||
/** | |||
* 获取账本信息; | |||
* | |||
* @param ledgerHash | |||
* @return 账本对象;如果不存在,则返回 null; | |||
*/ | |||
LedgerInfo getLedger(HashDigest ledgerHash); | |||
/** | |||
* 获取账本信息; | |||
* | |||
* @param ledgerHash | |||
* @return 账本对象;如果不存在,则返回 null; | |||
*/ | |||
LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash); | |||
/** | |||
* 返回当前账本的参与者信息列表 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash); | |||
/** | |||
* 返回当前账本的元数据 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
LedgerMetadata getLedgerMetadata(HashDigest ledgerHash); | |||
/** | |||
* 返回指定账本序号的区块; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param height 高度; | |||
* @return | |||
*/ | |||
LedgerBlock getBlock(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块hash的区块; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param blockHash 区块hash; | |||
* @return | |||
*/ | |||
LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回指定高度的区块中记录的交易总数; | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getTransactionCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定高度的区块中记录的交易总数; | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的交易总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getTransactionTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度的区块中记录的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getDataAccountCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定的区块中记录的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getDataAccountTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度区块中的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getUserCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块中的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getUserCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getUserTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度区块中的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getContractCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块中的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getContractCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getContractTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 分页返回指定账本序号的区块中的交易列表; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param height 账本高度; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 最小为1,最大值受到系统参数的限制;<br> | |||
* 注:通过 {@link #getBlock(String, long)} 方法获得的区块信息中可以得到区块的总交易数 | |||
* {@link Block#getTxCount()}; | |||
* @return | |||
*/ | |||
LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count); | |||
/** | |||
* 分页返回指定账本序号的区块中的交易列表; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param blockHash 账本高度; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 如果参数值为 -1,则返回全部的记录;<br> | |||
* 注:通过 {@link #getBlock(String, String)} | |||
* 方法获得的区块信息中可以得到区块的总交易数 {@link Block#getTxCount()}; | |||
* @return | |||
*/ | |||
LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count); | |||
/** | |||
* 根据交易内容的哈希获取对应的交易记录; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param contentHash 交易内容的hash,即交易的 {@link Transaction#getContentHash()} 属性的值; | |||
* @return | |||
*/ | |||
LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash); | |||
/** | |||
* 根据交易内容的哈希获取对应的交易状态; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param contentHash 交易内容的hash,即交易的 {@link Transaction#getContentHash()} 属性的值; | |||
* @return | |||
*/ | |||
TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash); | |||
/** | |||
* 返回用户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
UserInfo getUser(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户中指定的键的最新值; <br> | |||
* | |||
* 返回结果的顺序与指定的键的顺序是一致的;<br> | |||
* | |||
* 如果某个键不存在,则返回版本为 -1 的数据项; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @param keys | |||
* @return | |||
*/ | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); | |||
/** | |||
* 返回指定数据账户中KV数据的总数; <br> | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
long getDataEntriesTotalCount(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户中指定序号的最新值; 返回结果的顺序与指定的序号的顺序是一致的;<br> | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param address 数据账户地址; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 如果参数值为 -1,则返回全部的记录;<br> | |||
* @return | |||
*/ | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||
/** | |||
* 返回合约账户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
ContractInfo getContract(HashDigest ledgerHash, String address); | |||
/** | |||
* get users by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get data accounts by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get contract accounts by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import org.springframework.cglib.core.Block; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractInfo; | |||
import com.jd.blockchain.ledger.TypedKVEntry; | |||
import com.jd.blockchain.ledger.KVInfoVO; | |||
import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
import com.jd.blockchain.ledger.LedgerBlock; | |||
import com.jd.blockchain.ledger.LedgerInfo; | |||
import com.jd.blockchain.ledger.LedgerMetadata; | |||
import com.jd.blockchain.ledger.LedgerTransaction; | |||
import com.jd.blockchain.ledger.ParticipantNode; | |||
import com.jd.blockchain.ledger.Transaction; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.ledger.UserInfo; | |||
/** | |||
* 区块链查询器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface BlockchainQueryService { | |||
/** | |||
* 返回所有的账本的 hash 列表;<br> | |||
* | |||
* 注:账本的 hash 既是该账本的创世区块的 hash; | |||
* | |||
* @return 账本 hash 的集合; | |||
*/ | |||
HashDigest[] getLedgerHashs(); | |||
/** | |||
* 获取账本信息; | |||
* | |||
* @param ledgerHash | |||
* @return 账本对象;如果不存在,则返回 null; | |||
*/ | |||
LedgerInfo getLedger(HashDigest ledgerHash); | |||
/** | |||
* 获取账本信息; | |||
* | |||
* @param ledgerHash | |||
* @return 账本对象;如果不存在,则返回 null; | |||
*/ | |||
LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash); | |||
/** | |||
* 返回当前账本的参与者信息列表 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash); | |||
/** | |||
* 返回当前账本的元数据 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
LedgerMetadata getLedgerMetadata(HashDigest ledgerHash); | |||
/** | |||
* 返回指定账本序号的区块; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param height 高度; | |||
* @return | |||
*/ | |||
LedgerBlock getBlock(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块hash的区块; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param blockHash 区块hash; | |||
* @return | |||
*/ | |||
LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回指定高度的区块中记录的交易总数; | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getTransactionCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定高度的区块中记录的交易总数; | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的交易总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getTransactionTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度的区块中记录的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getDataAccountCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定的区块中记录的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的数据账户总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getDataAccountTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度区块中的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getUserCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块中的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getUserCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的用户总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getUserTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 返回指定高度区块中的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @param height | |||
* @return | |||
*/ | |||
long getContractCount(HashDigest ledgerHash, long height); | |||
/** | |||
* 返回指定区块中的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @param blockHash | |||
* @return | |||
*/ | |||
long getContractCount(HashDigest ledgerHash, HashDigest blockHash); | |||
/** | |||
* 返回当前账本的合约总数 | |||
* | |||
* @param ledgerHash | |||
* @return | |||
*/ | |||
long getContractTotalCount(HashDigest ledgerHash); | |||
/** | |||
* 分页返回指定账本序号的区块中的交易列表; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param height 账本高度; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 最小为1,最大值受到系统参数的限制;<br> | |||
* 注:通过 {@link #getBlock(String, long)} 方法获得的区块信息中可以得到区块的总交易数 | |||
* {@link Block#getTxCount()}; | |||
* @return | |||
*/ | |||
LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count); | |||
/** | |||
* 分页返回指定账本序号的区块中的交易列表; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param blockHash 账本高度; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 如果参数值为 -1,则返回全部的记录;<br> | |||
* 注:通过 {@link #getBlock(String, String)} | |||
* 方法获得的区块信息中可以得到区块的总交易数 {@link Block#getTxCount()}; | |||
* @return | |||
*/ | |||
LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count); | |||
/** | |||
* 根据交易内容的哈希获取对应的交易记录; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param contentHash 交易内容的hash,即交易的 {@link Transaction#getContentHash()} 属性的值; | |||
* @return | |||
*/ | |||
LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash); | |||
/** | |||
* 根据交易内容的哈希获取对应的交易状态; | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param contentHash 交易内容的hash,即交易的 {@link Transaction#getContentHash()} 属性的值; | |||
* @return | |||
*/ | |||
TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash); | |||
/** | |||
* 返回用户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
UserInfo getUser(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户中指定的键的最新值; <br> | |||
* | |||
* 返回结果的顺序与指定的键的顺序是一致的;<br> | |||
* | |||
* 如果某个键不存在,则返回版本为 -1 的数据项; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @param keys | |||
* @return | |||
*/ | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys); | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO); | |||
/** | |||
* 返回指定数据账户中KV数据的总数; <br> | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
long getDataEntriesTotalCount(HashDigest ledgerHash, String address); | |||
/** | |||
* 返回数据账户中指定序号的最新值; 返回结果的顺序与指定的序号的顺序是一致的;<br> | |||
* | |||
* @param ledgerHash 账本hash; | |||
* @param address 数据账户地址; | |||
* @param fromIndex 开始的记录数; | |||
* @param count 本次返回的记录数;<br> | |||
* 如果参数值为 -1,则返回全部的记录;<br> | |||
* @return | |||
*/ | |||
TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count); | |||
/** | |||
* 返回合约账户信息; | |||
* | |||
* @param ledgerHash | |||
* @param address | |||
* @return | |||
*/ | |||
ContractInfo getContract(HashDigest ledgerHash, String address); | |||
/** | |||
* get users by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get data accounts by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
/** | |||
* get contract accounts by ledgerHash and its range; | |||
* | |||
* @param ledgerHash | |||
* @param fromIndex | |||
* @param count | |||
* @return | |||
*/ | |||
BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count); | |||
} |
@@ -1,41 +1,41 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class ContractCodeDeployOpTemplate implements ContractCodeDeployOperation { | |||
static { | |||
DataContractRegistry.register(ContractCodeDeployOperation.class); | |||
} | |||
private BlockchainIdentity contractID; | |||
private byte[] chainCode; | |||
public ContractCodeDeployOpTemplate() { | |||
} | |||
public ContractCodeDeployOpTemplate(BlockchainIdentity contractID, byte[] chainCode) { | |||
this.contractID = contractID; | |||
this.chainCode = chainCode; | |||
} | |||
@Override | |||
public BlockchainIdentity getContractID() { | |||
return contractID; | |||
} | |||
@Override | |||
public byte[] getChainCode() { | |||
return chainCode; | |||
} | |||
@Override | |||
public DigitalSignature getAddressSignature() { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class ContractCodeDeployOpTemplate implements ContractCodeDeployOperation { | |||
static { | |||
DataContractRegistry.register(ContractCodeDeployOperation.class); | |||
} | |||
private BlockchainIdentity contractID; | |||
private byte[] chainCode; | |||
public ContractCodeDeployOpTemplate() { | |||
} | |||
public ContractCodeDeployOpTemplate(BlockchainIdentity contractID, byte[] chainCode) { | |||
this.contractID = contractID; | |||
this.chainCode = chainCode; | |||
} | |||
@Override | |||
public BlockchainIdentity getContractID() { | |||
return contractID; | |||
} | |||
@Override | |||
public byte[] getChainCode() { | |||
return chainCode; | |||
} | |||
@Override | |||
public DigitalSignature getAddressSignature() { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
} |
@@ -1,19 +1,19 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
public interface ContractCodeDeployOperationBuilder { | |||
/** | |||
* 部署合约; | |||
* | |||
* @param id | |||
* 区块链身份; | |||
* @param chainCode | |||
* 合约应用的字节代码; | |||
* @return | |||
*/ | |||
ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
public interface ContractCodeDeployOperationBuilder { | |||
/** | |||
* 部署合约; | |||
* | |||
* @param id | |||
* 区块链身份; | |||
* @param chainCode | |||
* 合约应用的字节代码; | |||
* @return | |||
*/ | |||
ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode); | |||
} |
@@ -1,14 +1,14 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
public class ContractCodeDeployOperationBuilderImpl implements ContractCodeDeployOperationBuilder{ | |||
@Override | |||
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { | |||
ContractCodeDeployOpTemplate op = new ContractCodeDeployOpTemplate(id, chainCode); | |||
return op; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.ContractCodeDeployOperation; | |||
public class ContractCodeDeployOperationBuilderImpl implements ContractCodeDeployOperationBuilder{ | |||
@Override | |||
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) { | |||
ContractCodeDeployOpTemplate op = new ContractCodeDeployOpTemplate(id, chainCode); | |||
return op; | |||
} | |||
} |
@@ -1,24 +1,24 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValueList; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface ContractEventSendOperationBuilder { | |||
/** | |||
* @param address 合约地址; | |||
* @param event 事件名; | |||
* @param args 事件参数; | |||
* @return | |||
*/ | |||
ContractEventSendOperation send(String address, String event, BytesValueList args); | |||
/** | |||
* @param address 合约地址; | |||
* @param event 事件名; | |||
* @param args 事件参数; | |||
* @return | |||
*/ | |||
ContractEventSendOperation send(Bytes address, String event, BytesValueList args); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValueList; | |||
import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public interface ContractEventSendOperationBuilder { | |||
/** | |||
* @param address 合约地址; | |||
* @param event 事件名; | |||
* @param args 事件参数; | |||
* @return | |||
*/ | |||
ContractEventSendOperation send(String address, String event, BytesValueList args); | |||
/** | |||
* @param address 合约地址; | |||
* @param event 事件名; | |||
* @param args 事件参数; | |||
* @return | |||
*/ | |||
ContractEventSendOperation send(Bytes address, String event, BytesValueList args); | |||
} |
@@ -1,21 +1,21 @@ | |||
//package com.jd.blockchain.transaction; | |||
// | |||
//import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
//import com.jd.blockchain.utils.Bytes; | |||
// | |||
//@Deprecated | |||
//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { | |||
// | |||
// @Override | |||
// public ContractEventSendOperation send(String address, String event, byte[] args) { | |||
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); | |||
// return op; | |||
// } | |||
// | |||
// @Override | |||
// public ContractEventSendOperation send(Bytes address, String event, byte[] args) { | |||
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); | |||
// return op; | |||
// } | |||
// | |||
//} | |||
//package com.jd.blockchain.transaction; | |||
// | |||
//import com.jd.blockchain.ledger.ContractEventSendOperation; | |||
//import com.jd.blockchain.utils.Bytes; | |||
// | |||
//@Deprecated | |||
//class ContractEventSendOperationBuilderImpl implements ContractEventSendOperationBuilder { | |||
// | |||
// @Override | |||
// public ContractEventSendOperation send(String address, String event, byte[] args) { | |||
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(Bytes.fromBase58(address), event, args); | |||
// return op; | |||
// } | |||
// | |||
// @Override | |||
// public ContractEventSendOperation send(Bytes address, String event, byte[] args) { | |||
// ContractEventSendOpTemplate op = new ContractEventSendOpTemplate(address, event, args); | |||
// return op; | |||
// } | |||
// | |||
//} |
@@ -1,44 +1,44 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.lang.reflect.Proxy; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 合约调用代理的构建器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class ContractInvocationProxyBuilder { | |||
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | |||
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public <T> T create(Bytes address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
ContractType contractType = resolveContractType(contractIntf); | |||
ContractInvocationHandler proxyHandler = new ContractInvocationHandler(address, contractType, contractEventBuilder); | |||
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | |||
new Class<?>[] { contractIntf }, proxyHandler); | |||
return proxy; | |||
} | |||
private ContractType resolveContractType(Class<?> contractIntf) { | |||
ContractType contractType = contractTypes.get(contractIntf); | |||
if (contractType != null) { | |||
return contractType; | |||
} | |||
ContractType ct = ContractType.resolve(contractIntf); | |||
contractTypes.put(contractIntf, ct); | |||
return ct; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.lang.reflect.Proxy; | |||
import java.util.Map; | |||
import java.util.concurrent.ConcurrentHashMap; | |||
import com.jd.blockchain.contract.ContractType; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* 合约调用代理的构建器; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class ContractInvocationProxyBuilder { | |||
private Map<Class<?>, ContractType> contractTypes = new ConcurrentHashMap<>(); | |||
public <T> T create(String address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
return create(Bytes.fromBase58(address), contractIntf, contractEventBuilder); | |||
} | |||
@SuppressWarnings("unchecked") | |||
public <T> T create(Bytes address, Class<T> contractIntf, ContractEventSendOperationBuilder contractEventBuilder) { | |||
ContractType contractType = resolveContractType(contractIntf); | |||
ContractInvocationHandler proxyHandler = new ContractInvocationHandler(address, contractType, contractEventBuilder); | |||
T proxy = (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), | |||
new Class<?>[] { contractIntf }, proxyHandler); | |||
return proxy; | |||
} | |||
private ContractType resolveContractType(Class<?> contractIntf) { | |||
ContractType contractType = contractTypes.get(contractIntf); | |||
if (contractType != null) { | |||
return contractType; | |||
} | |||
ContractType ct = ContractType.resolve(contractIntf); | |||
contractTypes.put(contractIntf, ct); | |||
return ct; | |||
} | |||
} |
@@ -1,65 +1,65 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccountKVSetOpTemplate implements DataAccountKVSetOperation { | |||
static { | |||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||
} | |||
private Bytes accountAddress; | |||
private Map<String, KVWriteEntry> kvset = new LinkedHashMap<>(); | |||
public DataAccountKVSetOpTemplate() { | |||
} | |||
public DataAccountKVSetOpTemplate(Bytes accountAddress) { | |||
this.accountAddress = accountAddress; | |||
} | |||
public DataAccountKVSetOpTemplate(Bytes accountAddress, Map<String, KVWriteEntry> kvset) { | |||
this.accountAddress = accountAddress; | |||
this.kvset = kvset; | |||
} | |||
@Override | |||
public Bytes getAccountAddress() { | |||
return accountAddress; | |||
} | |||
@Override | |||
public KVWriteEntry[] getWriteSet() { | |||
return kvset.values().toArray(new KVWriteEntry[kvset.size()]); | |||
} | |||
public void setWriteSet(Object[] kvEntries) { | |||
for (Object object : kvEntries) { | |||
KVWriteEntry kvEntry = (KVWriteEntry) object; | |||
set(kvEntry.getKey(), kvEntry.getValue(), kvEntry.getExpectedVersion()); | |||
} | |||
return; | |||
} | |||
public void set(String key, BytesValue value, long expVersion) { | |||
if (kvset.containsKey(key)) { | |||
throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
} | |||
KVData kvdata = new KVData(key, value, expVersion); | |||
kvset.put(key, kvdata); | |||
} | |||
public void set(KVData kvData) { | |||
if (kvset.containsKey(kvData.getKey())) { | |||
throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
} | |||
kvset.put(kvData.getKey(), kvData); | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccountKVSetOpTemplate implements DataAccountKVSetOperation { | |||
static { | |||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||
} | |||
private Bytes accountAddress; | |||
private Map<String, KVWriteEntry> kvset = new LinkedHashMap<>(); | |||
public DataAccountKVSetOpTemplate() { | |||
} | |||
public DataAccountKVSetOpTemplate(Bytes accountAddress) { | |||
this.accountAddress = accountAddress; | |||
} | |||
public DataAccountKVSetOpTemplate(Bytes accountAddress, Map<String, KVWriteEntry> kvset) { | |||
this.accountAddress = accountAddress; | |||
this.kvset = kvset; | |||
} | |||
@Override | |||
public Bytes getAccountAddress() { | |||
return accountAddress; | |||
} | |||
@Override | |||
public KVWriteEntry[] getWriteSet() { | |||
return kvset.values().toArray(new KVWriteEntry[kvset.size()]); | |||
} | |||
public void setWriteSet(Object[] kvEntries) { | |||
for (Object object : kvEntries) { | |||
KVWriteEntry kvEntry = (KVWriteEntry) object; | |||
set(kvEntry.getKey(), kvEntry.getValue(), kvEntry.getExpectedVersion()); | |||
} | |||
return; | |||
} | |||
public void set(String key, BytesValue value, long expVersion) { | |||
if (kvset.containsKey(key)) { | |||
throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
} | |||
KVData kvdata = new KVData(key, value, expVersion); | |||
kvset.put(key, kvdata); | |||
} | |||
public void set(KVData kvData) { | |||
if (kvset.containsKey(kvData.getKey())) { | |||
throw new IllegalArgumentException("Cann't set the same key repeatedly!"); | |||
} | |||
kvset.put(kvData.getKey(), kvData); | |||
} | |||
} |
@@ -1,151 +1,151 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface DataAccountKVSetOperationBuilder { | |||
/** | |||
* 数据账户的KV写入操作; | |||
* | |||
* @return | |||
*/ | |||
DataAccountKVSetOperation getOperation(); | |||
// /** | |||
// * 写入字节数组; | |||
// * | |||
// * @param key | |||
// * 键; | |||
// * @param value | |||
// * 值;byte[]格式 | |||
// * @param expVersion | |||
// * 预期的当前版本;如果版本不匹配,则写入失败; | |||
// * @return | |||
// */ | |||
// @Deprecated | |||
// DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion); | |||
/** | |||
* 写入字节数组; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;byte[]格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion); | |||
/** | |||
* 写入字节数组; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;Bytes格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion); | |||
/** | |||
* 写入键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion); | |||
// /** | |||
// * 写入文本键值; | |||
// * | |||
// * @param key | |||
// * 键; | |||
// * @param value | |||
// * 值;String格式 | |||
// * @param expVersion | |||
// * 预期的当前版本;如果版本不匹配,则写入失败; | |||
// * @return | |||
// */ | |||
// @Deprecated | |||
// DataAccountKVSetOperationBuilder set(String key, String value, long expVersion); | |||
/** | |||
* 写入文本键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion); | |||
/** | |||
* 写入JSON键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion); | |||
/** | |||
* 写入XML键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion); | |||
/** | |||
* 写入64位整数; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;long格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion); | |||
/** | |||
* 写入时间戳; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;long格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface DataAccountKVSetOperationBuilder { | |||
/** | |||
* 数据账户的KV写入操作; | |||
* | |||
* @return | |||
*/ | |||
DataAccountKVSetOperation getOperation(); | |||
// /** | |||
// * 写入字节数组; | |||
// * | |||
// * @param key | |||
// * 键; | |||
// * @param value | |||
// * 值;byte[]格式 | |||
// * @param expVersion | |||
// * 预期的当前版本;如果版本不匹配,则写入失败; | |||
// * @return | |||
// */ | |||
// @Deprecated | |||
// DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion); | |||
/** | |||
* 写入字节数组; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;byte[]格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion); | |||
/** | |||
* 写入字节数组; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;Bytes格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion); | |||
/** | |||
* 写入键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion); | |||
// /** | |||
// * 写入文本键值; | |||
// * | |||
// * @param key | |||
// * 键; | |||
// * @param value | |||
// * 值;String格式 | |||
// * @param expVersion | |||
// * 预期的当前版本;如果版本不匹配,则写入失败; | |||
// * @return | |||
// */ | |||
// @Deprecated | |||
// DataAccountKVSetOperationBuilder set(String key, String value, long expVersion); | |||
/** | |||
* 写入文本键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion); | |||
/** | |||
* 写入JSON键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion); | |||
/** | |||
* 写入XML键值; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;String格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion); | |||
/** | |||
* 写入64位整数; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;long格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion); | |||
/** | |||
* 写入时间戳; | |||
* | |||
* @param key | |||
* 键; | |||
* @param value | |||
* 值;long格式 | |||
* @param expVersion | |||
* 预期的当前版本;如果版本不匹配,则写入失败; | |||
* @return | |||
*/ | |||
DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion); | |||
} |
@@ -1,88 +1,88 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOperationBuilder { | |||
private DataAccountKVSetOpTemplate operation; | |||
public DataAccountKVSetOperationBuilderImpl(Bytes accountAddress) { | |||
operation = new DataAccountKVSetOpTemplate(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperation getOperation() { | |||
return operation; | |||
} | |||
// @Deprecated | |||
// @Override | |||
// public DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion) { | |||
// return setBytes(key, value, expVersion); | |||
// } | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromImage(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
// @Override | |||
// public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { | |||
// return setText(key, value, expVersion); | |||
// } | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromText(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromInt64(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromJSON(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromXML(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromTimestamp(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BytesValue; | |||
import com.jd.blockchain.ledger.TypedValue; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class DataAccountKVSetOperationBuilderImpl implements DataAccountKVSetOperationBuilder { | |||
private DataAccountKVSetOpTemplate operation; | |||
public DataAccountKVSetOperationBuilderImpl(Bytes accountAddress) { | |||
operation = new DataAccountKVSetOpTemplate(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperation getOperation() { | |||
return operation; | |||
} | |||
// @Deprecated | |||
// @Override | |||
// public DataAccountKVSetOperationBuilder set(String key, byte[] value, long expVersion) { | |||
// return setBytes(key, value, expVersion); | |||
// } | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setImage(String key, byte[] value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromImage(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
// @Override | |||
// public DataAccountKVSetOperationBuilder set(String key, String value, long expVersion) { | |||
// return setText(key, value, expVersion); | |||
// } | |||
@Override | |||
public DataAccountKVSetOperationBuilder setText(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromText(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setBytes(String key, Bytes value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromBytes(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setInt64(String key, long value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromInt64(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setJSON(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromJSON(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setXML(String key, String value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromXML(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder setTimestamp(String key, long value, long expVersion) { | |||
BytesValue bytesValue = TypedValue.fromTimestamp(value); | |||
operation.set(key, bytesValue, expVersion); | |||
return this; | |||
} | |||
} |
@@ -1,34 +1,34 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class DataAccountRegisterOpTemplate implements DataAccountRegisterOperation { | |||
static { | |||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||
} | |||
private BlockchainIdentity accountID; | |||
public DataAccountRegisterOpTemplate() { | |||
} | |||
public DataAccountRegisterOpTemplate(BlockchainIdentity accountID) { | |||
this.accountID = accountID; | |||
} | |||
@Override | |||
public BlockchainIdentity getAccountID() { | |||
return accountID; | |||
} | |||
@Override | |||
public DigitalSignature getAddressSignature() { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountKVSetOperation; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class DataAccountRegisterOpTemplate implements DataAccountRegisterOperation { | |||
static { | |||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||
} | |||
private BlockchainIdentity accountID; | |||
public DataAccountRegisterOpTemplate() { | |||
} | |||
public DataAccountRegisterOpTemplate(BlockchainIdentity accountID) { | |||
this.accountID = accountID; | |||
} | |||
@Override | |||
public BlockchainIdentity getAccountID() { | |||
return accountID; | |||
} | |||
@Override | |||
public DigitalSignature getAddressSignature() { | |||
// TODO Auto-generated method stub | |||
return null; | |||
} | |||
} |
@@ -1,14 +1,14 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
public interface DataAccountRegisterOperationBuilder { | |||
/** | |||
* @param id | |||
* @return | |||
*/ | |||
DataAccountRegisterOperation register(BlockchainIdentity id); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
public interface DataAccountRegisterOperationBuilder { | |||
/** | |||
* @param id | |||
* @return | |||
*/ | |||
DataAccountRegisterOperation register(BlockchainIdentity id); | |||
} |
@@ -1,15 +1,15 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
public class DataAccountRegisterOperationBuilderImpl implements DataAccountRegisterOperationBuilder{ | |||
@Override | |||
public DataAccountRegisterOperation register(BlockchainIdentity userID) { | |||
return new DataAccountRegisterOpTemplate(userID); | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DataAccountRegisterOperation; | |||
public class DataAccountRegisterOperationBuilderImpl implements DataAccountRegisterOperationBuilder{ | |||
@Override | |||
public DataAccountRegisterOperation register(BlockchainIdentity userID) { | |||
return new DataAccountRegisterOpTemplate(userID); | |||
} | |||
} |
@@ -1,116 +1,116 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MagicNumber; | |||
/** | |||
* 数字签名的字节块; | |||
* | |||
* <pre> | |||
* 字节位如下: | |||
* [第1字节]:标识数据类型为数字签名的魔数常量 ({@link MagicNumber#SIGNATURE}); | |||
* | |||
* [第2字节] - [第N字节]: 公钥; | |||
* 注:公钥的值是包含了公钥算法标识和公钥内容的字节码编码; | |||
* | |||
* [第N+1字节] - 结束: 摘要; | |||
* | |||
* </pre> | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class DigitalSignatureBlob implements DigitalSignature { | |||
private PubKey pubKey; | |||
private SignatureDigest digest; | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
@Override | |||
public SignatureDigest getDigest() { | |||
return digest; | |||
} | |||
public DigitalSignatureBlob() { | |||
} | |||
public DigitalSignatureBlob(PubKey pubKey, SignatureDigest digest) { | |||
this.pubKey = pubKey; | |||
this.digest = digest; | |||
} | |||
// @Override | |||
// public void resolvFrom(InputStream in) { | |||
// try { | |||
// byte[] buff = new byte[1]; | |||
// int len = in.read(buff); | |||
// if (len < 1) { | |||
// throw new IllegalArgumentException("No enough bytes was read for the magic number [SIGNATURE]!"); | |||
// } | |||
// if (buff[0] != MagicNumber.SIGNATURE) { | |||
// throw new IllegalArgumentException("Magic number [SIGNATURE] dismatch!"); | |||
// } | |||
// PubKey pk = CryptoKeyEncoding.readPubKey(in); | |||
// ByteArray dg = BytesEncoding.readAsByteArray(NumberMask.SHORT, in); | |||
// this.pubKey = pk; | |||
// this.digest = dg; | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public void writeTo(OutputStream out) { | |||
// try { | |||
// out.write(MagicNumber.SIGNATURE); | |||
// CryptoKeyEncoding.writeKey(pubKey, out); | |||
// BytesEncoding.write(digest, NumberMask.SHORT, out); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public boolean equals(Object o) { | |||
// if (this == o) return true; | |||
// if (!(o instanceof DigitalSignatureBlob)) return false; | |||
// DigitalSignatureBlob that = (DigitalSignatureBlob) o; | |||
// return Objects.equals(getPubKey(), that.getPubKey()) && | |||
// Objects.equals(getDigest(), that.getDigest()); | |||
// } | |||
// | |||
// public byte[] toBytes() { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// writeTo(out); | |||
// return out.toByteArray(); | |||
// } | |||
// | |||
// @Override | |||
// public String toString() { | |||
// return toBytes().toString(); | |||
// } | |||
// | |||
// @Override | |||
// public void writeExternal(ObjectOutput out) throws IOException { | |||
// byte[] bts = toBytes(); | |||
// out.writeInt(bts.length); | |||
// out.write(bts, 0, bts.length); | |||
// } | |||
// | |||
// @Override | |||
// public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |||
// int size = in.readInt(); | |||
// byte[] bs = new byte[size]; | |||
// in.readFully(bs, 0, size); | |||
// resolvFrom(new ByteArrayInputStream(bs)); | |||
// } | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.crypto.PubKey; | |||
import com.jd.blockchain.crypto.SignatureDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MagicNumber; | |||
/** | |||
* 数字签名的字节块; | |||
* | |||
* <pre> | |||
* 字节位如下: | |||
* [第1字节]:标识数据类型为数字签名的魔数常量 ({@link MagicNumber#SIGNATURE}); | |||
* | |||
* [第2字节] - [第N字节]: 公钥; | |||
* 注:公钥的值是包含了公钥算法标识和公钥内容的字节码编码; | |||
* | |||
* [第N+1字节] - 结束: 摘要; | |||
* | |||
* </pre> | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class DigitalSignatureBlob implements DigitalSignature { | |||
private PubKey pubKey; | |||
private SignatureDigest digest; | |||
@Override | |||
public PubKey getPubKey() { | |||
return pubKey; | |||
} | |||
@Override | |||
public SignatureDigest getDigest() { | |||
return digest; | |||
} | |||
public DigitalSignatureBlob() { | |||
} | |||
public DigitalSignatureBlob(PubKey pubKey, SignatureDigest digest) { | |||
this.pubKey = pubKey; | |||
this.digest = digest; | |||
} | |||
// @Override | |||
// public void resolvFrom(InputStream in) { | |||
// try { | |||
// byte[] buff = new byte[1]; | |||
// int len = in.read(buff); | |||
// if (len < 1) { | |||
// throw new IllegalArgumentException("No enough bytes was read for the magic number [SIGNATURE]!"); | |||
// } | |||
// if (buff[0] != MagicNumber.SIGNATURE) { | |||
// throw new IllegalArgumentException("Magic number [SIGNATURE] dismatch!"); | |||
// } | |||
// PubKey pk = CryptoKeyEncoding.readPubKey(in); | |||
// ByteArray dg = BytesEncoding.readAsByteArray(NumberMask.SHORT, in); | |||
// this.pubKey = pk; | |||
// this.digest = dg; | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public void writeTo(OutputStream out) { | |||
// try { | |||
// out.write(MagicNumber.SIGNATURE); | |||
// CryptoKeyEncoding.writeKey(pubKey, out); | |||
// BytesEncoding.write(digest, NumberMask.SHORT, out); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public boolean equals(Object o) { | |||
// if (this == o) return true; | |||
// if (!(o instanceof DigitalSignatureBlob)) return false; | |||
// DigitalSignatureBlob that = (DigitalSignatureBlob) o; | |||
// return Objects.equals(getPubKey(), that.getPubKey()) && | |||
// Objects.equals(getDigest(), that.getDigest()); | |||
// } | |||
// | |||
// public byte[] toBytes() { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// writeTo(out); | |||
// return out.toByteArray(); | |||
// } | |||
// | |||
// @Override | |||
// public String toString() { | |||
// return toBytes().toString(); | |||
// } | |||
// | |||
// @Override | |||
// public void writeExternal(ObjectOutput out) throws IOException { | |||
// byte[] bts = toBytes(); | |||
// out.writeInt(bts.length); | |||
// out.write(bts, 0, bts.length); | |||
// } | |||
// | |||
// @Override | |||
// public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { | |||
// int size = in.readInt(); | |||
// byte[] bs = new byte[size]; | |||
// in.readFully(bs, 0, size); | |||
// resolvFrom(new ByteArrayInputStream(bs)); | |||
// } | |||
} |
@@ -1,26 +1,26 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public class LedgerInitOpTemplate implements LedgerInitOperation { | |||
static { | |||
DataContractRegistry.register(LedgerInitOperation.class); | |||
} | |||
private LedgerInitSetting initSetting; | |||
public LedgerInitOpTemplate() { | |||
} | |||
public LedgerInitOpTemplate(LedgerInitSetting initSetting) { | |||
this.initSetting = initSetting; | |||
} | |||
@Override | |||
public LedgerInitSetting getInitSetting() { | |||
return initSetting; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public class LedgerInitOpTemplate implements LedgerInitOperation { | |||
static { | |||
DataContractRegistry.register(LedgerInitOperation.class); | |||
} | |||
private LedgerInitSetting initSetting; | |||
public LedgerInitOpTemplate() { | |||
} | |||
public LedgerInitOpTemplate(LedgerInitSetting initSetting) { | |||
this.initSetting = initSetting; | |||
} | |||
@Override | |||
public LedgerInitSetting getInitSetting() { | |||
return initSetting; | |||
} | |||
} |
@@ -1,17 +1,17 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public interface LedgerInitOperationBuilder { | |||
/** | |||
* 注册; | |||
* | |||
* @param initSetting | |||
* 账本初始化配置; | |||
* @return LedgerInitOperation | |||
*/ | |||
LedgerInitOperation create(LedgerInitSetting initSetting); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public interface LedgerInitOperationBuilder { | |||
/** | |||
* 注册; | |||
* | |||
* @param initSetting | |||
* 账本初始化配置; | |||
* @return LedgerInitOperation | |||
*/ | |||
LedgerInitOperation create(LedgerInitSetting initSetting); | |||
} |
@@ -1,13 +1,13 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public class LedgerInitOperationBuilderImpl implements LedgerInitOperationBuilder { | |||
@Override | |||
public LedgerInitOperation create(LedgerInitSetting initSetting) { | |||
return new LedgerInitOpTemplate(initSetting); | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.LedgerInitOperation; | |||
import com.jd.blockchain.ledger.LedgerInitSetting; | |||
public class LedgerInitOperationBuilderImpl implements LedgerInitOperationBuilder { | |||
@Override | |||
public LedgerInitOperation create(LedgerInitSetting initSetting) { | |||
return new LedgerInitOpTemplate(initSetting); | |||
} | |||
} |
@@ -1,38 +1,38 @@ | |||
package com.jd.blockchain.transaction; | |||
//package com.jd.blockchain.ledger.data; | |||
// | |||
//import com.jd.blockchain.ledger.OperationType; | |||
//import my.utils.io.ByteArray; | |||
// | |||
//public class NewLedgerOpBlob { | |||
// | |||
// private ByteArray genesisKey; | |||
// | |||
// public NewLedgerOpBlob() { | |||
// } | |||
// | |||
// public NewLedgerOpBlob(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public void resolvFrom(OpBlob opBlob) { | |||
//// if (OperationType.NEW_LEDGER.CODE != opBlob.getCode()) { | |||
//// throw new IllegalArgumentException( | |||
//// "Could not resolve operation info due to NEW_LEDGER operation code mismatch!"); | |||
//// } | |||
//// | |||
//// genesisKey = opBlob.getArg(0); | |||
// } | |||
// | |||
// public OpBlob toBlob() { | |||
// // 写入操作码; | |||
// OpBlob opBlob = new OpBlob(); | |||
// opBlob.setOperation(OperationType.NEW_LEDGER.CODE, genesisKey); | |||
// | |||
// return opBlob; | |||
// } | |||
// | |||
// public ByteArray getGenesisKey() { | |||
// return genesisKey; | |||
// } | |||
//} | |||
package com.jd.blockchain.transaction; | |||
//package com.jd.blockchain.ledger.data; | |||
// | |||
//import com.jd.blockchain.ledger.OperationType; | |||
//import my.utils.io.ByteArray; | |||
// | |||
//public class NewLedgerOpBlob { | |||
// | |||
// private ByteArray genesisKey; | |||
// | |||
// public NewLedgerOpBlob() { | |||
// } | |||
// | |||
// public NewLedgerOpBlob(ByteArray genesisKey) { | |||
// this.genesisKey = genesisKey; | |||
// } | |||
// | |||
// public void resolvFrom(OpBlob opBlob) { | |||
//// if (OperationType.NEW_LEDGER.CODE != opBlob.getCode()) { | |||
//// throw new IllegalArgumentException( | |||
//// "Could not resolve operation info due to NEW_LEDGER operation code mismatch!"); | |||
//// } | |||
//// | |||
//// genesisKey = opBlob.getArg(0); | |||
// } | |||
// | |||
// public OpBlob toBlob() { | |||
// // 写入操作码; | |||
// OpBlob opBlob = new OpBlob(); | |||
// opBlob.setOperation(OperationType.NEW_LEDGER.CODE, genesisKey); | |||
// | |||
// return opBlob; | |||
// } | |||
// | |||
// public ByteArray getGenesisKey() { | |||
// return genesisKey; | |||
// } | |||
//} |
@@ -1,25 +1,25 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.PermissionType; | |||
/** | |||
* 账户权限设置操作; | |||
* | |||
* <br> | |||
* | |||
* 注:默认情况下,在账户被注册时,账户自身会包含在权限设置表中,具有全部的权限; <br> | |||
* | |||
* 但这不是必须的,使用者可以根据业务需要,去掉账户自身的权限,并将权限赋予其它的账户,以此实现将区块链账户分别用于表示“角色”和“数据”这两种目的; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface PrivilegeSettingOperationBuilder { | |||
PrivilegeSettingOperationBuilder setThreshhold(PermissionType privilege, long threshhold); | |||
PrivilegeSettingOperationBuilder enable(PermissionType privilege, String address, int weight); | |||
PrivilegeSettingOperationBuilder disable(PermissionType privilege, String address); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.PermissionType; | |||
/** | |||
* 账户权限设置操作; | |||
* | |||
* <br> | |||
* | |||
* 注:默认情况下,在账户被注册时,账户自身会包含在权限设置表中,具有全部的权限; <br> | |||
* | |||
* 但这不是必须的,使用者可以根据业务需要,去掉账户自身的权限,并将权限赋予其它的账户,以此实现将区块链账户分别用于表示“角色”和“数据”这两种目的; | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public interface PrivilegeSettingOperationBuilder { | |||
PrivilegeSettingOperationBuilder setThreshhold(PermissionType privilege, long threshhold); | |||
PrivilegeSettingOperationBuilder enable(PermissionType privilege, String address, int weight); | |||
PrivilegeSettingOperationBuilder disable(PermissionType privilege, String address); | |||
} |
@@ -1,30 +1,30 @@ | |||
package com.jd.blockchain.transaction; | |||
//package com.jd.blockchain.ledger.data; | |||
// | |||
//import com.jd.blockchain.ledger.KeyType; | |||
//import com.jd.blockchain.ledger.PubKey; | |||
// | |||
//import my.utils.io.ByteArray; | |||
// | |||
//public class PubKeyData implements PubKey{ | |||
// | |||
// private KeyType type; | |||
// | |||
// private ByteArray value; | |||
// | |||
// public PubKeyData(KeyType type, ByteArray value) { | |||
// this.type = type; | |||
// this.value = value; | |||
// } | |||
// | |||
// @Override | |||
// public KeyType getType() { | |||
// return type; | |||
// } | |||
// | |||
// @Override | |||
// public ByteArray getValue() { | |||
// return value; | |||
// } | |||
// | |||
//} | |||
package com.jd.blockchain.transaction; | |||
//package com.jd.blockchain.ledger.data; | |||
// | |||
//import com.jd.blockchain.ledger.KeyType; | |||
//import com.jd.blockchain.ledger.PubKey; | |||
// | |||
//import my.utils.io.ByteArray; | |||
// | |||
//public class PubKeyData implements PubKey{ | |||
// | |||
// private KeyType type; | |||
// | |||
// private ByteArray value; | |||
// | |||
// public PubKeyData(KeyType type, ByteArray value) { | |||
// this.type = type; | |||
// this.value = value; | |||
// } | |||
// | |||
// @Override | |||
// public KeyType getType() { | |||
// return type; | |||
// } | |||
// | |||
// @Override | |||
// public ByteArray getValue() { | |||
// return value; | |||
// } | |||
// | |||
//} |
@@ -1,139 +1,139 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.Collections; | |||
import java.util.LinkedHashMap; | |||
import java.util.LinkedHashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||
import com.jd.blockchain.ledger.SecurityUtils; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.utils.ArrayUtils; | |||
public class RolesConfigureOpTemplate implements RolesConfigurer, RolesConfigureOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
DataContractRegistry.register(RolesConfigureOperation.class); | |||
DataContractRegistry.register(RolePrivilegeEntry.class); | |||
} | |||
private Map<String, RolePrivilegeConfig> rolesMap = Collections | |||
.synchronizedMap(new LinkedHashMap<String, RolePrivilegeConfig>()); | |||
public RolesConfigureOpTemplate() { | |||
} | |||
boolean isEmpty() { | |||
return rolesMap.isEmpty(); | |||
} | |||
@Override | |||
public RolePrivilegeEntry[] getRoles() { | |||
return rolesMap.values().toArray(new RolePrivilegeEntry[rolesMap.size()]); | |||
} | |||
@Override | |||
public RolesConfigureOperation getOperation() { | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer configure(String roleName) { | |||
roleName = SecurityUtils.formatRoleName(roleName); | |||
RolePrivilegeConfig roleConfig = rolesMap.get(roleName); | |||
if (roleConfig == null) { | |||
roleConfig = new RolePrivilegeConfig(roleName); | |||
rolesMap.put(roleName, roleConfig); | |||
} | |||
return roleConfig; | |||
} | |||
private class RolePrivilegeConfig implements RolePrivilegeConfigurer, RolePrivilegeEntry { | |||
private String roleName; | |||
private Set<LedgerPermission> enableLedgerPermissions = new LinkedHashSet<LedgerPermission>(); | |||
private Set<LedgerPermission> disableLedgerPermissions = new LinkedHashSet<LedgerPermission>(); | |||
private Set<TransactionPermission> enableTxPermissions = new LinkedHashSet<TransactionPermission>(); | |||
private Set<TransactionPermission> disableTxPermissions = new LinkedHashSet<TransactionPermission>(); | |||
private RolePrivilegeConfig(String roleName) { | |||
this.roleName = roleName; | |||
} | |||
@Override | |||
public String getRoleName() { | |||
return roleName; | |||
} | |||
@Override | |||
public LedgerPermission[] getEnableLedgerPermissions() { | |||
return ArrayUtils.toArray(enableLedgerPermissions, LedgerPermission.class); | |||
} | |||
@Override | |||
public LedgerPermission[] getDisableLedgerPermissions() { | |||
return ArrayUtils.toArray(disableLedgerPermissions, LedgerPermission.class); | |||
} | |||
@Override | |||
public TransactionPermission[] getEnableTransactionPermissions() { | |||
return ArrayUtils.toArray(enableTxPermissions, TransactionPermission.class); | |||
} | |||
@Override | |||
public TransactionPermission[] getDisableTransactionPermissions() { | |||
return ArrayUtils.toArray(disableTxPermissions, TransactionPermission.class); | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer enable(LedgerPermission... permissions) { | |||
List<LedgerPermission> permissionList = ArrayUtils.asList(permissions); | |||
enableLedgerPermissions.addAll(permissionList); | |||
disableLedgerPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer disable(LedgerPermission... permissions) { | |||
List<LedgerPermission> permissionList = ArrayUtils.asList(permissions); | |||
disableLedgerPermissions.addAll(permissionList); | |||
enableLedgerPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer enable(TransactionPermission... permissions) { | |||
List<TransactionPermission> permissionList = ArrayUtils.asList(permissions); | |||
enableTxPermissions.addAll(permissionList); | |||
disableTxPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer disable(TransactionPermission... permissions) { | |||
List<TransactionPermission> permissionList = ArrayUtils.asList(permissions); | |||
disableTxPermissions.addAll(permissionList); | |||
enableTxPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer configure(String roleName) { | |||
return RolesConfigureOpTemplate.this.configure(roleName); | |||
} | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.util.Collections; | |||
import java.util.LinkedHashMap; | |||
import java.util.LinkedHashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.LedgerPermission; | |||
import com.jd.blockchain.ledger.RolesConfigureOperation; | |||
import com.jd.blockchain.ledger.SecurityUtils; | |||
import com.jd.blockchain.ledger.TransactionPermission; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.utils.ArrayUtils; | |||
public class RolesConfigureOpTemplate implements RolesConfigurer, RolesConfigureOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
DataContractRegistry.register(RolesConfigureOperation.class); | |||
DataContractRegistry.register(RolePrivilegeEntry.class); | |||
} | |||
private Map<String, RolePrivilegeConfig> rolesMap = Collections | |||
.synchronizedMap(new LinkedHashMap<String, RolePrivilegeConfig>()); | |||
public RolesConfigureOpTemplate() { | |||
} | |||
boolean isEmpty() { | |||
return rolesMap.isEmpty(); | |||
} | |||
@Override | |||
public RolePrivilegeEntry[] getRoles() { | |||
return rolesMap.values().toArray(new RolePrivilegeEntry[rolesMap.size()]); | |||
} | |||
@Override | |||
public RolesConfigureOperation getOperation() { | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer configure(String roleName) { | |||
roleName = SecurityUtils.formatRoleName(roleName); | |||
RolePrivilegeConfig roleConfig = rolesMap.get(roleName); | |||
if (roleConfig == null) { | |||
roleConfig = new RolePrivilegeConfig(roleName); | |||
rolesMap.put(roleName, roleConfig); | |||
} | |||
return roleConfig; | |||
} | |||
private class RolePrivilegeConfig implements RolePrivilegeConfigurer, RolePrivilegeEntry { | |||
private String roleName; | |||
private Set<LedgerPermission> enableLedgerPermissions = new LinkedHashSet<LedgerPermission>(); | |||
private Set<LedgerPermission> disableLedgerPermissions = new LinkedHashSet<LedgerPermission>(); | |||
private Set<TransactionPermission> enableTxPermissions = new LinkedHashSet<TransactionPermission>(); | |||
private Set<TransactionPermission> disableTxPermissions = new LinkedHashSet<TransactionPermission>(); | |||
private RolePrivilegeConfig(String roleName) { | |||
this.roleName = roleName; | |||
} | |||
@Override | |||
public String getRoleName() { | |||
return roleName; | |||
} | |||
@Override | |||
public LedgerPermission[] getEnableLedgerPermissions() { | |||
return ArrayUtils.toArray(enableLedgerPermissions, LedgerPermission.class); | |||
} | |||
@Override | |||
public LedgerPermission[] getDisableLedgerPermissions() { | |||
return ArrayUtils.toArray(disableLedgerPermissions, LedgerPermission.class); | |||
} | |||
@Override | |||
public TransactionPermission[] getEnableTransactionPermissions() { | |||
return ArrayUtils.toArray(enableTxPermissions, TransactionPermission.class); | |||
} | |||
@Override | |||
public TransactionPermission[] getDisableTransactionPermissions() { | |||
return ArrayUtils.toArray(disableTxPermissions, TransactionPermission.class); | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer enable(LedgerPermission... permissions) { | |||
List<LedgerPermission> permissionList = ArrayUtils.asList(permissions); | |||
enableLedgerPermissions.addAll(permissionList); | |||
disableLedgerPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer disable(LedgerPermission... permissions) { | |||
List<LedgerPermission> permissionList = ArrayUtils.asList(permissions); | |||
disableLedgerPermissions.addAll(permissionList); | |||
enableLedgerPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer enable(TransactionPermission... permissions) { | |||
List<TransactionPermission> permissionList = ArrayUtils.asList(permissions); | |||
enableTxPermissions.addAll(permissionList); | |||
disableTxPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer disable(TransactionPermission... permissions) { | |||
List<TransactionPermission> permissionList = ArrayUtils.asList(permissions); | |||
disableTxPermissions.addAll(permissionList); | |||
enableTxPermissions.removeAll(permissionList); | |||
return this; | |||
} | |||
@Override | |||
public RolePrivilegeConfigurer configure(String roleName) { | |||
return RolesConfigureOpTemplate.this.configure(roleName); | |||
} | |||
} | |||
} |
@@ -1,19 +1,19 @@ | |||
package com.jd.blockchain.transaction; | |||
public interface SecurityOperationBuilder { | |||
/** | |||
* 配置角色; | |||
* | |||
* @return | |||
*/ | |||
RolesConfigurer roles(); | |||
/** | |||
* 授权用户; | |||
* | |||
* @return | |||
*/ | |||
UserAuthorizer authorziations(); | |||
} | |||
package com.jd.blockchain.transaction; | |||
public interface SecurityOperationBuilder { | |||
/** | |||
* 配置角色; | |||
* | |||
* @return | |||
*/ | |||
RolesConfigurer roles(); | |||
/** | |||
* 授权用户; | |||
* | |||
* @return | |||
*/ | |||
UserAuthorizer authorziations(); | |||
} |
@@ -1,27 +1,27 @@ | |||
package com.jd.blockchain.transaction; | |||
import org.springframework.util.Base64Utils; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class SignatureEncoding { | |||
public static byte[] encode(DigitalSignature signature) { | |||
return BinaryProtocol.encode(signature, DigitalSignature.class); | |||
} | |||
public static DigitalSignature decode(byte[] bytesSignature) { | |||
return BinaryProtocol.decode(bytesSignature); | |||
} | |||
public static DigitalSignature decodeFromBase64(String base64Signature) { | |||
byte[] bytesSignature = Base64Utils.decodeFromUrlSafeString(base64Signature); | |||
return decode(bytesSignature); | |||
} | |||
public static String encodeToBase64(DigitalSignature signature) { | |||
byte[] bytesSignature = encode(signature); | |||
return Base64Utils.encodeToUrlSafeString(bytesSignature); | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import org.springframework.util.Base64Utils; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
public class SignatureEncoding { | |||
public static byte[] encode(DigitalSignature signature) { | |||
return BinaryProtocol.encode(signature, DigitalSignature.class); | |||
} | |||
public static DigitalSignature decode(byte[] bytesSignature) { | |||
return BinaryProtocol.decode(bytesSignature); | |||
} | |||
public static DigitalSignature decodeFromBase64(String base64Signature) { | |||
byte[] bytesSignature = Base64Utils.decodeFromUrlSafeString(base64Signature); | |||
return decode(bytesSignature); | |||
} | |||
public static String encodeToBase64(DigitalSignature signature) { | |||
byte[] bytesSignature = encode(signature); | |||
return Base64Utils.encodeToUrlSafeString(bytesSignature); | |||
} | |||
} |
@@ -1,10 +1,10 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
public interface TransactionService { | |||
TransactionResponse process(TransactionRequest txRequest); | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
public interface TransactionService { | |||
TransactionResponse process(TransactionRequest txRequest); | |||
} |
@@ -1,106 +1,106 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
public class TxRequestBuilder implements TransactionRequestBuilder { | |||
private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | |||
private TransactionContent txContent; | |||
private List<DigitalSignature> endpointSignatures = new ArrayList<>(); | |||
private List<DigitalSignature> nodeSignatures = new ArrayList<>(); | |||
public TxRequestBuilder(TransactionContent txContent) { | |||
this.txContent = txContent; | |||
} | |||
@Override | |||
public HashDigest getHash() { | |||
return txContent.getHash(); | |||
} | |||
@Override | |||
public TransactionContent getTransactionContent() { | |||
return txContent; | |||
} | |||
@Override | |||
public DigitalSignature signAsEndpoint(AsymmetricKeypair keyPair) { | |||
DigitalSignature signature = SignatureUtils.sign(txContent, keyPair); | |||
addEndpointSignature(signature); | |||
return signature; | |||
} | |||
@Override | |||
public DigitalSignature signAsNode(AsymmetricKeypair keyPair) { | |||
DigitalSignature signature = SignatureUtils.sign(txContent, keyPair); | |||
addNodeSignature(signature); | |||
return signature; | |||
} | |||
@Override | |||
public void addNodeSignature(DigitalSignature... signatures) { | |||
if (signatures != null) { | |||
for (DigitalSignature s : signatures) { | |||
nodeSignatures.add(s); | |||
} | |||
} | |||
} | |||
@Override | |||
public void addEndpointSignature(DigitalSignature... signatures) { | |||
if (signatures != null) { | |||
for (DigitalSignature s : signatures) { | |||
endpointSignatures.add(s); | |||
} | |||
} | |||
} | |||
// public static DigitalSignature sign(TransactionContent txContent, AsymmetricKeypair keyPair) { | |||
// SignatureDigest signatureDigest = sign(txContent, keyPair.getPrivKey()); | |||
// DigitalSignature signature = new DigitalSignatureBlob(keyPair.getPubKey(), signatureDigest); | |||
// return signature; | |||
// } | |||
// | |||
// public static SignatureDigest sign(TransactionContent txContent, PrivKey privKey) { | |||
// return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, txContent.getHash().toBytes()); | |||
// } | |||
// public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { | |||
// if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
// return false; | |||
// } | |||
// return verifyHashSignature(txContent.getHash(), signDigest, pubKey); | |||
// } | |||
// | |||
// public static boolean verifyHashSignature(HashDigest hash, SignatureDigest signDigest, PubKey pubKey) { | |||
// return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey, hash.toBytes()); | |||
// } | |||
@Override | |||
public TransactionRequest buildRequest() { | |||
TxRequestMessage txMessage = new TxRequestMessage(txContent); | |||
txMessage.addEndpointSignatures(endpointSignatures); | |||
txMessage.addNodeSignatures(nodeSignatures); | |||
byte[] reqBytes = BinaryProtocol.encode(txMessage, NodeRequest.class); | |||
HashDigest reqHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(reqBytes); | |||
txMessage.setHash(reqHash); | |||
return txMessage; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
import com.jd.blockchain.crypto.Crypto; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
public class TxRequestBuilder implements TransactionRequestBuilder { | |||
private static final String DEFAULT_HASH_ALGORITHM = "SHA256"; | |||
private TransactionContent txContent; | |||
private List<DigitalSignature> endpointSignatures = new ArrayList<>(); | |||
private List<DigitalSignature> nodeSignatures = new ArrayList<>(); | |||
public TxRequestBuilder(TransactionContent txContent) { | |||
this.txContent = txContent; | |||
} | |||
@Override | |||
public HashDigest getHash() { | |||
return txContent.getHash(); | |||
} | |||
@Override | |||
public TransactionContent getTransactionContent() { | |||
return txContent; | |||
} | |||
@Override | |||
public DigitalSignature signAsEndpoint(AsymmetricKeypair keyPair) { | |||
DigitalSignature signature = SignatureUtils.sign(txContent, keyPair); | |||
addEndpointSignature(signature); | |||
return signature; | |||
} | |||
@Override | |||
public DigitalSignature signAsNode(AsymmetricKeypair keyPair) { | |||
DigitalSignature signature = SignatureUtils.sign(txContent, keyPair); | |||
addNodeSignature(signature); | |||
return signature; | |||
} | |||
@Override | |||
public void addNodeSignature(DigitalSignature... signatures) { | |||
if (signatures != null) { | |||
for (DigitalSignature s : signatures) { | |||
nodeSignatures.add(s); | |||
} | |||
} | |||
} | |||
@Override | |||
public void addEndpointSignature(DigitalSignature... signatures) { | |||
if (signatures != null) { | |||
for (DigitalSignature s : signatures) { | |||
endpointSignatures.add(s); | |||
} | |||
} | |||
} | |||
// public static DigitalSignature sign(TransactionContent txContent, AsymmetricKeypair keyPair) { | |||
// SignatureDigest signatureDigest = sign(txContent, keyPair.getPrivKey()); | |||
// DigitalSignature signature = new DigitalSignatureBlob(keyPair.getPubKey(), signatureDigest); | |||
// return signature; | |||
// } | |||
// | |||
// public static SignatureDigest sign(TransactionContent txContent, PrivKey privKey) { | |||
// return Crypto.getSignatureFunction(privKey.getAlgorithm()).sign(privKey, txContent.getHash().toBytes()); | |||
// } | |||
// public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { | |||
// if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
// return false; | |||
// } | |||
// return verifyHashSignature(txContent.getHash(), signDigest, pubKey); | |||
// } | |||
// | |||
// public static boolean verifyHashSignature(HashDigest hash, SignatureDigest signDigest, PubKey pubKey) { | |||
// return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey, hash.toBytes()); | |||
// } | |||
@Override | |||
public TransactionRequest buildRequest() { | |||
TxRequestMessage txMessage = new TxRequestMessage(txContent); | |||
txMessage.addEndpointSignatures(endpointSignatures); | |||
txMessage.addNodeSignatures(nodeSignatures); | |||
byte[] reqBytes = BinaryProtocol.encode(txMessage, NodeRequest.class); | |||
HashDigest reqHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(reqBytes); | |||
txMessage.setHash(reqHash); | |||
return txMessage; | |||
} | |||
} |
@@ -1,385 +1,385 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MagicNumber; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* TxRequestMessage 交易消息; | |||
* <p> | |||
* | |||
* TxRequestMessage 表示参与者提交的交易请求,由3部分组成:交易内容、参与者签名、网关节点签名;<br> | |||
* | |||
* <pre> | |||
* 字节位如下: | |||
* [第1字节]:标识数据类型为交易请求的魔数常量 ({@link MagicNumber#TX_REQUEST}); | |||
* | |||
* [第2字节] - [第N字节]: 交易内容; | |||
* | |||
* [第N+1字节]: 交易参与者数量(有效值范围 0 - 255); | |||
* 注:在单个交易中,参与者的数量总是有限的,对于那些需要更多参与者且数量不确定的场景,可以通过合约来实现把参与者分为多次 TX 提交,最终组合完成一次完整的业务进程; | |||
* [第N+2字节] - [第X字节]: 参与者的签名列表; | |||
* | |||
* [第X+1字节]:对交易请求的哈希算法的代码; | |||
* [第X+2字节] - [第Y字节]:对交易请求的哈希值;针对交易请求中此段之前的全部内容进行哈希计算,包括:交易请求魔数、交易内容、签名者列表、哈希算法代码; | |||
* | |||
* [第Y+1字节] - 结束: 网关节点针对交易请求的签名; | |||
* </pre> | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TxRequestMessage implements TransactionRequest {// , Externalizable { | |||
/** | |||
* 交易参与者的个数的最大值; | |||
*/ | |||
public static final int MAX_TX_PARTICIPANT_COUNT = 0xFF; | |||
private HashDigest hash; | |||
private TransactionContent transactionContent; | |||
private Map<Bytes, DigitalSignature> endpointSignatureMap = new LinkedHashMap<>(); | |||
private Map<Bytes, DigitalSignature> nodeSignatureMap = new LinkedHashMap<>(); | |||
// private CryptoAlgorithm defaultHashAlgorithm = CryptoAlgorithm.SHA_256; | |||
// public TxRequestMessage() { | |||
// } | |||
static { | |||
DataContractRegistry.register(NodeRequest.class); | |||
} | |||
public TxRequestMessage(TransactionContent txContent) { | |||
// if (!(txContent instanceof BytesWriter)) { | |||
// throw new IllegalArgumentException("The tx content must be instance of | |||
// BytesWriter!"); | |||
// } | |||
this.transactionContent = txContent; | |||
} | |||
public TxRequestMessage(TransactionRequest txRequest) { | |||
this.transactionContent = txRequest.getTransactionContent(); | |||
setHash(txRequest.getHash()); | |||
setEndpointSignatures(txRequest.getEndpointSignatures()); | |||
setNodeSignatures(txRequest.getNodeSignatures()); | |||
} | |||
@Override | |||
public TransactionContent getTransactionContent() { | |||
return this.transactionContent; | |||
} | |||
@Override | |||
public DigitalSignature[] getEndpointSignatures() { | |||
return endpointSignatureMap.values().toArray(new DigitalSignature[endpointSignatureMap.size()]); | |||
} | |||
@Override | |||
public DigitalSignature[] getNodeSignatures() { | |||
return nodeSignatureMap.values().toArray(new DigitalSignature[nodeSignatureMap.size()]); | |||
} | |||
public void setEndpointSignatures(Object[] endpointSignatures) { | |||
if (endpointSignatures != null) { | |||
for (Object object : endpointSignatures) { | |||
DigitalSignature endpointSignature = (DigitalSignature) object; | |||
addEndpointSignatures(endpointSignature); | |||
} | |||
} | |||
return; | |||
} | |||
public void setNodeSignatures(Object[] nodeSignatures) { | |||
if (nodeSignatures != null) { | |||
for (Object object : nodeSignatures) { | |||
DigitalSignature nodeSignature = (DigitalSignature) object; | |||
addNodeSignatures(nodeSignature); | |||
} | |||
} | |||
return; | |||
} | |||
private void doAddEndpointSignature(DigitalSignature signature) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
if (endpointSignatureMap.containsKey(address)) { | |||
throw new IllegalArgumentException( | |||
String.format("Participant signature of Address[%s] already exist!", address)); | |||
} | |||
endpointSignatureMap.put(address, signature); | |||
} | |||
/** | |||
* 从参与者签名列表中检查是否包含指定的参与者; | |||
* | |||
* @param userBid | |||
* 参与者的身份; | |||
* @return | |||
*/ | |||
public boolean containsEndpointSignature(BlockchainIdentity userBid) { | |||
return endpointSignatureMap.containsKey(userBid.getAddress()); | |||
} | |||
public boolean containsEndpointSignature(Bytes userAddress) { | |||
return endpointSignatureMap.containsKey(userAddress); | |||
} | |||
public void addEndpointSignatures(DigitalSignature... signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddEndpointSignature(sign); | |||
} | |||
} | |||
public void addEndpointSignatures(List<DigitalSignature> signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddEndpointSignature(sign); | |||
} | |||
} | |||
/** | |||
* 从节点签名列表中检查是否包含指定的节点; | |||
* | |||
* @param nodeBid | |||
* 节点的身份; | |||
* @return | |||
*/ | |||
public boolean containsNodeSignature(BlockchainIdentity nodeBid) { | |||
return nodeSignatureMap.containsKey(nodeBid.getAddress()); | |||
} | |||
public boolean containsNodeSignature(Bytes nodeAddress) { | |||
return nodeSignatureMap.containsKey(nodeAddress); | |||
} | |||
private void doAddNodeSignatures(DigitalSignature signature) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
if (nodeSignatureMap.containsKey(address)) { | |||
throw new IllegalArgumentException(String.format("Node signature of Address[%s] already exist!", address)); | |||
} | |||
nodeSignatureMap.put(address, signature); | |||
} | |||
public void addNodeSignatures(DigitalSignature... signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddNodeSignatures(sign); | |||
} | |||
} | |||
public void addNodeSignatures(List<DigitalSignature> signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddNodeSignatures(sign); | |||
} | |||
} | |||
@Override | |||
public HashDigest getHash() { | |||
return hash; | |||
} | |||
public void setHash(HashDigest hash) { | |||
this.hash = hash; | |||
} | |||
// public HashDigest updateHash() { | |||
// return computeHash(this.defaultHashAlgorithm); | |||
// } | |||
// public HashDigest updateHash(CryptoAlgorithm hashAlgorithm) { | |||
// return computeHash(hashAlgorithm); | |||
// } | |||
// | |||
// private HashDigest computeHash(CryptoAlgorithm hashAlgorithm) { | |||
// byte[] reqBody = getRequestBody(); | |||
// this.hash = CryptoUtils.hash(hashAlgorithm).hash(reqBody); | |||
// return this.hash; | |||
// } | |||
// @Override | |||
// public void resolvFrom(InputStream in) throws IOException { | |||
// // 解析校验交易请求魔数; | |||
// byte[] buff = new byte[1]; | |||
// int len = in.read(buff, 0, 1); | |||
// if (len < 1) { | |||
// throw new IllegalArgumentException("No bytes was read for the magic number | |||
// [TX_REQUEST]!"); | |||
// } | |||
// if (MagicNumber.TX_REQUEST != buff[0]) { | |||
// throw new IllegalArgumentException("Magic number [TX_REQUEST] dismatch!"); | |||
// } | |||
// | |||
// // 解析交易内容; | |||
// TxContentBlob txContentBlob = new TxContentBlob(); | |||
// txContentBlob.resolvFrom(in); | |||
// | |||
// // 解析参与者签名列表; | |||
// int participantCount = NumberMask.TINY.resolveMaskedNumber(in); | |||
// List<DigitalSignature> partiSignList = new ArrayList<>(); | |||
// for (int i = 0; i < participantCount; i++) { | |||
// DigitalSignatureBlob signature = new DigitalSignatureBlob(); | |||
// signature.resolvFrom(in); | |||
// | |||
// partiSignList.add(signature); | |||
// } | |||
// | |||
// // 解析节点签名列表; | |||
// int nodeCount = NumberMask.TINY.resolveMaskedNumber(in); | |||
// List<DigitalSignature> nodeSignList = new ArrayList<>(); | |||
// for (int i = 0; i < nodeCount; i++) { | |||
// DigitalSignatureBlob nodeSign = new DigitalSignatureBlob(); | |||
// nodeSign.resolvFrom(in); | |||
// nodeSignList.add(nodeSign); | |||
// } | |||
// | |||
// // 解析哈希算法标识符; | |||
// HashAlgorithm hashAlgorithm = HashAlgorithm.valueOf((byte) in.read()); | |||
// | |||
// // 解析原始的哈希; | |||
// ByteArray hash = HashEncoding.read(in); | |||
// | |||
// this.txContent = txContentBlob; | |||
// addParticipantSignatures(partiSignList); | |||
// addNodeSignatures(nodeSignList); | |||
// this.hash = hash; | |||
// | |||
// // 校验原始哈希; | |||
// byte[] bodyBytes = getRequestBody(); | |||
// ByteArray rHash = HashEncoding.computeHash(bodyBytes, hashAlgorithm); | |||
// if (!rHash.equals(hash)) { | |||
// throw new IllegalArgumentException("The hash is not match with request | |||
// content!"); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * 输出交易请求消息; | |||
// * | |||
// * 注:此方法不会自动重新计算hash;如果消息的内容发生改变后,需要调用主动调用 {@link #updateHash()} 方法重新计算 hash; | |||
// */ | |||
// @Override | |||
// public void writeTo(OutputStream out) throws IOException { | |||
// if (this.hash == null) { | |||
// updateHash(); | |||
// } | |||
// | |||
// buildRequestBody(out); | |||
// | |||
// // 写入 hash 值; | |||
// HashEncoding.write(hash, out); | |||
// } | |||
// /** | |||
// * 生成请求体,包括:交易请求魔数、交易内容、参与者签名者列表、哈希算法代号; | |||
// * | |||
// * @param out | |||
// * @throws IOException | |||
// */ | |||
// private void buildRequestBody(OutputStream out) throws IOException { | |||
// | |||
// buildParticipantRequest(out); | |||
// | |||
// // 写入节点签名列表; | |||
// NumberMask.TINY.writeMask(nodeSignatureMap.size(), out); | |||
// for (DigitalSignature nodeSignatureBlob : nodeSignatureMap.values()) { | |||
// nodeSignatureBlob.writeTo(out); | |||
// } | |||
// | |||
// // 写入 hash 算法代号; | |||
// out.write(hashAlgorithm.getAlgorithm()); | |||
// } | |||
// /** | |||
// * 生成参与者的请求数据; | |||
// * | |||
// * <br> | |||
// * 参与者的请求数据仅包含“交易请求模数({@link MagicNumber#TX_REQUEST })” | |||
// * “交易内容({@link #getTransactionContent()})” | |||
// * 和“参与者签名列表({@link #getParticipantSignatures()})”三项属性; | |||
// * | |||
// * @param out | |||
// */ | |||
// public void buildParticipantRequest(OutputStream out) { | |||
// try { | |||
// // 写入魔数; | |||
// out.write(MagicNumber.TX_REQUEST); | |||
// | |||
// // 写入交易内容; | |||
// txContent.writeTo(out); | |||
// | |||
// // 写入 1 个字节的参与者签名数量; | |||
// if (participantSignatureMap.size() > MAX_TX_PARTICIPANT_COUNT) { | |||
// throw new IllegalArgumentException("The number of participant signatures is | |||
// out of the max count[" | |||
// + MAX_TX_PARTICIPANT_COUNT + "]!"); | |||
// } | |||
// | |||
// NumberMask.TINY.writeMask(participantSignatureMap.size(), out); | |||
// // 写入参与者签名列表; | |||
// for (DigitalSignature digitalSignatureBlob : | |||
// participantSignatureMap.values()) { | |||
// digitalSignatureBlob.writeTo(out); | |||
// } | |||
// | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public void writeExternal(ObjectOutput out) throws IOException { | |||
// ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||
// writeTo(os); | |||
// byte[] bts = os.toByteArray(); | |||
// out.writeInt(bts.length); | |||
// out.write(bts); | |||
// } | |||
// | |||
// @Override | |||
// public void readExternal(ObjectInput in) throws IOException, | |||
// ClassNotFoundException { | |||
// int len = in.readInt(); | |||
// byte[] bts = new byte[len]; | |||
// in.readFully(bts); | |||
// this.resolvFrom(new ByteArrayInputStream(bts)); | |||
// } | |||
// @Override | |||
// public byte[] toBytes() { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// try { | |||
// writeTo(out); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// return out.toByteArray(); | |||
// } | |||
// @Override | |||
// public ByteArray getHashData() { | |||
// return ByteArray.wrap(getRequestBody()); | |||
// } | |||
// private byte[] getRequestBody() { | |||
// try { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// buildRequestBody(out); | |||
// | |||
// return out.toByteArray(); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.crypto.AddressEncoding; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.DigitalSignature; | |||
import com.jd.blockchain.ledger.MagicNumber; | |||
import com.jd.blockchain.ledger.NodeRequest; | |||
import com.jd.blockchain.ledger.TransactionContent; | |||
import com.jd.blockchain.ledger.TransactionRequest; | |||
import com.jd.blockchain.utils.Bytes; | |||
/** | |||
* TxRequestMessage 交易消息; | |||
* <p> | |||
* | |||
* TxRequestMessage 表示参与者提交的交易请求,由3部分组成:交易内容、参与者签名、网关节点签名;<br> | |||
* | |||
* <pre> | |||
* 字节位如下: | |||
* [第1字节]:标识数据类型为交易请求的魔数常量 ({@link MagicNumber#TX_REQUEST}); | |||
* | |||
* [第2字节] - [第N字节]: 交易内容; | |||
* | |||
* [第N+1字节]: 交易参与者数量(有效值范围 0 - 255); | |||
* 注:在单个交易中,参与者的数量总是有限的,对于那些需要更多参与者且数量不确定的场景,可以通过合约来实现把参与者分为多次 TX 提交,最终组合完成一次完整的业务进程; | |||
* [第N+2字节] - [第X字节]: 参与者的签名列表; | |||
* | |||
* [第X+1字节]:对交易请求的哈希算法的代码; | |||
* [第X+2字节] - [第Y字节]:对交易请求的哈希值;针对交易请求中此段之前的全部内容进行哈希计算,包括:交易请求魔数、交易内容、签名者列表、哈希算法代码; | |||
* | |||
* [第Y+1字节] - 结束: 网关节点针对交易请求的签名; | |||
* </pre> | |||
* | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TxRequestMessage implements TransactionRequest {// , Externalizable { | |||
/** | |||
* 交易参与者的个数的最大值; | |||
*/ | |||
public static final int MAX_TX_PARTICIPANT_COUNT = 0xFF; | |||
private HashDigest hash; | |||
private TransactionContent transactionContent; | |||
private Map<Bytes, DigitalSignature> endpointSignatureMap = new LinkedHashMap<>(); | |||
private Map<Bytes, DigitalSignature> nodeSignatureMap = new LinkedHashMap<>(); | |||
// private CryptoAlgorithm defaultHashAlgorithm = CryptoAlgorithm.SHA_256; | |||
// public TxRequestMessage() { | |||
// } | |||
static { | |||
DataContractRegistry.register(NodeRequest.class); | |||
} | |||
public TxRequestMessage(TransactionContent txContent) { | |||
// if (!(txContent instanceof BytesWriter)) { | |||
// throw new IllegalArgumentException("The tx content must be instance of | |||
// BytesWriter!"); | |||
// } | |||
this.transactionContent = txContent; | |||
} | |||
public TxRequestMessage(TransactionRequest txRequest) { | |||
this.transactionContent = txRequest.getTransactionContent(); | |||
setHash(txRequest.getHash()); | |||
setEndpointSignatures(txRequest.getEndpointSignatures()); | |||
setNodeSignatures(txRequest.getNodeSignatures()); | |||
} | |||
@Override | |||
public TransactionContent getTransactionContent() { | |||
return this.transactionContent; | |||
} | |||
@Override | |||
public DigitalSignature[] getEndpointSignatures() { | |||
return endpointSignatureMap.values().toArray(new DigitalSignature[endpointSignatureMap.size()]); | |||
} | |||
@Override | |||
public DigitalSignature[] getNodeSignatures() { | |||
return nodeSignatureMap.values().toArray(new DigitalSignature[nodeSignatureMap.size()]); | |||
} | |||
public void setEndpointSignatures(Object[] endpointSignatures) { | |||
if (endpointSignatures != null) { | |||
for (Object object : endpointSignatures) { | |||
DigitalSignature endpointSignature = (DigitalSignature) object; | |||
addEndpointSignatures(endpointSignature); | |||
} | |||
} | |||
return; | |||
} | |||
public void setNodeSignatures(Object[] nodeSignatures) { | |||
if (nodeSignatures != null) { | |||
for (Object object : nodeSignatures) { | |||
DigitalSignature nodeSignature = (DigitalSignature) object; | |||
addNodeSignatures(nodeSignature); | |||
} | |||
} | |||
return; | |||
} | |||
private void doAddEndpointSignature(DigitalSignature signature) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
if (endpointSignatureMap.containsKey(address)) { | |||
throw new IllegalArgumentException( | |||
String.format("Participant signature of Address[%s] already exist!", address)); | |||
} | |||
endpointSignatureMap.put(address, signature); | |||
} | |||
/** | |||
* 从参与者签名列表中检查是否包含指定的参与者; | |||
* | |||
* @param userBid | |||
* 参与者的身份; | |||
* @return | |||
*/ | |||
public boolean containsEndpointSignature(BlockchainIdentity userBid) { | |||
return endpointSignatureMap.containsKey(userBid.getAddress()); | |||
} | |||
public boolean containsEndpointSignature(Bytes userAddress) { | |||
return endpointSignatureMap.containsKey(userAddress); | |||
} | |||
public void addEndpointSignatures(DigitalSignature... signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddEndpointSignature(sign); | |||
} | |||
} | |||
public void addEndpointSignatures(List<DigitalSignature> signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddEndpointSignature(sign); | |||
} | |||
} | |||
/** | |||
* 从节点签名列表中检查是否包含指定的节点; | |||
* | |||
* @param nodeBid | |||
* 节点的身份; | |||
* @return | |||
*/ | |||
public boolean containsNodeSignature(BlockchainIdentity nodeBid) { | |||
return nodeSignatureMap.containsKey(nodeBid.getAddress()); | |||
} | |||
public boolean containsNodeSignature(Bytes nodeAddress) { | |||
return nodeSignatureMap.containsKey(nodeAddress); | |||
} | |||
private void doAddNodeSignatures(DigitalSignature signature) { | |||
Bytes address = AddressEncoding.generateAddress(signature.getPubKey()); | |||
if (nodeSignatureMap.containsKey(address)) { | |||
throw new IllegalArgumentException(String.format("Node signature of Address[%s] already exist!", address)); | |||
} | |||
nodeSignatureMap.put(address, signature); | |||
} | |||
public void addNodeSignatures(DigitalSignature... signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddNodeSignatures(sign); | |||
} | |||
} | |||
public void addNodeSignatures(List<DigitalSignature> signature) { | |||
for (DigitalSignature sign : signature) { | |||
doAddNodeSignatures(sign); | |||
} | |||
} | |||
@Override | |||
public HashDigest getHash() { | |||
return hash; | |||
} | |||
public void setHash(HashDigest hash) { | |||
this.hash = hash; | |||
} | |||
// public HashDigest updateHash() { | |||
// return computeHash(this.defaultHashAlgorithm); | |||
// } | |||
// public HashDigest updateHash(CryptoAlgorithm hashAlgorithm) { | |||
// return computeHash(hashAlgorithm); | |||
// } | |||
// | |||
// private HashDigest computeHash(CryptoAlgorithm hashAlgorithm) { | |||
// byte[] reqBody = getRequestBody(); | |||
// this.hash = CryptoUtils.hash(hashAlgorithm).hash(reqBody); | |||
// return this.hash; | |||
// } | |||
// @Override | |||
// public void resolvFrom(InputStream in) throws IOException { | |||
// // 解析校验交易请求魔数; | |||
// byte[] buff = new byte[1]; | |||
// int len = in.read(buff, 0, 1); | |||
// if (len < 1) { | |||
// throw new IllegalArgumentException("No bytes was read for the magic number | |||
// [TX_REQUEST]!"); | |||
// } | |||
// if (MagicNumber.TX_REQUEST != buff[0]) { | |||
// throw new IllegalArgumentException("Magic number [TX_REQUEST] dismatch!"); | |||
// } | |||
// | |||
// // 解析交易内容; | |||
// TxContentBlob txContentBlob = new TxContentBlob(); | |||
// txContentBlob.resolvFrom(in); | |||
// | |||
// // 解析参与者签名列表; | |||
// int participantCount = NumberMask.TINY.resolveMaskedNumber(in); | |||
// List<DigitalSignature> partiSignList = new ArrayList<>(); | |||
// for (int i = 0; i < participantCount; i++) { | |||
// DigitalSignatureBlob signature = new DigitalSignatureBlob(); | |||
// signature.resolvFrom(in); | |||
// | |||
// partiSignList.add(signature); | |||
// } | |||
// | |||
// // 解析节点签名列表; | |||
// int nodeCount = NumberMask.TINY.resolveMaskedNumber(in); | |||
// List<DigitalSignature> nodeSignList = new ArrayList<>(); | |||
// for (int i = 0; i < nodeCount; i++) { | |||
// DigitalSignatureBlob nodeSign = new DigitalSignatureBlob(); | |||
// nodeSign.resolvFrom(in); | |||
// nodeSignList.add(nodeSign); | |||
// } | |||
// | |||
// // 解析哈希算法标识符; | |||
// HashAlgorithm hashAlgorithm = HashAlgorithm.valueOf((byte) in.read()); | |||
// | |||
// // 解析原始的哈希; | |||
// ByteArray hash = HashEncoding.read(in); | |||
// | |||
// this.txContent = txContentBlob; | |||
// addParticipantSignatures(partiSignList); | |||
// addNodeSignatures(nodeSignList); | |||
// this.hash = hash; | |||
// | |||
// // 校验原始哈希; | |||
// byte[] bodyBytes = getRequestBody(); | |||
// ByteArray rHash = HashEncoding.computeHash(bodyBytes, hashAlgorithm); | |||
// if (!rHash.equals(hash)) { | |||
// throw new IllegalArgumentException("The hash is not match with request | |||
// content!"); | |||
// } | |||
// } | |||
// | |||
// /** | |||
// * 输出交易请求消息; | |||
// * | |||
// * 注:此方法不会自动重新计算hash;如果消息的内容发生改变后,需要调用主动调用 {@link #updateHash()} 方法重新计算 hash; | |||
// */ | |||
// @Override | |||
// public void writeTo(OutputStream out) throws IOException { | |||
// if (this.hash == null) { | |||
// updateHash(); | |||
// } | |||
// | |||
// buildRequestBody(out); | |||
// | |||
// // 写入 hash 值; | |||
// HashEncoding.write(hash, out); | |||
// } | |||
// /** | |||
// * 生成请求体,包括:交易请求魔数、交易内容、参与者签名者列表、哈希算法代号; | |||
// * | |||
// * @param out | |||
// * @throws IOException | |||
// */ | |||
// private void buildRequestBody(OutputStream out) throws IOException { | |||
// | |||
// buildParticipantRequest(out); | |||
// | |||
// // 写入节点签名列表; | |||
// NumberMask.TINY.writeMask(nodeSignatureMap.size(), out); | |||
// for (DigitalSignature nodeSignatureBlob : nodeSignatureMap.values()) { | |||
// nodeSignatureBlob.writeTo(out); | |||
// } | |||
// | |||
// // 写入 hash 算法代号; | |||
// out.write(hashAlgorithm.getAlgorithm()); | |||
// } | |||
// /** | |||
// * 生成参与者的请求数据; | |||
// * | |||
// * <br> | |||
// * 参与者的请求数据仅包含“交易请求模数({@link MagicNumber#TX_REQUEST })” | |||
// * “交易内容({@link #getTransactionContent()})” | |||
// * 和“参与者签名列表({@link #getParticipantSignatures()})”三项属性; | |||
// * | |||
// * @param out | |||
// */ | |||
// public void buildParticipantRequest(OutputStream out) { | |||
// try { | |||
// // 写入魔数; | |||
// out.write(MagicNumber.TX_REQUEST); | |||
// | |||
// // 写入交易内容; | |||
// txContent.writeTo(out); | |||
// | |||
// // 写入 1 个字节的参与者签名数量; | |||
// if (participantSignatureMap.size() > MAX_TX_PARTICIPANT_COUNT) { | |||
// throw new IllegalArgumentException("The number of participant signatures is | |||
// out of the max count[" | |||
// + MAX_TX_PARTICIPANT_COUNT + "]!"); | |||
// } | |||
// | |||
// NumberMask.TINY.writeMask(participantSignatureMap.size(), out); | |||
// // 写入参与者签名列表; | |||
// for (DigitalSignature digitalSignatureBlob : | |||
// participantSignatureMap.values()) { | |||
// digitalSignatureBlob.writeTo(out); | |||
// } | |||
// | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
// | |||
// @Override | |||
// public void writeExternal(ObjectOutput out) throws IOException { | |||
// ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||
// writeTo(os); | |||
// byte[] bts = os.toByteArray(); | |||
// out.writeInt(bts.length); | |||
// out.write(bts); | |||
// } | |||
// | |||
// @Override | |||
// public void readExternal(ObjectInput in) throws IOException, | |||
// ClassNotFoundException { | |||
// int len = in.readInt(); | |||
// byte[] bts = new byte[len]; | |||
// in.readFully(bts); | |||
// this.resolvFrom(new ByteArrayInputStream(bts)); | |||
// } | |||
// @Override | |||
// public byte[] toBytes() { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// try { | |||
// writeTo(out); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// return out.toByteArray(); | |||
// } | |||
// @Override | |||
// public ByteArray getHashData() { | |||
// return ByteArray.wrap(getRequestBody()); | |||
// } | |||
// private byte[] getRequestBody() { | |||
// try { | |||
// ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
// buildRequestBody(out); | |||
// | |||
// return out.toByteArray(); | |||
// } catch (IOException e) { | |||
// throw new RuntimeIOException(e.getMessage(), e); | |||
// } | |||
// } | |||
} |
@@ -1,86 +1,86 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TxResponseMessage implements TransactionResponse { | |||
private HashDigest contentHash; | |||
private HashDigest blockHash; | |||
private long blockHeight; | |||
private TransactionState executionState; | |||
private OperationResult[] operationResults; | |||
public TxResponseMessage() { | |||
} | |||
// 重新包装operationResults | |||
public TxResponseMessage(TransactionResponse transactionResponse, OperationResult[] operationResults) { | |||
this.contentHash = transactionResponse.getContentHash(); | |||
this.blockHash = transactionResponse.getBlockHash(); | |||
this.blockHeight = transactionResponse.getBlockHeight(); | |||
this.executionState = transactionResponse.getExecutionState(); | |||
this.operationResults = operationResults; | |||
} | |||
public TxResponseMessage(HashDigest contentHash) { | |||
this.contentHash = contentHash; | |||
} | |||
@Override | |||
public HashDigest getContentHash() { | |||
return contentHash; | |||
} | |||
@Override | |||
public TransactionState getExecutionState() { | |||
return executionState; | |||
} | |||
public void setExecutionState(TransactionState executionState) { | |||
this.executionState = executionState; | |||
} | |||
@Override | |||
public HashDigest getBlockHash() { | |||
return blockHash; | |||
} | |||
public void setBlockHash(HashDigest blockHash) { | |||
this.blockHash = blockHash; | |||
} | |||
@Override | |||
public long getBlockHeight() { | |||
return blockHeight; | |||
} | |||
public void setBlockHeight(long blockHeight) { | |||
this.blockHeight = blockHeight; | |||
} | |||
public void setOperationResults(OperationResult[] operationResults) { | |||
this.operationResults = operationResults; | |||
} | |||
@Override | |||
public boolean isSuccess() { | |||
return blockHash != null & executionState == TransactionState.SUCCESS; | |||
} | |||
@Override | |||
public OperationResult[] getOperationResults() { | |||
return operationResults; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.ledger.TransactionState; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.OperationResult; | |||
import com.jd.blockchain.ledger.TransactionResponse; | |||
/** | |||
* @author huanghaiquan | |||
* | |||
*/ | |||
public class TxResponseMessage implements TransactionResponse { | |||
private HashDigest contentHash; | |||
private HashDigest blockHash; | |||
private long blockHeight; | |||
private TransactionState executionState; | |||
private OperationResult[] operationResults; | |||
public TxResponseMessage() { | |||
} | |||
// 重新包装operationResults | |||
public TxResponseMessage(TransactionResponse transactionResponse, OperationResult[] operationResults) { | |||
this.contentHash = transactionResponse.getContentHash(); | |||
this.blockHash = transactionResponse.getBlockHash(); | |||
this.blockHeight = transactionResponse.getBlockHeight(); | |||
this.executionState = transactionResponse.getExecutionState(); | |||
this.operationResults = operationResults; | |||
} | |||
public TxResponseMessage(HashDigest contentHash) { | |||
this.contentHash = contentHash; | |||
} | |||
@Override | |||
public HashDigest getContentHash() { | |||
return contentHash; | |||
} | |||
@Override | |||
public TransactionState getExecutionState() { | |||
return executionState; | |||
} | |||
public void setExecutionState(TransactionState executionState) { | |||
this.executionState = executionState; | |||
} | |||
@Override | |||
public HashDigest getBlockHash() { | |||
return blockHash; | |||
} | |||
public void setBlockHash(HashDigest blockHash) { | |||
this.blockHash = blockHash; | |||
} | |||
@Override | |||
public long getBlockHeight() { | |||
return blockHeight; | |||
} | |||
public void setBlockHeight(long blockHeight) { | |||
this.blockHeight = blockHeight; | |||
} | |||
public void setOperationResults(OperationResult[] operationResults) { | |||
this.operationResults = operationResults; | |||
} | |||
@Override | |||
public boolean isSuccess() { | |||
return blockHash != null & executionState == TransactionState.SUCCESS; | |||
} | |||
@Override | |||
public OperationResult[] getOperationResults() { | |||
return operationResults; | |||
} | |||
} |
@@ -1,111 +1,111 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class TxTemplate implements TransactionTemplate { | |||
private TxBuilder txBuilder; | |||
private TransactionService txService; | |||
private TxStateManager stateManager; | |||
public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | |||
this.stateManager = new TxStateManager(); | |||
this.txBuilder = new TxBuilder(ledgerHash); | |||
this.txService = txService; | |||
} | |||
@Override | |||
public HashDigest getLedgerHash() { | |||
return txBuilder.getLedgerHash(); | |||
} | |||
@Override | |||
public PreparedTransaction prepare() { | |||
stateManager.prepare(); | |||
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
} | |||
@Override | |||
public SecurityOperationBuilder security() { | |||
stateManager.operate(); | |||
return txBuilder.security(); | |||
} | |||
@Override | |||
public UserRegisterOperationBuilder users() { | |||
stateManager.operate(); | |||
return txBuilder.users(); | |||
} | |||
@Override | |||
public DataAccountRegisterOperationBuilder dataAccounts() { | |||
stateManager.operate(); | |||
return txBuilder.dataAccounts(); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public ContractCodeDeployOperationBuilder contracts() { | |||
stateManager.operate(); | |||
return txBuilder.contracts(); | |||
} | |||
@Override | |||
public ParticipantRegisterOperationBuilder participants() { | |||
stateManager.operate(); | |||
return txBuilder.participants(); | |||
} | |||
@Override | |||
public ParticipantStateUpdateOperationBuilder states() { | |||
stateManager.operate(); | |||
return txBuilder.states(); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
if (!stateManager.close()) { | |||
Collection<OperationResultHandle> handlers = txBuilder.getReturnValuehandlers(); | |||
if (handlers.size() > 0) { | |||
TransactionCancelledExeption error = new TransactionCancelledExeption( | |||
"Transaction template has been cancelled!"); | |||
for (OperationResultHandle handle : handlers) { | |||
handle.complete(error); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.io.IOException; | |||
import java.util.Collection; | |||
import com.jd.blockchain.crypto.HashDigest; | |||
import com.jd.blockchain.ledger.PreparedTransaction; | |||
import com.jd.blockchain.ledger.TransactionRequestBuilder; | |||
import com.jd.blockchain.ledger.TransactionTemplate; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class TxTemplate implements TransactionTemplate { | |||
private TxBuilder txBuilder; | |||
private TransactionService txService; | |||
private TxStateManager stateManager; | |||
public TxTemplate(HashDigest ledgerHash, TransactionService txService) { | |||
this.stateManager = new TxStateManager(); | |||
this.txBuilder = new TxBuilder(ledgerHash); | |||
this.txService = txService; | |||
} | |||
@Override | |||
public HashDigest getLedgerHash() { | |||
return txBuilder.getLedgerHash(); | |||
} | |||
@Override | |||
public PreparedTransaction prepare() { | |||
stateManager.prepare(); | |||
TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); | |||
return new PreparedTx(stateManager, txReqBuilder, txService, txBuilder.getReturnValuehandlers()); | |||
} | |||
@Override | |||
public SecurityOperationBuilder security() { | |||
stateManager.operate(); | |||
return txBuilder.security(); | |||
} | |||
@Override | |||
public UserRegisterOperationBuilder users() { | |||
stateManager.operate(); | |||
return txBuilder.users(); | |||
} | |||
@Override | |||
public DataAccountRegisterOperationBuilder dataAccounts() { | |||
stateManager.operate(); | |||
return txBuilder.dataAccounts(); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(String accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public DataAccountKVSetOperationBuilder dataAccount(Bytes accountAddress) { | |||
stateManager.operate(); | |||
return txBuilder.dataAccount(accountAddress); | |||
} | |||
@Override | |||
public ContractCodeDeployOperationBuilder contracts() { | |||
stateManager.operate(); | |||
return txBuilder.contracts(); | |||
} | |||
@Override | |||
public ParticipantRegisterOperationBuilder participants() { | |||
stateManager.operate(); | |||
return txBuilder.participants(); | |||
} | |||
@Override | |||
public ParticipantStateUpdateOperationBuilder states() { | |||
stateManager.operate(); | |||
return txBuilder.states(); | |||
} | |||
@Override | |||
public <T> T contract(Bytes address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public <T> T contract(String address, Class<T> contractIntf) { | |||
stateManager.operate(); | |||
return txBuilder.contract(address, contractIntf); | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
if (!stateManager.close()) { | |||
Collection<OperationResultHandle> handlers = txBuilder.getReturnValuehandlers(); | |||
if (handlers.size() > 0) { | |||
TransactionCancelledExeption error = new TransactionCancelledExeption( | |||
"Transaction template has been cancelled!"); | |||
for (OperationResultHandle handle : handlers) { | |||
handle.complete(error); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,130 +1,130 @@ | |||
package com.jd.blockchain.transaction; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.LinkedHashSet; | |||
import java.util.Set; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.SecurityUtils; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.utils.ArrayUtils; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
DataContractRegistry.register(UserAuthorizeOperation.class); | |||
DataContractRegistry.register(UserRolesEntry.class); | |||
} | |||
private Set<AuthorizationDataEntry> userAuthMap = Collections | |||
.synchronizedSet(new LinkedHashSet<AuthorizationDataEntry>()); | |||
public UserAuthorizeOpTemplate() { | |||
} | |||
public UserAuthorizeOpTemplate(BlockchainIdentity userID) { | |||
} | |||
@Override | |||
public AuthorizationDataEntry[] getUserRolesAuthorizations() { | |||
return ArrayUtils.toArray(userAuthMap, AuthorizationDataEntry.class); | |||
} | |||
@Override | |||
public UserAuthorizeOperation getOperation() { | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||
AuthorizationDataEntry userRolesAuth = new AuthorizationDataEntry(userAddresses); | |||
userAuthMap.add(userRolesAuth); | |||
return userRolesAuth; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||
Bytes[] addresses = Arrays.stream(userIds).map(p -> p.getAddress()).toArray(Bytes[]::new); | |||
return forUser(addresses); | |||
} | |||
private class AuthorizationDataEntry implements UserRolesAuthorizer, UserRolesEntry { | |||
private Bytes[] userAddress; | |||
private RolesPolicy policy = RolesPolicy.UNION; | |||
private Set<String> authRoles = new LinkedHashSet<String>(); | |||
private Set<String> unauthRoles = new LinkedHashSet<String>(); | |||
private AuthorizationDataEntry(Bytes[] userAddress) { | |||
this.userAddress = userAddress; | |||
} | |||
@Override | |||
public Bytes[] getUserAddresses() { | |||
return userAddress; | |||
} | |||
@Override | |||
public RolesPolicy getPolicy() { | |||
return policy; | |||
} | |||
@Override | |||
public String[] getAuthorizedRoles() { | |||
return ArrayUtils.toArray(authRoles, String.class); | |||
} | |||
@Override | |||
public String[] getUnauthorizedRoles() { | |||
return ArrayUtils.toArray(unauthRoles, String.class); | |||
} | |||
@Override | |||
public UserRolesAuthorizer setPolicy(RolesPolicy policy) { | |||
this.policy = policy; | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer authorize(String... roles) { | |||
String roleName; | |||
for (String r : roles) { | |||
roleName = SecurityUtils.formatRoleName(r); | |||
authRoles.add(roleName); | |||
unauthRoles.remove(roleName); | |||
} | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer unauthorize(String... roles) { | |||
String roleName; | |||
for (String r : roles) { | |||
roleName = SecurityUtils.formatRoleName(r); | |||
unauthRoles.add(roleName); | |||
authRoles.remove(roleName); | |||
} | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||
return UserAuthorizeOpTemplate.this.forUser(userIds); | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||
return UserAuthorizeOpTemplate.this.forUser(userAddresses); | |||
} | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import java.util.LinkedHashSet; | |||
import java.util.Set; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.RolesPolicy; | |||
import com.jd.blockchain.ledger.SecurityUtils; | |||
import com.jd.blockchain.ledger.UserAuthorizeOperation; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
import com.jd.blockchain.utils.ArrayUtils; | |||
import com.jd.blockchain.utils.Bytes; | |||
public class UserAuthorizeOpTemplate implements UserAuthorizer, UserAuthorizeOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
DataContractRegistry.register(UserAuthorizeOperation.class); | |||
DataContractRegistry.register(UserRolesEntry.class); | |||
} | |||
private Set<AuthorizationDataEntry> userAuthMap = Collections | |||
.synchronizedSet(new LinkedHashSet<AuthorizationDataEntry>()); | |||
public UserAuthorizeOpTemplate() { | |||
} | |||
public UserAuthorizeOpTemplate(BlockchainIdentity userID) { | |||
} | |||
@Override | |||
public AuthorizationDataEntry[] getUserRolesAuthorizations() { | |||
return ArrayUtils.toArray(userAuthMap, AuthorizationDataEntry.class); | |||
} | |||
@Override | |||
public UserAuthorizeOperation getOperation() { | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||
AuthorizationDataEntry userRolesAuth = new AuthorizationDataEntry(userAddresses); | |||
userAuthMap.add(userRolesAuth); | |||
return userRolesAuth; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||
Bytes[] addresses = Arrays.stream(userIds).map(p -> p.getAddress()).toArray(Bytes[]::new); | |||
return forUser(addresses); | |||
} | |||
private class AuthorizationDataEntry implements UserRolesAuthorizer, UserRolesEntry { | |||
private Bytes[] userAddress; | |||
private RolesPolicy policy = RolesPolicy.UNION; | |||
private Set<String> authRoles = new LinkedHashSet<String>(); | |||
private Set<String> unauthRoles = new LinkedHashSet<String>(); | |||
private AuthorizationDataEntry(Bytes[] userAddress) { | |||
this.userAddress = userAddress; | |||
} | |||
@Override | |||
public Bytes[] getUserAddresses() { | |||
return userAddress; | |||
} | |||
@Override | |||
public RolesPolicy getPolicy() { | |||
return policy; | |||
} | |||
@Override | |||
public String[] getAuthorizedRoles() { | |||
return ArrayUtils.toArray(authRoles, String.class); | |||
} | |||
@Override | |||
public String[] getUnauthorizedRoles() { | |||
return ArrayUtils.toArray(unauthRoles, String.class); | |||
} | |||
@Override | |||
public UserRolesAuthorizer setPolicy(RolesPolicy policy) { | |||
this.policy = policy; | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer authorize(String... roles) { | |||
String roleName; | |||
for (String r : roles) { | |||
roleName = SecurityUtils.formatRoleName(r); | |||
authRoles.add(roleName); | |||
unauthRoles.remove(roleName); | |||
} | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer unauthorize(String... roles) { | |||
String roleName; | |||
for (String r : roles) { | |||
roleName = SecurityUtils.formatRoleName(r); | |||
unauthRoles.add(roleName); | |||
authRoles.remove(roleName); | |||
} | |||
return this; | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(BlockchainIdentity... userIds) { | |||
return UserAuthorizeOpTemplate.this.forUser(userIds); | |||
} | |||
@Override | |||
public UserRolesAuthorizer forUser(Bytes... userAddresses) { | |||
return UserAuthorizeOpTemplate.this.forUser(userAddresses); | |||
} | |||
} | |||
} |
@@ -1,27 +1,27 @@ | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
public class UserRegisterOpTemplate implements UserRegisterOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
} | |||
private BlockchainIdentity userID; | |||
public UserRegisterOpTemplate() { | |||
} | |||
public UserRegisterOpTemplate(BlockchainIdentity userID) { | |||
this.userID = userID; | |||
} | |||
@Override | |||
public BlockchainIdentity getUserID() { | |||
return userID; | |||
} | |||
} | |||
package com.jd.blockchain.transaction; | |||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
import com.jd.blockchain.ledger.BlockchainIdentity; | |||
import com.jd.blockchain.ledger.UserRegisterOperation; | |||
public class UserRegisterOpTemplate implements UserRegisterOperation { | |||
static { | |||
DataContractRegistry.register(UserRegisterOperation.class); | |||
} | |||
private BlockchainIdentity userID; | |||
public UserRegisterOpTemplate() { | |||
} | |||
public UserRegisterOpTemplate(BlockchainIdentity userID) { | |||
this.userID = userID; | |||
} | |||
@Override | |||
public BlockchainIdentity getUserID() { | |||
return userID; | |||
} | |||
} |