| @@ -1 +1 @@ | |||
| Subproject commit beea0d3bc9ce225805a3fd9c120e6000178d1866 | |||
| Subproject commit 22a2ea3d2238d4411103cd5bd935097962ce5a8c | |||
| @@ -5,7 +5,7 @@ | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>deploy-root</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| </parent> | |||
| <artifactId>deploy-gateway</artifactId> | |||
| @@ -5,7 +5,7 @@ | |||
| <parent> | |||
| <artifactId>deploy-root</artifactId> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| @@ -17,37 +17,37 @@ | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-protocol</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-engine</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-server</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-cli</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-benchmark</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>kvdb-client</artifactId> | |||
| <version>${version}</version> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| @@ -5,7 +5,7 @@ | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>deploy-root</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| </parent> | |||
| <artifactId>deploy-peer</artifactId> | |||
| @@ -9,11 +9,11 @@ | |||
| <relativePath>../project/parent</relativePath> | |||
| </parent> | |||
| <artifactId>deploy-root</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| <packaging>pom</packaging> | |||
| <properties> | |||
| <core.version>1.2.0.RELEASE</core.version> | |||
| <core.version>1.2.1.RELEASE</core.version> | |||
| </properties> | |||
| <modules> | |||
| @@ -1 +1 @@ | |||
| Subproject commit f6ea7b4ccbf8911dfa546d927c0e84293212ecd5 | |||
| Subproject commit 4d7675fc99e182a5097dc1fe8005d768fde21fec | |||
| @@ -1 +1 @@ | |||
| Subproject commit 4bab1a6b842324f576f69089d56e1df67cd0528d | |||
| Subproject commit 62855994675898a0dc922d5094378e62e5608087 | |||
| @@ -1 +1 @@ | |||
| Subproject commit 6e541d84081362c86430a89806c7dfcbb5fd8a71 | |||
| Subproject commit 2dfd3d8c35cecd5c78469ab15bcf903f1bcf3cde | |||
| @@ -5,7 +5,7 @@ | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>jdchain-root</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| <packaging>pom</packaging> | |||
| <description>jdchain root project</description> | |||
| @@ -6,7 +6,7 @@ | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>jdchain-samples</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| </parent> | |||
| <artifactId>contract-samples</artifactId> | |||
| @@ -11,11 +11,11 @@ | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>jdchain-samples</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| <packaging>pom</packaging> | |||
| <properties> | |||
| <framework.version>1.2.0.RELEASE</framework.version> | |||
| <framework.version>1.2.1.RELEASE</framework.version> | |||
| </properties> | |||
| <modules> | |||
| @@ -5,7 +5,7 @@ | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>jdchain-samples</artifactId> | |||
| <version>1.2.0.RELEASE</version> | |||
| <version>1.2.1.RELEASE</version> | |||
| </parent> | |||
| <artifactId>sdk-samples</artifactId> | |||
| @@ -1,18 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>base</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-log4j2</artifactId> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,30 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>binary-proto</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-log4j2</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>junit</groupId> | |||
| <artifactId>junit</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,77 +0,0 @@ | |||
| package com.jd.blockchain.binaryproto; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.InputStream; | |||
| import java.io.OutputStream; | |||
| import com.jd.blockchain.binaryproto.impl.DataContractContext; | |||
| import com.jd.blockchain.binaryproto.impl.HeaderEncoder; | |||
| import com.jd.blockchain.utils.io.BytesOutputBuffer; | |||
| import com.jd.blockchain.utils.io.BytesSlice; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| public class BinaryProtocol { | |||
| public static void encode(Object data, Class<?> contractType, OutputStream out) { | |||
| DataContractEncoder encoder = DataContractContext.resolve(contractType); | |||
| if (encoder == null) { | |||
| throw new IllegalArgumentException("Contract Type not exist!--" + contractType.getName()); | |||
| } | |||
| BytesOutputBuffer buffer = new BytesOutputBuffer(); | |||
| encoder.encode(data, buffer); | |||
| buffer.writeTo(out); | |||
| } | |||
| public static byte[] encode(Object data, Class<?> contractType) { | |||
| ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
| encode(data, contractType, out); | |||
| return out.toByteArray(); | |||
| } | |||
| public static <T> T decode(InputStream in) { | |||
| byte[] bytes = BytesUtils.copyToBytes(in); | |||
| return decode(bytes); | |||
| } | |||
| public static <T> T decode(byte[] dataSegment) { | |||
| BytesSlice bytes = new BytesSlice(dataSegment, 0, dataSegment.length); | |||
| int code = HeaderEncoder.resolveCode(bytes); | |||
| long version = HeaderEncoder.resolveVersion(bytes); | |||
| DataContractEncoder encoder = DataContractContext.ENCODER_LOOKUP.lookup(code, version); | |||
| if (encoder == null) { | |||
| throw new DataContractException( | |||
| String.format("No data contract was registered with code[%s] and version[%s]!", code, version)); | |||
| } | |||
| return encoder.decode(bytes.getInputStream()); | |||
| } | |||
| public static <T> T decode(byte[] dataSegment, Class<T> contractType) { | |||
| return decode(dataSegment, contractType, true); | |||
| } | |||
| public static <T> T decode(byte[] dataSegment, Class<T> contractType, boolean autoRegister) { | |||
| DataContractEncoder encoder = DataContractContext.ENCODER_LOOKUP.lookup(contractType); | |||
| if (encoder == null) { | |||
| if (autoRegister) { | |||
| encoder = DataContractContext.resolve(contractType); | |||
| } else { | |||
| throw new DataContractException("Contract type is not registered! --" + contractType.toString()); | |||
| } | |||
| } | |||
| BytesSlice bytes = new BytesSlice(dataSegment, 0, dataSegment.length); | |||
| return encoder.decode(bytes.getInputStream()); | |||
| } | |||
| @Deprecated | |||
| public static <T> T decodeAs(byte[] dataSegment, Class<T> contractType) { | |||
| return decode(dataSegment, contractType, true); | |||
| } | |||
| @Deprecated | |||
| public static <T> T decodeAs(byte[] dataSegment, Class<T> contractType, boolean autoRegister) { | |||
| return decode(dataSegment, contractType, autoRegister); | |||
| } | |||
| } | |||
| @@ -1,66 +0,0 @@ | |||
| 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,74 +0,0 @@ | |||
| <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>consensus</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>consensus-bftsmart</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>bft-smart</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>base</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.apache.commons</groupId> | |||
| <artifactId>commons-pool2</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>tools-keygen</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <!-- <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-core</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> --> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,75 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import bftsmart.tom.AsynchServiceProxy; | |||
| import com.jd.blockchain.consensus.MessageService; | |||
| import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||
| import com.jd.blockchain.utils.concurrent.CompletableAsyncFuture; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| public class BftsmartMessageService implements MessageService { | |||
| private BftsmartPeerProxyPool asyncPeerProxyPool; | |||
| public BftsmartMessageService(BftsmartPeerProxyPool peerProxyPool) { | |||
| this.asyncPeerProxyPool = peerProxyPool; | |||
| } | |||
| @Override | |||
| public AsyncFuture<byte[]> sendOrdered(byte[] message) { | |||
| return sendOrderedMessage(message); | |||
| } | |||
| private AsyncFuture<byte[]> sendOrderedMessage(byte[] message) { | |||
| CompletableAsyncFuture<byte[]> asyncFuture = new CompletableAsyncFuture<>(); | |||
| AsynchServiceProxy asynchServiceProxy = null; | |||
| try { | |||
| asynchServiceProxy = asyncPeerProxyPool.borrowObject(); | |||
| // //0: Transaction msg, 1: Commitblock msg | |||
| // byte[] msgType = BytesUtils.toBytes(0); | |||
| // byte[] wrapMsg = new byte[message.length + 4]; | |||
| // System.arraycopy(message, 0, wrapMsg, 4, message.length); | |||
| // System.arraycopy(msgType, 0, wrapMsg, 0, 4); | |||
| // | |||
| // System.out.printf("BftsmartMessageService invokeOrdered time = %s, id = %s threadId = %s \r\n", | |||
| // System.currentTimeMillis(), asynchServiceProxy.getProcessId(), Thread.currentThread().getId()); | |||
| byte[] result = asynchServiceProxy.invokeOrdered(message); | |||
| asyncFuture.complete(result); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } finally { | |||
| if (asynchServiceProxy != null) { | |||
| asyncPeerProxyPool.returnObject(asynchServiceProxy); | |||
| } | |||
| } | |||
| return asyncFuture; | |||
| } | |||
| @Override | |||
| public AsyncFuture<byte[]> sendUnordered(byte[] message) { | |||
| return sendUnorderedMessage(message); | |||
| } | |||
| private AsyncFuture<byte[]> sendUnorderedMessage(byte[] message) { | |||
| CompletableAsyncFuture<byte[]> asyncFuture = new CompletableAsyncFuture<>(); | |||
| AsynchServiceProxy asynchServiceProxy = null; | |||
| try { | |||
| asynchServiceProxy = asyncPeerProxyPool.borrowObject(); | |||
| byte[] result = asynchServiceProxy.invokeUnordered(message); | |||
| asyncFuture.complete(result); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } finally { | |||
| asyncPeerProxyPool.returnObject(asynchServiceProxy); | |||
| } | |||
| return asyncFuture; | |||
| } | |||
| } | |||
| @@ -1,549 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.service; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.util.*; | |||
| import java.util.concurrent.CopyOnWriteArrayList; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| import bftsmart.consensus.app.BatchAppResultImpl; | |||
| import bftsmart.tom.*; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.consensus.service.*; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.transaction.TxResponseMessage; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import com.jd.blockchain.consensus.ConsensusManageService; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartNodeSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartTopology; | |||
| import com.jd.blockchain.utils.PropertiesUtils; | |||
| import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import bftsmart.reconfiguration.util.HostsConfig; | |||
| import bftsmart.reconfiguration.util.TOMConfiguration; | |||
| import bftsmart.tom.server.defaultservices.DefaultRecoverable; | |||
| public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer { | |||
| private static Logger LOGGER = LoggerFactory.getLogger(BftsmartNodeServer.class); | |||
| // private static final String DEFAULT_BINDING_HOST = "0.0.0.0"; | |||
| private List<StateHandle> stateHandles = new CopyOnWriteArrayList<>(); | |||
| // TODO 暂不处理队列溢出问题 | |||
| private ExecutorService notifyReplyExecutors = Executors.newSingleThreadExecutor(); | |||
| private volatile Status status = Status.STOPPED; | |||
| private final Object mutex = new Object(); | |||
| private volatile ServiceReplica replica; | |||
| private StateMachineReplicate stateMachineReplicate; | |||
| private ServerSettings serverSettings; | |||
| private BftsmartConsensusManageService manageService; | |||
| private volatile BftsmartTopology topology; | |||
| private volatile BftsmartConsensusSettings setting; | |||
| private TOMConfiguration tomConfig; | |||
| // private TOMConfiguration outerTomConfig; | |||
| private HostsConfig hostsConfig; | |||
| private Properties systemConfig; | |||
| private MessageHandle messageHandle; | |||
| private String providerName; | |||
| private String realmName; | |||
| private int serverId; | |||
| public BftsmartNodeServer() { | |||
| } | |||
| public BftsmartNodeServer(ServerSettings serverSettings, MessageHandle messageHandler, StateMachineReplicate stateMachineReplicate) { | |||
| this.serverSettings = serverSettings; | |||
| this.realmName = serverSettings.getRealmName(); | |||
| //used later | |||
| this.stateMachineReplicate = stateMachineReplicate; | |||
| this.messageHandle = messageHandler; | |||
| createConfig(); | |||
| serverId = findServerId(); | |||
| initConfig(serverId, systemConfig, hostsConfig); | |||
| this.manageService = new BftsmartConsensusManageService(this); | |||
| } | |||
| protected int findServerId() { | |||
| int serverId = 0; | |||
| for (int i = 0; i < hostsConfig.getNum(); i++) { | |||
| String host = ((BftsmartNodeSettings)serverSettings.getReplicaSettings()).getNetworkAddress().getHost(); | |||
| int port = ((BftsmartNodeSettings)serverSettings.getReplicaSettings()).getNetworkAddress().getPort(); | |||
| if (hostsConfig.getHost(i).equals(host) && hostsConfig.getPort(i) == port) { | |||
| serverId = i; | |||
| break; | |||
| } | |||
| } | |||
| return serverId; | |||
| } | |||
| public int getServerId() { | |||
| return serverId; | |||
| } | |||
| protected void createConfig() { | |||
| setting = ((BftsmartServerSettings) serverSettings).getConsensusSettings(); | |||
| List<HostsConfig.Config> configList = new ArrayList<>(); | |||
| NodeSettings[] nodeSettingsArray = setting.getNodes(); | |||
| for (NodeSettings nodeSettings : nodeSettingsArray) { | |||
| BftsmartNodeSettings node = (BftsmartNodeSettings)nodeSettings; | |||
| configList.add(new HostsConfig.Config(node.getId(), node.getNetworkAddress().getHost(), node.getNetworkAddress().getPort())); | |||
| } | |||
| //create HostsConfig instance based on consensus realm nodes | |||
| hostsConfig = new HostsConfig(configList.toArray(new HostsConfig.Config[configList.size()])); | |||
| systemConfig = PropertiesUtils.createProperties(setting.getSystemConfigs()); | |||
| return; | |||
| } | |||
| protected void initConfig(int id, Properties systemsConfig, HostsConfig hostConfig) { | |||
| // byte[] serialHostConf = BinarySerializeUtils.serialize(hostConfig); | |||
| // Properties sysConfClone = (Properties)systemsConfig.clone(); | |||
| // int port = hostConfig.getPort(id); | |||
| // hostConfig.add(id, DEFAULT_BINDING_HOST, port); | |||
| this.tomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); | |||
| // this.outerTomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); | |||
| } | |||
| @Override | |||
| public ConsensusManageService getManageService() { | |||
| return manageService; | |||
| } | |||
| @Override | |||
| public ServerSettings getSettings() { | |||
| return serverSettings; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return BftsmartConsensusProvider.NAME; | |||
| } | |||
| public TOMConfiguration getTomConfig() { | |||
| return tomConfig; | |||
| } | |||
| public int getId() { | |||
| return tomConfig.getProcessId(); | |||
| } | |||
| public void setId(int id) { | |||
| if (id < 0) { | |||
| throw new IllegalArgumentException("ReplicaID is negative!"); | |||
| } | |||
| this.tomConfig.setProcessId(id); | |||
| // this.outerTomConfig.setProcessId(id); | |||
| } | |||
| public BftsmartConsensusSettings getConsensusSetting() { | |||
| return setting; | |||
| } | |||
| public BftsmartTopology getTopology() { | |||
| return topology; | |||
| } | |||
| public Status getStatus() { | |||
| return status; | |||
| } | |||
| @Override | |||
| public boolean isRunning() { | |||
| return status == Status.RUNNING; | |||
| } | |||
| public byte[] appExecuteUnordered(byte[] bytes, MessageContext messageContext) { | |||
| return messageHandle.processUnordered(bytes).get(); | |||
| } | |||
| /** | |||
| * | |||
| * Only block, no reply, used by state transfer when peer start | |||
| * | |||
| */ | |||
| private void block(List<byte[]> manageConsensusCmds) { | |||
| String batchId = messageHandle.beginBatch(realmName); | |||
| try { | |||
| int msgId = 0; | |||
| for (byte[] txContent : manageConsensusCmds) { | |||
| AsyncFuture<byte[]> asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); | |||
| } | |||
| messageHandle.completeBatch(realmName, batchId); | |||
| messageHandle.commitBatch(realmName, batchId); | |||
| } catch (Exception e) { | |||
| // todo 需要处理应答码 404 | |||
| LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); | |||
| messageHandle.rollbackBatch(realmName, batchId, TransactionState.CONSENSUS_ERROR.CODE); | |||
| } | |||
| } | |||
| /** | |||
| * | |||
| * Local peer has cid diff with remote peer, used by state transfer when peer start | |||
| * | |||
| */ | |||
| private byte[][] appExecuteDiffBatch(byte[][] commands, MessageContext[] msgCtxs) { | |||
| int manageConsensusId = msgCtxs[0].getConsensusId(); | |||
| List<byte[]> manageConsensusCmds = new ArrayList<>(); | |||
| int index = 0; | |||
| for (MessageContext msgCtx : msgCtxs) { | |||
| if (msgCtx.getConsensusId() == manageConsensusId) { | |||
| manageConsensusCmds.add(commands[index]); | |||
| } else { | |||
| // 达到结块标准,需要进行结块并应答 | |||
| block(manageConsensusCmds); | |||
| // 重置链表和共识ID | |||
| manageConsensusCmds = new ArrayList<>(); | |||
| manageConsensusId = msgCtx.getConsensusId(); | |||
| manageConsensusCmds.add(commands[index]); | |||
| } | |||
| index++; | |||
| } | |||
| // 结束时,肯定有最后一个结块请求未处理 | |||
| if (!manageConsensusCmds.isEmpty()) { | |||
| block(manageConsensusCmds); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * | |||
| * Invoked by state transfer when peer start | |||
| * | |||
| */ | |||
| @Override | |||
| public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus) { | |||
| // Not from consensus outcomes, from state transfer | |||
| if (!fromConsensus) { | |||
| return appExecuteDiffBatch(commands, msgCtxs); | |||
| } | |||
| return null; | |||
| } | |||
| /** | |||
| * | |||
| * From consensus outcomes, do nothing now | |||
| * The operation of executing the batch was moved to the consensus stage 2 and 3, in order to guaranteed ledger consistency | |||
| */ | |||
| @Override | |||
| public byte[][] appExecuteBatch(byte[][] commands, MessageContext[] msgCtxs, boolean fromConsensus, List<ReplyContextMessage> replyList) { | |||
| // if (replyList == null || replyList.size() == 0) { | |||
| // throw new IllegalArgumentException(); | |||
| // } | |||
| // // todo 此部分需要重新改造 | |||
| // /** | |||
| // * 默认BFTSmart接口提供的commands是一个或多个共识结果的顺序集合 | |||
| // * 根据共识的规定,目前的做法是将其根据msgCtxs的内容进行分组,每组都作为一个结块标识来处理 | |||
| // * 从msgCtxs可以获取对应commands的分组情况 | |||
| // */ | |||
| // int manageConsensusId = msgCtxs[0].getConsensusId(); | |||
| // List<byte[]> manageConsensusCmds = new ArrayList<>(); | |||
| // List<ReplyContextMessage> manageReplyMsgs = new ArrayList<>(); | |||
| // | |||
| // int index = 0; | |||
| // for (MessageContext msgCtx : msgCtxs) { | |||
| // if (msgCtx.getConsensusId() == manageConsensusId) { | |||
| // manageConsensusCmds.add(commands[index]); | |||
| // manageReplyMsgs.add(replyList.get(index)); | |||
| // } else { | |||
| // // 达到结块标准,需要进行结块并应答 | |||
| // blockAndReply(manageConsensusCmds, manageReplyMsgs); | |||
| // // 重置链表和共识ID | |||
| // manageConsensusCmds = new ArrayList<>(); | |||
| // manageReplyMsgs = new ArrayList<>(); | |||
| // manageConsensusId = msgCtx.getConsensusId(); | |||
| // manageConsensusCmds.add(commands[index]); | |||
| // manageReplyMsgs.add(replyList.get(index)); | |||
| // } | |||
| // index++; | |||
| // } | |||
| // // 结束时,肯定有最后一个结块请求未处理 | |||
| // if (!manageConsensusCmds.isEmpty()) { | |||
| // blockAndReply(manageConsensusCmds, manageReplyMsgs); | |||
| // } | |||
| return null; | |||
| } | |||
| /** | |||
| * | |||
| * Block and reply are moved to consensus completion stage | |||
| * | |||
| */ | |||
| private void blockAndReply(List<byte[]> manageConsensusCmds, List<ReplyContextMessage> replyList) { | |||
| // consensusBatchId = messageHandle.beginBatch(realmName); | |||
| // List<AsyncFuture<byte[]>> asyncFutureLinkedList = new ArrayList<>(manageConsensusCmds.size()); | |||
| // try { | |||
| // int msgId = 0; | |||
| // for (byte[] txContent : manageConsensusCmds) { | |||
| // AsyncFuture<byte[]> asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, consensusBatchId); | |||
| // asyncFutureLinkedList.add(asyncFuture); | |||
| // } | |||
| // messageHandle.completeBatch(realmName, consensusBatchId); | |||
| // messageHandle.commitBatch(realmName, consensusBatchId); | |||
| // } catch (Exception e) { | |||
| // // todo 需要处理应答码 404 | |||
| // LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); | |||
| // messageHandle.rollbackBatch(realmName, consensusBatchId, TransactionState.CONSENSUS_ERROR.CODE); | |||
| // } | |||
| // | |||
| // // 通知线程单独处理应答 | |||
| // notifyReplyExecutors.execute(() -> { | |||
| // // 应答对应的结果 | |||
| // int replyIndex = 0; | |||
| // for(ReplyContextMessage msg : replyList) { | |||
| // msg.setReply(asyncFutureLinkedList.get(replyIndex).get()); | |||
| // TOMMessage request = msg.getTomMessage(); | |||
| // ReplyContext replyContext = msg.getReplyContext(); | |||
| // request.reply = new TOMMessage(replyContext.getId(), request.getSession(), request.getSequence(), | |||
| // request.getOperationId(), msg.getReply(), replyContext.getCurrentViewId(), | |||
| // request.getReqType()); | |||
| // | |||
| // if (replyContext.getNumRepliers() > 0) { | |||
| // bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " | |||
| // + request.getSender() + " with sequence number " + request.getSequence() | |||
| // + " and operation ID " + request.getOperationId() + " via ReplyManager"); | |||
| // replyContext.getRepMan().send(request); | |||
| // } else { | |||
| // bftsmart.tom.util.Logger.println("(ServiceReplica.receiveMessages) sending reply to " | |||
| // + request.getSender() + " with sequence number " + request.getSequence() | |||
| // + " and operation ID " + request.getOperationId()); | |||
| // replyContext.getReplier().manageReply(request, msg.getMessageContext()); | |||
| // } | |||
| // replyIndex++; | |||
| // } | |||
| // }); | |||
| } | |||
| /** | |||
| * Used by consensus write phase, pre compute new block hash | |||
| */ | |||
| public BatchAppResultImpl preComputeAppHash(byte[][] commands) { | |||
| List<AsyncFuture<byte[]>> asyncFutureLinkedList = new ArrayList<>(commands.length); | |||
| List<byte[]> responseLinkedList = new ArrayList<>(); | |||
| StateSnapshot newStateSnapshot = null; | |||
| StateSnapshot preStateSnapshot = null; | |||
| StateSnapshot genisStateSnapshot = null; | |||
| BatchAppResultImpl result = null; | |||
| String batchId = null; | |||
| int msgId = 0; | |||
| try { | |||
| batchId = messageHandle.beginBatch(realmName); | |||
| genisStateSnapshot = messageHandle.getGenisStateSnapshot(realmName); | |||
| preStateSnapshot = messageHandle.getStateSnapshot(realmName); | |||
| if (preStateSnapshot == null) { | |||
| throw new IllegalStateException("Pre block state snapshot is null!"); | |||
| } | |||
| for (int i = 0; i < commands.length; i++) { | |||
| byte[] txContent = commands[i]; | |||
| AsyncFuture<byte[]> asyncFuture = messageHandle.processOrdered(msgId++, txContent, realmName, batchId); | |||
| asyncFutureLinkedList.add(asyncFuture); | |||
| } | |||
| newStateSnapshot = messageHandle.completeBatch(realmName, batchId); | |||
| for (int i = 0; i < asyncFutureLinkedList.size(); i++) { | |||
| responseLinkedList.add(asyncFutureLinkedList.get(i).get()); | |||
| } | |||
| result = new BatchAppResultImpl(responseLinkedList, newStateSnapshot.getSnapshot(), batchId, genisStateSnapshot.getSnapshot()); | |||
| result.setErrorCode((byte) 0); | |||
| } catch (Exception e) { | |||
| LOGGER.error("Error occurred while pre compute app! --" + e.getMessage(), e); | |||
| for (int i = 0; i < commands.length; i++) { | |||
| responseLinkedList.add(createAppResponse(commands[i],TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK)); | |||
| } | |||
| result = new BatchAppResultImpl(responseLinkedList,preStateSnapshot.getSnapshot(), batchId, genisStateSnapshot.getSnapshot()); | |||
| result.setErrorCode((byte) 1); | |||
| } | |||
| return result; | |||
| } | |||
| // Block full rollback responses, generated in pre compute phase, due to tx exception | |||
| private byte[] createAppResponse(byte[] command, TransactionState transactionState) { | |||
| TransactionRequest txRequest = BinaryProtocol.decode(command); | |||
| TxResponseMessage resp = new TxResponseMessage(txRequest.getTransactionContent().getHash()); | |||
| resp.setExecutionState(transactionState); | |||
| return BinaryProtocol.encode(resp, TransactionResponse.class); | |||
| } | |||
| public List<byte[]> updateAppResponses(List<byte[]> asyncResponseLinkedList, byte[] commonHash, boolean isConsistent) { | |||
| List<byte[]> updatedResponses = new ArrayList<>(); | |||
| TxResponseMessage resp = null; | |||
| for(int i = 0; i < asyncResponseLinkedList.size(); i++) { | |||
| TransactionResponse txResponse = BinaryProtocol.decode(asyncResponseLinkedList.get(i)); | |||
| if (isConsistent) { | |||
| resp = new TxResponseMessage(txResponse.getContentHash()); | |||
| } | |||
| else { | |||
| resp = new TxResponseMessage(new HashDigest(commonHash)); | |||
| } | |||
| resp.setExecutionState(TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); | |||
| updatedResponses.add(BinaryProtocol.encode(resp, TransactionResponse.class)); | |||
| } | |||
| return updatedResponses; | |||
| } | |||
| /** | |||
| * | |||
| * Decision has been made at the consensus stage, commit block | |||
| * | |||
| */ | |||
| public void preComputeAppCommit(String batchId) { | |||
| try { | |||
| messageHandle.commitBatch(realmName, batchId); | |||
| } catch (BlockRollbackException e) { | |||
| LOGGER.error("Error occurred while pre compute commit --" + e.getMessage(), e); | |||
| throw e; | |||
| } | |||
| } | |||
| /** | |||
| * | |||
| * Consensus write phase will terminate, new block hash values are inconsistent, rollback block | |||
| * | |||
| */ | |||
| public void preComputeAppRollback(String batchId) { | |||
| messageHandle.rollbackBatch(realmName, batchId, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK.CODE); | |||
| LOGGER.debug("Rollback of operations that cause inconsistencies in the ledger"); | |||
| } | |||
| //notice | |||
| public byte[] getSnapshot() { | |||
| LOGGER.debug("------- GetSnapshot...[replica.id=" + this.getId() + "]"); | |||
| ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||
| BytesUtils.writeInt(stateHandles.size(), out); | |||
| for (StateHandle stateHandle : stateHandles) { | |||
| // TODO: 测试代码; | |||
| return stateHandle.takeSnapshot(); | |||
| } | |||
| return out.toByteArray(); | |||
| } | |||
| public void installSnapshot(byte[] snapshot) { | |||
| // System.out.println("Not implement!"); | |||
| } | |||
| @Override | |||
| public void start() { | |||
| if (this.getId() < 0) { | |||
| throw new IllegalStateException("Unset server node ID!"); | |||
| } | |||
| LOGGER.debug("=============================== Start replica ==================================="); | |||
| if (status != Status.STOPPED) { | |||
| return; | |||
| } | |||
| synchronized (mutex) { | |||
| if (status != Status.STOPPED) { | |||
| return; | |||
| } | |||
| status = Status.STARTING; | |||
| try { | |||
| LOGGER.debug("Start replica...[ID=" + getId() + "]"); | |||
| this.replica = new ServiceReplica(tomConfig, this, this); | |||
| this.topology = new BftsmartTopology(replica.getReplicaContext().getCurrentView()); | |||
| status = Status.RUNNING; | |||
| // createProxyClient(); | |||
| LOGGER.debug( | |||
| "=============================== Replica started success! ==================================="); | |||
| } catch (RuntimeException e) { | |||
| status = Status.STOPPED; | |||
| throw e; | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public void stop() { | |||
| if (status != Status.RUNNING) { | |||
| return; | |||
| } | |||
| synchronized (mutex) { | |||
| if (status != Status.RUNNING) { | |||
| return; | |||
| } | |||
| status = Status.STOPPING; | |||
| try { | |||
| ServiceReplica rep = this.replica; | |||
| if (rep != null) { | |||
| LOGGER.debug("Stop replica...[ID=" + rep.getId() + "]"); | |||
| this.replica = null; | |||
| this.topology = null; | |||
| rep.kill(); | |||
| LOGGER.debug("Replica had stopped! --[ID=" + rep.getId() + "]"); | |||
| } | |||
| } finally { | |||
| status = Status.STOPPED; | |||
| } | |||
| } | |||
| } | |||
| enum Status { | |||
| STARTING, | |||
| RUNNING, | |||
| STOPPING, | |||
| STOPPED | |||
| } | |||
| } | |||
| @@ -1,34 +0,0 @@ | |||
| <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>consensus</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>consensus-framework</artifactId> | |||
| <dependencies> | |||
| <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>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,25 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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,79 +0,0 @@ | |||
| <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>consensus</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>consensus-mq</artifactId> | |||
| <name>consensus-mq</name> | |||
| <properties> | |||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | |||
| <maven.compiler.source>1.8</maven.compiler.source> | |||
| <maven.compiler.target>1.8</maven.compiler.target> | |||
| </properties> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>tools-keygen</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.lmax</groupId> | |||
| <artifactId>disruptor</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>io.nats</groupId> | |||
| <artifactId>jnats</artifactId> | |||
| </dependency> | |||
| <!-- rabbitmq --> | |||
| <dependency> | |||
| <groupId>com.rabbitmq</groupId> | |||
| <artifactId>amqp-client</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>junit</groupId> | |||
| <artifactId>junit</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,18 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>consensus</artifactId> | |||
| <packaging>pom</packaging> | |||
| <modules> | |||
| <module>consensus-framework</module> | |||
| <module>consensus-bftsmart</module> | |||
| <module>consensus-mq</module> | |||
| </modules> | |||
| </project> | |||
| @@ -1,44 +0,0 @@ | |||
| <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>contract</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>contract-framework</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,51 +0,0 @@ | |||
| <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>contract</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>contract-jvm</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>runtime-context</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>runtime-modular</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,74 +0,0 @@ | |||
| <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/maven-v4_0_0.xsd"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>contract-maven-plugin</artifactId> | |||
| <packaging>maven-plugin</packaging> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>sdk-client</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>tools-keygen</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.apache.maven</groupId> | |||
| <artifactId>maven-plugin-api</artifactId> | |||
| <version>3.3.9</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.apache.maven.plugin-tools</groupId> | |||
| <artifactId>maven-plugin-annotations</artifactId> | |||
| <version>3.6.0</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-assembly-plugin</artifactId> | |||
| <version>2.6</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.ow2.asm</groupId> | |||
| <artifactId>asm</artifactId> | |||
| <version>5.0.4</version> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-plugin-plugin</artifactId> | |||
| <version>3.5</version> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,19 +0,0 @@ | |||
| <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.4.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,56 +0,0 @@ | |||
| <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>crypto</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>crypto-adv</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-sm</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcprov-jdk15on</artifactId> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>binary-proto</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>net.i2p.crypto</groupId> | |||
| <artifactId>eddsa</artifactId> | |||
| <version>0.1.0</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>net.java.dev.jna</groupId> | |||
| <artifactId>jna</artifactId> | |||
| <version>5.1.0</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| <scope>compile</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,26 +0,0 @@ | |||
| <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>crypto</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>crypto-classic</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,34 +0,0 @@ | |||
| <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>crypto</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>base</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-serialize</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>binary-proto</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,65 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| package com.jd.blockchain.crypto; | |||
| /** | |||
| * 密钥; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public interface CryptoKey extends CryptoBytes { | |||
| /** | |||
| * 密钥的类型; | |||
| * @return | |||
| */ | |||
| CryptoKeyType getKeyType(); | |||
| /** | |||
| * 原始的密钥数据; | |||
| * | |||
| * @return | |||
| */ | |||
| byte[] getRawKeyBytes(); | |||
| } | |||
| @@ -1,29 +0,0 @@ | |||
| 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,34 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <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"> | |||
| <parent> | |||
| <artifactId>crypto</artifactId> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <artifactId>crypto-pki</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcprov-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> | |||
| <dependency> | |||
| <groupId>org.bouncycastle</groupId> | |||
| <artifactId>bcpkix-jdk15on</artifactId> | |||
| <version>1.61</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,20 +0,0 @@ | |||
| <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>crypto</artifactId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>crypto-sm</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| </dependencies> | |||
| </project> | |||
| @@ -1,22 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>crypto</artifactId> | |||
| <packaging>pom</packaging> | |||
| <modules> | |||
| <module>crypto-framework</module> | |||
| <module>crypto-classic</module> | |||
| <module>crypto-sm</module> | |||
| <!-- <module>crypto-jni-clib</module> --> | |||
| <module>crypto-adv</module> | |||
| <module>crypto-pki</module> | |||
| </modules> | |||
| </project> | |||
| @@ -1,14 +0,0 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <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"> | |||
| <parent> | |||
| <artifactId>jdchain-root</artifactId> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <version>1.1.4.RELEASE</version> | |||
| </parent> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <artifactId>deployAsEnd</artifactId> | |||
| </project> | |||
| @@ -1,38 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>deployment</artifactId> | |||
| <packaging>pom</packaging> | |||
| <modules> | |||
| <module>deployment-gateway</module> | |||
| <module>deployment-peer</module> | |||
| </modules> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,150 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>gateway</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-bftsmart</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-mq</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-rpc</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>sdk-base</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>tools-keygen</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>data-explorer</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-web</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> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-sm</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>commons-io</groupId> | |||
| <artifactId>commons-io</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-web</artifactId> | |||
| <exclusions> | |||
| <exclusion> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-logging</artifactId> | |||
| </exclusion> | |||
| </exclusions> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-log4j2</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-security</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-configuration-processor</artifactId> | |||
| <optional>true</optional> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-devtools</artifactId> | |||
| <optional>true</optional> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-jar-plugin</artifactId> | |||
| <configuration> | |||
| <archive> | |||
| <manifest> | |||
| <mainClass>com.jd.blockchain.gateway.GatewayServerBooter</mainClass> | |||
| <addClasspath>true</addClasspath> | |||
| <classpathPrefix>.</classpathPrefix> | |||
| <useUniqueVersions>false</useUniqueVersions> | |||
| </manifest> | |||
| </archive> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,14 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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,79 +0,0 @@ | |||
| package com.jd.blockchain.gateway.web; | |||
| import com.jd.blockchain.crypto.*; | |||
| import com.jd.blockchain.gateway.service.GatewayInterceptService; | |||
| import com.jd.blockchain.transaction.SignatureUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RequestMethod; | |||
| import org.springframework.web.bind.annotation.ResponseBody; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.gateway.PeerService; | |||
| import com.jd.blockchain.ledger.DigitalSignature; | |||
| import com.jd.blockchain.ledger.TransactionContent; | |||
| import com.jd.blockchain.ledger.TransactionRequest; | |||
| import com.jd.blockchain.ledger.TransactionResponse; | |||
| import com.jd.blockchain.transaction.TransactionService; | |||
| import com.jd.blockchain.utils.BusinessException; | |||
| import com.jd.blockchain.web.converters.BinaryMessageConverter; | |||
| /** | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| @RestController | |||
| public class TxProcessingController implements TransactionService { | |||
| private static Logger LOGGER = LoggerFactory.getLogger(TxProcessingController.class); | |||
| @Autowired | |||
| private PeerService peerService; | |||
| @Autowired | |||
| private GatewayInterceptService interceptService; | |||
| @RequestMapping(path = "rpc/tx", method = RequestMethod.POST, consumes = BinaryMessageConverter.CONTENT_TYPE_VALUE, produces = BinaryMessageConverter.CONTENT_TYPE_VALUE) | |||
| @Override | |||
| public @ResponseBody TransactionResponse process(@RequestBody TransactionRequest txRequest) { | |||
| // 拦截请求进行校验 | |||
| interceptService.intercept(txRequest); | |||
| // 检查交易请求的信息是否完整; | |||
| HashDigest ledgerHash = txRequest.getTransactionContent().getLedgerHash(); | |||
| if (ledgerHash == null) { | |||
| // 未指定交易的账本; | |||
| throw new IllegalArgumentException("The TransactionRequest miss ledger hash!"); | |||
| } | |||
| // 预期的请求中不应该包含节点签名,首个节点签名应该由当前网关提供; | |||
| if (txRequest.getNodeSignatures() != null && txRequest.getNodeSignatures().length > 0) { | |||
| throw new IllegalArgumentException("Gateway cann't accept TransactionRequest with any NodeSignature!"); | |||
| } | |||
| // TODO:检查参与者的签名; | |||
| DigitalSignature[] partiSigns = txRequest.getEndpointSignatures(); | |||
| if (partiSigns == null || partiSigns.length == 0) { | |||
| // 缺少参与者签名,则采用检查托管账户并进行托管签名;如果请求未包含托管账户,或者托管账户认证失败,则返回401错误; | |||
| // TODO: 未实现! | |||
| throw new IllegalStateException("Not implemented!"); | |||
| } else { | |||
| // 验证签名; | |||
| StringBuilder signer = new StringBuilder(txRequest.getHash().toString()).append("->"); | |||
| for (DigitalSignature sign : partiSigns) { | |||
| signer.append(AddressEncoding.generateAddress(sign.getPubKey()).toBase58()).append(","); | |||
| if (!SignatureUtils.verifySignature(txRequest.getTransactionContent(), sign.getDigest(), sign.getPubKey())) { | |||
| throw new BusinessException("The validation of participant signatures fail!"); | |||
| } | |||
| } | |||
| LOGGER.debug(signer.toString()); | |||
| } | |||
| // 注:转发前自动附加网关的签名并转发请求至共识节点;异步的处理方式 | |||
| return peerService.getTransactionService().process(txRequest); | |||
| } | |||
| } | |||
| @@ -1,31 +0,0 @@ | |||
| #网关的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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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,128 +0,0 @@ | |||
| <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.4.RELEASE</version> | |||
| </parent> | |||
| <artifactId>ledger-core</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>ledger-model</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>storage-service</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>storage-service</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>consensus-framework</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-jvm</artifactId> | |||
| <version>${project.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework</groupId> | |||
| <artifactId>spring-context</artifactId> | |||
| </dependency> | |||
| <!-- dependencies for test --> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-classic</artifactId> | |||
| <version>${project.version}</version> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>crypto-sm</artifactId> | |||
| <version>${project.version}</version> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.mockito</groupId> | |||
| <artifactId>mockito-core</artifactId> | |||
| <scope>test</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-deploy-plugin</artifactId> | |||
| <version>2.8.2</version> | |||
| <configuration> | |||
| <skip>true</skip> | |||
| </configuration> | |||
| </plugin> | |||
| <plugin> | |||
| <groupId>org.sonatype.plugins</groupId> | |||
| <artifactId>nexus-staging-maven-plugin</artifactId> | |||
| <configuration> | |||
| <skipNexusStagingDeployMojo>true</skipNexusStagingDeployMojo> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| <!--<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> | |||
| <artifactId>maven-surefire-plugin</artifactId> <version>2.5</version> <configuration> | |||
| <excludes> <exclude>**/TransactionBatchProcessorTest.java</exclude> </excludes> | |||
| </configuration> </plugin> </plugins> </build> --> | |||
| <!--<build> --> | |||
| <!--<plugins> --> | |||
| <!--<plugin> --> | |||
| <!--<groupId>org.apache.maven.plugins</groupId> --> | |||
| <!--<artifactId>maven-compiler-plugin</artifactId> --> | |||
| <!--<version>3.1</version> --> | |||
| <!--<configuration> --> | |||
| <!--<source>1.8</source> --> | |||
| <!--<target>1.8</target> --> | |||
| <!--<encoding>UTF-8</encoding> --> | |||
| <!--<compilerArgs> --> | |||
| <!--<!–<arg>-verbose</arg>–> --> | |||
| <!--<!–<arg>-Xlint:unchecked</arg>–> --> | |||
| <!--<!–<arg>-Xlint:deprecation</arg>–> --> | |||
| <!--<!–<arg>-bootclasspath</arg>–> --> | |||
| <!--<!–<arg>${env.JAVA_HOME}/jre/lib/rt.jar</arg>–> --> | |||
| <!--<arg>-extdirs</arg> --> | |||
| <!--<arg>${project.basedir}/../contract/contract-libs;$JAVA_HOME/jre/lib/ext</arg> --> | |||
| <!--</compilerArgs> --> | |||
| <!--</configuration> --> | |||
| <!--</plugin> --> | |||
| <!--</plugins> --> | |||
| <!--</build> --> | |||
| </project> | |||
| @@ -1,73 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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,432 +0,0 @@ | |||
| package com.jd.blockchain.ledger.core; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.BlockchainIdentity; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.ContractInfo; | |||
| import com.jd.blockchain.ledger.TypedKVEntry; | |||
| import com.jd.blockchain.ledger.TypedValue; | |||
| import com.jd.blockchain.ledger.TypedKVData; | |||
| import com.jd.blockchain.ledger.KVDataVO; | |||
| import com.jd.blockchain.ledger.KVInfoVO; | |||
| import com.jd.blockchain.ledger.LedgerAdminInfo; | |||
| import com.jd.blockchain.ledger.LedgerBlock; | |||
| import com.jd.blockchain.ledger.LedgerException; | |||
| 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.TransactionState; | |||
| import com.jd.blockchain.ledger.UserInfo; | |||
| import com.jd.blockchain.transaction.BlockchainQueryService; | |||
| import com.jd.blockchain.utils.ArrayUtils; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.DataEntry; | |||
| import com.jd.blockchain.utils.DataIterator; | |||
| import com.jd.blockchain.utils.QueryUtil; | |||
| public class LedgerQueryService implements BlockchainQueryService { | |||
| private static final TypedKVEntry[] EMPTY_ENTRIES = new TypedKVEntry[0]; | |||
| private HashDigest[] ledgerHashs; | |||
| private LedgerQuery ledger; | |||
| public LedgerQueryService(LedgerQuery ledger) { | |||
| this.ledger = ledger; | |||
| this.ledgerHashs = new HashDigest[] { ledger.getHash() }; | |||
| } | |||
| private void checkLedgerHash(HashDigest ledgerHash) { | |||
| if (!ledgerHashs[0].equals(ledgerHash)) { | |||
| throw new LedgerException("Unsupport cross chain query!"); | |||
| } | |||
| } | |||
| @Override | |||
| public HashDigest[] getLedgerHashs() { | |||
| return ledgerHashs; | |||
| } | |||
| @Override | |||
| public LedgerInfo getLedger(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerInfo ledgerInfo = new LedgerInfo(); | |||
| ledgerInfo.setHash(ledger.getHash()); | |||
| ledgerInfo.setLatestBlockHash(ledger.getLatestBlockHash()); | |||
| ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); | |||
| return ledgerInfo; | |||
| } | |||
| @Override | |||
| public LedgerAdminInfo getLedgerAdminInfo(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| LedgerAdminInfo administration = ledger.getAdminInfo(block); | |||
| return administration; | |||
| } | |||
| @Override | |||
| public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { | |||
| return getLedgerAdminInfo(ledgerHash).getParticipants(); | |||
| } | |||
| @Override | |||
| public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { | |||
| return getLedgerAdminInfo(ledgerHash).getMetadata(); | |||
| } | |||
| @Override | |||
| public LedgerBlock getBlock(HashDigest ledgerHash, long height) { | |||
| checkLedgerHash(ledgerHash); | |||
| return ledger.getBlock(height); | |||
| } | |||
| @Override | |||
| public LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| return ledger.getBlock(blockHash); | |||
| } | |||
| @Override | |||
| public long getTransactionCount(HashDigest ledgerHash, long height) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(height); | |||
| TransactionQuery txset = ledger.getTransactionSet(block); | |||
| return txset.getTotalCount(); | |||
| } | |||
| @Override | |||
| public long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(blockHash); | |||
| TransactionQuery txset = ledger.getTransactionSet(block); | |||
| return txset.getTotalCount(); | |||
| } | |||
| @Override | |||
| public long getTransactionTotalCount(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| TransactionQuery txset = ledger.getTransactionSet(block); | |||
| return txset.getTotalCount(); | |||
| } | |||
| @Override | |||
| public long getDataAccountCount(HashDigest ledgerHash, long height) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(height); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| return dataAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(blockHash); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| return dataAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getDataAccountTotalCount(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| return dataAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getUserCount(HashDigest ledgerHash, long height) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(height); | |||
| UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
| return userAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(blockHash); | |||
| UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
| return userAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getUserTotalCount(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
| return userAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getContractCount(HashDigest ledgerHash, long height) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(height); | |||
| ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
| return contractAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getBlock(blockHash); | |||
| ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
| return contractAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public long getContractTotalCount(HashDigest ledgerHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
| return contractAccountSet.getTotal(); | |||
| } | |||
| @Override | |||
| public LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock ledgerBlock = ledger.getBlock(height); | |||
| TransactionQuery transactionSet = ledger.getTransactionSet(ledgerBlock); | |||
| int lastHeightTxTotalNums = 0; | |||
| if (height > 0) { | |||
| lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); | |||
| } | |||
| int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); | |||
| // 取当前高度的增量交易数,在增量交易里进行查找 | |||
| int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; | |||
| // | |||
| // if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { | |||
| // fromIndex = 0; | |||
| // } | |||
| // if (count == -1) { | |||
| // fromIndex = 0; | |||
| // count = currentHeightTxNums; | |||
| // } | |||
| // if (count > currentHeightTxNums) { | |||
| // count = currentHeightTxNums - fromIndex; | |||
| // } | |||
| int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); | |||
| return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); | |||
| } | |||
| @Override | |||
| public LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock ledgerBlock = ledger.getBlock(blockHash); | |||
| long height = ledgerBlock.getHeight(); | |||
| TransactionQuery transactionSet = ledger.getTransactionSet(ledgerBlock); | |||
| int lastHeightTxTotalNums = 0; | |||
| if (height > 0) { | |||
| lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); | |||
| } | |||
| int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); | |||
| // 取当前块hash的增量交易数,在增量交易里进行查找 | |||
| int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; | |||
| // if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { | |||
| // fromIndex = 0; | |||
| // } | |||
| // if (count == -1) { | |||
| // fromIndex = 0; | |||
| // count = currentHeightTxNums; | |||
| // } | |||
| // if (count > currentHeightTxNums) { | |||
| // count = currentHeightTxNums - fromIndex; | |||
| // } | |||
| int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); | |||
| return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); | |||
| } | |||
| @Override | |||
| public LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| TransactionQuery txset = ledger.getTransactionSet(block); | |||
| return txset.get(contentHash); | |||
| } | |||
| @Override | |||
| public TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| TransactionQuery txset = ledger.getTransactionSet(block); | |||
| return txset.getState(contentHash); | |||
| } | |||
| @Override | |||
| public UserInfo getUser(HashDigest ledgerHash, String address) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
| return userAccountSet.getAccount(address); | |||
| } | |||
| @Override | |||
| public BlockchainIdentity getDataAccount(HashDigest ledgerHash, String address) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| return dataAccountSet.getAccount(Bytes.fromBase58(address)).getID(); | |||
| } | |||
| @Override | |||
| public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { | |||
| if (keys == null || keys.length == 0) { | |||
| return EMPTY_ENTRIES; | |||
| } | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
| TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
| long ver; | |||
| for (int i = 0; i < entries.length; i++) { | |||
| final String currKey = keys[i]; | |||
| ver = dataAccount == null ? -1 : dataAccount.getDataset().getVersion(currKey); | |||
| if (ver < 0) { | |||
| entries[i] = new TypedKVData(currKey, -1, null); | |||
| } else { | |||
| BytesValue value = dataAccount.getDataset().getValue(currKey, ver); | |||
| entries[i] = new TypedKVData(currKey, ver, value); | |||
| } | |||
| } | |||
| return entries; | |||
| } | |||
| public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) { | |||
| // parse kvInfoVO; | |||
| List<String> keyList = new ArrayList<>(); | |||
| List<Long> versionList = new ArrayList<>(); | |||
| if (kvInfoVO != null) { | |||
| for (KVDataVO kvDataVO : kvInfoVO.getData()) { | |||
| for (Long version : kvDataVO.getVersion()) { | |||
| keyList.add(kvDataVO.getKey()); | |||
| versionList.add(version); | |||
| } | |||
| } | |||
| } | |||
| String[] keys = keyList.toArray(new String[keyList.size()]); | |||
| Long[] versions = versionList.toArray(new Long[versionList.size()]); | |||
| if (keys == null || keys.length == 0) { | |||
| return null; | |||
| } | |||
| if (versions == null || versions.length == 0) { | |||
| return null; | |||
| } | |||
| if (keys.length != versions.length) { | |||
| throw new ContractException("keys.length!=versions.length!"); | |||
| } | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
| TypedKVEntry[] entries = new TypedKVEntry[keys.length]; | |||
| long ver = -1; | |||
| for (int i = 0; i < entries.length; i++) { | |||
| // ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); | |||
| // dataAccount.getBytes(Bytes.fromString(keys[i]),1); | |||
| ver = versions[i]; | |||
| if (ver < 0) { | |||
| entries[i] = new TypedKVData(keys[i], -1, null); | |||
| } else { | |||
| if (dataAccount.getDataset().getDataCount() == 0 | |||
| || dataAccount.getDataset().getValue(keys[i], ver) == null) { | |||
| // is the address is not exist; the result is null; | |||
| entries[i] = new TypedKVData(keys[i], -1, null); | |||
| } else { | |||
| BytesValue value = dataAccount.getDataset().getValue(keys[i], ver); | |||
| entries[i] = new TypedKVData(keys[i], ver, value); | |||
| } | |||
| } | |||
| } | |||
| return entries; | |||
| } | |||
| @Override | |||
| public TypedKVEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
| int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataset().getDataCount()); | |||
| // return dataAccount.getDataset().getDataEntry(key, version).getDataEntries(pages[0], pages[1]); | |||
| fromIndex = pages[0]; | |||
| count = pages[1]; | |||
| DataIterator<String, TypedValue> iterator = dataAccount.getDataset().iterator(); | |||
| iterator.skip(fromIndex); | |||
| DataEntry<String, TypedValue>[] dataEntries = iterator.next(count); | |||
| TypedKVEntry[] typedKVEntries = ArrayUtils.castTo(dataEntries, TypedKVEntry.class, | |||
| e -> e == null ? null : new TypedKVData(e.getKey(), e.getVersion(), e.getValue())); | |||
| return typedKVEntries; | |||
| } | |||
| @Override | |||
| public long getDataEntriesTotalCount(HashDigest ledgerHash, String address) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| DataAccount dataAccount = dataAccountSet.getAccount(Bytes.fromBase58(address)); | |||
| return dataAccount.getDataset().getDataCount(); | |||
| } | |||
| @Override | |||
| public ContractInfo getContract(HashDigest ledgerHash, String address) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
| return contractAccountSet.getAccount(Bytes.fromBase58(address)); | |||
| } | |||
| @Override | |||
| public BlockchainIdentity[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| UserAccountQuery userAccountSet = ledger.getUserAccountSet(block); | |||
| int pages[] = QueryUtil.calFromIndexAndCountDescend(fromIndex, count, (int) userAccountSet.getTotal()); | |||
| return userAccountSet.getHeaders(pages[0], pages[1]); | |||
| } | |||
| @Override | |||
| public BlockchainIdentity[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| DataAccountQuery dataAccountSet = ledger.getDataAccountSet(block); | |||
| int pages[] = QueryUtil.calFromIndexAndCountDescend(fromIndex, count, (int) dataAccountSet.getTotal()); | |||
| return dataAccountSet.getHeaders(pages[0], pages[1]); | |||
| } | |||
| @Override | |||
| public BlockchainIdentity[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { | |||
| checkLedgerHash(ledgerHash); | |||
| LedgerBlock block = ledger.getLatestBlock(); | |||
| ContractAccountQuery contractAccountSet = ledger.getContractAccountSet(block); | |||
| int pages[] = QueryUtil.calFromIndexAndCountDescend(fromIndex, count, (int) contractAccountSet.getTotal()); | |||
| return contractAccountSet.getHeaders(pages[0], pages[1]); | |||
| } | |||
| } | |||
| @@ -1,411 +0,0 @@ | |||
| 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,740 +0,0 @@ | |||
| package com.jd.blockchain.ledger.core; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.CryptoSetting; | |||
| import com.jd.blockchain.ledger.LedgerException; | |||
| import com.jd.blockchain.ledger.MerkleDataNode; | |||
| import com.jd.blockchain.ledger.MerkleProof; | |||
| 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.storage.service.utils.BufferedKVStorage; | |||
| import com.jd.blockchain.storage.service.utils.VersioningKVData; | |||
| import com.jd.blockchain.utils.ArrayUtils; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.DataEntry; | |||
| import com.jd.blockchain.utils.DataIterator; | |||
| import com.jd.blockchain.utils.Dataset; | |||
| import com.jd.blockchain.utils.Transactional; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| /** | |||
| * 对新的数据项按顺序递增进行编号的 Merkle 数据集; <br> | |||
| * | |||
| * 注:此实现不是线程安全的; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public class MerkleDataSet implements Transactional, MerkleProvable, Dataset<Bytes, byte[]> { | |||
| /** | |||
| * 4 MB MaxSize of value; | |||
| */ | |||
| public static final int MAX_SIZE_OF_VALUE = 4 * 1024 * 1024; | |||
| public static final Bytes SN_PREFIX = Bytes.fromString("SN" + LedgerConsts.KEY_SEPERATOR); | |||
| public static final Bytes DATA_PREFIX = Bytes.fromString("KV" + LedgerConsts.KEY_SEPERATOR); | |||
| public static final Bytes MERKLE_TREE_PREFIX = Bytes.fromString("MKL" + LedgerConsts.KEY_SEPERATOR); | |||
| private final Bytes snKeyPrefix; | |||
| private final Bytes dataKeyPrefix; | |||
| private final Bytes merkleKeyPrefix; | |||
| @SuppressWarnings("unchecked") | |||
| private static final DataEntry<Bytes, byte[]>[] EMPTY_ENTRIES = new DataEntry[0]; | |||
| private BufferedKVStorage bufferedStorage; | |||
| private VersioningKVStorage valueStorage; | |||
| private ExPolicyKVStorage snStorage; | |||
| private MerkleTree merkleTree; | |||
| private SNGenerator snGenerator; | |||
| private boolean readonly; | |||
| /* | |||
| * (non-Javadoc) | |||
| * | |||
| * @see com.jd.blockchain.ledger.core.MerkleProvable#getRootHash() | |||
| */ | |||
| @Override | |||
| public HashDigest getRootHash() { | |||
| return merkleTree.getRootHash(); | |||
| } | |||
| /** | |||
| * 创建一个新的 MerkleDataSet; | |||
| * | |||
| * @param setting 密码设置; | |||
| * @param exPolicyStorage 默克尔树的存储; | |||
| * @param versioningStorage 数据的存储; | |||
| */ | |||
| public MerkleDataSet(CryptoSetting setting, String keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
| VersioningKVStorage versioningStorage) { | |||
| this(setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage); | |||
| } | |||
| /** | |||
| * 创建一个新的 MerkleDataSet; | |||
| * | |||
| * @param setting 密码设置; | |||
| * @param exPolicyStorage 默克尔树的存储; | |||
| * @param versioningStorage 数据的存储; | |||
| */ | |||
| public MerkleDataSet(CryptoSetting setting, Bytes keyPrefix, ExPolicyKVStorage exPolicyStorage, | |||
| VersioningKVStorage versioningStorage) { | |||
| // 缓冲对KV的写入; | |||
| this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | |||
| // 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击; | |||
| // this.valueStorage = PrefixAppender.prefix(DATA_PREFIX, (VersioningKVStorage) | |||
| // bufferedStorage); | |||
| // this.snStorage = PrefixAppender.prefix(SN_PREFIX, (ExPolicyKVStorage) | |||
| // bufferedStorage); | |||
| snKeyPrefix = keyPrefix.concat(SN_PREFIX); | |||
| dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); | |||
| this.valueStorage = bufferedStorage; | |||
| this.snStorage = bufferedStorage; | |||
| // MerkleTree 本身是可缓冲的; | |||
| // ExPolicyKVStorage merkleTreeStorage = | |||
| // PrefixAppender.prefix(MERKLE_TREE_PREFIX, exPolicyStorage); | |||
| merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); | |||
| ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | |||
| this.merkleTree = new MerkleTree(setting, merkleKeyPrefix, merkleTreeStorage); | |||
| this.snGenerator = new MerkleSequenceSNGenerator(merkleTree); | |||
| } | |||
| /** | |||
| * 从指定的 Merkle 根构建的 MerkleDataSet; | |||
| * | |||
| * @param dataStorage | |||
| * @param defaultMerkleHashAlgorithm | |||
| * @param verifyMerkleHashOnLoad | |||
| * @param merkleTreeStorage | |||
| * @param snGenerator | |||
| */ | |||
| public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, String keyPrefix, | |||
| ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
| this(merkleRootHash, setting, Bytes.fromString(keyPrefix), exPolicyStorage, versioningStorage, readonly); | |||
| } | |||
| /** | |||
| * 从指定的 Merkle 根构建的 MerkleDataSet; | |||
| * | |||
| * @param dataStorage | |||
| * @param defaultMerkleHashAlgorithm | |||
| * @param verifyMerkleHashOnLoad | |||
| * @param merkleTreeStorage | |||
| * @param snGenerator | |||
| */ | |||
| public MerkleDataSet(HashDigest merkleRootHash, CryptoSetting setting, Bytes keyPrefix, | |||
| ExPolicyKVStorage exPolicyStorage, VersioningKVStorage versioningStorage, boolean readonly) { | |||
| // 缓冲对KV的写入; | |||
| this.bufferedStorage = new BufferedKVStorage(exPolicyStorage, versioningStorage, false); | |||
| // 把存储数据值、SN、Merkle节点的 key 分别加入独立的前缀,避免针对 key 的注入攻击; | |||
| // snKeyPrefix = Bytes.fromString(keyPrefix + SN_PREFIX); | |||
| // dataKeyPrefix = Bytes.fromString(keyPrefix + DATA_PREFIX); | |||
| snKeyPrefix = keyPrefix.concat(SN_PREFIX); | |||
| dataKeyPrefix = keyPrefix.concat(DATA_PREFIX); | |||
| this.valueStorage = bufferedStorage; | |||
| this.snStorage = bufferedStorage; | |||
| // MerkleTree 本身是可缓冲的; | |||
| merkleKeyPrefix = keyPrefix.concat(MERKLE_TREE_PREFIX); | |||
| ExPolicyKVStorage merkleTreeStorage = exPolicyStorage; | |||
| this.merkleTree = new MerkleTree(merkleRootHash, setting, merkleKeyPrefix, merkleTreeStorage, readonly); | |||
| this.snGenerator = new MerkleSequenceSNGenerator(merkleTree); | |||
| this.readonly = readonly; | |||
| } | |||
| public boolean isReadonly() { | |||
| return readonly; | |||
| } | |||
| void setReadonly() { | |||
| this.readonly = true; | |||
| } | |||
| @Override | |||
| public long getDataCount() { | |||
| return merkleTree.getDataCount(); | |||
| } | |||
| /** | |||
| * 返回理论上允许的最大数据索引; | |||
| * | |||
| * @return | |||
| */ | |||
| public long getMaxIndex() { | |||
| return merkleTree.getMaxSn(); | |||
| } | |||
| public byte[][] getLatestValues(long fromIndex, int count) { | |||
| if (count > LedgerConsts.MAX_LIST_COUNT) { | |||
| throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
| } | |||
| if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | |||
| throw new IllegalArgumentException("Index out of bound!"); | |||
| } | |||
| byte[][] values = new byte[count][]; | |||
| for (int i = 0; i < count; i++) { | |||
| MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | |||
| Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
| values[i] = valueStorage.get(dataKey, dataNode.getVersion()); | |||
| } | |||
| return values; | |||
| } | |||
| public DataEntry<Bytes, byte[]>[] getLatestDataEntries(long fromIndex, int count) { | |||
| if (count > LedgerConsts.MAX_LIST_COUNT) { | |||
| throw new IllegalArgumentException("Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
| } | |||
| if (fromIndex < 0 || (fromIndex + count) > merkleTree.getDataCount()) { | |||
| throw new IllegalArgumentException("Index out of bound!"); | |||
| } | |||
| if (count == 0) { | |||
| return EMPTY_ENTRIES; | |||
| } | |||
| @SuppressWarnings("unchecked") | |||
| DataEntry<Bytes, byte[]>[] values = new DataEntry[count]; | |||
| byte[] bytesValue; | |||
| for (int i = 0; i < count; i++) { | |||
| MerkleDataNode dataNode = merkleTree.getData(fromIndex + i); | |||
| Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
| bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); | |||
| values[i] = new VersioningKVData<Bytes, byte[]>(dataNode.getKey(), dataNode.getVersion(), bytesValue); | |||
| } | |||
| return values; | |||
| } | |||
| public DataEntry<Bytes, byte[]> getLatestDataEntry(long index) { | |||
| if (index < 0 || index + 1 > merkleTree.getDataCount()) { | |||
| throw new IllegalArgumentException("Index out of bound!"); | |||
| } | |||
| byte[] bytesValue; | |||
| MerkleDataNode dataNode = merkleTree.getData(index); | |||
| Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
| bytesValue = valueStorage.get(dataKey, dataNode.getVersion()); | |||
| DataEntry<Bytes, byte[]> entry = new VersioningKVData<Bytes, byte[]>(dataNode.getKey(), dataNode.getVersion(), | |||
| bytesValue); | |||
| return entry; | |||
| } | |||
| /** | |||
| * get the data at the specific index; | |||
| * | |||
| * @param fromIndex | |||
| * @return | |||
| */ | |||
| public byte[] getValuesAtIndex(int fromIndex) { | |||
| MerkleDataNode dataNode = merkleTree.getData(fromIndex); | |||
| Bytes dataKey = encodeDataKey(dataNode.getKey()); | |||
| return valueStorage.get(dataKey, dataNode.getVersion()); | |||
| } | |||
| /** | |||
| * get the key at the specific index; | |||
| * | |||
| * @param fromIndex | |||
| * @return | |||
| */ | |||
| public String getKeyAtIndex(int fromIndex) { | |||
| MerkleDataNode dataNode = merkleTree.getData(fromIndex); | |||
| // TODO: 未去掉前缀; | |||
| return dataNode.getKey().toUTF8String(); | |||
| } | |||
| // /** | |||
| // * 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, it will be created when the version arg was -1. | |||
| // * <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 latest 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; | |||
| // */ | |||
| // @Override | |||
| // public long setValue(String key, byte[] value, long version) { | |||
| // return setValue(Bytes.fromString(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, it will be created when the version arg was -1. | |||
| * <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 latest 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; | |||
| */ | |||
| @Override | |||
| public long setValue(Bytes key, byte[] value, long version) { | |||
| if (readonly) { | |||
| throw new IllegalArgumentException("This merkle dataset is readonly!"); | |||
| } | |||
| if (value.length > MAX_SIZE_OF_VALUE) { | |||
| throw new IllegalArgumentException( | |||
| "The size of value is great than the max size[" + MAX_SIZE_OF_VALUE + "]!"); | |||
| } | |||
| Bytes dataKey = encodeDataKey(key); | |||
| long latestVersion = valueStorage.getVersion(dataKey); | |||
| if (version != latestVersion) { | |||
| return -1; | |||
| } | |||
| // set into versioning kv storage before adding to merkle tree, in order to | |||
| // check version confliction first; | |||
| long sn; | |||
| long newVersion; | |||
| if (version < 0) { | |||
| // creating ; | |||
| sn = snGenerator.generate(key); | |||
| newVersion = valueStorage.set(dataKey, value, -1); | |||
| if (newVersion < 0) { | |||
| return -1; | |||
| } | |||
| byte[] snBytes = BytesUtils.toBytes(sn); | |||
| Bytes snKey = encodeSNKey(key); | |||
| boolean nx = snStorage.set(snKey, snBytes, ExPolicy.NOT_EXISTING); | |||
| if (!nx) { | |||
| throw new LedgerException("SN already exist! --[KEY=" + key + "]"); | |||
| } | |||
| } else { | |||
| // updating; | |||
| // TODO: 未在当前实例的层面,实现对输入键-值的缓冲,而直接写入了存储,而 MerkleTree 在未调用 commit | |||
| // 之前是缓冲的,这使得在存储层面的数据会不一致,而未来需要优化; | |||
| newVersion = valueStorage.set(dataKey, value, version); | |||
| if (newVersion < 0) { | |||
| return -1; | |||
| } | |||
| sn = getSN(key); | |||
| } | |||
| // update merkle tree; | |||
| merkleTree.setData(sn, key, newVersion, value); | |||
| // TODO: 未在当前实例的层面,实现对输入键-值的缓冲,而直接写入了存储,而 MerkleTree 在未调用 commit | |||
| // 之前是缓冲的,这使得在存储层面的数据会不一致,而未来需要优化; | |||
| return newVersion; | |||
| } | |||
| private Bytes encodeSNKey(Bytes key) { | |||
| return new Bytes(snKeyPrefix, key); | |||
| } | |||
| private Bytes encodeDataKey(Bytes key) { | |||
| return new Bytes(dataKeyPrefix, key); | |||
| } | |||
| /** | |||
| * 返回指定 key 对应的序号,如果不存在,则返回 -1; | |||
| * | |||
| * @param key | |||
| * @return | |||
| */ | |||
| private long getSN(Bytes key) { | |||
| // SN-KEY index entry has never changed; | |||
| Bytes snKey = encodeSNKey(key); | |||
| byte[] snBytes = snStorage.get(snKey); | |||
| if (snBytes == null) { | |||
| // throw new IllegalStateException("Cann't found SN of key[" + key + "] from | |||
| // data storage!"); | |||
| return -1; | |||
| } | |||
| return BytesUtils.toLong(snBytes); | |||
| } | |||
| /** | |||
| * 返回默克尔树中记录的指定键的版本,在由默克尔树表示的数据集的快照中,这是指定键的最新版本,<br> | |||
| * 但该版本有可能小于实际存储的最新版本(由于后续追加的新修改被之后生成的快照维护); | |||
| * | |||
| * @param key | |||
| * @return 返回指定的键的版本;如果不存在,则返回 -1; | |||
| */ | |||
| private long getMerkleVersion(Bytes key) { | |||
| long sn = getSN(key); | |||
| if (sn < 0) { | |||
| return -1; | |||
| } | |||
| MerkleDataNode mdn = merkleTree.getData(sn); | |||
| if (mdn == null) { | |||
| return -1; | |||
| } | |||
| return mdn.getVersion(); | |||
| } | |||
| // /** | |||
| // * Return the specified version's value;<br> | |||
| // * | |||
| // * If the key with the specified version doesn't exist, then return null;<br> | |||
| // * If the version is specified to -1, then return the latest version's value; | |||
| // * | |||
| // * @param key | |||
| // * @param version | |||
| // */ | |||
| // @Override | |||
| // public byte[] getValue(String key, long version) { | |||
| // return getValue(Bytes.fromString(key), version); | |||
| // } | |||
| /** | |||
| * Return the specified version's value;<br> | |||
| * | |||
| * If the key with the specified version doesn't exist, then return null;<br> | |||
| * If the version is specified to -1, then return the latest version's value; | |||
| * | |||
| * @param key | |||
| * @param version | |||
| */ | |||
| @Override | |||
| public byte[] getValue(Bytes key, long version) { | |||
| long latestVersion = getMerkleVersion(key); | |||
| if (latestVersion < 0 || version > latestVersion) { | |||
| // key not exist, or the specified version is out of the latest version indexed | |||
| // by the current merkletree; | |||
| return null; | |||
| } | |||
| version = version < 0 ? latestVersion : version; | |||
| Bytes dataKey = encodeDataKey(key); | |||
| return valueStorage.get(dataKey, version); | |||
| } | |||
| // /** | |||
| // * Return the latest version's value; | |||
| // * | |||
| // * @param key | |||
| // * @return return null if not exist; | |||
| // */ | |||
| // @Override | |||
| // public byte[] getValue(String key) { | |||
| // return getValue(Bytes.fromString(key)); | |||
| // } | |||
| /** | |||
| * Return the latest version's value; | |||
| * | |||
| * @param key | |||
| * @return return null if not exist; | |||
| */ | |||
| @Override | |||
| public byte[] getValue(Bytes key) { | |||
| long latestVersion = getMerkleVersion(key); | |||
| if (latestVersion < 0) { | |||
| return null; | |||
| } | |||
| Bytes dataKey = encodeDataKey(key); | |||
| return valueStorage.get(dataKey, latestVersion); | |||
| } | |||
| // /** | |||
| // * Return the latest version entry associated the specified key; If the key | |||
| // * doesn't exist, then return -1; | |||
| // * | |||
| // * @param key | |||
| // * @return | |||
| // */ | |||
| // @Override | |||
| // public long getVersion(String key) { | |||
| // return getMerkleVersion(Bytes.fromString(key)); | |||
| // } | |||
| /** | |||
| * Return the latest version entry associated the specified key; If the key | |||
| * doesn't exist, then return -1; | |||
| * | |||
| * @param key | |||
| * @return | |||
| */ | |||
| @Override | |||
| public long getVersion(Bytes key) { | |||
| return getMerkleVersion(key); | |||
| } | |||
| // @Override | |||
| // public VersioningKVEntry<String, byte[]> getDataEntry(String key) { | |||
| // return getDataEntry(key, -1); | |||
| // } | |||
| /** | |||
| * | |||
| * @param key | |||
| * @return Null if the key doesn't exist! | |||
| */ | |||
| @Override | |||
| public DataEntry<Bytes, byte[]> getDataEntry(Bytes key) { | |||
| return getDataEntry(key, -1); | |||
| } | |||
| // @Override | |||
| // public VersioningKVEntry<String, byte[]> getDataEntry(String key, long version) { | |||
| // Bytes keyBytes = Bytes.fromString(key); | |||
| // long latestVersion = getMerkleVersion(keyBytes); | |||
| // if (latestVersion < 0 || version > latestVersion) { | |||
| // // key not exist, or the specified version is out of the latest version indexed | |||
| // // by the current merkletree; | |||
| // return null; | |||
| // } | |||
| // version = version < 0 ? latestVersion : version; | |||
| // Bytes dataKey = encodeDataKey(keyBytes); | |||
| // byte[] value = valueStorage.get(dataKey, version); | |||
| // if (value == null) { | |||
| // return null; | |||
| // } | |||
| // return new VersioningKVData<String, byte[]>(key, version, value); | |||
| // } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]> getDataEntry(Bytes key, long version) { | |||
| long latestVersion = getMerkleVersion(key); | |||
| if (latestVersion < 0 || version > latestVersion) { | |||
| // key not exist, or the specified version is out of the latest version indexed | |||
| // by the current merkletree; | |||
| return null; | |||
| } | |||
| version = version < 0 ? latestVersion : version; | |||
| Bytes dataKey = encodeDataKey(key); | |||
| byte[] value = valueStorage.get(dataKey, version); | |||
| if (value == null) { | |||
| return null; | |||
| } | |||
| return new VersioningKVData<Bytes, byte[]>(key, version, value); | |||
| } | |||
| @Override | |||
| public DataIterator<Bytes, byte[]> iterator() { | |||
| return new AscDataInterator(getDataCount()); | |||
| } | |||
| @Override | |||
| public DataIterator<Bytes, byte[]> iteratorDesc() { | |||
| return new DescDataInterator(getDataCount()); | |||
| } | |||
| public MerkleDataEntry getMerkleEntry(Bytes key, long version) { | |||
| DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key, version); | |||
| if (dataEntry == null) { | |||
| return null; | |||
| } | |||
| MerkleProof proof = getProof(key); | |||
| return new MerkleDataEntryWrapper(dataEntry, proof); | |||
| } | |||
| public MerkleDataEntry getMerkleEntry(Bytes key) { | |||
| DataEntry<Bytes, byte[]> dataEntry = getDataEntry(key); | |||
| if (dataEntry == null) { | |||
| return null; | |||
| } | |||
| MerkleProof proof = getProof(key); | |||
| return new MerkleDataEntryWrapper(dataEntry, proof); | |||
| } | |||
| public MerkleProof getProof(String key) { | |||
| return getProof(Bytes.fromString(key)); | |||
| } | |||
| /* | |||
| * (non-Javadoc) | |||
| * | |||
| * @see com.jd.blockchain.ledger.core.MerkleProvable#getProof(java.lang.String) | |||
| */ | |||
| @Override | |||
| public MerkleProof getProof(Bytes key) { | |||
| long sn = getSN(key); | |||
| if (sn < 0) { | |||
| return null; | |||
| } | |||
| return merkleTree.getProof(sn); | |||
| } | |||
| /** | |||
| * A wrapper for {@link DataEntry} and {@link MerkleProof}; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| private static class MerkleDataEntryWrapper implements MerkleDataEntry { | |||
| private DataEntry<Bytes, byte[]> data; | |||
| private MerkleProof proof; | |||
| public MerkleDataEntryWrapper(DataEntry<Bytes, byte[]> data, MerkleProof proof) { | |||
| this.data = data; | |||
| this.proof = proof; | |||
| } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]> getData() { | |||
| return data; | |||
| } | |||
| @Override | |||
| public MerkleProof getProof() { | |||
| return proof; | |||
| } | |||
| } | |||
| @Override | |||
| public boolean isUpdated() { | |||
| return bufferedStorage.isUpdated() || merkleTree.isUpdated(); | |||
| } | |||
| @Override | |||
| public void commit() { | |||
| bufferedStorage.commit(); | |||
| merkleTree.commit(); | |||
| } | |||
| @Override | |||
| public void cancel() { | |||
| bufferedStorage.cancel(); | |||
| merkleTree.cancel(); | |||
| snGenerator = new MerkleSequenceSNGenerator(merkleTree); | |||
| } | |||
| // ---------------------------------------------------------- | |||
| private class AscDataInterator implements DataIterator<Bytes, byte[]> { | |||
| private final long total; | |||
| private long cursor = 0; | |||
| public AscDataInterator(long total) { | |||
| this.total = total; | |||
| } | |||
| @Override | |||
| public void skip(long count) { | |||
| cursor = nextCursor(count); | |||
| } | |||
| private long nextCursor(long skippingCount) { | |||
| long c = cursor + skippingCount; | |||
| return c > total ? total : c; | |||
| } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]> next() { | |||
| if (hasNext()) { | |||
| DataEntry<Bytes, byte[]> entry = getLatestDataEntry(cursor); | |||
| cursor = nextCursor(1); | |||
| return entry; | |||
| } | |||
| return null; | |||
| } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]>[] next(int count) { | |||
| if (hasNext()) { | |||
| long from = cursor; | |||
| long nextCursor = nextCursor(count); | |||
| long c = nextCursor - cursor; | |||
| if (c > LedgerConsts.MAX_LIST_COUNT) { | |||
| throw new IllegalArgumentException( | |||
| "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
| } | |||
| DataEntry<Bytes, byte[]>[] entries = getLatestDataEntries(from, (int) c); | |||
| cursor = nextCursor; | |||
| return entries; | |||
| } | |||
| return EMPTY_ENTRIES; | |||
| } | |||
| @Override | |||
| public boolean hasNext() { | |||
| return cursor < total; | |||
| } | |||
| } | |||
| private class DescDataInterator implements DataIterator<Bytes, byte[]> { | |||
| private final long total; | |||
| private long cursor; | |||
| public DescDataInterator(long total) { | |||
| this.total = total; | |||
| this.cursor = total - 1; | |||
| } | |||
| @Override | |||
| public void skip(long count) { | |||
| cursor = nextCursor(count); | |||
| } | |||
| private long nextCursor(long skippingCount) { | |||
| long c = cursor - skippingCount; | |||
| return c < 0 ? -1 : c; | |||
| } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]> next() { | |||
| if (hasNext()) { | |||
| DataEntry<Bytes, byte[]> entry = getLatestDataEntry(cursor); | |||
| cursor = nextCursor(1); | |||
| return entry; | |||
| } | |||
| return null; | |||
| } | |||
| @Override | |||
| public DataEntry<Bytes, byte[]>[] next(int count) { | |||
| if (hasNext()) { | |||
| long nextCursor = nextCursor(count); | |||
| long from = nextCursor + 1; | |||
| long c = cursor - nextCursor; | |||
| if (c > LedgerConsts.MAX_LIST_COUNT) { | |||
| throw new IllegalArgumentException( | |||
| "Count exceed the upper limit[" + LedgerConsts.MAX_LIST_COUNT + "]!"); | |||
| } | |||
| DataEntry<Bytes, byte[]>[] entries = getLatestDataEntries(from, (int) c); | |||
| // reverse; | |||
| ArrayUtils.reverse(entries); | |||
| cursor = nextCursor; | |||
| return entries; | |||
| } | |||
| return EMPTY_ENTRIES; | |||
| } | |||
| @Override | |||
| public boolean hasNext() { | |||
| return cursor < total; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,11 +0,0 @@ | |||
| package com.jd.blockchain.ledger.core; | |||
| public class Node { | |||
| public Node(){ | |||
| } | |||
| } | |||
| @@ -1,73 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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,508 +0,0 @@ | |||
| package com.jd.blockchain.ledger.core; | |||
| import java.util.*; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.core.TransactionRequestExtension.Credential; | |||
| import com.jd.blockchain.service.TransactionBatchProcess; | |||
| import com.jd.blockchain.service.TransactionBatchResult; | |||
| import com.jd.blockchain.service.TransactionBatchResultHandle; | |||
| import com.jd.blockchain.transaction.SignatureUtils; | |||
| import com.jd.blockchain.transaction.TxBuilder; | |||
| import com.jd.blockchain.transaction.TxResponseMessage; | |||
| public class TransactionBatchProcessor implements TransactionBatchProcess { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(TransactionBatchProcessor.class); | |||
| private LedgerSecurityManager securityManager; | |||
| private LedgerEditor newBlockEditor; | |||
| private LedgerQuery ledger; | |||
| private OperationHandleRegisteration handlesRegisteration; | |||
| // 新创建的交易; | |||
| private LedgerBlock block; | |||
| private TransactionState globalResult; | |||
| private List<TransactionResponse> responseList = new ArrayList<>(); | |||
| private TransactionBatchResult batchResult; | |||
| public byte[] getPrevLatestBlockHash() { | |||
| return ledger.getLatestBlockHash().toBytes(); | |||
| } | |||
| public byte[] getGenisBlockHash() { | |||
| return ledger.getBlockHash(0).toBytes(); | |||
| } | |||
| public long getPreLatestBlockHeight() { | |||
| return ledger.getLatestBlockHeight(); | |||
| } | |||
| public HashDigest getLedgerHash() { | |||
| return ledger.getHash(); | |||
| } | |||
| /** | |||
| * @param newBlockEditor 新区块的数据编辑器; | |||
| * @param newBlockEditor 账本查询器,只包含新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; | |||
| * @param opHandles 操作处理对象注册表; | |||
| */ | |||
| public TransactionBatchProcessor(LedgerSecurityManager securityManager, LedgerEditor newBlockEditor, | |||
| LedgerQuery ledger, OperationHandleRegisteration opHandles) { | |||
| this.securityManager = securityManager; | |||
| this.newBlockEditor = newBlockEditor; | |||
| this.ledger = ledger; | |||
| this.handlesRegisteration = opHandles; | |||
| } | |||
| public TransactionBatchProcessor(LedgerRepository ledgerRepo, OperationHandleRegisteration handlesRegisteration) { | |||
| this.ledger = ledgerRepo; | |||
| this.handlesRegisteration = handlesRegisteration; | |||
| LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | |||
| LedgerDataQuery ledgerDataQuery = ledgerRepo.getLedgerData(ledgerBlock); | |||
| LedgerAdminDataQuery previousAdminDataset = ledgerDataQuery.getAdminDataset(); | |||
| this.securityManager = new LedgerSecurityManagerImpl(previousAdminDataset.getAdminInfo().getRolePrivileges(), | |||
| previousAdminDataset.getAdminInfo().getAuthorizations(), previousAdminDataset.getParticipantDataset(), | |||
| ledgerDataQuery.getUserAccountSet()); | |||
| this.newBlockEditor = ledgerRepo.createNextBlock(); | |||
| } | |||
| public static TransactionBatchProcess create(LedgerRepository ledgerRepo, | |||
| OperationHandleRegisteration handlesRegisteration) { | |||
| LedgerBlock ledgerBlock = ledgerRepo.getLatestBlock(); | |||
| LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); | |||
| LedgerDataQuery previousBlockDataset = ledgerRepo.getLedgerData(ledgerBlock); | |||
| LedgerAdminDataQuery previousAdminDataset = previousBlockDataset.getAdminDataset(); | |||
| LedgerSecurityManager securityManager = new LedgerSecurityManagerImpl( | |||
| previousAdminDataset.getAdminInfo().getRolePrivileges(), | |||
| previousAdminDataset.getAdminInfo().getAuthorizations(), previousAdminDataset.getParticipantDataset(), | |||
| previousBlockDataset.getUserAccountSet()); | |||
| TransactionBatchProcessor processor = new TransactionBatchProcessor(securityManager, newBlockEditor, ledgerRepo, | |||
| handlesRegisteration); | |||
| return processor; | |||
| } | |||
| /* | |||
| * (non-Javadoc) | |||
| * | |||
| * @see | |||
| * com.jd.blockchain.ledger.core.impl.TransactionBatchProcess#schedule(com.jd. | |||
| * blockchain.ledger.TransactionRequest) | |||
| */ | |||
| @Override | |||
| public TransactionResponse schedule(TransactionRequest request) { | |||
| TransactionResponse resp; | |||
| try { | |||
| LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
| TransactionRequestExtension reqExt = new TransactionRequestExtensionImpl(request); | |||
| // 初始化交易的用户安全策略; | |||
| // Set<Bytes> endPointAddresses = reqExt.getEndpointAddresses(); | |||
| // int index = 0; | |||
| // for (Bytes address : endPointAddresses) { | |||
| // System.out.printf("EndPoint Sign Address %s[%s] -> %s \r\n", request.getHash(), index++, address.toBase58()); | |||
| //// LOGGER.debug("EndPoint Sign Address {}[{}] -> {}", request.getHash(), index++, address.toBase58()); | |||
| // } | |||
| SecurityPolicy securityPolicy = securityManager.createSecurityPolicy(reqExt.getEndpointAddresses(), | |||
| reqExt.getNodeAddresses()); | |||
| SecurityContext.setContextUsersPolicy(securityPolicy); | |||
| // 安全校验; | |||
| checkSecurity(securityPolicy); | |||
| // 验证交易请求; | |||
| checkRequest(reqExt); | |||
| // 创建交易上下文; | |||
| // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; | |||
| LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); | |||
| // 处理交易; | |||
| resp = handleTx(reqExt, txCtx); | |||
| LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); | |||
| } catch (IllegalTransactionException e) { | |||
| // 抛弃发生处理异常的交易请求; | |||
| resp = discard(request, e.getTxState()); | |||
| LOGGER.error(String.format( | |||
| "Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } catch (BlockRollbackException e) { | |||
| // 发生区块级别的处理异常,向上重新抛出异常进行处理,整个区块可能被丢弃; | |||
| resp = discard(request, e.getState()); | |||
| LOGGER.error(String.format( | |||
| "Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| throw e; | |||
| } catch (Exception e) { | |||
| // 抛弃发生处理异常的交易请求; | |||
| resp = discard(request, TransactionState.SYSTEM_ERROR); | |||
| LOGGER.error(String.format( | |||
| "Ignore transaction caused by the system exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } finally { | |||
| // 清空交易的用户安全策略; | |||
| SecurityContext.removeContextUsersPolicy(); | |||
| } | |||
| responseList.add(resp); | |||
| return resp; | |||
| } | |||
| /** | |||
| * 执行安全验证; | |||
| */ | |||
| private void checkSecurity(SecurityPolicy securityPolicy) { | |||
| // 验证节点和终端身份的合法性; | |||
| // 多重身份签署的必须全部身份都合法; | |||
| securityPolicy.checkEndpointValidity(MultiIDsPolicy.ALL); | |||
| securityPolicy.checkNodeValidity(MultiIDsPolicy.ALL); | |||
| // 验证参与方节点是否具有核准交易的权限; | |||
| securityPolicy.checkNodePermission(LedgerPermission.APPROVE_TX, MultiIDsPolicy.AT_LEAST_ONE); | |||
| } | |||
| private void checkRequest(TransactionRequestExtension reqExt) { | |||
| // TODO: 把验签和创建交易并行化; | |||
| checkTxContentHash(reqExt); | |||
| checkEndpointSignatures(reqExt); | |||
| checkNodeSignatures(reqExt); | |||
| } | |||
| private void checkTxContentHash(TransactionRequestExtension requestExt) { | |||
| TransactionContent txContent = requestExt.getTransactionContent(); | |||
| if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { | |||
| // 由于哈希校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
| throw new IllegalTransactionException( | |||
| "Wrong transaction content hash! --[TxHash=" + requestExt.getTransactionContent().getHash() + "]!", | |||
| TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
| } | |||
| } | |||
| private void checkNodeSignatures(TransactionRequestExtension request) { | |||
| TransactionContent txContent = request.getTransactionContent(); | |||
| Collection<Credential> nodes = request.getNodes(); | |||
| if (nodes != null) { | |||
| for (Credential node : nodes) { | |||
| if (!SignatureUtils.verifyHashSignature(txContent.getHash(), node.getSignature().getDigest(), | |||
| node.getPubKey())) { | |||
| // 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
| throw new IllegalTransactionException( | |||
| String.format("Wrong transaction node signature! --[Tx Hash=%s][Node Signer=%s]!", | |||
| request.getTransactionContent().getHash(), node.getAddress()), | |||
| TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private void checkEndpointSignatures(TransactionRequestExtension request) { | |||
| TransactionContent txContent = request.getTransactionContent(); | |||
| Collection<Credential> endpoints = request.getEndpoints(); | |||
| if (endpoints != null) { | |||
| for (Credential endpoint : endpoints) { | |||
| if (!SignatureUtils.verifyHashSignature(txContent.getHash(), endpoint.getSignature().getDigest(), | |||
| endpoint.getPubKey())) { | |||
| // 由于签名校验失败,引发IllegalTransactionException,使外部调用抛弃此交易请求; | |||
| throw new IllegalTransactionException( | |||
| String.format("Wrong transaction endpoint signature! --[Tx Hash=%s][Endpoint Signer=%s]!", | |||
| request.getTransactionContent().getHash(), endpoint.getAddress()), | |||
| TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 处理交易;<br> | |||
| * | |||
| * 此方法会处理所有的异常,以不同结果的 {@link TransactionResponse} 返回; | |||
| * | |||
| * @param request | |||
| * @param txCtx | |||
| * @return | |||
| */ | |||
| private TransactionResponse handleTx(TransactionRequestExtension request, LedgerTransactionContext txCtx) { | |||
| TransactionState result; | |||
| List<OperationResult> operationResults = new ArrayList<>(); | |||
| try { | |||
| LedgerDataset dataset = txCtx.getDataset(); | |||
| // 执行操作; | |||
| Operation[] ops = request.getTransactionContent().getOperations(); | |||
| OperationHandleContext handleContext = new OperationHandleContext() { | |||
| @Override | |||
| public void handle(Operation operation) { | |||
| // assert; Instance of operation are one of User related operations or | |||
| // DataAccount related operations; | |||
| OperationHandle hdl = handlesRegisteration.getHandle(operation.getClass()); | |||
| hdl.process(operation, dataset, request, ledger, this); | |||
| } | |||
| }; | |||
| OperationHandle opHandle; | |||
| int opIndex = 0; | |||
| for (Operation op : ops) { | |||
| opHandle = handlesRegisteration.getHandle(op.getClass()); | |||
| BytesValue opResult = opHandle.process(op, dataset, request, ledger, handleContext); | |||
| if (opResult != null) { | |||
| operationResults.add(new OperationResultData(opIndex, opResult)); | |||
| } | |||
| opIndex++; | |||
| } | |||
| // 提交交易(事务); | |||
| result = TransactionState.SUCCESS; | |||
| txCtx.commit(result, operationResults); | |||
| } catch (TransactionRollbackException e) { | |||
| result = TransactionState.IGNORED_BY_TX_FULL_ROLLBACK; | |||
| txCtx.rollback(); | |||
| LOGGER.error(String.format( | |||
| "Transaction was full rolled back! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } catch (BlockRollbackException e) { | |||
| // rollback all the block; | |||
| // TODO: handle the BlockRollbackException in detail; | |||
| result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; | |||
| txCtx.rollback(); | |||
| LOGGER.error( | |||
| String.format("Transaction was rolled back! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), | |||
| request.getTransactionContent().getHash(), e.getMessage()), | |||
| e); | |||
| // 重新抛出由上层错误处理; | |||
| throw e; | |||
| } catch (LedgerException e) { | |||
| // TODO: 识别更详细的异常类型以及执行对应的处理; | |||
| result = TransactionState.LEDGER_ERROR; | |||
| if (e instanceof DataAccountDoesNotExistException) { | |||
| result = TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST; | |||
| } else if (e instanceof UserDoesNotExistException) { | |||
| result = TransactionState.USER_DOES_NOT_EXIST; | |||
| } else if (e instanceof ContractDoesNotExistException) { | |||
| result = TransactionState.CONTRACT_DOES_NOT_EXIST; | |||
| } else if (e instanceof ParticipantDoesNotExistException) { | |||
| result = TransactionState.PARTICIPANT_DOES_NOT_EXIST; | |||
| } else if (e instanceof DataVersionConflictException) { | |||
| result = TransactionState.DATA_VERSION_CONFLICT; | |||
| } | |||
| txCtx.discardAndCommit(result, operationResults); | |||
| LOGGER.error(String.format( | |||
| "Due to ledger exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } catch (LedgerSecurityException e) { | |||
| // TODO: 识别更详细的异常类型以及执行对应的处理; | |||
| result = TransactionState.REJECTED_BY_SECURITY_POLICY; | |||
| txCtx.discardAndCommit(result, operationResults); | |||
| LOGGER.error(String.format( | |||
| "Due to ledger security exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } catch (Exception e) { | |||
| result = TransactionState.SYSTEM_ERROR; | |||
| txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); | |||
| LOGGER.error(String.format( | |||
| "Due to system exception, the data changes resulting from transaction execution will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| e.getMessage()), e); | |||
| } | |||
| TxResponseHandle resp = new TxResponseHandle(request, result); | |||
| if (!operationResults.isEmpty()) { | |||
| OperationResult[] operationResultArray = new OperationResult[operationResults.size()]; | |||
| resp.setOperationResults(operationResults.toArray(operationResultArray)); | |||
| } | |||
| return resp; | |||
| } | |||
| /** | |||
| * 直接丢弃交易; | |||
| * | |||
| * @param request | |||
| * @param txState | |||
| * @return 丢弃交易的回复;只包含原始请求中的交易内容哈希和交易被丢弃的原因,而不包含区块信息; | |||
| */ | |||
| private TransactionResponse discard(TransactionRequest request, TransactionState txState) { | |||
| // 丢弃交易的回复;只返回请求的交易内容哈希和交易被丢弃的原因, | |||
| TxResponseMessage resp = new TxResponseMessage(request.getTransactionContent().getHash()); | |||
| resp.setExecutionState(txState); | |||
| LOGGER.error("Discard transaction request! --[BlockHeight={}][RequestHash={}][TxHash={}][ResponseState={}]", | |||
| newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), | |||
| resp.getExecutionState()); | |||
| return resp; | |||
| } | |||
| /* | |||
| * (non-Javadoc) | |||
| * | |||
| * @see com.jd.blockchain.ledger.core.impl.TransactionBatchProcess#prepare() | |||
| */ | |||
| @Override | |||
| public TransactionBatchResultHandle prepare() { | |||
| if (batchResult != null) { | |||
| throw new IllegalStateException("Batch result has already been prepared or canceled!"); | |||
| } | |||
| this.block = newBlockEditor.prepare(); | |||
| this.batchResult = new TransactionBatchResultHandleImpl(); | |||
| return (TransactionBatchResultHandle) batchResult; | |||
| } | |||
| /* | |||
| * (non-Javadoc) | |||
| * | |||
| * @see | |||
| * com.jd.blockchain.ledger.core.impl.TransactionBatchProcess#cancel(com.jd. | |||
| * blockchain.ledger.ExecutionState) | |||
| */ | |||
| @Override | |||
| public TransactionBatchResult cancel(TransactionState errorResult) { | |||
| if (batchResult != null) { | |||
| throw new IllegalStateException("Batch result has already been prepared or canceled!"); | |||
| } | |||
| cancelInError(errorResult); | |||
| batchResult = new TransactionBatchResultImpl(); | |||
| return batchResult; | |||
| } | |||
| @Override | |||
| public long blockHeight() { | |||
| // if (block != null) { | |||
| // return block.getHeight(); | |||
| // } | |||
| // return 0; | |||
| return ledger.getLatestBlockHeight(); | |||
| } | |||
| private void commitSuccess() { | |||
| newBlockEditor.commit(); | |||
| onCommitted(); | |||
| } | |||
| private void cancelInError(TransactionState errorResult) { | |||
| if (errorResult == TransactionState.SUCCESS) { | |||
| throw new IllegalArgumentException("Cann't cancel by an success result!"); | |||
| } | |||
| newBlockEditor.cancel(); | |||
| this.globalResult = errorResult; | |||
| onCanceled(); | |||
| } | |||
| /** | |||
| * 模板事件方法:交易已提交; | |||
| */ | |||
| protected void onCommitted() { | |||
| } | |||
| /** | |||
| * 模板事件方法:交易已取消; | |||
| */ | |||
| protected void onCanceled() { | |||
| } | |||
| private class TxResponseHandle implements TransactionResponse { | |||
| private TransactionRequest request; | |||
| private TransactionState result; | |||
| private OperationResult[] operationResults; | |||
| public TxResponseHandle(TransactionRequest request, TransactionState result) { | |||
| this.request = request; | |||
| this.result = result; | |||
| } | |||
| @Override | |||
| public HashDigest getContentHash() { | |||
| return request.getTransactionContent().getHash(); | |||
| } | |||
| @Override | |||
| public TransactionState getExecutionState() { | |||
| return result; | |||
| } | |||
| @Override | |||
| public HashDigest getBlockHash() { | |||
| return block == null ? null : block.getHash(); | |||
| } | |||
| @Override | |||
| public long getBlockHeight() { | |||
| return block == null ? -1 : block.getHeight(); | |||
| } | |||
| @Override | |||
| public boolean isSuccess() { | |||
| return globalResult == null ? result == TransactionState.SUCCESS : globalResult == TransactionState.SUCCESS; | |||
| } | |||
| @Override | |||
| public OperationResult[] getOperationResults() { | |||
| return operationResults; | |||
| } | |||
| public void setOperationResults(OperationResult[] operationResults) { | |||
| this.operationResults = operationResults; | |||
| } | |||
| } | |||
| private class TransactionBatchResultImpl implements TransactionBatchResult { | |||
| @Override | |||
| public LedgerBlock getBlock() { | |||
| return block; | |||
| } | |||
| @Override | |||
| public Iterator<TransactionResponse> getResponses() { | |||
| return responseList.iterator(); | |||
| } | |||
| } | |||
| private class TransactionBatchResultHandleImpl extends TransactionBatchResultImpl | |||
| implements TransactionBatchResultHandle { | |||
| @Override | |||
| public void commit() { | |||
| commitSuccess(); | |||
| } | |||
| @Override | |||
| public void cancel(TransactionState errorResult) { | |||
| cancelInError(errorResult); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,85 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| <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.4.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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| //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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| //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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| //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 +0,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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| package com.jd.blockchain.ledger; | |||
| public interface SignatureInfo { | |||
| /** | |||
| * 签署账户的地址; | |||
| * | |||
| * @return | |||
| */ | |||
| String getAddress(); | |||
| /** | |||
| * 签名的摘要; | |||
| * | |||
| * 注:采用Base64编码; | |||
| * | |||
| * @return | |||
| */ | |||
| String getDigest(); | |||
| } | |||
| @@ -1,37 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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 +0,0 @@ | |||
| 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(); | |||
| } | |||