| @@ -1,55 +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-core</artifactId> | |||
| <version>1.2.0-SNAPSHOT</version> | |||
| </parent> | |||
| <artifactId>consensus-bftsmart</artifactId> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>bft-smart</artifactId> | |||
| <version>${bftsmart.version}</version> | |||
| </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>${framework.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>utils-common</artifactId> | |||
| <version>${framework.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>${framework.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> | |||
| </project> | |||
| @@ -1,67 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| public class BftsmartClientIncomingConfig implements BftsmartClientIncomingSettings { | |||
| private BftsmartConsensusSettings consensusSettings; | |||
| private byte[] topology; | |||
| private byte[] tomConfig; | |||
| private int clientId; | |||
| private PubKey pubKey; | |||
| @Override | |||
| public BftsmartConsensusSettings getConsensusSettings() { | |||
| return consensusSettings; | |||
| } | |||
| public void setConsensusSettings(BftsmartConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| } | |||
| @Override | |||
| public byte[] getTopology() { | |||
| return topology; | |||
| } | |||
| public void setTopology(byte[] topology) { | |||
| this.topology = topology; | |||
| } | |||
| @Override | |||
| public int getClientId() { | |||
| return clientId; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return BftsmartConsensusProvider.NAME; | |||
| } | |||
| public void setClientId(int clientId) { | |||
| this.clientId = clientId; | |||
| } | |||
| @Override | |||
| public byte[] getTomConfig() { | |||
| return tomConfig; | |||
| } | |||
| public void setTomConfig(byte[] tomConfig) { | |||
| this.tomConfig = tomConfig; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public void setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| } | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| @DataContract(code = DataCodes.CONSENSUS_BFTSMART_CLI_INCOMING_SETTINGS) | |||
| public interface BftsmartClientIncomingSettings extends ClientIncomingSettings { | |||
| @DataField(order = 1, primitiveType = PrimitiveType.BYTES) | |||
| byte[] getTopology(); | |||
| @DataField(order = 2, primitiveType = PrimitiveType.BYTES) | |||
| byte[] getTomConfig(); | |||
| @DataField(order = 3, primitiveType=PrimitiveType.BYTES) | |||
| PubKey getPubKey(); | |||
| } | |||
| @@ -1,35 +0,0 @@ | |||
| //package com.jd.blockchain.consensus.bftsmart; | |||
| // | |||
| //public class BftsmartCommitBlockConfig implements BftsmartCommitBlockSettings { | |||
| // | |||
| // private int txSizePerBlock; | |||
| // | |||
| // private long maxDelayMilliSecondsPerBlock; | |||
| // | |||
| // | |||
| // public BftsmartCommitBlockConfig() { | |||
| // | |||
| // } | |||
| // | |||
| // public BftsmartCommitBlockConfig(int txSizePerBlock, long maxDelayMilliSecondsPerBlock) { | |||
| // this.txSizePerBlock = txSizePerBlock; | |||
| // this.maxDelayMilliSecondsPerBlock = maxDelayMilliSecondsPerBlock; | |||
| // } | |||
| // @Override | |||
| // public int getTxSizePerBlock() { | |||
| // return txSizePerBlock; | |||
| // } | |||
| // | |||
| // public void setTxSizePerBlock(int txSizePerBlock) { | |||
| // this.txSizePerBlock = txSizePerBlock; | |||
| // } | |||
| // | |||
| // @Override | |||
| // public long getMaxDelayMilliSecondsPerBlock() { | |||
| // return maxDelayMilliSecondsPerBlock; | |||
| // } | |||
| // | |||
| // public void setMaxDelayMilliSecondsPerBlock(long maxDelayMilliSecondsPerBlock) { | |||
| // this.maxDelayMilliSecondsPerBlock = maxDelayMilliSecondsPerBlock; | |||
| // } | |||
| //} | |||
| @@ -1,17 +0,0 @@ | |||
| //package com.jd.blockchain.consensus.bftsmart; | |||
| // | |||
| //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.CONSENSUS_BFTSMART_BLOCK_SETTINGS) | |||
| //public interface BftsmartCommitBlockSettings { | |||
| // | |||
| // @DataField(order = 0, primitiveType = PrimitiveType.INT32) | |||
| // int getTxSizePerBlock(); | |||
| // | |||
| // @DataField(order = 1, primitiveType = PrimitiveType.INT64) | |||
| // long getMaxDelayMilliSecondsPerBlock(); | |||
| //} | |||
| @@ -1,54 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.utils.Property; | |||
| public class BftsmartConsensusConfig implements BftsmartConsensusSettings { | |||
| private Property[] bftsmartSystemConfig; | |||
| private BftsmartNodeSettings[] nodes; | |||
| // private BftsmartCommitBlockSettings commitBlockSettings; | |||
| static { | |||
| DataContractRegistry.register(BftsmartConsensusSettings.class); | |||
| } | |||
| /** | |||
| * 创建 bftsmart 共识配置; | |||
| * | |||
| * @param nodes | |||
| * 节点列表 | |||
| * @param commitBlockSettings | |||
| * 结块设置; | |||
| * @param bftsmartSystemConfigs | |||
| * bftsmart系统配置; | |||
| */ | |||
| public BftsmartConsensusConfig(BftsmartNodeSettings[] nodes, | |||
| // BftsmartCommitBlockSettings commitBlockSettings, | |||
| Property[] bftsmartSystemConfigs) { | |||
| this.nodes = nodes; | |||
| // this.commitBlockSettings = commitBlockSettings; | |||
| this.bftsmartSystemConfig = bftsmartSystemConfigs; | |||
| } | |||
| @Override | |||
| public BftsmartNodeSettings[] getNodes() { | |||
| return nodes; | |||
| } | |||
| @Override | |||
| public Property[] getSystemConfigs() { | |||
| return bftsmartSystemConfig; | |||
| } | |||
| // @Override | |||
| // public BftsmartCommitBlockSettings getCommitBlockSettings() { | |||
| // return commitBlockSettings; | |||
| // } | |||
| // | |||
| // | |||
| // public void setCommitBlockSettings(BftsmartCommitBlockSettings commitBlockSettings) { | |||
| // this.commitBlockSettings = commitBlockSettings; | |||
| // } | |||
| } | |||
| @@ -1,42 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.consensus.ConsensusProvider; | |||
| import com.jd.blockchain.consensus.SettingsFactory; | |||
| import com.jd.blockchain.consensus.bftsmart.client.BftsmartConsensusClientFactory; | |||
| import com.jd.blockchain.consensus.bftsmart.service.BftsmartNodeServerFactory; | |||
| import com.jd.blockchain.consensus.client.ClientFactory; | |||
| import com.jd.blockchain.consensus.service.NodeServerFactory; | |||
| public class BftsmartConsensusProvider implements ConsensusProvider { | |||
| public static final String NAME = BftsmartConsensusProvider.class.getName(); | |||
| private static BftsmartSettingsFactory settingsFactory = new BftsmartSettingsFactory(); | |||
| private static BftsmartConsensusClientFactory clientFactory = new BftsmartConsensusClientFactory(); | |||
| private static BftsmartNodeServerFactory nodeServerFactory = new BftsmartNodeServerFactory(); | |||
| @Override | |||
| public String getName() { | |||
| return NAME; | |||
| } | |||
| @Override | |||
| public SettingsFactory getSettingsFactory() { | |||
| return settingsFactory; | |||
| } | |||
| @Override | |||
| public ClientFactory getClientFactory() { | |||
| return clientFactory; | |||
| } | |||
| @Override | |||
| public NodeServerFactory getServerFactory() { | |||
| return nodeServerFactory; | |||
| } | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.utils.Property; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| @DataContract(code = DataCodes.CONSENSUS_BFTSMART_SETTINGS) | |||
| public interface BftsmartConsensusSettings extends ConsensusSettings { | |||
| @DataField(order = 1, primitiveType = PrimitiveType.BYTES, list=true) | |||
| Property[] getSystemConfigs(); | |||
| // @DataField(order = 2, refContract = true) | |||
| // BftsmartCommitBlockSettings getCommitBlockSettings(); | |||
| } | |||
| @@ -1,308 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import java.util.Properties; | |||
| import com.jd.blockchain.consensus.ConsensusProviders; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.ledger.ParticipantInfo; | |||
| import com.jd.blockchain.ledger.ParticipantNode; | |||
| import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.PropertiesUtils; | |||
| import com.jd.blockchain.utils.Property; | |||
| import com.jd.blockchain.utils.codec.Base58Utils; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| import org.springframework.core.io.ClassPathResource; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.ConsensusSettingsBuilder; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| public class BftsmartConsensusSettingsBuilder implements ConsensusSettingsBuilder { | |||
| private static final int DEFAULT_TXSIZE = 1000; | |||
| private static final int DEFAULT_MAXDELAY = 1000; | |||
| private static final String CONFIG_TEMPLATE_FILE = "bftsmart.config"; | |||
| private static final String CONFIG_LEDGER_INIT = "ledger.init"; | |||
| /** | |||
| * 参数键:节点数量; | |||
| */ | |||
| public static final String SERVER_NUM_KEY = "system.servers.num"; | |||
| /** | |||
| * 参数键:结块条件设置; | |||
| */ | |||
| public static final String BFTSMART_BLOCK_TXSIZE_KEY = "system.block.txsize"; | |||
| public static final String BFTSMART_BLOCK_MAXDELAY_KEY = "system.block.maxdelay"; | |||
| // /** | |||
| // * 参数键格式:节点地址; | |||
| // */ | |||
| // public static final String ADDRESS_PATTERN = "node.%s.address"; | |||
| /** | |||
| * 参数键格式:节点公钥; | |||
| */ | |||
| public static final String PUBKEY_PATTERN = "system.server.%s.pubkey"; | |||
| /** | |||
| * 参数键格式:节点共识服务的网络地址; | |||
| */ | |||
| public static final String CONSENSUS_HOST_PATTERN = "system.server.%s.network.host"; | |||
| /** | |||
| * 参数键格式:节点共识服务的端口; | |||
| */ | |||
| public static final String CONSENSUS_PORT_PATTERN = "system.server.%s.network.port"; | |||
| /** | |||
| * 参数键格式:节点共识服务的通讯是否开启安全选项; | |||
| */ | |||
| public static final String CONSENSUS_SECURE_PATTERN = "system.server.%s.network.secure"; | |||
| public static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"; | |||
| private static Properties CONFIG_TEMPLATE; | |||
| static { | |||
| ClassPathResource configResource = new ClassPathResource(CONFIG_TEMPLATE_FILE); | |||
| try { | |||
| try (InputStream in = configResource.getInputStream()) { | |||
| CONFIG_TEMPLATE = PropertiesUtils.load(in, BytesUtils.DEFAULT_CHARSET); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| //解析得到结块的相关配置信息 | |||
| // public BftsmartCommitBlockConfig createBlockConfig(Properties resolvingProps) { | |||
| // BftsmartCommitBlockConfig blockConfig = new BftsmartCommitBlockConfig(); | |||
| // | |||
| // String txSizeString = PropertiesUtils.getRequiredProperty(resolvingProps, BFTSMART_BLOCK_TXSIZE_KEY); | |||
| // resolvingProps.remove(BFTSMART_BLOCK_TXSIZE_KEY); | |||
| // | |||
| // if (txSizeString == null || txSizeString.length() == 0) { | |||
| // blockConfig.setTxSizePerBlock(DEFAULT_TXSIZE); | |||
| // } | |||
| // else { | |||
| // blockConfig.setTxSizePerBlock(Integer.parseInt(txSizeString)); | |||
| // } | |||
| // | |||
| // String maxDelayString = PropertiesUtils.getRequiredProperty(resolvingProps, BFTSMART_BLOCK_MAXDELAY_KEY); | |||
| // resolvingProps.remove(BFTSMART_BLOCK_MAXDELAY_KEY); | |||
| // | |||
| // if (maxDelayString == null || maxDelayString.length() == 0) { | |||
| // blockConfig.setMaxDelayMilliSecondsPerBlock(DEFAULT_MAXDELAY); | |||
| // } | |||
| // else { | |||
| // blockConfig.setMaxDelayMilliSecondsPerBlock(Long.parseLong(maxDelayString)); | |||
| // } | |||
| // | |||
| // return blockConfig; | |||
| // } | |||
| @Override | |||
| public Properties createPropertiesTemplate() { | |||
| return PropertiesUtils.cloneFrom(CONFIG_TEMPLATE); | |||
| } | |||
| @Override | |||
| public BftsmartConsensusSettings createSettings(Properties props, ParticipantNode[] participantNodes) { | |||
| Properties resolvingProps = PropertiesUtils.cloneFrom(props); | |||
| int serversNum = PropertiesUtils.getInt(resolvingProps, SERVER_NUM_KEY); | |||
| if (serversNum < 0) { | |||
| throw new IllegalArgumentException(String.format("Property[%s] is negative!", SERVER_NUM_KEY)); | |||
| } | |||
| if (serversNum < 4) { | |||
| throw new IllegalArgumentException(String.format("Property[%s] is less than 4!", SERVER_NUM_KEY)); | |||
| } | |||
| if (participantNodes == null) { | |||
| throw new IllegalArgumentException("ParticipantNodes is Empty !!!"); | |||
| } | |||
| if (serversNum != participantNodes.length) { | |||
| throw new IllegalArgumentException(String.format("Property[%s] which is [%s] unequal " + | |||
| "ParticipantNodes's length which is [%s] !", SERVER_NUM_KEY, serversNum, participantNodes.length)); | |||
| } | |||
| // BftsmartCommitBlockConfig blockConfig = createBlockConfig(resolvingProps); | |||
| BftsmartNodeSettings[] nodesSettings = new BftsmartNodeSettings[serversNum]; | |||
| for (int i = 0; i < serversNum; i++) { | |||
| int id = i; | |||
| // String keyOfPubkey = keyOfNode(PUBKEY_PATTERN, id); | |||
| // String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | |||
| // PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | |||
| // PubKey pubKey = KeyGenCommand.decodePubKey(base58PubKey); | |||
| PubKey pubKey = participantNodes[i].getPubKey(); | |||
| // resolvingProps.remove(keyOfPubkey); | |||
| String keyOfHost = keyOfNode(CONSENSUS_HOST_PATTERN, id); | |||
| String networkAddressHost = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfHost); | |||
| resolvingProps.remove(keyOfHost); | |||
| String keyOfPort = keyOfNode(CONSENSUS_PORT_PATTERN, id); | |||
| int networkAddressPort = PropertiesUtils.getInt(resolvingProps, keyOfPort); | |||
| resolvingProps.remove(keyOfPort); | |||
| String keyOfSecure = keyOfNode(CONSENSUS_SECURE_PATTERN, id); | |||
| boolean networkAddressSecure = PropertiesUtils.getBoolean(resolvingProps, keyOfSecure); | |||
| resolvingProps.remove(keyOfSecure); | |||
| BftsmartNodeConfig nodeConfig = new BftsmartNodeConfig(pubKey, id, | |||
| new NetworkAddress(networkAddressHost, networkAddressPort, networkAddressSecure)); | |||
| nodesSettings[i] = nodeConfig; | |||
| } | |||
| BftsmartConsensusConfig config = new BftsmartConsensusConfig(nodesSettings, | |||
| // blockConfig, | |||
| PropertiesUtils.getOrderedValues(resolvingProps)); | |||
| return config; | |||
| } | |||
| @Override | |||
| public Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo) { | |||
| //update consensus setting through node and system config two aspects | |||
| BftsmartConsensusSettings consensusSettings = (BftsmartConsensusSettings) ConsensusProviders.getProvider(BFTSMART_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder().decode(oldConsensusSettings.toBytes()); | |||
| Property[] systemConfigs = systemConfigs(consensusSettings.getSystemConfigs()); | |||
| BftsmartNodeSettings[] nodeSettings = nodeSettings(consensusSettings.getNodes(), participantInfo); | |||
| BftsmartConsensusConfig bftsmartConsensusConfig = new BftsmartConsensusConfig(nodeSettings, systemConfigs); | |||
| // for(int i = 0 ;i < bftsmartConsensusConfig.getNodes().length; i++) { | |||
| // System.out.printf("id = %d, host = %s, port = %d\r\n", bftsmartConsensusConfig.getNodes()[i].getId(), bftsmartConsensusConfig.getNodes()[i].getNetworkAddress().getHost(), bftsmartConsensusConfig.getNodes()[i].getNetworkAddress().getPort()); | |||
| // } | |||
| // | |||
| // for(int i = 0 ;i < bftsmartConsensusConfig.getSystemConfigs().length; i++) { | |||
| // System.out.printf("property name = %s, property value = %s\r\n",bftsmartConsensusConfig.getSystemConfigs()[i].getName(), bftsmartConsensusConfig.getSystemConfigs()[i].getValue()); | |||
| // } | |||
| return new Bytes(ConsensusProviders.getProvider(BFTSMART_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder().encode(bftsmartConsensusConfig)); | |||
| } | |||
| private static String keyOfNode(String pattern, int id) { | |||
| return String.format(pattern, id); | |||
| } | |||
| @Override | |||
| public void writeSettings(ConsensusSettings settings, Properties props) { | |||
| int serversNum = PropertiesUtils.getInt(props, SERVER_NUM_KEY); | |||
| if (serversNum > 0) { | |||
| for (int i = 0; i < serversNum; i++) { | |||
| int id = i; | |||
| // String keyOfPubkey = keyOfNode(PUBKEY_PATTERN, id); | |||
| // props.remove(keyOfPubkey); | |||
| String keyOfHost = keyOfNode(CONSENSUS_HOST_PATTERN, id); | |||
| props.remove(keyOfHost); | |||
| String keyOfPort = keyOfNode(CONSENSUS_PORT_PATTERN, id); | |||
| props.remove(keyOfPort); | |||
| String keyOfSecure = keyOfNode(CONSENSUS_SECURE_PATTERN, id); | |||
| props.remove(keyOfSecure); | |||
| } | |||
| } | |||
| BftsmartConsensusSettings bftsmartSettings = (BftsmartConsensusSettings) settings; | |||
| BftsmartNodeSettings[] nodesSettings = (BftsmartNodeSettings[]) bftsmartSettings.getNodes(); | |||
| serversNum = nodesSettings.length; | |||
| props.setProperty(SERVER_NUM_KEY, serversNum + ""); | |||
| //获得结块相关的属性信息 | |||
| // BftsmartCommitBlockSettings blockSettings = bftsmartSettings.getCommitBlockSettings(); | |||
| // if (blockSettings == null) { | |||
| // props.setProperty(BFTSMART_BLOCK_TXSIZE_KEY, DEFAULT_TXSIZE + ""); | |||
| // props.setProperty(BFTSMART_BLOCK_MAXDELAY_KEY, DEFAULT_MAXDELAY + ""); | |||
| // } else { | |||
| // int txSize = blockSettings.getTxSizePerBlock(); | |||
| // long maxDelay = blockSettings.getMaxDelayMilliSecondsPerBlock(); | |||
| // props.setProperty(BFTSMART_BLOCK_TXSIZE_KEY, txSize + ""); | |||
| // props.setProperty(BFTSMART_BLOCK_MAXDELAY_KEY, maxDelay + ""); | |||
| // } | |||
| for (int i = 0; i < serversNum; i++) { | |||
| BftsmartNodeSettings ns = nodesSettings[i]; | |||
| int id = i; | |||
| // String keyOfPubkey = keyOfNode(PUBKEY_PATTERN, id); | |||
| // props.setProperty(keyOfPubkey, ns.getPubKey().toBase58()); | |||
| String keyOfHost = keyOfNode(CONSENSUS_HOST_PATTERN, id); | |||
| props.setProperty(keyOfHost, ns.getNetworkAddress() == null ? "" : ns.getNetworkAddress().getHost()); | |||
| String keyOfPort = keyOfNode(CONSENSUS_PORT_PATTERN, id); | |||
| props.setProperty(keyOfPort, ns.getNetworkAddress() == null ? "" : ns.getNetworkAddress().getPort() + ""); | |||
| String keyOfSecure = keyOfNode(CONSENSUS_SECURE_PATTERN, id); | |||
| props.setProperty(keyOfSecure, ns.getNetworkAddress() == null ? "false" : ns.getNetworkAddress().isSecure() + ""); | |||
| } | |||
| PropertiesUtils.setValues(props, bftsmartSettings.getSystemConfigs()); | |||
| } | |||
| /** | |||
| * | |||
| * update system.servers.num property | |||
| * | |||
| */ | |||
| private Property[] systemConfigs(Property[] systemConfigs) { | |||
| Map<String, Property> propertyMap = convert2Map(systemConfigs); | |||
| int serverNum = Integer.parseInt(propertyMap.get("system.servers.num").getValue()); | |||
| propertyMap.put("system.servers.num", new Property("system.servers.num", String.valueOf(serverNum + 1))); | |||
| return convert2Array(propertyMap); | |||
| } | |||
| private Map<String, Property> convert2Map(Property[] properties) { | |||
| Map<String, Property> propertyMap = new HashMap<>(); | |||
| for (Property property : properties) { | |||
| propertyMap.put(property.getName(), property); | |||
| } | |||
| return propertyMap; | |||
| } | |||
| private Property[] convert2Array(Map<String, Property> map) { | |||
| Property[] properties = new Property[map.size()]; | |||
| int index = 0; | |||
| for (Map.Entry<String, Property> entry : map.entrySet()) { | |||
| properties[index++] = entry.getValue(); | |||
| } | |||
| return properties; | |||
| } | |||
| /** | |||
| * | |||
| * update node setting | |||
| * | |||
| */ | |||
| private BftsmartNodeSettings[] nodeSettings(NodeSettings[] nodeSettings, ParticipantInfo participantInfo) { | |||
| BftsmartNodeConfig bftsmartNodeConfig = new BftsmartNodeConfig(participantInfo.getPubKey(), nodeSettings.length, participantInfo.getNetworkAddress()); | |||
| BftsmartNodeSettings[] bftsmartNodeSettings = new BftsmartNodeSettings[nodeSettings.length + 1]; | |||
| for (int i = 0; i < nodeSettings.length; i++) { | |||
| bftsmartNodeSettings[i] = (BftsmartNodeSettings)nodeSettings[i]; | |||
| } | |||
| bftsmartNodeSettings[nodeSettings.length] = bftsmartNodeConfig; | |||
| return bftsmartNodeSettings; | |||
| } | |||
| } | |||
| @@ -1,66 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class BftsmartNodeConfig implements BftsmartNodeSettings { | |||
| private int id; | |||
| private String address; | |||
| private PubKey pubKey; | |||
| private NetworkAddress networkAddress; | |||
| public BftsmartNodeConfig() { | |||
| } | |||
| static { | |||
| DataContractRegistry.register(BftsmartNodeSettings.class); | |||
| } | |||
| public BftsmartNodeConfig(PubKey pubKey, int id, NetworkAddress networkAddress) { | |||
| this.address = AddressEncoding.generateAddress(pubKey).toBase58(); | |||
| this.pubKey = pubKey; | |||
| this.id = id; | |||
| this.networkAddress = networkAddress; | |||
| } | |||
| @Override | |||
| public String getAddress() { | |||
| return address; | |||
| } | |||
| @Override | |||
| public int getId() { | |||
| return id; | |||
| } | |||
| @Override | |||
| public NetworkAddress getNetworkAddress() { | |||
| return networkAddress; | |||
| } | |||
| public void setId(int id) { | |||
| this.id = id; | |||
| } | |||
| public void setAddress(String address) { | |||
| this.address = address; | |||
| } | |||
| public void setNetworkAddress(NetworkAddress networkAddress) { | |||
| this.networkAddress = networkAddress; | |||
| } | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public void setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| } | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| @DataContract(code = DataCodes.CONSENSUS_BFTSMART_NODE_SETTINGS) | |||
| public interface BftsmartNodeSettings extends NodeSettings { | |||
| /** | |||
| * 节点所属的参与方的区块链地址; | |||
| */ | |||
| // @DataField(order = 0, primitiveType = ValueType.TEXT) | |||
| // @Override | |||
| // String getAddress(); | |||
| /** | |||
| * Base58 格式的公钥; | |||
| * | |||
| * @return | |||
| */ | |||
| // @DataField(order = 1, primitiveType = ValueType.BYTES) | |||
| // PubKey getPubKey(); | |||
| /** | |||
| * 节点的ID; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 2, primitiveType = PrimitiveType.INT32) | |||
| int getId(); | |||
| /** | |||
| * 共识协议的网络地址; | |||
| * | |||
| * @return | |||
| */ | |||
| @DataField(order = 3, primitiveType = PrimitiveType.BYTES) | |||
| NetworkAddress getNetworkAddress(); | |||
| } | |||
| @@ -1,73 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.consensus.*; | |||
| import com.jd.blockchain.utils.io.BytesEncoder; | |||
| public class BftsmartSettingsFactory implements SettingsFactory { | |||
| private static ConsensusSettingsEncoder CS_ENCODER = new ConsensusSettingsEncoder(); | |||
| private static ClientIncomingSettingsEncoder CI_ENCODER =new ClientIncomingSettingsEncoder(); | |||
| static { | |||
| DataContractRegistry.register(BftsmartConsensusSettings.class); | |||
| DataContractRegistry.register(BftsmartClientIncomingSettings.class); | |||
| } | |||
| @Override | |||
| public BftsmartConsensusSettingsBuilder getConsensusSettingsBuilder() { | |||
| return new BftsmartConsensusSettingsBuilder(); | |||
| } | |||
| @Override | |||
| public BytesEncoder<ConsensusSettings> getConsensusSettingsEncoder() { | |||
| return CS_ENCODER; | |||
| } | |||
| @Override | |||
| public BytesEncoder<ClientIncomingSettings> getIncomingSettingsEncoder() { | |||
| return CI_ENCODER; | |||
| } | |||
| private static class ConsensusSettingsEncoder implements BytesEncoder<ConsensusSettings>{ | |||
| @Override | |||
| public byte[] encode(ConsensusSettings data) { | |||
| if (data instanceof BftsmartConsensusSettings) { | |||
| return BinaryProtocol.encode(data, BftsmartConsensusSettings.class); | |||
| } | |||
| throw new IllegalArgumentException("Settings data isn't supported! Accept BftsmartConsensusSettings only!"); | |||
| } | |||
| @Override | |||
| public ConsensusSettings decode(byte[] bytes) { | |||
| return BinaryProtocol.decodeAs(bytes, BftsmartConsensusSettings.class); | |||
| } | |||
| } | |||
| private static class ClientIncomingSettingsEncoder implements BytesEncoder<ClientIncomingSettings>{ | |||
| @Override | |||
| public byte[] encode(ClientIncomingSettings data) { | |||
| if (data instanceof BftsmartClientIncomingSettings) { | |||
| return BinaryProtocol.encode(data, BftsmartClientIncomingSettings.class); | |||
| } | |||
| throw new IllegalArgumentException("Settings data isn't supported! Accept BftsmartClientIncomingSettings only!"); | |||
| } | |||
| @Override | |||
| public ClientIncomingSettings decode(byte[] bytes) { | |||
| return BinaryProtocol.decodeAs(bytes, BftsmartClientIncomingSettings.class); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart; | |||
| import bftsmart.reconfiguration.views.View; | |||
| import com.jd.blockchain.consensus.Topology; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| public class BftsmartTopology implements Topology { | |||
| private static final long serialVersionUID = -3042599438265726240L; | |||
| private View view; | |||
| public BftsmartTopology(View view){ | |||
| this.view = view; | |||
| } | |||
| @Override | |||
| public int getId() { | |||
| return view.getId(); | |||
| } | |||
| @Override | |||
| public Topology copyOf() { | |||
| return BinarySerializeUtils.copyOf(this); | |||
| } | |||
| public View getView() { | |||
| return view; | |||
| } | |||
| } | |||
| @@ -1,16 +0,0 @@ | |||
| //package com.jd.blockchain.consensus.bftsmart; | |||
| // | |||
| //public enum BftsmartTransactionType { | |||
| // TRANSACTION((int)0), | |||
| // COMMITBLOCK((int)1); | |||
| // | |||
| // public final int CODE; | |||
| // | |||
| // public int getCode() { | |||
| // return CODE; | |||
| // } | |||
| // private BftsmartTransactionType(int code) { | |||
| // this.CODE = code; | |||
| // } | |||
| // | |||
| //} | |||
| @@ -1,79 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartClientIncomingSettings; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| public class BftsmartClientConfig implements BftsmartClientSettings { | |||
| private int clientId; | |||
| private PubKey clientPubkey; | |||
| private ConsensusSettings consensusSettings; | |||
| private byte[] topology; | |||
| private byte[] tomConfig; | |||
| BftsmartClientIncomingSettings clientIncomingSettings; | |||
| public BftsmartClientConfig(int clientId, PubKey clientPubkey, ConsensusSettings consensusSettings, byte[] topology, byte[] tomConfig) { | |||
| this.clientId = clientId; | |||
| this.clientPubkey = clientPubkey; | |||
| this.consensusSettings = consensusSettings; | |||
| this.topology = topology; | |||
| this.tomConfig = tomConfig; | |||
| } | |||
| public BftsmartClientConfig(BftsmartClientIncomingSettings clientIncomingSettings) { | |||
| this.clientIncomingSettings = clientIncomingSettings; | |||
| this.clientId = clientIncomingSettings.getClientId(); | |||
| this.clientPubkey = clientIncomingSettings.getPubKey(); | |||
| this.consensusSettings = clientIncomingSettings.getConsensusSettings(); | |||
| this.topology = clientIncomingSettings.getTopology(); | |||
| this.tomConfig = clientIncomingSettings.getTomConfig(); | |||
| } | |||
| @Override | |||
| public int getClientId() { | |||
| return clientId; | |||
| } | |||
| public void setClientId(int clientId) { | |||
| this.clientId = clientId; | |||
| } | |||
| @Override | |||
| public PubKey getClientPubKey() { | |||
| return clientPubkey; | |||
| } | |||
| public void setClientPubkey(PubKey clientPubkey) { | |||
| this.clientPubkey = clientPubkey; | |||
| } | |||
| @Override | |||
| public ConsensusSettings getConsensusSettings() { | |||
| return consensusSettings; | |||
| } | |||
| public void setConsensusSettings(ConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| } | |||
| public byte[] getTopology() { | |||
| return topology; | |||
| } | |||
| public void setTopology(byte[] topology) { | |||
| this.topology = topology; | |||
| } | |||
| @Override | |||
| public byte[] getTomConfig() { | |||
| return tomConfig; | |||
| } | |||
| public void setTomConfig(byte[] tomConfig) { | |||
| this.tomConfig = tomConfig; | |||
| } | |||
| } | |||
| @@ -1,56 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import com.jd.blockchain.consensus.ClientIdentification; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureDigest; | |||
| public class BftsmartClientIdentification implements ClientIdentification { | |||
| private byte[] identityInfo; | |||
| private PubKey pubKey; | |||
| private SignatureDigest signatureDigest; | |||
| public BftsmartClientIdentification() { | |||
| } | |||
| public BftsmartClientIdentification(ClientIdentification clientIdentification) { | |||
| identityInfo = clientIdentification.getIdentityInfo(); | |||
| pubKey = clientIdentification.getPubKey(); | |||
| signatureDigest = clientIdentification.getSignature(); | |||
| } | |||
| @Override | |||
| public byte[] getIdentityInfo() { | |||
| return identityInfo; | |||
| } | |||
| public void setIdentityInfo(byte[] identityInfo) { | |||
| this.identityInfo = identityInfo; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| public void setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| } | |||
| @Override | |||
| public SignatureDigest getSignature() { | |||
| return signatureDigest; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return BftsmartConsensusProvider.NAME; | |||
| } | |||
| public void setSignatureDigest(SignatureDigest signatureDigest) { | |||
| this.signatureDigest = signatureDigest; | |||
| } | |||
| } | |||
| @@ -1,12 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| public interface BftsmartClientSettings extends ClientSettings { | |||
| byte[] getTopology(); | |||
| byte[] getTomConfig(); | |||
| } | |||
| @@ -1,129 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import com.jd.blockchain.consensus.MessageService; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| import com.jd.blockchain.consensus.client.ConsensusClient; | |||
| import java.util.concurrent.atomic.AtomicInteger; | |||
| public class BftsmartConsensusClient implements ConsensusClient { | |||
| private final AtomicInteger addId = new AtomicInteger(); | |||
| private BftsmartPeerProxyPool asyncPeerProxyPool; | |||
| private int gatewayId; | |||
| private ClientSettings clientSettings; | |||
| public BftsmartConsensusClient(ClientSettings clientSettings) { | |||
| this.clientSettings = clientSettings; | |||
| this.gatewayId = clientSettings.getClientId(); | |||
| } | |||
| public BftsmartPeerProxyPool getConsensusClientPool() { | |||
| return this.asyncPeerProxyPool; | |||
| } | |||
| @Override | |||
| public MessageService getMessageService() { | |||
| return new BftsmartMessageService(asyncPeerProxyPool); | |||
| } | |||
| @Override | |||
| public ClientSettings getSettings() { | |||
| return clientSettings; | |||
| } | |||
| @Override | |||
| public boolean isConnected() { | |||
| return this.asyncPeerProxyPool != null; | |||
| } | |||
| @Override | |||
| public synchronized void connect() { | |||
| //consensus client pool | |||
| BftsmartPeerProxyFactory peerProxyFactory = new BftsmartPeerProxyFactory((BftsmartClientSettings)clientSettings, gatewayId); | |||
| this.asyncPeerProxyPool = new BftsmartPeerProxyPool(peerProxyFactory); | |||
| // MemoryBasedViewStorage viewStorage = new MemoryBasedViewStorage(((BftsmartClientSettings)clientSettings).getTopology().getView()); | |||
| // TOMConfiguration tomConfiguration = ((BftsmartConsensusConfig)clientSettings.getConsensusSettings()).getBftsmartConfig(); | |||
| // | |||
| // //by serialize keep origin tom config | |||
| // byte[] tomBytes = BinarySerializeUtils.serialize(tomConfiguration); | |||
| // TOMConfiguration decodeTom = BinarySerializeUtils.deserialize(tomBytes); | |||
| // | |||
| // int clientId = gatewayId *100 + addId.incrementAndGet(); | |||
| // | |||
| // //every proxy client has unique id; | |||
| // decodeTom.setProcessId(clientId); | |||
| // this.peerProxy = new AsynchServiceProxy(decodeTom, viewStorage); | |||
| } | |||
| @Override | |||
| public void close() { | |||
| if (asyncPeerProxyPool != null) { | |||
| asyncPeerProxyPool.close(); | |||
| } | |||
| } | |||
| // public void asyncSendOrdered(byte[] message, AsyncCallback<byte[]> callback) { | |||
| // AsyncReplier replier = new AsyncReplier(callback, peerProxy); | |||
| // peerProxy.invokeAsynchRequest(message, replier, TOMMessageType.ORDERED_REQUEST); | |||
| // } | |||
| // private static class AsyncReplier implements ReplyListener { | |||
| // | |||
| // private AsynchServiceProxy peerProxy; | |||
| // | |||
| // private AtomicInteger replies = new AtomicInteger(0); | |||
| // | |||
| // private AsyncCallback<byte[]> messageHandle; | |||
| // | |||
| // public AsyncReplier(AsyncCallback<byte[]> messageHandle, AsynchServiceProxy peerProxy) { | |||
| // this.messageHandle = messageHandle; | |||
| // this.peerProxy = peerProxy; | |||
| // } | |||
| // | |||
| // @Override | |||
| // public void reset() { | |||
| // replies.set(0); | |||
| // } | |||
| // | |||
| // @Override | |||
| // public void replyReceived(RequestContext context, TOMMessage reply) { | |||
| // int replyCount = replies.incrementAndGet(); | |||
| // | |||
| // double q = Math.ceil((double) (peerProxy.getViewManager().getCurrentViewN() | |||
| // + peerProxy.getViewManager().getCurrentViewF() + 1) / 2.0); | |||
| // | |||
| // if (replyCount >= q) { | |||
| // peerProxy.cleanAsynchRequest(context.getOperationId()); | |||
| // messageHandle.complete(reply.getContent(), null); | |||
| // } | |||
| // } | |||
| // | |||
| // } | |||
| // private static class BftsmartAsyncFuture<T> extends CompletableAsyncFuture<T> { | |||
| // @Override | |||
| // public void setSuccess(T value) { | |||
| // super.setSuccess(value); | |||
| // } | |||
| // | |||
| // @Override | |||
| // public void setError(Throwable ex) { | |||
| // super.setError(ex); | |||
| // } | |||
| // | |||
| // @Override | |||
| // public void setError(String errorCode) { | |||
| // super.setError(errorCode); | |||
| // } | |||
| // } | |||
| } | |||
| @@ -1,133 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import java.util.concurrent.atomic.AtomicInteger; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.ConsensusManageService; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.client.ClientFactory; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| import com.jd.blockchain.consensus.client.ConsensusClient; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.PrivKey; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureDigest; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| public class BftsmartConsensusClientFactory implements ClientFactory { | |||
| private AtomicInteger addId = new AtomicInteger(); | |||
| private String localDomain = "localhost"; | |||
| private String localIp = "127.0.0.1"; | |||
| public BftsmartConsensusClientFactory() { | |||
| } | |||
| @Override | |||
| public BftsmartClientIdentification buildAuthId(AsymmetricKeypair clientKeyPair) { | |||
| PubKey pubKey = clientKeyPair.getPubKey(); | |||
| PrivKey privKey = clientKeyPair.getPrivKey(); | |||
| SignatureFunction signatureFunction =Crypto.getSignatureFunction(pubKey.getAlgorithm()); | |||
| SignatureDigest signatureDigest = signatureFunction.sign(privKey, pubKey.toBytes()); | |||
| BftsmartClientIdentification bftsmartClientIdentification = new BftsmartClientIdentification(); | |||
| bftsmartClientIdentification.setIdentityInfo(pubKey.toBytes()); | |||
| bftsmartClientIdentification.setPubKey(pubKey); | |||
| bftsmartClientIdentification.setSignatureDigest(signatureDigest); | |||
| return bftsmartClientIdentification; | |||
| } | |||
| @Override | |||
| public ClientSettings buildClientSettings(ClientIncomingSettings incomingSettings) { | |||
| BftsmartClientIncomingSettings clientIncomingSettings = (BftsmartClientIncomingSettings) incomingSettings; | |||
| BftsmartClientSettings clientSettings = new BftsmartClientConfig(clientIncomingSettings); | |||
| return clientSettings; | |||
| } | |||
| @Override | |||
| public ConsensusClient setupClient(ClientSettings settings) { | |||
| return new BftsmartConsensusClient(settings); | |||
| } | |||
| @Override | |||
| public ConsensusManageService createManageServiceClient(String[] serviceNodes) { | |||
| // BftsmartConsensusManageService consensusManageService = null; | |||
| // BftsmartClientIncomingSettings clientIncomingSettings; | |||
| // | |||
| // | |||
| // try { | |||
| // if (serviceNodes == null) { | |||
| // throw new ConsensusSecurityException("createManageServiceClient param error!"); | |||
| // } | |||
| // | |||
| // for (int i = 0; i < serviceNodes.length; i++) { | |||
| // | |||
| // NetworkAddress networkAddress = getIpPortFromUrl(serviceNodes[i]); | |||
| // if (networkAddress == null) { | |||
| // continue; | |||
| // } | |||
| // ServiceEndpoint peerServer = new ServiceEndpoint(networkAddress.getHost(), networkAddress.getPort(), false); | |||
| // consensusManageService = HttpServiceAgent.createService(BftsmartConsensusManageService.class, peerServer); | |||
| // clientIncomingSettings = consensusManageService.authClientIncoming(clientIdentification); | |||
| // | |||
| // if (clientIncomingSettings == null) { | |||
| // consensusManageService = null; | |||
| // } else { | |||
| // //认证成功 | |||
| // break; | |||
| // } | |||
| // } | |||
| // | |||
| // } catch (Exception e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // return consensusManageService; | |||
| return null; | |||
| } | |||
| private NetworkAddress getIpPortFromUrl(String url) { | |||
| // 1.check null | |||
| if (url == null || url.trim().equals("")) { | |||
| return null; | |||
| } | |||
| // 2. localhost replace to 127.0.0.1 | |||
| if(url.startsWith("http://" + localDomain) ){ | |||
| url = url.replace("http://" + localDomain, "http://" + localIp) ; | |||
| } | |||
| String host = ""; | |||
| Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+(:\\d{0,5})?"); | |||
| Matcher matcher = p.matcher(url); | |||
| if (matcher.find()) { | |||
| host = matcher.group() ; | |||
| } | |||
| if(host.contains(":") == false){ | |||
| //default port :80 | |||
| return new NetworkAddress(host, 80); | |||
| } | |||
| else { | |||
| String[] ipPortArr = host.split(":"); | |||
| return new NetworkAddress(ipPortArr[0], Integer.parseInt(ipPortArr[1])); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,73 +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 { | |||
| 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,47 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import bftsmart.reconfiguration.util.TOMConfiguration; | |||
| import bftsmart.reconfiguration.views.MemoryBasedViewStorage; | |||
| import bftsmart.tom.AsynchServiceProxy; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusConfig; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartTopology; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| import org.apache.commons.pool2.BasePooledObjectFactory; | |||
| import org.apache.commons.pool2.PooledObject; | |||
| import org.apache.commons.pool2.impl.DefaultPooledObject; | |||
| import java.util.concurrent.atomic.AtomicInteger; | |||
| public class BftsmartPeerProxyFactory extends BasePooledObjectFactory<AsynchServiceProxy> { | |||
| private BftsmartClientSettings bftsmartClientSettings; | |||
| private int gatewayId; | |||
| private AtomicInteger index = new AtomicInteger(1); | |||
| public BftsmartPeerProxyFactory(BftsmartClientSettings bftsmartClientSettings, int gatewayId) { | |||
| this.bftsmartClientSettings = bftsmartClientSettings; | |||
| this.gatewayId = gatewayId; | |||
| } | |||
| @Override | |||
| public AsynchServiceProxy create() throws Exception { | |||
| BftsmartTopology topology = BinarySerializeUtils.deserialize(bftsmartClientSettings.getTopology()); | |||
| MemoryBasedViewStorage viewStorage = new MemoryBasedViewStorage(topology.getView()); | |||
| TOMConfiguration tomConfiguration = BinarySerializeUtils.deserialize(bftsmartClientSettings.getTomConfig()); | |||
| //every proxy client has unique id; | |||
| tomConfiguration.setProcessId(gatewayId + index.getAndIncrement()); | |||
| AsynchServiceProxy peerProxy = new AsynchServiceProxy(tomConfiguration, viewStorage); | |||
| return peerProxy; | |||
| } | |||
| @Override | |||
| public PooledObject<AsynchServiceProxy> wrap(AsynchServiceProxy asynchServiceProxy) { | |||
| return new DefaultPooledObject<>(asynchServiceProxy); | |||
| } | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.bft.BftsmartConsensusClientPool | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/10/30 下午6:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import bftsmart.tom.AsynchServiceProxy; | |||
| import org.apache.commons.pool2.PooledObjectFactory; | |||
| import org.apache.commons.pool2.impl.GenericObjectPool; | |||
| import org.apache.commons.pool2.impl.GenericObjectPoolConfig; | |||
| public class BftsmartPeerProxyPool extends GenericObjectPool<AsynchServiceProxy> { | |||
| public BftsmartPeerProxyPool(PooledObjectFactory<AsynchServiceProxy> factory) { | |||
| this(factory, null); | |||
| } | |||
| public BftsmartPeerProxyPool(PooledObjectFactory<AsynchServiceProxy> factory, GenericObjectPoolConfig config) { | |||
| super(factory, config == null ? new BftsmartPeerProxyPoolConfig() : config); | |||
| } | |||
| } | |||
| @@ -1,32 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.bft.BftsmartConsensusClientPool | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/10/30 下午6:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.bftsmart.client; | |||
| import org.apache.commons.pool2.impl.GenericObjectPoolConfig; | |||
| public class BftsmartPeerProxyPoolConfig extends GenericObjectPoolConfig { | |||
| public static final int MAX_TOTAL = 100; | |||
| private final int MIN_IDLE = 0; | |||
| private final int MAX_IDLE = 100; | |||
| public BftsmartPeerProxyPoolConfig() { | |||
| setMaxTotal(MAX_TOTAL); | |||
| setMinIdle(MIN_IDLE); | |||
| setMaxIdle(MAX_IDLE); | |||
| } | |||
| public BftsmartPeerProxyPoolConfig(int maxTotal, int minIdle, int maxIdle) { | |||
| setMaxTotal(maxTotal); | |||
| setMinIdle(minIdle); | |||
| setMaxIdle(maxIdle); | |||
| } | |||
| } | |||
| @@ -1,71 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.service; | |||
| import java.util.concurrent.locks.Lock; | |||
| import java.util.concurrent.locks.ReentrantLock; | |||
| import com.jd.blockchain.consensus.ClientIdentification; | |||
| import com.jd.blockchain.consensus.ConsensusManageService; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartClientIncomingConfig; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartClientIncomingSettings; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| public class BftsmartConsensusManageService implements ConsensusManageService { | |||
| public static final int GATEWAY_SIZE = 100; | |||
| public static final int CLIENT_SIZE_PER_GATEWAY = 1000; | |||
| public static final int CLIENT_RANGE = GATEWAY_SIZE * CLIENT_SIZE_PER_GATEWAY; | |||
| private BftsmartNodeServer nodeServer; | |||
| private int clientId; | |||
| private static final Lock authLock = new ReentrantLock(); | |||
| public BftsmartConsensusManageService(BftsmartNodeServer nodeServer) { | |||
| this.nodeServer = nodeServer; | |||
| // Assume that each peer node corresponds to up to 100 gateways | |||
| clientId = nodeServer.getServerId() * CLIENT_RANGE; | |||
| } | |||
| @Override | |||
| public BftsmartClientIncomingSettings authClientIncoming(ClientIdentification authId) { | |||
| if (verify(authId)) { | |||
| BftsmartClientIncomingConfig clientIncomingSettings = new BftsmartClientIncomingConfig(); | |||
| clientIncomingSettings | |||
| .setTopology(BinarySerializeUtils.serialize(nodeServer.getTopology())); | |||
| clientIncomingSettings | |||
| .setTomConfig(BinarySerializeUtils.serialize(nodeServer.getTomConfig())); | |||
| clientIncomingSettings | |||
| .setConsensusSettings(nodeServer.getConsensusSetting()); | |||
| clientIncomingSettings.setPubKey(authId.getPubKey()); | |||
| // compute gateway id | |||
| authLock.lock(); | |||
| try { | |||
| clientIncomingSettings.setClientId(clientId++); | |||
| clientId += CLIENT_SIZE_PER_GATEWAY; | |||
| } finally { | |||
| authLock.unlock(); | |||
| } | |||
| return clientIncomingSettings; | |||
| } | |||
| return null; | |||
| } | |||
| public boolean verify(ClientIdentification authId) { | |||
| SignatureFunction signatureFunction = Crypto | |||
| .getSignatureFunction(authId.getPubKey().getAlgorithm()); | |||
| return signatureFunction.verify(authId.getSignature(), authId.getPubKey(), authId.getIdentityInfo()); | |||
| } | |||
| } | |||
| @@ -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, sysConfClone, BinarySerializeUtils.deserialize(serialHostConf)); | |||
| } | |||
| @Override | |||
| public ConsensusManageService getManageService() { | |||
| return manageService; | |||
| } | |||
| @Override | |||
| public ServerSettings getSettings() { | |||
| return serverSettings; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return BftsmartConsensusProvider.NAME; | |||
| } | |||
| public TOMConfiguration getTomConfig() { | |||
| return outerTomConfig; | |||
| } | |||
| 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,110 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.service; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartNodeSettings; | |||
| import com.jd.blockchain.consensus.service.MessageHandle; | |||
| import com.jd.blockchain.consensus.service.NodeServer; | |||
| import com.jd.blockchain.consensus.service.NodeServerFactory; | |||
| import com.jd.blockchain.consensus.service.ServerSettings; | |||
| import com.jd.blockchain.consensus.service.StateMachineReplicate; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| import java.util.Arrays; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| public class BftsmartNodeServerFactory implements NodeServerFactory { | |||
| private static Map<String, NodeSettings[]> nodeServerMap = new ConcurrentHashMap<>(); | |||
| @Override | |||
| public ServerSettings buildServerSettings(String realmName, ConsensusSettings consensusSetting, String currentNodeAddress) { | |||
| NodeSettings serverNode = null; | |||
| BftsmartServerSettingConfig serverSettings = new BftsmartServerSettingConfig(); | |||
| //find current node according to current address | |||
| for (NodeSettings nodeSettings : consensusSetting.getNodes()) { | |||
| if (nodeSettings.getAddress().equals(currentNodeAddress)) { | |||
| serverNode = nodeSettings; | |||
| break; | |||
| } | |||
| } | |||
| if (serverNode == null) { | |||
| throw new IllegalArgumentException(); | |||
| } | |||
| //set server settings | |||
| serverSettings.setRealmName(realmName); | |||
| serverSettings.setReplicaSettings(serverNode); | |||
| serverSettings.setConsensusSettings((BftsmartConsensusSettings) consensusSetting); | |||
| return serverSettings; | |||
| } | |||
| @Override | |||
| public NodeServer setupServer(ServerSettings serverSettings, MessageHandle messageHandler, | |||
| StateMachineReplicate stateMachineReplicator) { | |||
| NodeSettings[] currNodeSettings = (((BftsmartServerSettings)serverSettings).getConsensusSettings()).getNodes(); | |||
| //check conflict realm | |||
| if (!hasIntersection(currNodeSettings)) { | |||
| BftsmartNodeServer nodeServer = new BftsmartNodeServer(serverSettings, messageHandler, stateMachineReplicator); | |||
| nodeServerMap.put(serverSettings.getRealmName(), currNodeSettings); | |||
| return nodeServer; | |||
| } | |||
| else { | |||
| throw new IllegalArgumentException("setupServer serverSettings parameters error!"); | |||
| } | |||
| } | |||
| //check if consensus realm conflict, by this support multi ledgers | |||
| private boolean hasIntersection(NodeSettings[] currNodeSettings) { | |||
| int currHashCode = getHashcode(currNodeSettings); | |||
| //first check if is same consensus realm | |||
| for (NodeSettings[] exisitNodeSettings : nodeServerMap.values()) { | |||
| if (currHashCode == getHashcode(exisitNodeSettings)) { | |||
| return false; | |||
| } | |||
| } | |||
| //check conflict | |||
| for (NodeSettings[] exisitNodeSettings : nodeServerMap.values()) { | |||
| for (NodeSettings curr : currNodeSettings) { | |||
| for (NodeSettings exist : exisitNodeSettings) { | |||
| if (((BftsmartNodeSettings)curr).getNetworkAddress().equals(((BftsmartNodeSettings)exist).getNetworkAddress())) { | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| //compute hashcode for consensus nodes | |||
| private int getHashcode(NodeSettings[] nodeSettings) { | |||
| int i = 0; | |||
| NetworkAddress[] nodeAddrs = new NetworkAddress[nodeSettings.length]; | |||
| for (NodeSettings setting : nodeSettings) { | |||
| nodeAddrs[i++] = ((BftsmartNodeSettings)setting).getNetworkAddress(); | |||
| } | |||
| int hashCode = Arrays.hashCode(nodeAddrs); | |||
| return hashCode; | |||
| } | |||
| } | |||
| @@ -1,40 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.service; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusSettings; | |||
| public class BftsmartServerSettingConfig implements BftsmartServerSettings { | |||
| private NodeSettings replicaSettings; | |||
| private String realmName; | |||
| private BftsmartConsensusSettings consensusSettings; | |||
| @Override | |||
| public String getRealmName() { | |||
| return realmName; | |||
| } | |||
| public void setRealmName(String realmName) { | |||
| this.realmName = realmName; | |||
| } | |||
| @Override | |||
| public NodeSettings getReplicaSettings() { | |||
| return replicaSettings; | |||
| } | |||
| public void setReplicaSettings(NodeSettings replicaSettings) { | |||
| this.replicaSettings = replicaSettings; | |||
| } | |||
| @Override | |||
| public BftsmartConsensusSettings getConsensusSettings() { | |||
| return consensusSettings; | |||
| } | |||
| public void setConsensusSettings(BftsmartConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| } | |||
| } | |||
| @@ -1,10 +0,0 @@ | |||
| package com.jd.blockchain.consensus.bftsmart.service; | |||
| import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusSettings; | |||
| import com.jd.blockchain.consensus.service.ServerSettings; | |||
| public interface BftsmartServerSettings extends ServerSettings { | |||
| BftsmartConsensusSettings getConsensusSettings(); | |||
| } | |||
| @@ -1,144 +0,0 @@ | |||
| # Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| ############################################ | |||
| ####### Communication Configurations ####### | |||
| ############################################ | |||
| #HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) | |||
| #This parameter is not currently being used being used | |||
| #system.authentication.hmacAlgorithm = HmacSHA1 | |||
| #Specify if the communication system should use a thread to send data (true or false) | |||
| system.communication.useSenderThread = true | |||
| #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments | |||
| #and benchmarks, but must not be used in production systems. | |||
| system.communication.defaultkeys = true | |||
| ############################################ | |||
| ### Replication Algorithm Configurations ### | |||
| ############################################ | |||
| #Timeout to asking for a client request | |||
| system.totalordermulticast.timeout = 2000 | |||
| #Maximum batch size (in number of messages) | |||
| system.totalordermulticast.maxbatchsize = 400 | |||
| #Number of nonces (for non-determinism actions) generated | |||
| system.totalordermulticast.nonces = 10 | |||
| #if verification of leader-generated timestamps are increasing | |||
| #it can only be used on systems in which the network clocks | |||
| #are synchronized | |||
| system.totalordermulticast.verifyTimestamps = false | |||
| #Quantity of messages that can be stored in the receive queue of the communication system | |||
| system.communication.inQueueSize = 500000 | |||
| # Quantity of messages that can be stored in the send queue of each replica | |||
| system.communication.outQueueSize = 500000 | |||
| #Set to 1 if SMaRt should use signatures, set to 0 if otherwise | |||
| system.communication.useSignatures = 0 | |||
| #Set to 1 if SMaRt should use MAC's, set to 0 if otherwise | |||
| system.communication.useMACs = 1 | |||
| #Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise | |||
| system.debug = 0 | |||
| #Print information about the replica when it is shutdown | |||
| system.shutdownhook = true | |||
| ############################################ | |||
| ###### State Transfer Configurations ####### | |||
| ############################################ | |||
| #Activate the state transfer protocol ('true' to activate, 'false' to de-activate) | |||
| system.totalordermulticast.state_transfer = true | |||
| #Maximum ahead-of-time message not discarded | |||
| system.totalordermulticast.highMark = 10000 | |||
| #Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) | |||
| system.totalordermulticast.revival_highMark = 10 | |||
| #Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs | |||
| system.totalordermulticast.timeout_highMark = 200 | |||
| ############################################ | |||
| ###### Log and Checkpoint Configurations ### | |||
| ############################################ | |||
| system.totalordermulticast.log = true | |||
| system.totalordermulticast.log_parallel = false | |||
| system.totalordermulticast.log_to_disk = false | |||
| system.totalordermulticast.sync_log = false | |||
| #Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) | |||
| system.totalordermulticast.checkpoint_period = 1000 | |||
| system.totalordermulticast.global_checkpoint_period = 120000 | |||
| system.totalordermulticast.checkpoint_to_disk = false | |||
| system.totalordermulticast.sync_ckp = false | |||
| ############################################ | |||
| ###### Reconfiguration Configurations ###### | |||
| ############################################ | |||
| #The ID of the trust third party (TTP) | |||
| system.ttp.id = 7002 | |||
| #This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults | |||
| system.bft = true | |||
| #Custom View Storage; | |||
| #view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage | |||
| #Number of servers in the group | |||
| system.servers.num = 4 | |||
| #Maximum number of faulty replicas | |||
| system.servers.f = 1 | |||
| #Replicas ID for the initial view, separated by a comma. | |||
| # The number of replicas in this parameter should be equal to that specified in 'system.servers.num' | |||
| system.initial.view = 0,1,2,3 | |||
| #Configuration of all node servers; | |||
| #PubKey of node server with specified ID, with base58 encoding. | |||
| system.server.0.pubkey= | |||
| system.server.0.network.host=127.0.0.1 | |||
| system.server.0.network.port=8900 | |||
| system.server.0.network.secure=false | |||
| system.server.1.pubkey= | |||
| system.server.1.network.host=127.0.0.1 | |||
| system.server.1.network.port=8910 | |||
| system.server.1.network.secure=false | |||
| system.server.2.pubkey= | |||
| system.server.2.network.host=127.0.0.1 | |||
| system.server.2.network.port=8920 | |||
| system.server.2.network.secure=false | |||
| system.server.3.pubkey= | |||
| system.server.3.network.host=127.0.0.1 | |||
| system.server.3.network.port=8920 | |||
| system.server.3.network.secure=false | |||
| @@ -1,137 +0,0 @@ | |||
| package test.com.jd.blockchain.consensus.bftsmart; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.bftsmart.*; | |||
| import com.jd.blockchain.consensus.bftsmart.client.BftsmartClientConfig; | |||
| import com.jd.blockchain.consensus.bftsmart.client.BftsmartConsensusClient; | |||
| import com.jd.blockchain.consensus.bftsmart.client.BftsmartMessageService; | |||
| import com.jd.blockchain.consensus.bftsmart.service.BftsmartNodeServer; | |||
| import com.jd.blockchain.consensus.bftsmart.service.BftsmartServerSettingConfig; | |||
| import com.jd.blockchain.consensus.service.ServerSettings; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.BlockchainKeyGenerator; | |||
| import com.jd.blockchain.ledger.BlockchainKeypair; | |||
| import com.jd.blockchain.utils.PropertiesUtils; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; | |||
| import org.junit.Test; | |||
| import org.springframework.core.io.ClassPathResource; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Properties; | |||
| import java.util.Random; | |||
| import java.util.concurrent.CountDownLatch; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| public class ProxyClientTest { | |||
| int number = 1500000; | |||
| int peerStartPort = 11000; | |||
| int nodeNum = 4; | |||
| Random random = new Random(); | |||
| byte[] bytes = null; | |||
| CountDownLatch startPeer = new CountDownLatch(nodeNum); | |||
| private static Properties bftsmartConf; | |||
| private final ExecutorService nodeStartPools = Executors.newCachedThreadPool(); | |||
| private final ExecutorService txSendPools = Executors.newFixedThreadPool(20); | |||
| static { | |||
| ClassPathResource configResource = new ClassPathResource("system.config"); | |||
| try { | |||
| try (InputStream in = configResource.getInputStream()) { | |||
| bftsmartConf = PropertiesUtils.load(in, BytesUtils.DEFAULT_CHARSET); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| public void peerStart(BftsmartNodeServer[] nodeServers) { | |||
| BftsmartNodeSettings[] nodesSettings = new BftsmartNodeSettings[nodeNum]; | |||
| for (int i = 0; i < nodeNum; i++) { | |||
| BlockchainKeypair keyPair = BlockchainKeyGenerator.getInstance().generate(); | |||
| PubKey pubKey = keyPair.getPubKey(); | |||
| NetworkAddress peerNodeServ = new NetworkAddress("127.0.0.1", peerStartPort + i * 10); | |||
| NodeSettings node = new BftsmartNodeConfig(pubKey, i, peerNodeServ); | |||
| nodesSettings[i] = (BftsmartNodeSettings) node; | |||
| } | |||
| BftsmartConsensusConfig consensusConfig = new BftsmartConsensusConfig(nodesSettings, | |||
| // null, | |||
| PropertiesUtils.getOrderedValues(bftsmartConf)); | |||
| for (int j = 0; j < nodeNum; j++) { | |||
| BftsmartServerSettingConfig serverSettings = new BftsmartServerSettingConfig(); | |||
| serverSettings.setReplicaSettings(nodesSettings[j]); | |||
| serverSettings.setConsensusSettings(consensusConfig); | |||
| BftsmartNodeServer server = new BftsmartNodeServer(serverSettings, null, null); | |||
| nodeServers[j] = server; | |||
| nodeStartPools.execute(() -> { | |||
| server.start(); | |||
| startPeer.countDown(); | |||
| }); | |||
| } | |||
| } | |||
| public void proxyClientSend(BftsmartNodeServer nodeServer) { | |||
| BftsmartClientIncomingConfig clientIncomingConfig = new BftsmartClientIncomingConfig(); | |||
| BlockchainKeypair keyPair = BlockchainKeyGenerator.getInstance().generate(); | |||
| clientIncomingConfig.setPubKey(keyPair.getPubKey()); | |||
| clientIncomingConfig.setClientId(0); | |||
| clientIncomingConfig.setConsensusSettings(nodeServer.getConsensusSetting()); | |||
| clientIncomingConfig.setTomConfig(BinarySerializeUtils.serialize(nodeServer.getTomConfig())); | |||
| clientIncomingConfig.setTopology(BinarySerializeUtils.serialize(nodeServer.getTopology())); | |||
| BftsmartClientConfig clientSettings = new BftsmartClientConfig(clientIncomingConfig); | |||
| BftsmartConsensusClient consensusClient = new BftsmartConsensusClient(clientSettings); | |||
| bytes = new byte[1024]; | |||
| BftsmartMessageService messageService = (BftsmartMessageService) consensusClient.getMessageService(); | |||
| for (int j = 0; j < number; j++) { | |||
| txSendPools.execute(() -> { | |||
| random.nextBytes(bytes); | |||
| messageService.sendOrdered(bytes); | |||
| }); | |||
| } | |||
| } | |||
| // @Test | |||
| public void sendTest() { | |||
| BftsmartNodeServer[] nodeServers = new BftsmartNodeServer[nodeNum]; | |||
| //启动服务 | |||
| peerStart(nodeServers); | |||
| try { | |||
| startPeer.await(); | |||
| Thread.sleep(5000); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| proxyClientSend(nodeServers[0]); | |||
| try { | |||
| Thread.sleep(50000); | |||
| System.out.println("send test complete!"); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,178 +0,0 @@ | |||
| # Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| ############################################ | |||
| ###### Consensus Commit Block Parameters: transaction count ###### | |||
| ############################################ | |||
| system.block.txsize=15 | |||
| ############################################ | |||
| ###### Consensus Commit Block Parameters: delay time ###### | |||
| ############################################ | |||
| system.block.maxdelay=500 | |||
| ############################################ | |||
| ###### Consensus Participant0 ###### | |||
| ############################################ | |||
| system.server.0.pubkey=endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna | |||
| system.server.0.network.host=127.0.0.1 | |||
| system.server.0.network.port=8910 | |||
| system.server.0.network.secure=false | |||
| ############################################ | |||
| ###### #Consensus Participant1 ###### | |||
| ############################################ | |||
| system.server.1.pubkey=endPsK36sC5JdPCDPDAXUwZtS3sxEmqEhFcC4whayAsTTh8Z6eoZ | |||
| system.server.1.network.host=127.0.0.1 | |||
| system.server.1.network.port=8920 | |||
| system.server.1.network.secure=false | |||
| ############################################ | |||
| ###### #Consensus Participant2 ###### | |||
| ############################################ | |||
| system.server.2.pubkey=endPsK36jEG281HMHeh6oSqzqLkT95DTnCM6REDURjdb2c67uR3R | |||
| system.server.2.network.host=127.0.0.1 | |||
| system.server.2.network.port=8930 | |||
| system.server.2.network.secure=false | |||
| ############################################ | |||
| ###### Consensus Participant3 ###### | |||
| ############################################ | |||
| system.server.3.pubkey=endPsK36nse1dck4uF19zPvAMijCV336Y3zWdgb4rQG8QoRj5ktR | |||
| system.server.3.network.host=127.0.0.1 | |||
| system.server.3.network.port=8940 | |||
| system.server.3.network.secure=false | |||
| ############################################ | |||
| ####### Communication Configurations ####### | |||
| ############################################ | |||
| #HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) | |||
| #This parameter is not currently being used being used | |||
| #system.authentication.hmacAlgorithm = HmacSHA1 | |||
| #Specify if the communication system should use a thread to send data (true or false) | |||
| system.communication.useSenderThread = true | |||
| #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments | |||
| #and benchmarks, but must not be used in production systems. | |||
| system.communication.defaultkeys = true | |||
| ############################################ | |||
| ### Replication Algorithm Configurations ### | |||
| ############################################ | |||
| #Number of servers in the group | |||
| system.servers.num = 4 | |||
| #Maximum number of faulty replicas | |||
| #system.servers.f = 1 | |||
| #Timeout to asking for a client request | |||
| system.totalordermulticast.timeout = 2000 | |||
| #Maximum batch size (in number of messages) | |||
| system.totalordermulticast.maxbatchsize = 400 | |||
| #Number of nonces (for non-determinism actions) generated | |||
| system.totalordermulticast.nonces = 10 | |||
| #if verification of leader-generated timestamps are increasing | |||
| #it can only be used on systems in which the network clocks | |||
| #are synchronized | |||
| system.totalordermulticast.verifyTimestamps = false | |||
| #Quantity of messages that can be stored in the receive queue of the communication system | |||
| system.communication.inQueueSize = 500000 | |||
| # Quantity of messages that can be stored in the send queue of each replica | |||
| system.communication.outQueueSize = 500000 | |||
| #Set to 1 if SMaRt should use signatures, set to 0 if otherwise | |||
| system.communication.useSignatures = 0 | |||
| #Set to 1 if SMaRt should use MAC's, set to 0 if otherwise | |||
| system.communication.useMACs = 1 | |||
| #Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise | |||
| system.debug = 0 | |||
| #Print information about the replica when it is shutdown | |||
| system.shutdownhook = true | |||
| ############################################ | |||
| ###### State Transfer Configurations ####### | |||
| ############################################ | |||
| #Activate the state transfer protocol ('true' to activate, 'false' to de-activate) | |||
| system.totalordermulticast.state_transfer = true | |||
| #Maximum ahead-of-time message not discarded | |||
| system.totalordermulticast.highMark = 10000 | |||
| #Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) | |||
| system.totalordermulticast.revival_highMark = 10 | |||
| #Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs | |||
| system.totalordermulticast.timeout_highMark = 200 | |||
| ############################################ | |||
| ###### Log and Checkpoint Configurations ### | |||
| ############################################ | |||
| system.totalordermulticast.log = true | |||
| system.totalordermulticast.log_parallel = false | |||
| system.totalordermulticast.log_to_disk = false | |||
| system.totalordermulticast.sync_log = false | |||
| #Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) | |||
| system.totalordermulticast.checkpoint_period = 1000 | |||
| system.totalordermulticast.global_checkpoint_period = 120000 | |||
| system.totalordermulticast.checkpoint_to_disk = false | |||
| system.totalordermulticast.sync_ckp = false | |||
| ############################################ | |||
| ###### Reconfiguration Configurations ###### | |||
| ############################################ | |||
| #Replicas ID for the initial view, separated by a comma. | |||
| # The number of replicas in this parameter should be equal to that specified in 'system.servers.num' | |||
| #system.initial.view = 0,1,2,3 | |||
| #The ID of the trust third party (TTP) | |||
| system.ttp.id = 7002 | |||
| #This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults | |||
| system.bft = true | |||
| #Custom View Storage; | |||
| #view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage | |||
| @@ -1,121 +0,0 @@ | |||
| # Copyright (c) 2007-2013 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags | |||
| # | |||
| # Licensed under the Apache License, Version 2.0 (the "License"); | |||
| # you may not use this file except in compliance with the License. | |||
| # You may obtain a copy of the License at | |||
| # | |||
| # http://www.apache.org/licenses/LICENSE-2.0 | |||
| # | |||
| # Unless required by applicable law or agreed to in writing, software | |||
| # distributed under the License is distributed on an "AS IS" BASIS, | |||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| # See the License for the specific language governing permissions and | |||
| # limitations under the License. | |||
| ############################################ | |||
| ####### Communication Configurations ####### | |||
| ############################################ | |||
| #HMAC algorithm used to authenticate messages between processes (HmacMD5 is the default value) | |||
| #This parameter is not currently being used being used | |||
| #system.authentication.hmacAlgorithm = HmacSHA1 | |||
| #Specify if the communication system should use a thread to send data (true or false) | |||
| system.communication.useSenderThread = true | |||
| #Force all processes to use the same public/private keys pair and secret key. This is useful when deploying experiments | |||
| #and benchmarks, but must not be used in production systems. | |||
| system.communication.defaultkeys = true | |||
| ############################################ | |||
| ### Replication Algorithm Configurations ### | |||
| ############################################ | |||
| #Number of servers in the group | |||
| system.servers.num = 4 | |||
| #Maximum number of faulty replicas | |||
| #system.servers.f = 1 | |||
| #Timeout to asking for a client request | |||
| system.totalordermulticast.timeout = 2000 | |||
| #Maximum batch size (in number of messages) | |||
| system.totalordermulticast.maxbatchsize = 400 | |||
| #Number of nonces (for non-determinism actions) generated | |||
| system.totalordermulticast.nonces = 10 | |||
| #if verification of leader-generated timestamps are increasing | |||
| #it can only be used on systems in which the network clocks | |||
| #are synchronized | |||
| system.totalordermulticast.verifyTimestamps = false | |||
| #Quantity of messages that can be stored in the receive queue of the communication system | |||
| system.communication.inQueueSize = 500000 | |||
| # Quantity of messages that can be stored in the send queue of each replica | |||
| system.communication.outQueueSize = 500000 | |||
| #Set to 1 if SMaRt should use signatures, set to 0 if otherwise | |||
| system.communication.useSignatures = 0 | |||
| #Set to 1 if SMaRt should use MAC's, set to 0 if otherwise | |||
| system.communication.useMACs = 1 | |||
| #Set to 1 if SMaRt should use the standard output to display debug messages, set to 0 if otherwise | |||
| system.debug = 0 | |||
| #Print information about the replica when it is shutdown | |||
| system.shutdownhook = true | |||
| ############################################ | |||
| ###### State Transfer Configurations ####### | |||
| ############################################ | |||
| #Activate the state transfer protocol ('true' to activate, 'false' to de-activate) | |||
| system.totalordermulticast.state_transfer = true | |||
| #Maximum ahead-of-time message not discarded | |||
| system.totalordermulticast.highMark = 10000 | |||
| #Maximum ahead-of-time message not discarded when the replica is still on EID 0 (after which the state transfer is triggered) | |||
| system.totalordermulticast.revival_highMark = 10 | |||
| #Number of ahead-of-time messages necessary to trigger the state transfer after a request timeout occurs | |||
| system.totalordermulticast.timeout_highMark = 200 | |||
| ############################################ | |||
| ###### Log and Checkpoint Configurations ### | |||
| ############################################ | |||
| system.totalordermulticast.log = true | |||
| system.totalordermulticast.log_parallel = false | |||
| system.totalordermulticast.log_to_disk = false | |||
| system.totalordermulticast.sync_log = false | |||
| #Period at which BFT-SMaRt requests the state to the application (for the state transfer state protocol) | |||
| system.totalordermulticast.checkpoint_period = 1000 | |||
| system.totalordermulticast.global_checkpoint_period = 120000 | |||
| system.totalordermulticast.checkpoint_to_disk = false | |||
| system.totalordermulticast.sync_ckp = false | |||
| ############################################ | |||
| ###### Reconfiguration Configurations ###### | |||
| ############################################ | |||
| #Replicas ID for the initial view, separated by a comma. | |||
| # The number of replicas in this parameter should be equal to that specified in 'system.servers.num' | |||
| #system.initial.view = 0,1,2,3 | |||
| #The ID of the trust third party (TTP) | |||
| system.ttp.id = 7002 | |||
| #This sets if the system will function in Byzantine or crash-only mode. Set to "true" to support Byzantine faults | |||
| system.bft = true | |||
| #Custom View Storage; | |||
| #view.storage.handler=bftsmart.reconfiguration.views.DefaultViewStorage | |||
| @@ -1,71 +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-core</artifactId> | |||
| <version>1.2.0-SNAPSHOT</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> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,55 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/18 下午2:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq; | |||
| import com.jd.blockchain.consensus.ConsensusProvider; | |||
| import com.jd.blockchain.consensus.SettingsFactory; | |||
| import com.jd.blockchain.consensus.client.ClientFactory; | |||
| import com.jd.blockchain.consensus.mq.client.MsgQueueClientFactory; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueSettingsFactory; | |||
| import com.jd.blockchain.consensus.mq.server.MsgQueueNodeServerFactory; | |||
| import com.jd.blockchain.consensus.service.NodeServerFactory; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/18 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueConsensusProvider implements ConsensusProvider { | |||
| public static final String NAME = MsgQueueConsensusProvider.class.getName(); | |||
| private static MsgQueueSettingsFactory settingsFactory = new MsgQueueSettingsFactory(); | |||
| private static MsgQueueClientFactory clientFactory = new MsgQueueClientFactory(); | |||
| private static MsgQueueNodeServerFactory nodeServerFactory = new MsgQueueNodeServerFactory(); | |||
| @Override | |||
| public String getName() { | |||
| return NAME; | |||
| } | |||
| @Override | |||
| public SettingsFactory getSettingsFactory() { | |||
| return settingsFactory; | |||
| } | |||
| @Override | |||
| public ClientFactory getClientFactory() { | |||
| return clientFactory; | |||
| } | |||
| @Override | |||
| public NodeServerFactory getServerFactory() { | |||
| return nodeServerFactory; | |||
| } | |||
| } | |||
| @@ -1,301 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.MsgQueueConsensusSettingsBuilder | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午1:46 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq; | |||
| import com.jd.blockchain.consensus.ConsensusProviders; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.ConsensusSettingsBuilder; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueBlockConfig; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueConsensusConfig; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueNetworkConfig; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueNodeConfig; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueBlockSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
| import com.jd.blockchain.crypto.AddressEncoding; | |||
| import com.jd.blockchain.crypto.KeyGenUtils; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.ParticipantInfo; | |||
| import com.jd.blockchain.ledger.ParticipantNode; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.PropertiesUtils; | |||
| import com.jd.blockchain.utils.codec.Base58Utils; | |||
| import com.jd.blockchain.utils.io.BytesEncoder; | |||
| import com.jd.blockchain.utils.io.BytesUtils; | |||
| import com.jd.blockchain.utils.io.FileUtils; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| import org.springframework.core.io.ClassPathResource; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Properties; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueConsensusSettingsBuilder implements ConsensusSettingsBuilder { | |||
| private static final String DEFAULT_TOPIC_TX = "tx-topic"; | |||
| private static final String DEFAULT_TOPIC_BL = "bl-topic"; | |||
| private static final String DEFAULT_TOPIC_MSG = "msg-topic"; | |||
| private static final int DEFAULT_TXSIZE = 1000; | |||
| private static final int DEFAULT_MAXDELAY = 1000; | |||
| /** | |||
| * | |||
| */ | |||
| private static final String CONFIG_TEMPLATE_FILE = "mq.config"; | |||
| /** | |||
| * 参数键:节点数量; | |||
| */ | |||
| public static final String SERVER_NUM_KEY = "system.servers.num"; | |||
| /** | |||
| * 参数键格式:节点公钥; | |||
| */ | |||
| public static final String PUBKEY_PATTERN = "system.server.%s.pubkey"; | |||
| public static final String MSG_QUEUE_SERVER = "system.msg.queue.server"; | |||
| public static final String MSG_QUEUE_TOPIC_TX = "system.msg.queue.topic.tx"; | |||
| public static final String MSG_QUEUE_TOPIC_BL = "system.msg.queue.topic.bl"; | |||
| public static final String MSG_QUEUE_TOPIC_MSG = "system.msg.queue.topic.msg"; | |||
| public static final String MSG_QUEUE_BLOCK_TXSIZE = "system.msg.queue.block.txsize"; | |||
| public static final String MSG_QUEUE_BLOCK_MAXDELAY = "system.msg.queue.block.maxdelay"; | |||
| public static final String MSG_QUEUE_PROVIDER = "com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider"; | |||
| private static Properties CONFIG_TEMPLATE; | |||
| static { | |||
| if (FileUtils.existFile(CONFIG_TEMPLATE_FILE)) { | |||
| ClassPathResource configResource = new ClassPathResource(CONFIG_TEMPLATE_FILE); | |||
| try { | |||
| try (InputStream in = configResource.getInputStream()) { | |||
| CONFIG_TEMPLATE = PropertiesUtils.load(in, BytesUtils.DEFAULT_CHARSET); | |||
| } | |||
| } catch (IOException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusSettings createSettings(Properties props, ParticipantNode[] participantNodes) { | |||
| MsgQueueNetworkConfig networkConfig = new MsgQueueNetworkConfig(); | |||
| Properties resolvingProps = PropertiesUtils.cloneFrom(props); | |||
| String server = PropertiesUtils.getProperty(resolvingProps, MSG_QUEUE_SERVER, true); | |||
| if (server == null || server.length()<= 0) { | |||
| throw new IllegalArgumentException(String.format("Property[%s] is empty!", MSG_QUEUE_SERVER)); | |||
| } | |||
| networkConfig.setServer(server) | |||
| .setTxTopic(initProp(resolvingProps, MSG_QUEUE_TOPIC_TX, DEFAULT_TOPIC_TX)) | |||
| .setBlTopic(initProp(resolvingProps, MSG_QUEUE_TOPIC_BL, DEFAULT_TOPIC_BL)) | |||
| .setMsgTopic(initProp(resolvingProps, MSG_QUEUE_TOPIC_MSG, DEFAULT_TOPIC_MSG)) | |||
| ; | |||
| MsgQueueBlockConfig blockConfig = new MsgQueueBlockConfig() | |||
| .setTxSizePerBlock(initProp(resolvingProps, MSG_QUEUE_BLOCK_TXSIZE, DEFAULT_TXSIZE)) | |||
| .setMaxDelayMilliSecondsPerBlock(initProp(resolvingProps, MSG_QUEUE_BLOCK_MAXDELAY, DEFAULT_MAXDELAY)) | |||
| ; | |||
| MsgQueueConsensusConfig consensusConfig = new MsgQueueConsensusConfig() | |||
| .setBlockSettings(blockConfig) | |||
| .setNetworkSettings(networkConfig) | |||
| ; | |||
| // load node settings | |||
| int serversNum = PropertiesUtils.getInt(resolvingProps, SERVER_NUM_KEY); | |||
| for (int i = 0; i < serversNum; i++) { | |||
| int id = i; | |||
| String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | |||
| String base58PubKey = PropertiesUtils.getRequiredProperty(resolvingProps, keyOfPubkey); | |||
| PubKey pubKey = KeyGenUtils.decodePubKey(base58PubKey); | |||
| // PubKey pubKey = new PubKey(Base58Utils.decode(base58PubKey)); | |||
| resolvingProps.remove(keyOfPubkey); | |||
| Bytes address = AddressEncoding.generateAddress(pubKey); | |||
| String networkAddress = address.toBase58(); | |||
| MsgQueueNodeConfig nodeConfig = new MsgQueueNodeConfig() | |||
| .setAddress(networkAddress) | |||
| .setPubKey(pubKey) | |||
| ; | |||
| consensusConfig.addNodeSettings(nodeConfig); | |||
| } | |||
| return consensusConfig; | |||
| } | |||
| private MsgQueueNodeSettings[] nodeSettings(NodeSettings[] nodeSettings, ParticipantInfo participantInfo) { | |||
| MsgQueueNodeSettings msgQueueNodeSettings = new MsgQueueNodeConfig(); | |||
| ((MsgQueueNodeConfig) msgQueueNodeSettings).setAddress(AddressEncoding.generateAddress(participantInfo.getPubKey()).toBase58()); | |||
| ((MsgQueueNodeConfig) msgQueueNodeSettings).setPubKey(participantInfo.getPubKey()); | |||
| MsgQueueNodeSettings[] msgQueuetNodeSettings = new MsgQueueNodeSettings[nodeSettings.length + 1]; | |||
| for (int i = 0; i < nodeSettings.length; i++) { | |||
| msgQueuetNodeSettings[i] = (MsgQueueNodeSettings)nodeSettings[i]; | |||
| } | |||
| msgQueuetNodeSettings[nodeSettings.length] = msgQueueNodeSettings; | |||
| return msgQueuetNodeSettings; | |||
| } | |||
| @Override | |||
| public Bytes updateSettings(Bytes oldConsensusSettings, ParticipantInfo participantInfo) { | |||
| BytesEncoder<ConsensusSettings> consensusEncoder = ConsensusProviders.getProvider(MSG_QUEUE_PROVIDER).getSettingsFactory().getConsensusSettingsEncoder(); | |||
| MsgQueueConsensusSettings consensusSettings = (MsgQueueConsensusSettings) consensusEncoder.decode(oldConsensusSettings.toBytes()); | |||
| MsgQueueNodeSettings[] nodeSettings = nodeSettings(consensusSettings.getNodes(), participantInfo); | |||
| MsgQueueConsensusConfig msgQueueConsensusConfig = new MsgQueueConsensusConfig(); | |||
| for (int i = 0; i < nodeSettings.length; i++) { | |||
| msgQueueConsensusConfig.addNodeSettings(nodeSettings[i]); | |||
| } | |||
| msgQueueConsensusConfig.setBlockSettings(consensusSettings.getBlockSettings()); | |||
| msgQueueConsensusConfig.setNetworkSettings(consensusSettings.getNetworkSettings()); | |||
| // for(int i = 0 ;i < msgQueueConsensusConfig.getNodes().length; i++) { | |||
| // System.out.printf("node addr = %s\r\n", msgQueueConsensusConfig.getNodes()[i].getAddress()); | |||
| // } | |||
| return new Bytes(consensusEncoder.encode(msgQueueConsensusConfig)); | |||
| } | |||
| @Override | |||
| public Properties createPropertiesTemplate() { | |||
| return PropertiesUtils.cloneFrom(CONFIG_TEMPLATE); | |||
| } | |||
| @Override | |||
| public void writeSettings(ConsensusSettings settings, Properties props) { | |||
| if (!(settings instanceof MsgQueueConsensusSettings)) { | |||
| throw new IllegalArgumentException("ConsensusSettings data isn't supported! Accept MsgQueueConsensusSettings only!"); | |||
| } | |||
| MsgQueueConsensusSettings consensusSettings = (MsgQueueConsensusSettings) settings; | |||
| MsgQueueNetworkSettings networkSettings = consensusSettings.getNetworkSettings(); | |||
| if (networkSettings == null || networkSettings.getServer() == null || networkSettings.getServer().length() <= 0) { | |||
| throw new IllegalArgumentException("MsgQueue Consensus server is empty!"); | |||
| } | |||
| String server = networkSettings.getServer(); | |||
| props.setProperty(MSG_QUEUE_SERVER, server); | |||
| String txTopic = networkSettings.getTxTopic(); | |||
| if (txTopic == null || txTopic.length() <= 0) { | |||
| txTopic = DEFAULT_TOPIC_TX; | |||
| } | |||
| props.setProperty(MSG_QUEUE_TOPIC_TX, txTopic); | |||
| String blTopic = networkSettings.getBlTopic(); | |||
| if (blTopic == null || blTopic.length() <= 0) { | |||
| blTopic = DEFAULT_TOPIC_BL; | |||
| } | |||
| props.setProperty(MSG_QUEUE_TOPIC_BL, blTopic); | |||
| String msgTopic = networkSettings.getMsgTopic(); | |||
| if (msgTopic == null || msgTopic.length() <= 0) { | |||
| msgTopic = DEFAULT_TOPIC_MSG; | |||
| } | |||
| props.setProperty(MSG_QUEUE_TOPIC_MSG, msgTopic); | |||
| MsgQueueBlockSettings blockSettings = consensusSettings.getBlockSettings(); | |||
| if (blockSettings == null) { | |||
| props.setProperty(MSG_QUEUE_BLOCK_TXSIZE, DEFAULT_TXSIZE + ""); | |||
| props.setProperty(MSG_QUEUE_BLOCK_MAXDELAY, DEFAULT_MAXDELAY + ""); | |||
| } else { | |||
| int txSize = blockSettings.getTxSizePerBlock(); | |||
| long maxDelay = blockSettings.getMaxDelayMilliSecondsPerBlock(); | |||
| props.setProperty(MSG_QUEUE_BLOCK_TXSIZE, txSize + ""); | |||
| props.setProperty(MSG_QUEUE_BLOCK_MAXDELAY, maxDelay + ""); | |||
| } | |||
| // int serversNum = PropertiesUtils.getInt(props, SERVER_NUM_KEY); | |||
| // if (serversNum > 0) { | |||
| // for (int i = 0; i < serversNum; i++) { | |||
| // int id = i; | |||
| // String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | |||
| // props.remove(keyOfPubkey); | |||
| // | |||
| // String keyOfHost = nodeKey(CONSENSUS_HOST_PATTERN, id); | |||
| // props.remove(keyOfHost); | |||
| // } | |||
| // } | |||
| // | |||
| // NodeSettings[] nodesSettings = consensusSettings.getNodes(); | |||
| // serversNum = nodesSettings.length; | |||
| // props.setProperty(SERVER_NUM_KEY, serversNum + ""); | |||
| // | |||
| // for (int i = 0; i < serversNum; i++) { | |||
| // MsgQueueNodeSettings mqns = (MsgQueueNodeSettings) nodesSettings[i]; | |||
| // int id = i; | |||
| // String keyOfPubkey = nodeKey(PUBKEY_PATTERN, id); | |||
| // props.setProperty(keyOfPubkey, mqns.getPubKey().toBase58()); | |||
| // | |||
| // String keyOfHost = nodeKey(CONSENSUS_HOST_PATTERN, id); | |||
| // props.setProperty(keyOfHost, mqns.getAddress() == null ? "" : mqns.getAddress()); | |||
| // } | |||
| } | |||
| private String initProp(Properties resolvingProps, String key, String defaultVal) { | |||
| try { | |||
| String value = PropertiesUtils.getProperty(resolvingProps, key, true); | |||
| if (value == null || value.length() <= 0) { | |||
| value = defaultVal; | |||
| } | |||
| return value; | |||
| } catch (Exception e) { | |||
| return defaultVal; | |||
| } | |||
| } | |||
| private int initProp(Properties resolvingProps, String key, int defaultVal) { | |||
| try { | |||
| int value = PropertiesUtils.getInt(resolvingProps, key); | |||
| if (value <= 0) { | |||
| value = defaultVal; | |||
| } | |||
| return value; | |||
| } catch (Exception e) { | |||
| return defaultVal; | |||
| } | |||
| } | |||
| private static String nodeKey(String pattern, int id) { | |||
| return String.format(pattern, id); | |||
| } | |||
| } | |||
| @@ -1,311 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.client.DefaultMessageTransmitter | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午3:05 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.client; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| import java.util.concurrent.atomic.AtomicBoolean; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import com.jd.blockchain.consensus.MessageService; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.event.TxBlockedEvent; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.util.MessageConvertUtil; | |||
| import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||
| import com.jd.blockchain.utils.concurrent.CompletableAsyncFuture; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DefaultMessageTransmitter implements MessageTransmitter, MessageService { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMessageTransmitter.class); | |||
| private final ExecutorService messageExecutorArray = Executors.newFixedThreadPool(10); | |||
| // private final ExecutorService blockExecutor = Executors.newSingleThreadExecutor(); | |||
| // | |||
| // private final ExecutorService extendExecutor = Executors.newSingleThreadExecutor(); | |||
| private final Map<String, MessageListener> messageListeners = new ConcurrentHashMap<>(); | |||
| private final BlockEventHandler blockEventHandler = new BlockEventHandler(); | |||
| private final ExtendEventHandler extendEventHandler = new ExtendEventHandler(); | |||
| private MsgQueueProducer txProducer; | |||
| private MsgQueueProducer msgProducer; | |||
| private MsgQueueConsumer blConsumer; | |||
| private MsgQueueConsumer msgConsumer; | |||
| private boolean isConnected = false; | |||
| public DefaultMessageTransmitter setTxProducer(MsgQueueProducer txProducer) { | |||
| this.txProducer = txProducer; | |||
| return this; | |||
| } | |||
| public DefaultMessageTransmitter setMsgProducer(MsgQueueProducer msgProducer) { | |||
| this.msgProducer = msgProducer; | |||
| return this; | |||
| } | |||
| public DefaultMessageTransmitter setBlConsumer(MsgQueueConsumer blConsumer) { | |||
| this.blConsumer = blConsumer; | |||
| return this; | |||
| } | |||
| public DefaultMessageTransmitter setMsgConsumer(MsgQueueConsumer msgConsumer) { | |||
| this.msgConsumer = msgConsumer; | |||
| return this; | |||
| } | |||
| @Override | |||
| public AsyncFuture<byte[]> sendOrdered(byte[] message) { | |||
| AsyncFuture<byte[]> messageFuture; | |||
| try { | |||
| publishMessage(txProducer, message); | |||
| messageFuture = messageHandle(message); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return messageFuture; | |||
| } | |||
| @Override | |||
| public AsyncFuture<byte[]> sendUnordered(byte[] message) { | |||
| AsyncFuture<byte[]> messageFuture; | |||
| try { | |||
| publishMessage(msgProducer, message); | |||
| messageFuture = messageHandle(message); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return messageFuture; | |||
| } | |||
| @Override | |||
| public void connect() throws Exception{ | |||
| if (!isConnected) { | |||
| this.txProducer.connect(); | |||
| this.blConsumer.connect(blockEventHandler); | |||
| this.msgProducer.connect(); | |||
| this.msgConsumer.connect(extendEventHandler); | |||
| isConnected = true; | |||
| blConsumer.start(); | |||
| msgConsumer.start(); | |||
| // blockConsumerListening(); | |||
| // extendConsumerListening(); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishMessage(MsgQueueProducer producer, byte[] message) throws Exception { | |||
| producer.publish(message); | |||
| } | |||
| @Override | |||
| public void close() { | |||
| try { | |||
| txProducer.close(); | |||
| blConsumer.close(); | |||
| msgProducer.close(); | |||
| msgConsumer.close(); | |||
| isConnected = false; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| private AsyncFuture<byte[]> messageHandle(byte[] message) throws Exception { | |||
| // 异步回调 | |||
| // 需要监听MQ结块的应答 | |||
| // 首先需要一个Consumer,在子类已实现 | |||
| String messageKey = messageKey(message); | |||
| AsyncFuture<byte[]> messageFuture = registerMessageListener(messageKey); | |||
| return messageFuture; | |||
| } | |||
| private String messageKey(byte[] message) { | |||
| return MessageConvertUtil.messageKey(message); | |||
| } | |||
| private AsyncFuture<byte[]> registerMessageListener(String messageKey) { | |||
| CompletableAsyncFuture<byte[]> future = new CompletableAsyncFuture<>(); | |||
| MessageListener messageListener = new MessageListener(messageKey, future); | |||
| messageListener.addListener(); | |||
| return future; | |||
| } | |||
| // private void blockConsumerListening() { | |||
| // // 区块事件由单独一个线程处理 | |||
| // blockExecutor.execute(() -> { | |||
| // while(isConnected) { | |||
| // try { | |||
| // byte[] txBlockedEventBytes = blConsumer.start(); | |||
| // // 交由事件处理机制来处理 | |||
| // if (txBlockedEventBytes != null && txBlockedEventBytes.length > 0) { | |||
| // txBlockedEventHandle(txBlockedEventBytes); | |||
| // } | |||
| // } catch (Exception e) { | |||
| // LOGGER.error("process block listening message exception {}", e.getMessage()); | |||
| // } | |||
| // } | |||
| // }); | |||
| // } | |||
| // private void extendConsumerListening() { | |||
| // extendExecutor.execute(() -> { | |||
| // while (isConnected) { | |||
| // try { | |||
| // byte[] msgBytes = msgConsumer.start(); | |||
| // // 交由事件处理机制来处理 | |||
| // if (msgBytes != null && msgBytes.length > 0) { | |||
| // extendMessageHandle(msgBytes); | |||
| // } | |||
| // } catch (Exception e) { | |||
| // LOGGER.error("process extend listening message exception {}", e.getMessage()); | |||
| // } | |||
| // } | |||
| // }); | |||
| // } | |||
| private void txBlockedEventHandle(byte[] bytes) { | |||
| messageExecutorArray.execute(() -> { | |||
| if (!this.messageListeners.isEmpty()) { | |||
| // 首先将字节数组转换为BlockEvent | |||
| final TxBlockedEvent txBlockedEvent = | |||
| MessageConvertUtil.convertBytes2TxBlockedEvent(bytes); | |||
| if (txBlockedEvent != null) { | |||
| // 需要判断该区块是否需要处理 | |||
| if (isTxBlockedEventNeedManage(txBlockedEvent)) { | |||
| dealTxBlockedEvent(txBlockedEvent); | |||
| } | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| private void extendMessageHandle(byte[] message) { | |||
| messageExecutorArray.execute(() -> { | |||
| String messageKey = messageKey(message); | |||
| if (messageListeners.containsKey(messageKey)) { | |||
| dealExtendMessage(messageKey, message); | |||
| } | |||
| }); | |||
| } | |||
| private boolean isTxBlockedEventNeedManage(final TxBlockedEvent txBlockedEvent) { | |||
| if (this.messageListeners.isEmpty()) { | |||
| return false; | |||
| } | |||
| if (messageListeners.containsKey(txBlockedEvent.getTxKey())) { | |||
| return true; | |||
| } | |||
| // 无须处理区块高度 | |||
| return false; | |||
| } | |||
| private void dealTxBlockedEvent(final TxBlockedEvent txBlockedEvent) { | |||
| String txKey = txBlockedEvent.getTxKey(); | |||
| MessageListener txListener = this.messageListeners.get(txKey); | |||
| if (txListener != null) { | |||
| txListener.received(txBlockedEvent); | |||
| this.messageListeners.remove(txKey); | |||
| } | |||
| } | |||
| private void dealExtendMessage(final String messageKey, final byte[] message) { | |||
| MessageListener txListener = this.messageListeners.get(messageKey); | |||
| if (txListener != null) { | |||
| txListener.received(message); | |||
| this.messageListeners.remove(messageKey); | |||
| } | |||
| } | |||
| private class MessageListener { | |||
| final String messageKey; | |||
| final CompletableAsyncFuture<byte[]> future; | |||
| final AtomicBoolean isDeal = new AtomicBoolean(false); | |||
| public MessageListener(String messageKey, CompletableAsyncFuture<byte[]> future) { | |||
| this.messageKey = messageKey; | |||
| this.future = future; | |||
| addListener(); | |||
| } | |||
| public void addListener() { | |||
| synchronized (messageListeners) { | |||
| messageListeners.put(messageKey, this); | |||
| } | |||
| } | |||
| public void received(final TxBlockedEvent txBlockedEvent) { | |||
| // 期望是false,假设是false则设置为true,成功的情况下表示是第一次 | |||
| byte[] txResp = txBlockedEvent.txResponseBytes(); | |||
| if (txResp != null) { | |||
| if (isDeal.compareAndSet(false, true)) { | |||
| //生成对应的交易应答 | |||
| future.complete(txResp); | |||
| } | |||
| } | |||
| } | |||
| public void received(final byte[] message) { | |||
| // 期望是false,假设是false则设置为true,成功的情况下表示是第一次 | |||
| if (message != null) { | |||
| if (isDeal.compareAndSet(false, true)) { | |||
| //生成对应的交易应答 | |||
| future.complete(message); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| public class BlockEventHandler implements EventHandler<EventEntity<byte[]>> { | |||
| @Override | |||
| public void onEvent(EventEntity<byte[]> event, long sequence, boolean endOfBatch) throws Exception { | |||
| byte[] txBlockedEventBytes = event.getEntity(); | |||
| if (txBlockedEventBytes != null && txBlockedEventBytes.length > 0) { | |||
| txBlockedEventHandle(txBlockedEventBytes); | |||
| } | |||
| } | |||
| } | |||
| public class ExtendEventHandler implements EventHandler<EventEntity<byte[]>> { | |||
| @Override | |||
| public void onEvent(EventEntity<byte[]> event, long sequence, boolean endOfBatch) throws Exception { | |||
| byte[] msgBytes = event.getEntity(); | |||
| if (msgBytes != null && msgBytes.length > 0) { | |||
| extendMessageHandle(msgBytes); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.client.MessageTransmitter | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:21 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.client; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MessageTransmitter { | |||
| void connect() throws Exception; | |||
| void publishMessage(MsgQueueProducer producer, byte[] message) throws Exception; | |||
| // void processMsg(byte[] message); | |||
| void close(); | |||
| } | |||
| @@ -1,92 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.client.MsgQueueClientFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:23 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.client; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.ConsensusManageService; | |||
| import com.jd.blockchain.consensus.client.ClientFactory; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueClientConfig; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.crypto.AsymmetricKeypair; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureDigest; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueClientFactory implements ClientFactory { | |||
| @Override | |||
| public MsgQueueClientIdentification buildAuthId(AsymmetricKeypair clientKeyPair) { | |||
| PubKey pubKey = clientKeyPair.getPubKey(); | |||
| byte[] address = pubKey.toBytes(); // 使用公钥地址作为认证信息 | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(pubKey.getAlgorithm()); | |||
| SignatureDigest signatureDigest = signatureFunction.sign(clientKeyPair.getPrivKey(), address); | |||
| MsgQueueClientIdentification mqci = new MsgQueueClientIdentification() | |||
| .setPubKey(clientKeyPair.getPubKey()) | |||
| .setIdentityInfo(address) | |||
| .setSignature(signatureDigest) | |||
| ; | |||
| return mqci; | |||
| } | |||
| @Override | |||
| public MsgQueueClientSettings buildClientSettings(ClientIncomingSettings incomingSettings) { | |||
| MsgQueueClientIncomingSettings mqcic = (MsgQueueClientIncomingSettings)incomingSettings; | |||
| if (mqcic != null) { | |||
| return buildClientSettings(mqcic.getClientId(), mqcic.getPubKey(), (MsgQueueConsensusSettings)(mqcic.getConsensusSettings())); | |||
| } | |||
| throw new IllegalArgumentException("ClientIncomingSettings data isn't supported! Accept MsgQueueClientIncomingSettings only!"); | |||
| } | |||
| private MsgQueueClientSettings buildClientSettings(int clientId, PubKey pubKey, MsgQueueConsensusSettings mqcs) { | |||
| MsgQueueClientSettings msgQueueClientConfig = new MsgQueueClientConfig() | |||
| .setId(clientId) | |||
| .setPubKey(pubKey) | |||
| .setConsensusSettings(mqcs) | |||
| ; | |||
| return msgQueueClientConfig; | |||
| } | |||
| @Override | |||
| public ConsensusManageService createManageServiceClient(String[] serviceNodes) { | |||
| // todo serviceNodes // IP:port | |||
| return null; | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusClient setupClient(ClientSettings settings) { | |||
| if (settings instanceof MsgQueueClientSettings) { | |||
| return setupClient((MsgQueueClientSettings)settings); | |||
| } | |||
| throw new IllegalArgumentException("ClientSettings data isn't supported! Accept MsgQueueClientSettings only!"); | |||
| } | |||
| private MsgQueueConsensusClient setupClient(MsgQueueClientSettings settings) { | |||
| MsgQueueConsensusClient mqcc = new MsgQueueConsensusClient() | |||
| .setClientSettings(settings) | |||
| .setMsgQueueNetworkSettings(settings.getMsgQueueNetworkSettings()) | |||
| ; | |||
| mqcc.init(); | |||
| return mqcc; | |||
| } | |||
| } | |||
| @@ -1,74 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.client.MsgQueueClientIdentification | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午2:04 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.client; | |||
| import com.jd.blockchain.consensus.ClientIdentification; | |||
| import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureDigest; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueClientIdentification implements ClientIdentification { | |||
| private byte[] identityInfo; | |||
| private PubKey pubKey; | |||
| private SignatureDigest signature; | |||
| public MsgQueueClientIdentification() { | |||
| } | |||
| public MsgQueueClientIdentification(ClientIdentification clientIdentification) { | |||
| identityInfo = clientIdentification.getIdentityInfo(); | |||
| pubKey = clientIdentification.getPubKey(); | |||
| signature = clientIdentification.getSignature(); | |||
| } | |||
| public MsgQueueClientIdentification setIdentityInfo(byte[] identityInfo) { | |||
| this.identityInfo = identityInfo; | |||
| return this; | |||
| } | |||
| public MsgQueueClientIdentification setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| return this; | |||
| } | |||
| public MsgQueueClientIdentification setSignature(SignatureDigest signature) { | |||
| this.signature = signature; | |||
| return this; | |||
| } | |||
| @Override | |||
| public byte[] getIdentityInfo() { | |||
| return this.identityInfo; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return this.pubKey; | |||
| } | |||
| @Override | |||
| public SignatureDigest getSignature() { | |||
| return this.signature; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return MsgQueueConsensusProvider.NAME; | |||
| } | |||
| } | |||
| @@ -1,100 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.client.MsgQueueConsensusClient | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午3:23 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.client; | |||
| import com.jd.blockchain.consensus.MessageService; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| import com.jd.blockchain.consensus.client.ConsensusClient; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.factory.MsgQueueFactory; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueConsensusClient implements ConsensusClient { | |||
| private boolean isConnected; | |||
| private DefaultMessageTransmitter transmitter; | |||
| private MsgQueueNetworkSettings msgQueueNetworkSettings; | |||
| private MsgQueueClientSettings clientSettings; | |||
| public MsgQueueConsensusClient setClientSettings(MsgQueueClientSettings clientSettings) { | |||
| this.clientSettings = clientSettings; | |||
| return this; | |||
| } | |||
| public MsgQueueConsensusClient setMsgQueueNetworkSettings(MsgQueueNetworkSettings msgQueueNetworkSettings) { | |||
| this.msgQueueNetworkSettings = msgQueueNetworkSettings; | |||
| return this; | |||
| } | |||
| public void init() { | |||
| String server = msgQueueNetworkSettings.getServer(); | |||
| String txTopic = msgQueueNetworkSettings.getTxTopic(); | |||
| String blTopic = msgQueueNetworkSettings.getBlTopic(); | |||
| String msgTopic = msgQueueNetworkSettings.getMsgTopic(); | |||
| MsgQueueProducer txProducer = MsgQueueFactory.newProducer(server, txTopic); | |||
| MsgQueueProducer msgProducer = MsgQueueFactory.newProducer(server, msgTopic); | |||
| MsgQueueConsumer blConsumer = MsgQueueFactory.newConsumer(server, blTopic); | |||
| MsgQueueConsumer msgConsumer = MsgQueueFactory.newConsumer(server, msgTopic); | |||
| transmitter = new DefaultMessageTransmitter() | |||
| .setTxProducer(txProducer) | |||
| .setMsgProducer(msgProducer) | |||
| .setBlConsumer(blConsumer) | |||
| .setMsgConsumer(msgConsumer) | |||
| ; | |||
| } | |||
| @Override | |||
| public MessageService getMessageService() { | |||
| return transmitter; | |||
| } | |||
| @Override | |||
| public ClientSettings getSettings() { | |||
| return clientSettings; | |||
| } | |||
| @Override | |||
| public boolean isConnected() { | |||
| return isConnected; | |||
| } | |||
| @Override | |||
| public synchronized void connect() { | |||
| if (!isConnected) { | |||
| try { | |||
| this.transmitter.connect(); | |||
| isConnected = true; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public synchronized void close() { | |||
| if (isConnected) { | |||
| transmitter.close(); | |||
| isConnected = false; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,47 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueBlockConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午2:57 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueBlockSettings; | |||
| import java.lang.reflect.Method; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueBlockConfig implements MsgQueueBlockSettings { | |||
| private int txSizePerBlock; | |||
| private long maxDelayMilliSecondsPerBlock; | |||
| @Override | |||
| public int getTxSizePerBlock() { | |||
| return txSizePerBlock; | |||
| } | |||
| public MsgQueueBlockConfig setTxSizePerBlock(int txSizePerBlock) { | |||
| this.txSizePerBlock = txSizePerBlock; | |||
| return this; | |||
| } | |||
| @Override | |||
| public long getMaxDelayMilliSecondsPerBlock() { | |||
| return maxDelayMilliSecondsPerBlock; | |||
| } | |||
| public MsgQueueBlockConfig setMaxDelayMilliSecondsPerBlock(long maxDelayMilliSecondsPerBlock) { | |||
| this.maxDelayMilliSecondsPerBlock = maxDelayMilliSecondsPerBlock; | |||
| return this; | |||
| } | |||
| } | |||
| @@ -1,65 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueClientConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午2:23 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueClientConfig implements MsgQueueClientSettings { | |||
| private int id; | |||
| private PubKey pubKey; | |||
| private MsgQueueConsensusSettings consensusSettings; | |||
| public MsgQueueClientConfig setId(int id) { | |||
| this.id = id; | |||
| return this; | |||
| } | |||
| public MsgQueueClientConfig setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| return this; | |||
| } | |||
| public MsgQueueClientConfig setConsensusSettings(MsgQueueConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| return this; | |||
| } | |||
| @Override | |||
| public int getClientId() { | |||
| return this.id; | |||
| } | |||
| @Override | |||
| public PubKey getClientPubKey() { | |||
| return this.pubKey; | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusSettings getConsensusSettings() { | |||
| return this.consensusSettings; | |||
| } | |||
| @Override | |||
| public MsgQueueNetworkSettings getMsgQueueNetworkSettings() { | |||
| return this.consensusSettings.getNetworkSettings(); | |||
| } | |||
| } | |||
| @@ -1,69 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueClientIncomingConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import java.lang.reflect.Method; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueClientIncomingConfig implements MsgQueueClientIncomingSettings { | |||
| private int clientId; | |||
| private PubKey pubKey; | |||
| private MsgQueueConsensusSettings consensusSettings; | |||
| public MsgQueueClientIncomingConfig setConsensusSettings(MsgQueueConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| return this; | |||
| } | |||
| public MsgQueueClientIncomingConfig setClientId(int clientId) { | |||
| this.clientId = clientId; | |||
| return this; | |||
| } | |||
| public MsgQueueClientIncomingConfig setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| return this; | |||
| } | |||
| @Override | |||
| public int getClientId() { | |||
| return this.clientId; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return MsgQueueConsensusProvider.NAME; | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusSettings getConsensusSettings() { | |||
| return this.consensusSettings; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return pubKey; | |||
| } | |||
| } | |||
| @@ -1,65 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueConsensusConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:26 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.*; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import java.lang.reflect.Method; | |||
| import java.lang.reflect.Proxy; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| /** | |||
| * 设置消息队列的信息 | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueConsensusConfig implements MsgQueueConsensusSettings { | |||
| private List<NodeSettings> nodeSettingsList = new ArrayList<>(); | |||
| private MsgQueueNetworkSettings networkSettings; | |||
| private MsgQueueBlockSettings blockSettings; | |||
| public MsgQueueConsensusConfig addNodeSettings(MsgQueueNodeSettings nodeSettings) { | |||
| nodeSettingsList.add(nodeSettings); | |||
| return this; | |||
| } | |||
| public MsgQueueConsensusConfig setNetworkSettings(MsgQueueNetworkSettings networkSettings) { | |||
| this.networkSettings = networkSettings; | |||
| return this; | |||
| } | |||
| public MsgQueueConsensusConfig setBlockSettings(MsgQueueBlockSettings blockSettings) { | |||
| this.blockSettings = blockSettings; | |||
| return this; | |||
| } | |||
| @Override | |||
| public NodeSettings[] getNodes() { | |||
| return nodeSettingsList.toArray(new NodeSettings[nodeSettingsList.size()]); | |||
| } | |||
| @Override | |||
| public MsgQueueNetworkSettings getNetworkSettings() { | |||
| return networkSettings; | |||
| } | |||
| @Override | |||
| public MsgQueueBlockSettings getBlockSettings() { | |||
| return blockSettings; | |||
| } | |||
| } | |||
| @@ -1,71 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueNetworkConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午4:55 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| import java.lang.reflect.Method; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueNetworkConfig implements MsgQueueNetworkSettings { | |||
| private String server; | |||
| private String txTopic; | |||
| private String blTopic; | |||
| private String msgTopic; | |||
| public MsgQueueNetworkConfig setServer(String server) { | |||
| this.server = server; | |||
| return this; | |||
| } | |||
| public MsgQueueNetworkConfig setTxTopic(String txTopic) { | |||
| this.txTopic = txTopic; | |||
| return this; | |||
| } | |||
| public MsgQueueNetworkConfig setBlTopic(String blTopic) { | |||
| this.blTopic = blTopic; | |||
| return this; | |||
| } | |||
| public MsgQueueNetworkConfig setMsgTopic(String msgTopic) { | |||
| this.msgTopic = msgTopic; | |||
| return this; | |||
| } | |||
| @Override | |||
| public String getServer() { | |||
| return server; | |||
| } | |||
| @Override | |||
| public String getTxTopic() { | |||
| return txTopic; | |||
| } | |||
| @Override | |||
| public String getBlTopic() { | |||
| return blTopic; | |||
| } | |||
| @Override | |||
| public String getMsgTopic() { | |||
| return msgTopic; | |||
| } | |||
| } | |||
| @@ -1,46 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueNodeConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:33 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| /** | |||
| * peer节点IP | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueNodeConfig implements MsgQueueNodeSettings { | |||
| private String address; | |||
| private PubKey pubKey; | |||
| public MsgQueueNodeConfig setAddress(String address) { | |||
| this.address = address; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeConfig setPubKey(PubKey pubKey) { | |||
| this.pubKey = pubKey; | |||
| return this; | |||
| } | |||
| @Override | |||
| public String getAddress() { | |||
| return this.address; | |||
| } | |||
| @Override | |||
| public PubKey getPubKey() { | |||
| return this.pubKey; | |||
| } | |||
| } | |||
| @@ -1,72 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueServerConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:32 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueBlockSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueServerSettings; | |||
| /** | |||
| * peer节点配置 | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueServerConfig implements MsgQueueServerSettings { | |||
| private MsgQueueBlockSettings blockSettings; | |||
| private MsgQueueConsensusSettings consensusSettings; | |||
| private MsgQueueNodeSettings nodeSettings; | |||
| private String realmName; | |||
| public MsgQueueServerConfig setRealmName(String realmName) { | |||
| this.realmName = realmName; | |||
| return this; | |||
| } | |||
| public MsgQueueServerConfig setBlockSettings(MsgQueueBlockSettings blockSettings) { | |||
| this.blockSettings = blockSettings; | |||
| return this; | |||
| } | |||
| public MsgQueueServerConfig setConsensusSettings(MsgQueueConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| return setBlockSettings(consensusSettings.getBlockSettings()); | |||
| } | |||
| public MsgQueueServerConfig setNodeSettings(MsgQueueNodeSettings nodeSettings) { | |||
| this.nodeSettings = nodeSettings; | |||
| return this; | |||
| } | |||
| @Override | |||
| public String getRealmName() { | |||
| return this.realmName; | |||
| } | |||
| @Override | |||
| public MsgQueueNodeSettings getReplicaSettings() { | |||
| return nodeSettings; | |||
| } | |||
| @Override | |||
| public MsgQueueBlockSettings getBlockSettings() { | |||
| return blockSettings; | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusSettings getConsensusSettings() { | |||
| return consensusSettings; | |||
| } | |||
| } | |||
| @@ -1,105 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueSettingsFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:49 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.config; | |||
| import com.jd.blockchain.binaryproto.BinaryProtocol; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consensus.SettingsFactory; | |||
| import com.jd.blockchain.consensus.mq.MsgQueueConsensusSettingsBuilder; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueBlockSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
| import com.jd.blockchain.utils.io.BytesEncoder; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueSettingsFactory implements SettingsFactory { | |||
| static { | |||
| DataContractRegistry.register(NodeSettings.class); | |||
| DataContractRegistry.register(MsgQueueNodeSettings.class); | |||
| DataContractRegistry.register(ConsensusSettings.class); | |||
| DataContractRegistry.register(MsgQueueConsensusSettings.class); | |||
| DataContractRegistry.register(MsgQueueNetworkSettings.class); | |||
| DataContractRegistry.register(MsgQueueBlockSettings.class); | |||
| DataContractRegistry.register(MsgQueueClientIncomingSettings.class); | |||
| DataContractRegistry.register(ClientIncomingSettings.class); | |||
| } | |||
| private static final MsgQueueConsensusSettingsEncoder MQCS_ENCODER = new MsgQueueConsensusSettingsEncoder(); | |||
| private static final MsgQueueClientIncomingSettingsEncoder MQCIS_ENCODER = new MsgQueueClientIncomingSettingsEncoder(); | |||
| private static final MsgQueueConsensusSettingsBuilder BUILDER = new MsgQueueConsensusSettingsBuilder(); | |||
| @Override | |||
| public MsgQueueConsensusSettingsBuilder getConsensusSettingsBuilder() { | |||
| return BUILDER; | |||
| } | |||
| @Override | |||
| public BytesEncoder<ConsensusSettings> getConsensusSettingsEncoder() { | |||
| return MQCS_ENCODER; | |||
| } | |||
| @Override | |||
| public BytesEncoder<ClientIncomingSettings> getIncomingSettingsEncoder() { | |||
| return MQCIS_ENCODER; | |||
| } | |||
| private static class MsgQueueConsensusSettingsEncoder implements BytesEncoder<ConsensusSettings>{ | |||
| @Override | |||
| public byte[] encode(ConsensusSettings data) { | |||
| if (data instanceof MsgQueueConsensusSettings) { | |||
| return BinaryProtocol.encode(data, MsgQueueConsensusSettings.class); | |||
| } | |||
| throw new IllegalArgumentException("Settings data isn't supported! Accept MsgQueueConsensusSettings only!"); | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusSettings decode(byte[] bytes) { | |||
| return BinaryProtocol.decodeAs(bytes, MsgQueueConsensusSettings.class); | |||
| } | |||
| } | |||
| private static class MsgQueueClientIncomingSettingsEncoder implements BytesEncoder<ClientIncomingSettings>{ | |||
| @Override | |||
| public byte[] encode(ClientIncomingSettings data) { | |||
| if (data instanceof MsgQueueClientIncomingSettings) { | |||
| return BinaryProtocol.encode(data, MsgQueueClientIncomingSettings.class); | |||
| } | |||
| throw new IllegalArgumentException("Settings data isn't supported! Accept MsgQueueClientIncomingSettings only!"); | |||
| } | |||
| @Override | |||
| public MsgQueueClientIncomingSettings decode(byte[] bytes) { | |||
| return BinaryProtocol.decodeAs(bytes, MsgQueueClientIncomingSettings.class); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,44 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.consumer.AbstractConsumer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/29 下午12:31 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.consumer; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.event.EventProducer; | |||
| import com.jd.blockchain.consensus.mq.exchange.BytesEventFactory; | |||
| import com.jd.blockchain.consensus.mq.exchange.BytesEventProducer; | |||
| import com.lmax.disruptor.BlockingWaitStrategy; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import com.lmax.disruptor.RingBuffer; | |||
| import com.lmax.disruptor.dsl.Disruptor; | |||
| import com.lmax.disruptor.dsl.ProducerType; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/29 | |||
| * @since 1.0.0 | |||
| */ | |||
| public abstract class AbstractConsumer implements MsgQueueConsumer { | |||
| protected EventProducer eventProducer; | |||
| protected void initEventHandler(EventHandler eventHandler) { | |||
| Disruptor<EventEntity<byte[]>> disruptor = | |||
| new Disruptor<>(new BytesEventFactory(), | |||
| BytesEventFactory.BUFFER_SIZE, r -> { | |||
| return new Thread(r); | |||
| }, ProducerType.SINGLE, new BlockingWaitStrategy()); | |||
| disruptor.handleEventsWith(eventHandler); | |||
| disruptor.start(); | |||
| RingBuffer<EventEntity<byte[]>> ringBuffer = disruptor.getRingBuffer(); | |||
| this.eventProducer = new BytesEventProducer(ringBuffer); | |||
| } | |||
| } | |||
| @@ -1,28 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: MsgQueueConsumer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:38 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.consumer; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import java.io.Closeable; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MsgQueueConsumer extends Closeable { | |||
| void connect(EventHandler eventHandler) throws Exception; | |||
| void start() throws Exception; | |||
| } | |||
| @@ -1,76 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.nats.RabbitConsumer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:40 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.consumer; | |||
| import com.jd.blockchain.utils.ConsoleUtils; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import io.nats.client.*; | |||
| import java.io.IOException; | |||
| import java.time.Duration; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class NatsConsumer extends AbstractConsumer implements MsgQueueConsumer { | |||
| private final ExecutorService msgListener = Executors.newSingleThreadExecutor(); | |||
| private Connection nc; | |||
| private Subscription sub; | |||
| private String server; | |||
| private String topic; | |||
| public NatsConsumer(String server, String topic) { | |||
| this.server = server; | |||
| this.topic = topic; | |||
| } | |||
| @Override | |||
| public void connect(EventHandler eventHandler) throws Exception { | |||
| initEventHandler(eventHandler); | |||
| Options options = new Options.Builder().server(server).noReconnect().build(); | |||
| this.nc = Nats.connect(options); | |||
| this.sub = nc.subscribe(topic); | |||
| this.nc.flush(Duration.ZERO); | |||
| ConsoleUtils.info("[*] NatsConsumer[%s, %s] connect success !!!", this.server, this.topic); | |||
| } | |||
| @Override | |||
| public void start() { | |||
| msgListener.execute(() -> { | |||
| for (;;) { | |||
| try { | |||
| Message msg = this.sub.nextMessage(Duration.ZERO); | |||
| eventProducer.publish(msg.getData()); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| try { | |||
| nc.close(); | |||
| } catch (Exception e) { | |||
| throw new IOException(e); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,92 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.nats.RabbitConsumer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:40 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.consumer; | |||
| import com.jd.blockchain.consensus.mq.factory.RabbitFactory; | |||
| import com.jd.blockchain.utils.ConsoleUtils; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import com.rabbitmq.client.*; | |||
| import java.io.IOException; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class RabbitConsumer extends AbstractConsumer implements MsgQueueConsumer { | |||
| private Connection connection; | |||
| private Channel channel; | |||
| private String exchangeName; | |||
| private String server; | |||
| private String queueName; | |||
| public RabbitConsumer(String server, String topic) { | |||
| this.server = server; | |||
| this.exchangeName = topic; | |||
| } | |||
| private void rabbitConsumerHandle() throws Exception { | |||
| rabbitConsumerHandleByQueue(); | |||
| } | |||
| private void rabbitConsumerHandleByQueue() throws IOException { | |||
| DefaultConsumer consumer = new DefaultConsumer(channel) { | |||
| @Override | |||
| public void handleDelivery(String consumerTag, Envelope envelope, | |||
| AMQP.BasicProperties properties, byte[] body) { | |||
| // 此处将收到的消息加入队列即可 | |||
| try { | |||
| eventProducer.publish(body); | |||
| channel.basicAck(envelope.getDeliveryTag(), false); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| }; | |||
| this.channel.basicConsume(this.queueName, false, consumer); | |||
| } | |||
| @Override | |||
| public void connect(EventHandler eventHandler) throws Exception { | |||
| initEventHandler(eventHandler); | |||
| ConnectionFactory factory = RabbitFactory.initConnectionFactory(server); | |||
| connection = factory.newConnection(); | |||
| channel = connection.createChannel(); | |||
| channel.exchangeDeclare(this.exchangeName, "fanout"); | |||
| queueName = channel.queueDeclare().getQueue(); | |||
| channel.queueBind(queueName, this.exchangeName, ""); | |||
| channel.basicQos(8); | |||
| ConsoleUtils.info("[*] RabbitConsumer[%s, %s] connect success !!!", this.server, this.exchangeName); | |||
| } | |||
| @Override | |||
| public void start() throws Exception { | |||
| rabbitConsumerHandle(); | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| try { | |||
| this.channel.close(); | |||
| this.connection.close(); | |||
| } catch (Exception e) { | |||
| throw new IOException(e); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,64 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: BlockEvent | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/20 上午11:32 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.event; | |||
| import com.jd.blockchain.consensus.mq.util.MessageConvertUtil; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/20 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class BlockEvent { | |||
| private Map<String, String> txMap = new HashMap<>(); | |||
| public Map<String, String> getTxMap() { | |||
| return txMap; | |||
| } | |||
| public void setTxMap(Map<String, String> txMap) { | |||
| this.txMap = txMap; | |||
| } | |||
| public void put(String txKey, String txResp) { | |||
| txMap.put(txKey, txResp); | |||
| } | |||
| public void put(String txKey, byte[] txResp) { | |||
| put(txKey, MessageConvertUtil.base64Encode(txResp)); | |||
| } | |||
| public String getTxResp(String txKey) { | |||
| return txMap.get(txKey); | |||
| } | |||
| public byte[] getTxRespBytes(String txKey) { | |||
| String txResp = getTxResp(txKey); | |||
| if (txResp != null && txResp.length() > 0) { | |||
| // 字符串转字节数组 | |||
| return MessageConvertUtil.base64Decode(txResp); | |||
| } | |||
| return null; | |||
| } | |||
| public boolean containTxResp(String txKey) { | |||
| return txMap.containsKey(txKey); | |||
| } | |||
| public boolean isEmpty() { | |||
| if (txMap == null) return true; | |||
| return txMap.isEmpty(); | |||
| } | |||
| } | |||
| @@ -1,44 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.peer.consensus.MessageEvent | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/23 上午11:45 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.event; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/23 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MessageEvent { | |||
| String messageKey; | |||
| byte[] message; | |||
| public MessageEvent(String messageKey, byte[] message) { | |||
| this.messageKey = messageKey; | |||
| this.message = message; | |||
| } | |||
| public String getMessageKey() { | |||
| return messageKey; | |||
| } | |||
| public void setMessageKey(String messageKey) { | |||
| this.messageKey = messageKey; | |||
| } | |||
| public byte[] getMessage() { | |||
| return message; | |||
| } | |||
| public void setMessage(byte[] message) { | |||
| this.message = message; | |||
| } | |||
| } | |||
| @@ -1,58 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: BlockEvent | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/20 上午11:32 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.event; | |||
| import com.jd.blockchain.consensus.mq.util.MessageConvertUtil; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/20 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class TxBlockedEvent { | |||
| private String txKey; | |||
| private String transaction; | |||
| public TxBlockedEvent() { | |||
| } | |||
| public TxBlockedEvent(String txKey, String transaction) { | |||
| this.txKey = txKey; | |||
| this.transaction = transaction; | |||
| } | |||
| public void setTxKey(String txKey) { | |||
| this.txKey = txKey; | |||
| } | |||
| public void setTransaction(String transaction) { | |||
| this.transaction = transaction; | |||
| } | |||
| public String getTxKey() { | |||
| return txKey; | |||
| } | |||
| public String getTransaction() { | |||
| return transaction; | |||
| } | |||
| public byte[] txResponseBytes() { | |||
| if (transaction != null && transaction.length() > 0) { | |||
| // 字符串转字节数组 | |||
| return MessageConvertUtil.base64Decode(transaction); | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.rabbitmq.nats.consensus.disruptor.ExchangeEventFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 上午10:48 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.lmax.disruptor.EventFactory; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class BytesEventFactory implements EventFactory<EventEntity<byte[]>> { | |||
| public static final int BUFFER_SIZE = 256 * 1024; | |||
| // public static final int BUFFER_SIZE = 8 * 1024; | |||
| @Override | |||
| public EventEntity<byte[]> newInstance() { | |||
| return new EventEntity<>(); | |||
| } | |||
| } | |||
| @@ -1,40 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.rabbitmq.nats.consensus.disruptor.ExchangeEventProducer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 上午10:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.event.EventProducer; | |||
| import com.lmax.disruptor.RingBuffer; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class BytesEventProducer implements EventProducer<byte[]> { | |||
| private final RingBuffer<EventEntity<byte[]>> ringBuffer; | |||
| public BytesEventProducer(RingBuffer<EventEntity<byte[]>> ringBuffer) { | |||
| this.ringBuffer = ringBuffer; | |||
| } | |||
| @Override | |||
| public void publish(byte[] entity) { | |||
| long sequence = ringBuffer.next(); | |||
| try { | |||
| EventEntity<byte[]> event = ringBuffer.get(sequence); | |||
| event.setEntity(entity); | |||
| } finally { | |||
| this.ringBuffer.publish(sequence); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,31 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.ExchangeEntityFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午4:08 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class ExchangeEntityFactory { | |||
| public static ExchangeEventInnerEntity newBlockInstance() { | |||
| return new ExchangeEventInnerEntity(ExchangeType.BLOCK); | |||
| } | |||
| public static ExchangeEventInnerEntity newEmptyInstance() { | |||
| return new ExchangeEventInnerEntity(ExchangeType.EMPTY); | |||
| } | |||
| public static ExchangeEventInnerEntity newTransactionInstance(byte[] content) { | |||
| return new ExchangeEventInnerEntity(ExchangeType.TRANSACTION, content); | |||
| } | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.rabbitmq.nats.consensus.disruptor.ExchangeEventFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 上午10:48 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.lmax.disruptor.EventFactory; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class ExchangeEventFactory implements EventFactory<EventEntity<ExchangeEventInnerEntity>> { | |||
| public static final int BUFFER_SIZE = 256 * 1024; | |||
| // public static final int BUFFER_SIZE = 8 * 1024; | |||
| @Override | |||
| public EventEntity<ExchangeEventInnerEntity> newInstance() { | |||
| return new EventEntity<>(); | |||
| } | |||
| } | |||
| @@ -1,53 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.ExchangeEventInnerEntity | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午4:04 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class ExchangeEventInnerEntity { | |||
| private ExchangeType type; | |||
| private byte[] content; | |||
| public ExchangeEventInnerEntity() { | |||
| } | |||
| public ExchangeEventInnerEntity(ExchangeType type) { | |||
| this.type = type; | |||
| } | |||
| public ExchangeEventInnerEntity(ExchangeType type, byte[] content) { | |||
| this.type = type; | |||
| this.content = content; | |||
| } | |||
| public ExchangeType getType() { | |||
| return type; | |||
| } | |||
| public void setType(ExchangeType type) { | |||
| this.type = type; | |||
| } | |||
| public byte[] getContent() { | |||
| return content; | |||
| } | |||
| public void setContent(byte[] content) { | |||
| this.content = content; | |||
| } | |||
| } | |||
| @@ -1,40 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.rabbitmq.nats.consensus.disruptor.ExchangeEventProducer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 上午10:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.event.EventProducer; | |||
| import com.lmax.disruptor.RingBuffer; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class ExchangeEventProducer implements EventProducer<ExchangeEventInnerEntity> { | |||
| private final RingBuffer<EventEntity<ExchangeEventInnerEntity>> ringBuffer; | |||
| public ExchangeEventProducer(RingBuffer<EventEntity<ExchangeEventInnerEntity>> ringBuffer) { | |||
| this.ringBuffer = ringBuffer; | |||
| } | |||
| @Override | |||
| public void publish(ExchangeEventInnerEntity entity) { | |||
| long sequence = ringBuffer.next(); | |||
| try { | |||
| EventEntity<ExchangeEventInnerEntity> event = ringBuffer.get(sequence); | |||
| event.setEntity(entity); | |||
| } finally { | |||
| this.ringBuffer.publish(sequence); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.nats.ExchangeType | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午3:34 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.exchange; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public enum ExchangeType { | |||
| BLOCK, | |||
| EMPTY, | |||
| TRANSACTION, | |||
| ; | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.factory.MsgQueueConfig | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午5:16 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.factory; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public final class MsgQueueConfig { | |||
| public static final String NATS_PREFIX = "nats"; | |||
| public static final String RABBIT_PREFIX = "rabbit"; | |||
| } | |||
| @@ -1,52 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: MsgQueueFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:13 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.factory; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import static com.jd.blockchain.consensus.mq.factory.MsgQueueConfig.NATS_PREFIX; | |||
| import static com.jd.blockchain.consensus.mq.factory.MsgQueueConfig.RABBIT_PREFIX; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueFactory { | |||
| public static MsgQueueProducer newProducer(String server, String topic) { | |||
| try { | |||
| if (server.startsWith(NATS_PREFIX)) { | |||
| return NatsFactory.newProducer(server, topic); | |||
| } else if (server.startsWith(RABBIT_PREFIX)) { | |||
| return RabbitFactory.newProducer(server, topic); | |||
| } | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return null; | |||
| } | |||
| public static MsgQueueConsumer newConsumer(String server, String topic) { | |||
| try { | |||
| if (server.startsWith(NATS_PREFIX)) { | |||
| return NatsFactory.newConsumer(server, topic); | |||
| } else if (server.startsWith(RABBIT_PREFIX)) { | |||
| return RabbitFactory.newConsumer(server, topic); | |||
| } | |||
| return null; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,32 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: NatsFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:15 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.factory; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.consumer.NatsConsumer; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.producer.NatsProducer; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class NatsFactory { | |||
| public static MsgQueueProducer newProducer(String server, String topic) throws Exception { | |||
| return new NatsProducer(server, topic); | |||
| } | |||
| public static MsgQueueConsumer newConsumer(String server, String topic) throws Exception { | |||
| return new NatsConsumer(server, topic); | |||
| } | |||
| } | |||
| @@ -1,52 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.nats.RabbitFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:15 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.factory; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.consumer.RabbitConsumer; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.producer.RabbitProducer; | |||
| import com.rabbitmq.client.ConnectionFactory; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class RabbitFactory { | |||
| public static MsgQueueProducer newProducer(String server, String topic) throws Exception { | |||
| return new RabbitProducer(server, topic); | |||
| } | |||
| public static MsgQueueConsumer newConsumer(String server, String topic) throws Exception { | |||
| return new RabbitConsumer(server, topic); | |||
| } | |||
| public static ConnectionFactory initConnectionFactory(String server) { | |||
| ConnectionFactory factory = new ConnectionFactory(); | |||
| // 解析server,生成host+port,默认格式:rabbit://localhost:5672 | |||
| try { | |||
| String[] hostAndPort = server.split("//")[1].split(":"); | |||
| if (hostAndPort == null || hostAndPort.length == 0) { | |||
| factory.setHost("localhost"); | |||
| } else if (hostAndPort.length == 1) { | |||
| factory.setHost(hostAndPort[0]); | |||
| } else { | |||
| factory.setHost(hostAndPort[0]); | |||
| factory.setPort(Integer.parseInt(hostAndPort[1])); | |||
| } | |||
| } catch (Exception e) { | |||
| factory.setHost("localhost"); | |||
| } | |||
| return factory; | |||
| } | |||
| } | |||
| @@ -1,36 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: MsgQueueProducer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:37 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.producer; | |||
| import java.io.Closeable; | |||
| import java.util.List; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MsgQueueProducer extends Closeable { | |||
| void connect() throws Exception; | |||
| void publish(byte[] message) throws Exception; | |||
| void publishString(String message) throws Exception; | |||
| void publishStringList(List<String> messages) throws Exception; | |||
| void publishStringArray(String[] messages) throws Exception; | |||
| void publishBytesArray(byte[][] message) throws Exception; | |||
| void publishBytesList(List<byte[]> messages) throws Exception; | |||
| } | |||
| @@ -1,100 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: NatsProducer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:39 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.producer; | |||
| import io.nats.client.Connection; | |||
| import io.nats.client.Nats; | |||
| import io.nats.client.Options; | |||
| import java.io.IOException; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.util.List; | |||
| import com.jd.blockchain.utils.ConsoleUtils; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class NatsProducer implements MsgQueueProducer { | |||
| // 主要操作:发送MQ请求 | |||
| private Connection nc; | |||
| private String server; | |||
| // 主题 | |||
| private String topic; | |||
| public NatsProducer() { | |||
| } | |||
| public NatsProducer(String server, String topic) { | |||
| this.topic = topic; | |||
| this.server = server; | |||
| } | |||
| @Override | |||
| public void connect() throws Exception{ | |||
| Options o = new Options.Builder().server(server).noReconnect().build(); | |||
| this.nc = Nats.connect(o); | |||
| ConsoleUtils.info("[*] NatsProducer[%s, %s] connect success !!!", this.server, this.topic); | |||
| } | |||
| @Override | |||
| public void publish(byte[] message) { | |||
| nc.publish(topic, message); | |||
| } | |||
| @Override | |||
| public void publishString(String message) { | |||
| publish(message.getBytes(StandardCharsets.UTF_8)); | |||
| } | |||
| @Override | |||
| public void publishStringList(List<String> messages) { | |||
| for (String message : messages) { | |||
| publishString(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishStringArray(String[] messages) { | |||
| for (String message : messages) { | |||
| publishString(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishBytesArray(byte[][] message) { | |||
| for (byte[] bytes : message) { | |||
| publish(bytes); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishBytesList(List<byte[]> messages) { | |||
| for (byte[] message : messages) { | |||
| publish(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| try { | |||
| nc.close(); | |||
| } catch (Exception e) { | |||
| throw new IOException(e); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,106 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.nats.RabbitProducer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/5 下午10:39 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.producer; | |||
| import com.jd.blockchain.consensus.mq.factory.RabbitFactory; | |||
| import com.jd.blockchain.utils.ConsoleUtils; | |||
| import com.rabbitmq.client.Channel; | |||
| import com.rabbitmq.client.Connection; | |||
| import com.rabbitmq.client.ConnectionFactory; | |||
| import java.io.IOException; | |||
| import java.nio.charset.StandardCharsets; | |||
| import java.util.List; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/5 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class RabbitProducer implements MsgQueueProducer { | |||
| // 主要操作时发送JMQ请求 | |||
| private Channel channel; | |||
| private Connection connection; | |||
| private String exchangeName; | |||
| private String server; | |||
| public RabbitProducer() { | |||
| } | |||
| public RabbitProducer(String server, String topic) throws Exception { | |||
| this.exchangeName = topic; | |||
| this.server = server; | |||
| } | |||
| @Override | |||
| public void connect() throws Exception { | |||
| ConnectionFactory factory = RabbitFactory.initConnectionFactory(server); | |||
| connection = factory.newConnection(); | |||
| channel = connection.createChannel(); | |||
| channel.exchangeDeclare(this.exchangeName, "fanout"); | |||
| ConsoleUtils.info("[*] RabbitProducer[%s, %s] connect success !!!", this.server, this.exchangeName); | |||
| } | |||
| @Override | |||
| public void publish(byte[] message) throws Exception { | |||
| channel.basicPublish(this.exchangeName, "", null, message); | |||
| } | |||
| @Override | |||
| public void publishString(String message) throws Exception { | |||
| publish(message.getBytes(StandardCharsets.UTF_8)); | |||
| } | |||
| @Override | |||
| public void publishStringList(List<String> messages) throws Exception { | |||
| for (String message : messages) { | |||
| publishString(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishStringArray(String[] messages) throws Exception { | |||
| for (String message : messages) { | |||
| publishString(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishBytesArray(byte[][] message) throws Exception { | |||
| for (byte[] bytes : message) { | |||
| publish(bytes); | |||
| } | |||
| } | |||
| @Override | |||
| public void publishBytesList(List<byte[]> messages) throws Exception { | |||
| for (byte[] message : messages) { | |||
| publish(message); | |||
| } | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| try { | |||
| channel.close(); | |||
| connection.close(); | |||
| } catch (Exception e) { | |||
| throw new IOException(e); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,297 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.server.DefaultMsgQueueMessageDispatcher | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 上午11:05 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.event.EventProducer; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeEntityFactory; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeEventFactory; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeEventInnerEntity; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeEventProducer; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.lmax.disruptor.BlockingWaitStrategy; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import com.lmax.disruptor.RingBuffer; | |||
| import com.lmax.disruptor.dsl.Disruptor; | |||
| import com.lmax.disruptor.dsl.ProducerType; | |||
| import java.io.IOException; | |||
| import java.util.concurrent.*; | |||
| import java.util.concurrent.atomic.AtomicLong; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class DefaultMsgQueueMessageDispatcher implements MsgQueueMessageDispatcher, EventHandler<EventEntity<byte[]>> { | |||
| private static final byte[] blockCommitBytes = new byte[]{0x00}; | |||
| private final BlockingQueue<byte[]> dataQueue = new ArrayBlockingQueue<>(1024 * 16); | |||
| private final ExecutorService dataExecutor = Executors.newSingleThreadExecutor(); | |||
| private final ScheduledThreadPoolExecutor timeHandleExecutor = new ScheduledThreadPoolExecutor(2); | |||
| private final AtomicLong blockIndex = new AtomicLong(); | |||
| private long syncIndex = 0L; | |||
| private MsgQueueProducer txProducer; | |||
| private MsgQueueConsumer txConsumer; | |||
| private EventProducer eventProducer; | |||
| private EventHandler eventHandler; | |||
| private final int TX_SIZE_PER_BLOCK; | |||
| private final long MAX_DELAY_MILLISECONDS_PER_BLOCK; | |||
| private boolean isRunning; | |||
| private boolean isConnected; | |||
| public DefaultMsgQueueMessageDispatcher(int txSizePerBlock, long maxDelayMilliSecondsPerBlock) { | |||
| this.TX_SIZE_PER_BLOCK = txSizePerBlock; | |||
| this.MAX_DELAY_MILLISECONDS_PER_BLOCK = maxDelayMilliSecondsPerBlock; | |||
| } | |||
| public DefaultMsgQueueMessageDispatcher setTxProducer(MsgQueueProducer txProducer) { | |||
| this.txProducer = txProducer; | |||
| return this; | |||
| } | |||
| public DefaultMsgQueueMessageDispatcher setTxConsumer(MsgQueueConsumer txConsumer) { | |||
| this.txConsumer = txConsumer; | |||
| return this; | |||
| } | |||
| public DefaultMsgQueueMessageDispatcher setEventHandler(EventHandler eventHandler) { | |||
| this.eventHandler = eventHandler; | |||
| return this; | |||
| } | |||
| public void init() { | |||
| handleDisruptor(eventHandler); | |||
| } | |||
| private void handleDisruptor(EventHandler eventHandler) { | |||
| Disruptor<EventEntity<ExchangeEventInnerEntity>> disruptor = | |||
| new Disruptor<>(new ExchangeEventFactory(), | |||
| ExchangeEventFactory.BUFFER_SIZE, r -> { | |||
| return new Thread(r); | |||
| }, ProducerType.SINGLE, new BlockingWaitStrategy()); | |||
| disruptor.handleEventsWith(eventHandler); | |||
| disruptor.start(); | |||
| RingBuffer<EventEntity<ExchangeEventInnerEntity>> ringBuffer = disruptor.getRingBuffer(); | |||
| this.eventProducer = new ExchangeEventProducer(ringBuffer); | |||
| } | |||
| public synchronized void connect() throws Exception { | |||
| if (!isConnected) { | |||
| txProducer.connect(); | |||
| txConsumer.connect(this); | |||
| isConnected = true; | |||
| } | |||
| } | |||
| @Override | |||
| public synchronized void stop() throws Exception { | |||
| isRunning = false; | |||
| close(); | |||
| } | |||
| @Override | |||
| public void run() { | |||
| this.isRunning = true; | |||
| try { | |||
| txConsumer.start(); | |||
| } catch (Exception e) { | |||
| } | |||
| // handleData(); | |||
| // listen(); | |||
| } | |||
| // private void listen() { | |||
| // while (isRunning) { | |||
| // try { | |||
| // byte[] data = this.txConsumer.start(); | |||
| // dataQueue.put(data); | |||
| // // 收到数据后由队列处理 | |||
| //// handleData(data); | |||
| // } catch (Exception e) { | |||
| // // 日志打印 | |||
| // ConsoleUtils.info("ERROR dispatcher start data exception {%s}", e.getMessage()); | |||
| // } | |||
| // } | |||
| // } | |||
| // private void handleData() { | |||
| // dataExecutor.execute(() -> { | |||
| // byte[] data; | |||
| // for (;;) { | |||
| // try { | |||
| // data = dataQueue.take(); | |||
| // if (data.length == 1) { | |||
| // // 结块标识优先处理 | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } else { | |||
| // if (syncIndex == 0) { // 收到第一个交易 | |||
| // // 需要判断是否需要进行定时任务 | |||
| // if (MAX_DELAY_MILLISECONDS_PER_BLOCK > 0) { | |||
| // this.timeHandleExecutor.schedule( | |||
| // timeBlockTask(this.blockIndex.get()), | |||
| // MAX_DELAY_MILLISECONDS_PER_BLOCK, TimeUnit.MILLISECONDS); | |||
| // } | |||
| // } | |||
| // syncIndex++; | |||
| // eventProducer.publish(ExchangeEntityFactory.newTransactionInstance(data)); | |||
| // if (syncIndex == TX_SIZE_PER_BLOCK) { | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } | |||
| // } | |||
| // | |||
| // } catch (Exception e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // } | |||
| // }); | |||
| // for (;;) { | |||
| // try { | |||
| // final byte[] data = dataQueue.take(); | |||
| // dataExecutor.execute(() -> { | |||
| // if (data.length == 1) { | |||
| // // 结块标识优先处理 | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } else { | |||
| // if (syncIndex == 0) { // 收到第一个交易 | |||
| // // 需要判断是否需要进行定时任务 | |||
| // if (MAX_DELAY_MILLISECONDS_PER_BLOCK > 0) { | |||
| // this.timeHandleExecutor.schedule( | |||
| // timeBlockTask(this.blockIndex.get()), | |||
| // MAX_DELAY_MILLISECONDS_PER_BLOCK, TimeUnit.MILLISECONDS); | |||
| // } | |||
| // } | |||
| // syncIndex++; | |||
| // eventProducer.publish(ExchangeEntityFactory.newTransactionInstance(data)); | |||
| // if (syncIndex == TX_SIZE_PER_BLOCK) { | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } | |||
| // } | |||
| // } | |||
| // ); | |||
| // } catch (Exception e) { | |||
| // e.printStackTrace(); | |||
| // } | |||
| // } | |||
| // } | |||
| // private void handleData(final byte[] data) { | |||
| // dataExecutor.execute(() -> { | |||
| // try { | |||
| // if (data.length == 1) { | |||
| // // 结块标识优先处理 | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } else { | |||
| // if (syncIndex == 0) { // 收到第一个交易 | |||
| // // 需要判断是否需要进行定时任务 | |||
| // if (MAX_DELAY_MILLISECONDS_PER_BLOCK > 0) { | |||
| // this.timeHandleExecutor.schedule( | |||
| // timeBlockTask(this.blockIndex.get()), | |||
| // MAX_DELAY_MILLISECONDS_PER_BLOCK, TimeUnit.MILLISECONDS); | |||
| // } | |||
| // } | |||
| // syncIndex++; | |||
| // eventProducer.publish(ExchangeEntityFactory.newTransactionInstance(data)); | |||
| // if (syncIndex == TX_SIZE_PER_BLOCK) { | |||
| // syncIndex = 0L; | |||
| // this.blockIndex.getAndIncrement(); | |||
| // eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| // } | |||
| // } | |||
| // } catch (Exception e) { | |||
| // // 记录日志 | |||
| // ConsoleUtils.info("ERROR TransactionDispatcher process queue data exception {%s}", e.getMessage()); | |||
| // } | |||
| // }); | |||
| // | |||
| // } | |||
| private Runnable timeBlockTask(final long currentBlockIndex) { | |||
| return () -> { | |||
| final boolean isEqualBlock = this.blockIndex.compareAndSet( | |||
| currentBlockIndex, currentBlockIndex + 1); | |||
| if (isEqualBlock) { | |||
| try { | |||
| txProducer.publish(blockCommitBytes); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| this.txProducer.close(); | |||
| this.txConsumer.close(); | |||
| } | |||
| @Override | |||
| public void onEvent(EventEntity<byte[]> event, long sequence, boolean endOfBatch) throws Exception { | |||
| try { | |||
| byte[] data = event.getEntity(); | |||
| // System.out.printf("Thread [%s, $s] on event !!!\r\n", | |||
| // Thread.currentThread().getId(), Thread.currentThread().getName()); | |||
| if (data.length == 1) { | |||
| // 结块标识优先处理 | |||
| syncIndex = 0L; | |||
| this.blockIndex.getAndIncrement(); | |||
| eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| } else { | |||
| if (syncIndex == 0) { // 收到第一个交易 | |||
| // 需要判断是否需要进行定时任务 | |||
| if (MAX_DELAY_MILLISECONDS_PER_BLOCK > 0) { | |||
| this.timeHandleExecutor.schedule( | |||
| timeBlockTask(this.blockIndex.get()), | |||
| MAX_DELAY_MILLISECONDS_PER_BLOCK, TimeUnit.MILLISECONDS); | |||
| } | |||
| } | |||
| syncIndex++; | |||
| eventProducer.publish(ExchangeEntityFactory.newTransactionInstance(data)); | |||
| if (syncIndex == TX_SIZE_PER_BLOCK) { | |||
| syncIndex = 0L; | |||
| this.blockIndex.getAndIncrement(); | |||
| eventProducer.publish(ExchangeEntityFactory.newBlockInstance()); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,126 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.server.DefaultMsgQueueMessageDispatcher | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 上午11:05 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.service.MessageHandle; | |||
| import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.io.IOException; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class ExtendMsgQueueMessageExecutor implements MsgQueueMessageDispatcher, EventHandler<EventEntity<byte[]>> { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(ExtendMsgQueueMessageExecutor.class); | |||
| private final ExecutorService dataExecutor = Executors.newSingleThreadExecutor(); | |||
| private MsgQueueProducer msgProducer; | |||
| private MsgQueueConsumer msgConsumer; | |||
| private MessageHandle messageHandle; | |||
| private boolean isRunning; | |||
| private boolean isConnected; | |||
| public ExtendMsgQueueMessageExecutor setMsgProducer(MsgQueueProducer msgProducer) { | |||
| this.msgProducer = msgProducer; | |||
| return this; | |||
| } | |||
| public ExtendMsgQueueMessageExecutor setMsgConsumer(MsgQueueConsumer msgConsumer) { | |||
| this.msgConsumer = msgConsumer; | |||
| return this; | |||
| } | |||
| public ExtendMsgQueueMessageExecutor setMessageHandle(MessageHandle messageHandle) { | |||
| this.messageHandle = messageHandle; | |||
| return this; | |||
| } | |||
| @Override | |||
| public void init() { | |||
| // do nothing | |||
| } | |||
| public synchronized void connect() throws Exception { | |||
| if (!isConnected) { | |||
| msgProducer.connect(); | |||
| msgConsumer.connect(this); | |||
| msgConsumer.start(); | |||
| isConnected = true; | |||
| } | |||
| } | |||
| @Override | |||
| public synchronized void stop() throws Exception { | |||
| isRunning = false; | |||
| close(); | |||
| } | |||
| @Override | |||
| public void run() { | |||
| this.isRunning = true; | |||
| // this.msgConsumer.start(); | |||
| // listen(); | |||
| } | |||
| // private void listen() { | |||
| // while (isRunning) { | |||
| // try { | |||
| // byte[] data = this.msgConsumer.start(); | |||
| // // 收到数据后由队列处理 | |||
| // handleData(data); | |||
| // } catch (Exception e) { | |||
| // // 日志打印 | |||
| // LOGGER.error("extend message handle exception {}", e.getMessage()); | |||
| // } | |||
| // } | |||
| // } | |||
| private void handleData(byte[] data) { | |||
| dataExecutor.execute(() -> { | |||
| try { | |||
| AsyncFuture<byte[]> result = messageHandle.processUnordered(data); | |||
| msgProducer.publish(result.get()); | |||
| } catch (Exception e) { | |||
| LOGGER.error("process Unordered message exception {}", e.getMessage()); | |||
| } | |||
| }); | |||
| } | |||
| @Override | |||
| public void close() throws IOException { | |||
| isConnected = false; | |||
| this.msgProducer.close(); | |||
| this.msgConsumer.close(); | |||
| } | |||
| @Override | |||
| public void onEvent(EventEntity<byte[]> event, long sequence, boolean endOfBatch) throws Exception { | |||
| byte[] data = event.getEntity(); | |||
| handleData(data); | |||
| } | |||
| } | |||
| @@ -1,70 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.server.MsgQueueConsensusManageService | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 下午1:46 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import java.util.Arrays; | |||
| import com.jd.blockchain.consensus.ClientIdentification; | |||
| import com.jd.blockchain.consensus.ConsensusManageService; | |||
| import com.jd.blockchain.consensus.ConsensusSecurityException; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueClientIncomingConfig; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.crypto.Crypto; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.crypto.SignatureFunction; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueConsensusManageService implements ConsensusManageService { | |||
| private MsgQueueConsensusSettings consensusSettings; | |||
| public MsgQueueConsensusManageService setConsensusSettings(MsgQueueConsensusSettings consensusSettings) { | |||
| this.consensusSettings = consensusSettings; | |||
| return this; | |||
| } | |||
| @Override | |||
| public MsgQueueClientIncomingSettings authClientIncoming(ClientIdentification authId) throws ConsensusSecurityException { | |||
| boolean isLegal = isLegal(authId); | |||
| if (isLegal) { | |||
| MsgQueueClientIncomingSettings mqcis = new MsgQueueClientIncomingConfig() | |||
| .setPubKey(authId.getPubKey()) | |||
| .setClientId(clientId(authId.getIdentityInfo())) | |||
| .setConsensusSettings(this.consensusSettings) | |||
| ; | |||
| return mqcis; | |||
| } | |||
| return null; | |||
| } | |||
| private int clientId(byte[] identityInfo) { | |||
| // todo | |||
| return 0; | |||
| } | |||
| public boolean isLegal(ClientIdentification authId) { | |||
| boolean isLegal = false; | |||
| PubKey pubKey = authId.getPubKey(); | |||
| byte[] identityInfo = authId.getIdentityInfo(); | |||
| byte[] address = pubKey.toBytes(); // 使用公钥地址作为认证信息 | |||
| if (Arrays.equals(address, identityInfo)) { | |||
| SignatureFunction signatureFunction = Crypto.getSignatureFunction(pubKey.getAlgorithm()); | |||
| isLegal = signatureFunction.verify(authId.getSignature(), pubKey, identityInfo); | |||
| } | |||
| return isLegal; | |||
| } | |||
| } | |||
| @@ -1,28 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.server.MsgQueueMessageDispatcher | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:30 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import java.io.Closeable; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MsgQueueMessageDispatcher extends Runnable, Closeable { | |||
| void init(); | |||
| void connect() throws Exception; | |||
| void stop() throws Exception; | |||
| } | |||
| @@ -1,182 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.server.MsgQueueMessageExecutor | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午2:10 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import com.jd.blockchain.consensus.event.EventEntity; | |||
| import com.jd.blockchain.consensus.mq.event.MessageEvent; | |||
| import com.jd.blockchain.consensus.mq.event.TxBlockedEvent; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeEventInnerEntity; | |||
| import com.jd.blockchain.consensus.mq.exchange.ExchangeType; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.util.MessageConvertUtil; | |||
| import com.jd.blockchain.consensus.service.MessageHandle; | |||
| import com.jd.blockchain.consensus.service.StateMachineReplicate; | |||
| import com.jd.blockchain.ledger.TransactionState; | |||
| import com.jd.blockchain.utils.concurrent.AsyncFuture; | |||
| import com.lmax.disruptor.EventHandler; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.util.ArrayList; | |||
| import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ExecutorService; | |||
| import java.util.concurrent.Executors; | |||
| import java.util.concurrent.atomic.AtomicInteger; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueMessageExecutor implements EventHandler<EventEntity<ExchangeEventInnerEntity>> { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(MsgQueueMessageExecutor.class); | |||
| // todo 暂不处理队列溢出导致的OOM | |||
| private final ExecutorService blockEventExecutor = Executors.newFixedThreadPool(10); | |||
| private MsgQueueProducer blProducer; | |||
| private List<MessageEvent> exchangeEvents = new ArrayList<>(); | |||
| private String realmName; | |||
| private MessageHandle messageHandle; | |||
| private final AtomicInteger messageId = new AtomicInteger(); | |||
| private int txSizePerBlock = 1000; | |||
| private StateMachineReplicate stateMachineReplicator; | |||
| public MsgQueueMessageExecutor setRealmName(String realmName) { | |||
| this.realmName = realmName; | |||
| return this; | |||
| } | |||
| public MsgQueueMessageExecutor setBlProducer(MsgQueueProducer blProducer) { | |||
| this.blProducer = blProducer; | |||
| return this; | |||
| } | |||
| public MsgQueueMessageExecutor setTxSizePerBlock(int txSizePerBlock) { | |||
| this.txSizePerBlock = txSizePerBlock; | |||
| return this; | |||
| } | |||
| public MsgQueueMessageExecutor setMessageHandle(MessageHandle messageHandle) { | |||
| this.messageHandle = messageHandle; | |||
| return this; | |||
| } | |||
| public MsgQueueMessageExecutor setStateMachineReplicator(StateMachineReplicate stateMachineReplicator) { | |||
| this.stateMachineReplicator = stateMachineReplicator; | |||
| return this; | |||
| } | |||
| public MsgQueueMessageExecutor init() { | |||
| try { | |||
| long latestStateId = stateMachineReplicator.getLatestStateID(realmName); | |||
| // 设置基础消息ID | |||
| messageId.set(((int)latestStateId + 1) * txSizePerBlock); | |||
| blProducer.connect(); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return this; | |||
| } | |||
| @Override | |||
| public void onEvent(EventEntity<ExchangeEventInnerEntity> event, long sequence, boolean endOfBatch) throws Exception { | |||
| ExchangeEventInnerEntity entity = event.getEntity(); | |||
| if (entity != null) { | |||
| if (entity.getType() == ExchangeType.BLOCK || entity.getType() == ExchangeType.EMPTY) { | |||
| if (!exchangeEvents.isEmpty()) { | |||
| process(exchangeEvents); | |||
| exchangeEvents.clear(); | |||
| } | |||
| } else { | |||
| byte[] bytes = event.getEntity().getContent(); | |||
| String key = bytes2Key(bytes); | |||
| exchangeEvents.add(new MessageEvent(key, bytes)); | |||
| } | |||
| } | |||
| } | |||
| private void process(List<MessageEvent> messageEvents) { | |||
| if (messageEvents != null && !messageEvents.isEmpty()) { | |||
| try { | |||
| Map<String, AsyncFuture<byte[]>> txResponseMap = execute(messageEvents); | |||
| if (txResponseMap != null && !txResponseMap.isEmpty()) { | |||
| // byte[] asyncFuture; | |||
| for (Map.Entry<String, AsyncFuture<byte[]>> entry : txResponseMap.entrySet()) { | |||
| final String txKey = entry.getKey(); | |||
| final AsyncFuture<byte[]> asyncFuture = entry.getValue(); | |||
| // asyncFuture = entry.getValue().get(); | |||
| blockEventExecutor.execute(() -> { | |||
| TxBlockedEvent txBlockedEvent = new TxBlockedEvent(txKey, | |||
| MessageConvertUtil.base64Encode(asyncFuture.get())); | |||
| byte[] serializeBytes = MessageConvertUtil.serializeTxBlockedEvent(txBlockedEvent); | |||
| // 通过消息队列发送该消息 | |||
| try { | |||
| this.blProducer.publish(serializeBytes); | |||
| } catch (Exception e) { | |||
| LOGGER.error("publish block event message exception {}", e.getMessage()); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| } catch (Exception e) { | |||
| // 打印日志 | |||
| LOGGER.error("process message exception {}", e.getMessage()); | |||
| } | |||
| } | |||
| } | |||
| private Map<String, AsyncFuture<byte[]>> execute(List<MessageEvent> messageEvents) { | |||
| // System.out.printf("Thread[%s %s] execute messageEvents !!! \r\n", | |||
| // Thread.currentThread().getId(), Thread.currentThread().getName()); | |||
| Map<String, AsyncFuture<byte[]>> asyncFutureMap = new HashMap<>(); | |||
| // 使用MessageHandle处理 | |||
| // long startTime = System.currentTimeMillis(); | |||
| // int txSize = messageEvents.size(); | |||
| String batchId = messageHandle.beginBatch(realmName); | |||
| try { | |||
| for (MessageEvent messageEvent : messageEvents) { | |||
| String txKey = messageEvent.getMessageKey(); | |||
| byte[] txContent = messageEvent.getMessage(); | |||
| AsyncFuture<byte[]> asyncFuture = messageHandle.processOrdered(messageId.getAndIncrement(), txContent, realmName, batchId); | |||
| asyncFutureMap.put(txKey, asyncFuture); | |||
| } | |||
| messageHandle.completeBatch(realmName, batchId); | |||
| messageHandle.commitBatch(realmName, batchId); | |||
| // long totalTime = System.currentTimeMillis() - startTime; | |||
| // String content = String.format("batch[%s] process, time = {%s}ms, TPS = %.2f \r\n", | |||
| // batchId, totalTime, txSize * 1000.0D / totalTime); | |||
| // System.out.println(content); | |||
| // logQueue.put(content); | |||
| // 提交之后需要获取对应的结果 | |||
| } catch (Exception e) { | |||
| // todo 需要处理应答码 404 | |||
| messageHandle.rollbackBatch(realmName, batchId, TransactionState.CONSENSUS_ERROR.CODE); | |||
| } | |||
| return asyncFutureMap; | |||
| } | |||
| private String bytes2Key(byte[] bytes) { | |||
| return MessageConvertUtil.messageKey(bytes); | |||
| } | |||
| } | |||
| @@ -1,196 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.server.MsgQueueNodeServer | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 上午11:20 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider; | |||
| import com.jd.blockchain.consensus.mq.consumer.MsgQueueConsumer; | |||
| import com.jd.blockchain.consensus.mq.factory.MsgQueueFactory; | |||
| import com.jd.blockchain.consensus.mq.producer.MsgQueueProducer; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueBlockSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNetworkSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueServerSettings; | |||
| import com.jd.blockchain.consensus.service.MessageHandle; | |||
| import com.jd.blockchain.consensus.service.NodeServer; | |||
| import com.jd.blockchain.consensus.service.StateMachineReplicate; | |||
| import java.util.concurrent.Executors; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueNodeServer implements NodeServer { | |||
| private DefaultMsgQueueMessageDispatcher dispatcher; | |||
| private ExtendMsgQueueMessageExecutor extendExecutor; | |||
| private MessageHandle messageHandle; | |||
| private StateMachineReplicate stateMachineReplicator; | |||
| private MsgQueueMessageExecutor messageExecutor; | |||
| private MsgQueueNetworkSettings networkSettings; | |||
| private MsgQueueConsensusManageService manageService; | |||
| private int txSizePerBlock = 1000; | |||
| private long maxDelayMilliSecondsPerBlock = 1000; | |||
| private MsgQueueServerSettings serverSettings; | |||
| private boolean isRunning; | |||
| public MsgQueueNodeServer setMessageHandle(MessageHandle messageHandle) { | |||
| this.messageHandle = messageHandle; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer setStateMachineReplicator(StateMachineReplicate stateMachineReplicator) { | |||
| this.stateMachineReplicator = stateMachineReplicator; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer setTxSizePerBlock(int txSizePerBlock) { | |||
| this.txSizePerBlock = txSizePerBlock; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer setMaxDelayMilliSecondsPerBlock(long maxDelayMilliSecondsPerBlock) { | |||
| this.maxDelayMilliSecondsPerBlock = maxDelayMilliSecondsPerBlock; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer setMsgQueueNetworkSettings(MsgQueueNetworkSettings networkSettings) { | |||
| this.networkSettings = networkSettings; | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer setServerSettings(MsgQueueServerSettings serverSettings) { | |||
| this.serverSettings = serverSettings; | |||
| this.manageService = new MsgQueueConsensusManageService() | |||
| .setConsensusSettings(serverSettings.getConsensusSettings()); | |||
| return this; | |||
| } | |||
| public MsgQueueNodeServer init() { | |||
| String realmName = this.serverSettings.getRealmName(); | |||
| MsgQueueBlockSettings blockSettings = this.serverSettings.getBlockSettings(); | |||
| MsgQueueConsensusSettings consensusSettings = this.serverSettings.getConsensusSettings(); | |||
| this.setTxSizePerBlock(blockSettings.getTxSizePerBlock()) | |||
| .setMaxDelayMilliSecondsPerBlock(blockSettings.getMaxDelayMilliSecondsPerBlock()) | |||
| .setMsgQueueNetworkSettings(consensusSettings.getNetworkSettings()) | |||
| ; | |||
| String server = networkSettings.getServer(), | |||
| txTopic = networkSettings.getTxTopic(), | |||
| blTopic = networkSettings.getBlTopic(), | |||
| msgTopic = networkSettings.getMsgTopic(); | |||
| MsgQueueProducer blProducer = MsgQueueFactory.newProducer(server, blTopic), | |||
| txProducer = MsgQueueFactory.newProducer(server, txTopic), | |||
| msgProducer = MsgQueueFactory.newProducer(server, msgTopic); | |||
| MsgQueueConsumer txConsumer = MsgQueueFactory.newConsumer(server, txTopic), | |||
| msgConsumer = MsgQueueFactory.newConsumer(server, msgTopic); | |||
| initMessageExecutor(blProducer, realmName); | |||
| initDispatcher(txProducer, txConsumer); | |||
| initExtendExecutor(msgProducer, msgConsumer); | |||
| return this; | |||
| } | |||
| @Override | |||
| public String getProviderName() { | |||
| return MsgQueueConsensusProvider.NAME; | |||
| } | |||
| @Override | |||
| public MsgQueueConsensusManageService getManageService() { | |||
| return this.manageService; | |||
| } | |||
| @Override | |||
| public MsgQueueServerSettings getSettings() { | |||
| return serverSettings; | |||
| } | |||
| @Override | |||
| public boolean isRunning() { | |||
| return isRunning; | |||
| } | |||
| @Override | |||
| public synchronized void start() { | |||
| if (!isRunning) { | |||
| try { | |||
| dispatcher.connect(); | |||
| Executors.newSingleThreadExecutor().execute(dispatcher); | |||
| extendExecutor.connect(); | |||
| Executors.newSingleThreadExecutor().execute(extendExecutor); | |||
| isRunning = true; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| } | |||
| @Override | |||
| public synchronized void stop() { | |||
| if (isRunning) { | |||
| try { | |||
| dispatcher.stop(); | |||
| extendExecutor.stop(); | |||
| isRunning = false; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| } | |||
| } | |||
| private void initMessageExecutor(MsgQueueProducer blProducer, final String realmName) { | |||
| messageExecutor = new MsgQueueMessageExecutor() | |||
| .setRealmName(realmName) | |||
| .setMessageHandle(messageHandle) | |||
| .setBlProducer(blProducer) | |||
| .setStateMachineReplicator(stateMachineReplicator) | |||
| .setTxSizePerBlock(txSizePerBlock) | |||
| .init() | |||
| ; | |||
| } | |||
| private void initDispatcher(MsgQueueProducer txProducer, MsgQueueConsumer txConsumer) { | |||
| dispatcher = new DefaultMsgQueueMessageDispatcher(txSizePerBlock, maxDelayMilliSecondsPerBlock) | |||
| .setTxProducer(txProducer) | |||
| .setTxConsumer(txConsumer) | |||
| .setEventHandler(messageExecutor) | |||
| ; | |||
| dispatcher.init(); | |||
| } | |||
| private void initExtendExecutor(MsgQueueProducer msgProducer, MsgQueueConsumer msgConsumer) { | |||
| extendExecutor = new ExtendMsgQueueMessageExecutor() | |||
| .setMessageHandle(messageHandle) | |||
| .setMsgConsumer(msgConsumer) | |||
| .setMsgProducer(msgProducer) | |||
| ; | |||
| extendExecutor.init(); | |||
| } | |||
| } | |||
| @@ -1,61 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.server.MsgQueueNodeServerFactory | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:30 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.server; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueNodeConfig; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueServerConfig; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings; | |||
| import com.jd.blockchain.consensus.mq.settings.MsgQueueServerSettings; | |||
| import com.jd.blockchain.consensus.service.*; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MsgQueueNodeServerFactory implements NodeServerFactory { | |||
| @Override | |||
| public MsgQueueServerSettings buildServerSettings(String realmName, ConsensusSettings consensusSetting, String currentNodeAddress) { | |||
| if (!(consensusSetting instanceof MsgQueueConsensusSettings)) { | |||
| throw new IllegalArgumentException("ConsensusSettings data isn't supported! Accept MsgQueueConsensusSettings only!"); | |||
| } | |||
| MsgQueueNodeSettings nodeSettings = new MsgQueueNodeConfig().setAddress(currentNodeAddress); | |||
| MsgQueueServerSettings serverSettings = new MsgQueueServerConfig() | |||
| .setRealmName(realmName) | |||
| .setNodeSettings(nodeSettings) | |||
| .setConsensusSettings((MsgQueueConsensusSettings) consensusSetting) | |||
| ; | |||
| return serverSettings; | |||
| } | |||
| @Override | |||
| public MsgQueueNodeServer setupServer(ServerSettings serverSettings, MessageHandle messageHandler, StateMachineReplicate stateMachineReplicator) { | |||
| if (!(serverSettings instanceof MsgQueueServerSettings)) { | |||
| throw new IllegalArgumentException("ServerSettings data isn't supported! Accept MsgQueueServerSettings only!"); | |||
| } | |||
| MsgQueueNodeServer nodeServer = new MsgQueueNodeServer() | |||
| .setServerSettings((MsgQueueServerSettings) serverSettings) | |||
| .setMessageHandle(messageHandler) | |||
| .setStateMachineReplicator(stateMachineReplicator) | |||
| .init() | |||
| ; | |||
| return nodeServer; | |||
| } | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueBlockSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:28 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| 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 shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| @DataContract(code = DataCodes.CONSENSUS_MSGQUEUE_BLOCK_SETTINGS) | |||
| public interface MsgQueueBlockSettings { | |||
| @DataField(order = 0, primitiveType = PrimitiveType.INT32) | |||
| int getTxSizePerBlock(); | |||
| @DataField(order = 1, primitiveType = PrimitiveType.INT64) | |||
| long getMaxDelayMilliSecondsPerBlock(); | |||
| } | |||
| @@ -1,30 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueClientIncomingSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:35 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consensus.ClientIncomingSettings; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| @DataContract(code = DataCodes.CONSENSUS_MSGQUEUE_CLI_INCOMING_SETTINGS) | |||
| public interface MsgQueueClientIncomingSettings extends ClientIncomingSettings { | |||
| @DataField(order = 1, primitiveType=PrimitiveType.BYTES) | |||
| PubKey getPubKey(); | |||
| } | |||
| @@ -1,23 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueClientSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:30 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| import com.jd.blockchain.consensus.client.ClientSettings; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MsgQueueClientSettings extends ClientSettings { | |||
| MsgQueueNetworkSettings getMsgQueueNetworkSettings(); | |||
| } | |||
| @@ -1,33 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueConsensusSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:37 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.binaryproto.DataField; | |||
| import com.jd.blockchain.binaryproto.PrimitiveType; | |||
| import com.jd.blockchain.consensus.ConsensusSettings; | |||
| import com.jd.blockchain.consensus.mq.config.MsgQueueBlockConfig; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| import com.jd.blockchain.utils.Property; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| @DataContract(code = DataCodes.CONSENSUS_MSGQUEUE_SETTINGS) | |||
| public interface MsgQueueConsensusSettings extends ConsensusSettings { | |||
| @DataField(order = 0, refContract = true) | |||
| MsgQueueNetworkSettings getNetworkSettings(); | |||
| @DataField(order = 1, refContract = true) | |||
| MsgQueueBlockSettings getBlockSettings(); | |||
| } | |||
| @@ -1,36 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.mq.config.MsgQueueNetworkSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/12 上午11:43 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| 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 shaozhuguang | |||
| * @create 2018/12/12 | |||
| * @since 1.0.0 | |||
| */ | |||
| @DataContract(code = DataCodes.CONSENSUS_MSGQUEUE_NETWORK_SETTINGS) | |||
| public interface MsgQueueNetworkSettings { | |||
| @DataField(order = 0, primitiveType = PrimitiveType.TEXT) | |||
| String getServer(); | |||
| @DataField(order = 1, primitiveType = PrimitiveType.TEXT) | |||
| String getTxTopic(); | |||
| @DataField(order = 2, primitiveType = PrimitiveType.TEXT) | |||
| String getBlTopic(); | |||
| @DataField(order = 3, primitiveType = PrimitiveType.TEXT) | |||
| String getMsgTopic(); | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.settings.MsgQueueNodeSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:50 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| import com.jd.blockchain.binaryproto.DataContract; | |||
| import com.jd.blockchain.consensus.NodeSettings; | |||
| import com.jd.blockchain.consts.DataCodes; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| @DataContract(code=DataCodes.CONSENSUS_MSGQUEUE_NODE_SETTINGS) | |||
| public interface MsgQueueNodeSettings extends NodeSettings { | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.consensus.mq.config.MsgQueueServerSettings | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/12/13 下午4:39 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.settings; | |||
| import com.jd.blockchain.consensus.service.ServerSettings; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/12/13 | |||
| * @since 1.0.0 | |||
| */ | |||
| public interface MsgQueueServerSettings extends ServerSettings { | |||
| MsgQueueBlockSettings getBlockSettings(); | |||
| MsgQueueConsensusSettings getConsensusSettings(); | |||
| } | |||
| @@ -1,95 +0,0 @@ | |||
| /** | |||
| * Copyright: Copyright 2016-2020 JD.COM All Right Reserved | |||
| * FileName: com.jd.blockchain.sdk.mq.event.MessageConvertUtil | |||
| * Author: shaozhuguang | |||
| * Department: 区块链研发部 | |||
| * Date: 2018/11/21 下午7:28 | |||
| * Description: | |||
| */ | |||
| package com.jd.blockchain.consensus.mq.util; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.jd.blockchain.consensus.mq.event.BlockEvent; | |||
| import com.jd.blockchain.consensus.mq.event.TxBlockedEvent; | |||
| import com.jd.blockchain.utils.security.ShaUtils; | |||
| import org.springframework.util.Base64Utils; | |||
| /** | |||
| * | |||
| * @author shaozhuguang | |||
| * @create 2018/11/21 | |||
| * @since 1.0.0 | |||
| */ | |||
| public class MessageConvertUtil { | |||
| public static final String defaultCharsetName = "UTF-8"; | |||
| public static String base64Encode(byte[] src) { | |||
| return Base64Utils.encodeToString(src); | |||
| } | |||
| public static byte[] base64Decode(String src) { | |||
| return Base64Utils.decodeFromString(src); | |||
| } | |||
| public static String messageKey(byte[] src) { | |||
| return base64Encode(ShaUtils.hash_256(src)); | |||
| } | |||
| public static BlockEvent convertBytes2BlockEvent(byte[] serializeBytes) { | |||
| String text; | |||
| try{ | |||
| text = new String(serializeBytes, defaultCharsetName); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return convertString2BlockEvent(text); | |||
| } | |||
| public static BlockEvent convertString2BlockEvent(String serializeString) { | |||
| return JSON.parseObject(serializeString, BlockEvent.class); | |||
| } | |||
| public static TxBlockedEvent convertBytes2TxBlockedEvent(byte[] serializeBytes) { | |||
| String text; | |||
| try{ | |||
| text = new String(serializeBytes, defaultCharsetName); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return convertString2TxBlockedEvent(text); | |||
| } | |||
| public static TxBlockedEvent convertString2TxBlockedEvent(String serializeString) { | |||
| return JSON.parseObject(serializeString, TxBlockedEvent.class); | |||
| } | |||
| public static byte[] serializeBlockEvent(BlockEvent blockEvent) { | |||
| String serializeString = serializeEvent(blockEvent); | |||
| byte[] serializeBytes; | |||
| try { | |||
| serializeBytes = serializeString.getBytes(defaultCharsetName); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return serializeBytes; | |||
| } | |||
| public static byte[] serializeTxBlockedEvent(TxBlockedEvent txBlockedEvent) { | |||
| String serializeString = JSON.toJSONString(txBlockedEvent); | |||
| byte[] serializeBytes; | |||
| try { | |||
| serializeBytes = serializeString.getBytes(defaultCharsetName); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| return serializeBytes; | |||
| } | |||
| public static String serializeEvent(BlockEvent blockEvent) { | |||
| return JSON.toJSONString(blockEvent); | |||
| } | |||
| } | |||
| @@ -1,17 +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-core</artifactId> | |||
| <version>1.2.0-SNAPSHOT</version> | |||
| </parent> | |||
| <artifactId>consensus-core</artifactId> | |||
| <packaging>pom</packaging> | |||
| <modules> | |||
| <module>consensus-bftsmart</module> | |||
| <module>consensus-mq</module> | |||
| </modules> | |||
| </project> | |||
| @@ -1,27 +0,0 @@ | |||
| ### 合约相关说明 | |||
| 1. 编译合约入口:ContractCompilerCmdTest.java; | |||
| 2. 账本调用合约测试入口:ContractEventSendOperationHandleTest.java; | |||
| ### 单元测试注意事项 | |||
| 使用ContractEventSendOperationHandleTest.java进行单元测试,注意事项: | |||
| 1. 设置合约使用PUB_CLASS_PATH、CORE_CLASS_PATH位置(sys-contract.properties); | |||
| PUB包在根目录中的contract-libs文件夹;core包需要编译来生成。具体如下: | |||
| - 进入contract-jar模块,执行maven命令: | |||
| ``` | |||
| mvn clean assembly:assembly | |||
| ``` | |||
| - 生成的core包位于模块的target中的contract-jar-xxx所在的coreLib中; | |||
| - 将此coreLib目录作为CORE_CLASS_PATH指向的目录。 | |||
| 2. 编译生成合约压缩包,即执行:ContractCompilerCmdTest.java对应的mainTestOk(); | |||
| 在编译之前,修改sys-contract.properties文件的变量CONTRACT_FROM_PATH(合约源文件位置)、CONTRACT_SAVE_TO_PATH(合约保存位置)。 | |||
| 3. 在合约保存位置中可看到生成的压缩包:xxx.contract;然后执行 ContractEventSendOperationHandleTest.java测试用例test1()即可。 | |||
| ### 20180910版本改造 | |||
| 1. 在contract-jar中添加了mvn assembly处理逻辑,将合约用到的lib包全部放置其target/xxx/pubLib文件夹中,执行: | |||
| ``` | |||
| mvn clean assembly:assembly | |||
| ``` | |||
| 2. 修改了sys-contract.properties文件,新增了CONTRACT_CLASS_LIBS参数; | |||
| - 将CONTRACT_CLASS_PATH专用于存储路径 | |||
| - CONTRACT_CLASS_LIBS来存放所有的jar包 | |||
| 3. 删减了contract-libs文件夹中需要动态生成的jar。 | |||
| @@ -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>contract-core</artifactId> | |||
| <version>1.2.0-SNAPSHOT</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> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| @@ -1,105 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import java.lang.reflect.Method; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.util.ReflectionUtils; | |||
| import com.jd.blockchain.contract.ContractEventContext; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.contract.EventProcessingAware; | |||
| import com.jd.blockchain.contract.engine.ContractCode; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.ledger.BytesValueEncoding; | |||
| import com.jd.blockchain.ledger.BytesValueList; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| /** | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public abstract class AbstractContractCode implements ContractCode { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(AbstractContractCode.class); | |||
| private Bytes address; | |||
| private long version; | |||
| private ContractDefinition contractDefinition; | |||
| public AbstractContractCode(Bytes address, long version, ContractDefinition contractDefinition) { | |||
| this.address = address; | |||
| this.version = version; | |||
| this.contractDefinition = contractDefinition; | |||
| } | |||
| public ContractDefinition getContractDefinition() { | |||
| return contractDefinition; | |||
| } | |||
| @Override | |||
| public Bytes getAddress() { | |||
| return address; | |||
| } | |||
| @Override | |||
| public long getVersion() { | |||
| return version; | |||
| } | |||
| @Override | |||
| public BytesValue processEvent(ContractEventContext eventContext) { | |||
| EventProcessingAware evtProcAwire = null; | |||
| Object retn = null; | |||
| Method handleMethod = null; | |||
| Exception error = null; | |||
| try { | |||
| // 执行预处理; | |||
| Object contractInstance = getContractInstance(); | |||
| if (contractInstance instanceof EventProcessingAware) { | |||
| evtProcAwire = (EventProcessingAware) contractInstance; | |||
| } | |||
| if (evtProcAwire != null) { | |||
| evtProcAwire.beforeEvent(eventContext); | |||
| } | |||
| // 反序列化参数; | |||
| handleMethod = contractDefinition.getType().getHandleMethod(eventContext.getEvent()); | |||
| if (handleMethod == null) { | |||
| throw new ContractException( | |||
| String.format("Contract[%s:%s] has no handle method to handle event[%s]!", address.toString(), | |||
| contractDefinition.getType().getName(), eventContext.getEvent())); | |||
| } | |||
| BytesValueList bytesValues = eventContext.getArgs(); | |||
| Object[] args = BytesValueEncoding.decode(bytesValues, handleMethod.getParameterTypes()); | |||
| retn = ReflectionUtils.invokeMethod(handleMethod, contractInstance, args); | |||
| } catch (Exception e) { | |||
| error = e; | |||
| } | |||
| if (evtProcAwire != null) { | |||
| try { | |||
| evtProcAwire.postEvent(eventContext, error); | |||
| } catch (Exception e) { | |||
| String errorMessage = "Error occurred while posting contract event! --" + e.getMessage(); | |||
| LOGGER.error(errorMessage, e); | |||
| throw new ContractException(errorMessage, e); | |||
| } | |||
| } | |||
| if (error != null) { | |||
| // Rethrow error; | |||
| throw new ContractException(String.format("Error occurred while processing event[%s] of contract[%s]! --%s", | |||
| eventContext.getEvent(), address.toString(), error.getMessage()), error); | |||
| } | |||
| BytesValue retnBytes = BytesValueEncoding.encodeSingle(retn, handleMethod.getReturnType()); | |||
| return retnBytes; | |||
| } | |||
| protected abstract Object getContractInstance(); | |||
| } | |||
| @@ -1,24 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import com.jd.blockchain.contract.ContractType; | |||
| public class ContractDefinition { | |||
| private ContractType type; | |||
| private Class<?> mainClass; | |||
| public Class<?> getMainClass() { | |||
| return mainClass; | |||
| } | |||
| public ContractType getType() { | |||
| return type; | |||
| } | |||
| public ContractDefinition(ContractType type, Class<?> mainClass) { | |||
| this.type = type; | |||
| this.mainClass = mainClass; | |||
| } | |||
| } | |||
| @@ -1,25 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import com.jd.blockchain.contract.ContractType; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class InstantiatedContractCode<T> extends AbstractContractCode { | |||
| private T instance; | |||
| public InstantiatedContractCode(Bytes address, long version, Class<T> delaredInterface, T instance) { | |||
| super(address, version, resolveContractDefinition(delaredInterface, instance.getClass())); | |||
| this.instance = instance; | |||
| } | |||
| private static ContractDefinition resolveContractDefinition(Class<?> declaredIntf, Class<?> implementedClass) { | |||
| ContractType contractType = ContractType.resolve(declaredIntf); | |||
| return new ContractDefinition(contractType, implementedClass); | |||
| } | |||
| @Override | |||
| protected T getContractInstance() { | |||
| return instance; | |||
| } | |||
| } | |||
| @@ -1,41 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import com.jd.blockchain.contract.engine.ContractCode; | |||
| import com.jd.blockchain.contract.engine.ContractEngine; | |||
| import com.jd.blockchain.runtime.Module; | |||
| import com.jd.blockchain.runtime.RuntimeContext; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| public class JVMContractEngine implements ContractEngine { | |||
| private RuntimeContext runtimeContext = RuntimeContext.get(); | |||
| private String getCodeName(Bytes address, long version) { | |||
| return address.toBase58() + "_" + version; | |||
| } | |||
| @Override | |||
| public ContractCode getContract(Bytes address, long version) { | |||
| String codeName = getCodeName(address, version); | |||
| Module module = runtimeContext.getDynamicModule(codeName); | |||
| if (module == null) { | |||
| return null; | |||
| } | |||
| return new JavaContractCode(address, version, module); | |||
| } | |||
| @Override | |||
| public ContractCode setupContract(Bytes address, long version, byte[] code) { | |||
| //is there the contractCode before setup? if yes ,then return; | |||
| ContractCode contractCode = getContract(address,version); | |||
| if(contractCode != null){ | |||
| return contractCode; | |||
| } | |||
| String codeName = getCodeName(address, version); | |||
| Module module = runtimeContext.createDynamicModule(codeName,code); | |||
| if (module == null) { | |||
| return null; | |||
| } | |||
| return new JavaContractCode(address, version, module); | |||
| } | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import com.jd.blockchain.contract.engine.ContractEngine; | |||
| import com.jd.blockchain.contract.engine.ContractServiceProvider; | |||
| public class JVMContractServiceProvider implements ContractServiceProvider { | |||
| @Override | |||
| public String getName() { | |||
| return JVMContractServiceProvider.class.getName(); | |||
| } | |||
| @Override | |||
| public ContractEngine getEngine() { | |||
| return InnerEngine.INSTANCE; | |||
| } | |||
| private static class InnerEngine { | |||
| private static final ContractEngine INSTANCE = new JVMContractEngine(); | |||
| } | |||
| } | |||
| @@ -1,108 +0,0 @@ | |||
| package com.jd.blockchain.contract.jvm; | |||
| import java.util.concurrent.Callable; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import com.jd.blockchain.contract.Contract; | |||
| import com.jd.blockchain.contract.ContractEventContext; | |||
| import com.jd.blockchain.contract.ContractException; | |||
| import com.jd.blockchain.contract.ContractType; | |||
| import com.jd.blockchain.ledger.BytesValue; | |||
| import com.jd.blockchain.runtime.Module; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| /** | |||
| * 基于 java jar 包并且以模块化方式独立加载的合约代码; | |||
| * | |||
| * @author huanghaiquan | |||
| * | |||
| */ | |||
| public class JavaContractCode extends AbstractContractCode { | |||
| private static final Logger LOGGER = LoggerFactory.getLogger(JavaContractCode.class); | |||
| private Module codeModule; | |||
| private Bytes address; | |||
| private long version; | |||
| public JavaContractCode(Bytes address, long version, Module codeModule) { | |||
| super(address, version, resolveContractDefinition(codeModule)); | |||
| this.address = address; | |||
| this.version = version; | |||
| this.codeModule = codeModule; | |||
| } | |||
| protected static ContractDefinition resolveContractDefinition(Module codeModule) { | |||
| String mainClassName = codeModule.getMainClass(); | |||
| Class<?> mainClass = codeModule.loadClass(mainClassName); | |||
| Class<?>[] interfaces = mainClass.getInterfaces(); | |||
| Class<?> contractInterface = null; | |||
| for (Class<?> itf : interfaces) { | |||
| Contract annoContract = itf.getAnnotation(Contract.class); | |||
| if (annoContract != null) { | |||
| if (contractInterface == null) { | |||
| contractInterface = itf; | |||
| } else { | |||
| throw new ContractException( | |||
| "One contract definition is only allowed to implement one contract type!"); | |||
| } | |||
| } | |||
| } | |||
| if (contractInterface == null) { | |||
| throw new ContractException("No contract type is implemented!"); | |||
| } | |||
| ContractType type = ContractType.resolve(contractInterface); | |||
| return new ContractDefinition(type, mainClass); | |||
| } | |||
| @Override | |||
| public Bytes getAddress() { | |||
| return address; | |||
| } | |||
| @Override | |||
| public long getVersion() { | |||
| return version; | |||
| } | |||
| @Override | |||
| public BytesValue processEvent(ContractEventContext eventContext) { | |||
| if (LOGGER.isDebugEnabled()) { | |||
| LOGGER.debug("Start processing event{} of contract{}...", eventContext.getEvent(), address.toString()); | |||
| } | |||
| try { | |||
| return codeModule.call(new ContractExecution(eventContext)); | |||
| } catch (Exception ex) { | |||
| LOGGER.error(String.format("Error occurred while processing event[%s] of contract[%s]! --%s", | |||
| eventContext.getEvent(), address.toString(), ex.getMessage()), ex); | |||
| throw ex; | |||
| } finally { | |||
| if (LOGGER.isDebugEnabled()) { | |||
| LOGGER.debug("End processing event{} of contract{}. ", eventContext.getEvent(), address.toString()); | |||
| } | |||
| } | |||
| } | |||
| protected Object getContractInstance() { | |||
| try { | |||
| // 每一次调用都通过反射创建合约的实例; | |||
| return getContractDefinition().getMainClass().newInstance(); | |||
| } catch (InstantiationException | IllegalAccessException e) { | |||
| throw new IllegalStateException(e.getMessage(), e); | |||
| } | |||
| } | |||
| private class ContractExecution implements Callable<BytesValue> { | |||
| private ContractEventContext eventContext; | |||
| public ContractExecution(ContractEventContext contractEventContext) { | |||
| this.eventContext = contractEventContext; | |||
| } | |||
| @Override | |||
| public BytesValue call() throws Exception { | |||
| return JavaContractCode.super.processEvent(eventContext); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,274 +0,0 @@ | |||
| # 合约编译插件使用教程 | |||
| ### 1、maven引入 | |||
| 在pom.xml文件中引入合约编译插件: | |||
| ```xml | |||
| <plugin> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-maven-plugin</artifactId> | |||
| <version>1.0.0.RELEASE</version> | |||
| <executions> | |||
| <execution> | |||
| <id>make-contract</id> | |||
| <phase>package</phase> | |||
| <goals> | |||
| <goal>compile</goal> | |||
| </goals> | |||
| </execution> | |||
| </executions> | |||
| <configuration> | |||
| <archive> | |||
| <manifest> | |||
| <mainClass>com.jd.chain.contracts.ContractTestInfImpl</mainClass> | |||
| </manifest> | |||
| </archive> | |||
| <finalName>contract</finalName> | |||
| </configuration> | |||
| </plugin> | |||
| ``` | |||
| 需要说明的几点如下: | |||
| + 1)version:请根据实际JDChain发布版本确认,不同版本会有区别; | |||
| + 2)executions->execution->id:该值请随意指定; | |||
| + 3)executions->execution->phase:建议使用package及其后续阶段(若不了解phase含义,请自行查阅相关信息); | |||
| + 4)executions->execution->goals->goal:必须使用compile; | |||
| + 5)mainClass:必填,该类为需要发布的合约执行类(注意此处是类,不是接口),必须正确配置; | |||
| + 6)finalName:必填,最终在编译正常的情况下,会产生{finalName}-JDChain-Contract.jar文件,只有该文件是可以发布到JDChain的合约包; | |||
| ### 2、执行命令 | |||
| 使用mvn执行命令,下面两种方式均可: | |||
| 方式一:只执行contract插件命令 | |||
| ```shell | |||
| mvn clean compile contract:compile | |||
| ``` | |||
| 方式二:直接执行打包命令: | |||
| ```shell | |||
| mvn clean package | |||
| ``` | |||
| ### 3、合约编写要求 | |||
| 合约的执行结果会对整条链产生比较深刻的影响,为了使用户能够更好、更合理的使用合约,目前JDChain约定合约编写规则包括以下几点: | |||
| (违反其中任何一点都可能导致合约编译失败,但即使合约编译通过也不能保证合约可百分百运行正常) | |||
| + 1)合约工程必须引入com.jd.blockchain:sdk-pack:该包中有合约正常编写需要使用的基本类; | |||
| + 2)com.jd.blockchain:sdk-pack的scope必须定义为provided; | |||
| + 3)合约发布必须通过合约编译插件进行打包:合约编译插件不但会对Jar包进行校验,同时也会加入JDChain独有的特征,只有具有该特征的Jar才能正常发布; | |||
| + 4)合约中严禁使用随机数、IO、NIO等操作; | |||
| + 5)合约打包时,请使用<scope>provided</scope>排除常用的工具包,例如FastJson、apache下的一些工具包等; | |||
| + 6)合约必须有一个接口和该接口的实现类,详细要求如下: | |||
| - a. 接口必须有@Contract注解; | |||
| - b. 接口的可调用方法上必须有@ContractEvent注解,且每个注解中的name属性不能重复; | |||
| - c. 合约方法支持入参和返回值,其主要包括所有基本类型; | |||
| ### 4、合约案例 | |||
| #### 4.1、代码实例 | |||
| 以下是一个可创建银行账户,指定具体金额,并可以转账的合约代码(逻辑较简单,仅供参考): | |||
| 合约接口代码如下: | |||
| ```java | |||
| package com.jd.chain.contract; | |||
| @Contract | |||
| public interface TransferContract { | |||
| @ContractEvent(name = "create") | |||
| String create(String address, String account, long money); | |||
| @ContractEvent(name = "transfer") | |||
| String transfer(String address, String from, String to, long money); | |||
| @ContractEvent(name = "read") | |||
| long read(String address, String account); | |||
| @ContractEvent(name = "readAll") | |||
| String readAll(String address, String account); | |||
| } | |||
| ``` | |||
| 合约实现类代码如下: | |||
| ```java | |||
| package com.jd.chain.contract; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.ledger.KVDataEntry; | |||
| import com.jd.blockchain.ledger.KVDataVO; | |||
| import com.jd.blockchain.ledger.KVInfoVO; | |||
| public class TransferContractImpl implements EventProcessingAware, TransferContract { | |||
| private ContractEventContext eventContext; | |||
| private HashDigest ledgerHash; | |||
| @Override | |||
| public String create(String address, String account, long money) { | |||
| KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
| // 肯定有返回值,但若不存在则返回version=-1 | |||
| if (kvDataEntries != null && kvDataEntries.length > 0) { | |||
| long currVersion = kvDataEntries[0].getVersion(); | |||
| if (currVersion > -1) { | |||
| throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account)); | |||
| } | |||
| eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L); | |||
| } else { | |||
| throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58())); | |||
| } | |||
| return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n", | |||
| address, account, money); | |||
| } | |||
| @Override | |||
| public String transfer(String address, String from, String to, long money) { | |||
| // 首先查询余额 | |||
| KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); | |||
| if (kvDataEntries == null || kvDataEntries.length != 2) { | |||
| throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | |||
| } else { | |||
| // 判断from账号中钱数量是否足够 | |||
| long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | |||
| for (KVDataEntry kvDataEntry : kvDataEntries) { | |||
| if (kvDataEntry.getKey().equals(from)) { | |||
| fromMoney = (long) kvDataEntry.getValue(); | |||
| fromVersion = kvDataEntry.getVersion(); | |||
| } else { | |||
| toMoney = (long) kvDataEntry.getValue(); | |||
| toVersion = kvDataEntry.getVersion(); | |||
| } | |||
| } | |||
| if (fromMoney < money) { | |||
| throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from)); | |||
| } | |||
| long fromNewMoney = fromMoney - money; | |||
| long toNewMoney = toMoney + money; | |||
| // 重新设置 | |||
| eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion); | |||
| eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion); | |||
| } | |||
| return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money); | |||
| } | |||
| @Override | |||
| public long read(String address, String account) { | |||
| KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
| if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
| return -1; | |||
| } | |||
| return (long)kvDataEntries[0].getValue(); | |||
| } | |||
| @Override | |||
| public String readAll(String address, String account) { | |||
| KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||
| // 获取最新的版本号 | |||
| if (kvDataEntries == null || kvDataEntries.length == 0) { | |||
| return ""; | |||
| } | |||
| long newestVersion = kvDataEntries[0].getVersion(); | |||
| if (newestVersion == -1) { | |||
| return ""; | |||
| } | |||
| KVDataVO[] kvDataVOS = new KVDataVO[1]; | |||
| long[] versions = new long[(int)newestVersion + 1]; | |||
| for (int i = 0; i < versions.length; i++) { | |||
| versions[i] = i; | |||
| } | |||
| KVDataVO kvDataVO = new KVDataVO(account, versions); | |||
| kvDataVOS[0] = kvDataVO; | |||
| KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); | |||
| KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); | |||
| return JSON.toJSONString(allEntries); | |||
| } | |||
| @Override | |||
| public void beforeEvent(ContractEventContext eventContext) { | |||
| this.eventContext = eventContext; | |||
| this.ledgerHash = eventContext.getCurrentLedgerHash(); | |||
| } | |||
| @Override | |||
| public void postEvent(ContractEventContext eventContext, Exception error) { | |||
| } | |||
| } | |||
| ``` | |||
| #### 4.2、pom.xml文件实例 | |||
| ```xml | |||
| <?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"> | |||
| <groupId>com.jd.chain</groupId> | |||
| <version>1.0.0.RELEASE</version> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <artifactId>contract-samples</artifactId> | |||
| <name>contract-samples</name> | |||
| <dependencies> | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>sdk-pack</artifactId> | |||
| <version>1.0.0.RELEASE</version> | |||
| <scope>provided</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.alibaba</groupId> | |||
| <artifactId>fastjson</artifactId> | |||
| <version>1.2.32</version> | |||
| <scope>provided</scope> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| <plugins> | |||
| <plugin> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>contract-maven-plugin</artifactId> | |||
| <version>1.0.0.RELEASE</version> | |||
| <executions> | |||
| <execution> | |||
| <id>make-contract</id> | |||
| <phase>package</phase> | |||
| <goals> | |||
| <goal>compile</goal> | |||
| </goals> | |||
| </execution> | |||
| </executions> | |||
| <configuration> | |||
| <archive> | |||
| <manifest> | |||
| <mainClass>com.jd.chain.contract.TransferContractImpl</mainClass> | |||
| </manifest> | |||
| </archive> | |||
| <finalName>contract</finalName> | |||
| </configuration> | |||
| </plugin> | |||
| </plugins> | |||
| </build> | |||
| </project> | |||
| ``` | |||
| @@ -1 +0,0 @@ | |||
| 177gjsuHdbf3PU68Sm1ZU2aMcyB7sLWj94xwBUoUKvTgHq7qGUfg6ynDB62hocYYXSRXD4X | |||
| @@ -1 +0,0 @@ | |||
| endPsK36imXrY66pru6ttZ8dZ3TynWekmdqoM1K7ZRRoRBBiYVzM | |||
| @@ -1 +0,0 @@ | |||
| abc | |||
| @@ -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-core</artifactId> | |||
| <version>1.2.0-SNAPSHOT</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 @@ | |||
| 说明 | |||
| 1.编译:mvn clean install | |||
| 快速自测: | |||
| 1.ContractRemoteAutoMojoTest类用于快速自测发布和执行,快速自测是在测试链的环境中发布和执行合约; | |||
| 2.修改sys-contract.properties文件中的相关信息; | |||
| 3.合约发布之后,会在控制台生成合约地址,待5秒钟之后,会执行此合约。sys-contract.properties的contractArgs参数可修改,查看其不同效果; | |||
| ### | |||
| contract's address=5SmEqUsnLY4APVfS32xYDpRPuz55Rsuupdt1 | |||
| execute the contract,result=true | |||
| exeContract(),SUCCESS | |||
| ### | |||
| 4.在peer节点的控制台可以看到输出的结果信息。 | |||
| 通过maven插件中通过ContractAllAutoMojo做简单的编译、发布和执行测试,对应单元测试类ContractAllAutoMojoTest; | |||
| @@ -1,178 +0,0 @@ | |||
| package com.jd.blockchain; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import com.jd.blockchain.binaryproto.DataContractRegistry; | |||
| import com.jd.blockchain.crypto.HashDigest; | |||
| import com.jd.blockchain.crypto.KeyGenUtils; | |||
| import com.jd.blockchain.crypto.PrivKey; | |||
| import com.jd.blockchain.crypto.PubKey; | |||
| import com.jd.blockchain.ledger.*; | |||
| import com.jd.blockchain.sdk.BlockchainService; | |||
| import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||
| import com.jd.blockchain.utils.Bytes; | |||
| import com.jd.blockchain.utils.codec.Base58Utils; | |||
| import com.jd.blockchain.utils.net.NetworkAddress; | |||
| /** | |||
| * @Author zhaogw | |||
| * @Date 2018/11/2 10:18 | |||
| */ | |||
| public enum ContractDeployExeUtil { | |||
| instance; | |||
| private BlockchainService bcsrv; | |||
| private Bytes contractAddress; | |||
| public BlockchainKeypair getKeyPair(String pubPath, String prvPath, String rawPassword){ | |||
| PubKey pub = null; | |||
| PrivKey prv = null; | |||
| try { | |||
| prv = KeyGenUtils.readPrivKey(prvPath, KeyGenUtils.encodePassword(rawPassword)); | |||
| pub = KeyGenUtils.readPubKey(pubPath); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return new BlockchainKeypair(pub, prv); | |||
| } | |||
| public PubKey getPubKey(String pubPath){ | |||
| PubKey pub = null; | |||
| try { | |||
| if(pubPath == null){ | |||
| BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | |||
| pub = contractKeyPair.getPubKey(); | |||
| }else { | |||
| pub = KeyGenUtils.readPubKey(pubPath); | |||
| } | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return pub; | |||
| } | |||
| public byte[] getChainCode(String path){ | |||
| byte[] chainCode = null; | |||
| File file = null; | |||
| InputStream input = null; | |||
| try { | |||
| file = new File(path); | |||
| input = new FileInputStream(file); | |||
| chainCode = new byte[input.available()]; | |||
| input.read(chainCode); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } finally { | |||
| try { | |||
| if(input!=null){ | |||
| input.close(); | |||
| } | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| return chainCode; | |||
| } | |||
| private void register(){ | |||
| DataContractRegistry.register(TransactionContent.class); | |||
| DataContractRegistry.register(TransactionContentBody.class); | |||
| DataContractRegistry.register(TransactionRequest.class); | |||
| DataContractRegistry.register(NodeRequest.class); | |||
| DataContractRegistry.register(EndpointRequest.class); | |||
| DataContractRegistry.register(TransactionResponse.class); | |||
| DataContractRegistry.register(DataAccountKVSetOperation.class); | |||
| DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); | |||
| DataContractRegistry.register(Operation.class); | |||
| DataContractRegistry.register(ContractCodeDeployOperation.class); | |||
| DataContractRegistry.register(ContractEventSendOperation.class); | |||
| DataContractRegistry.register(DataAccountRegisterOperation.class); | |||
| DataContractRegistry.register(UserRegisterOperation.class); | |||
| DataContractRegistry.register(ParticipantRegisterOperation.class); | |||
| DataContractRegistry.register(ParticipantStateUpdateOperation.class); | |||
| } | |||
| public BlockchainService initBcsrv(String host, int port) { | |||
| if(bcsrv!=null){ | |||
| return bcsrv; | |||
| } | |||
| NetworkAddress addr = new NetworkAddress(host, port); | |||
| GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(addr); | |||
| bcsrv = gwsrvFact.getBlockchainService(); | |||
| return bcsrv; | |||
| } | |||
| public boolean deploy(HashDigest ledgerHash, BlockchainIdentity contractIdentity, BlockchainKeypair ownerKey, byte[] chainCode){ | |||
| register(); | |||
| TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||
| txTpl.contracts().deploy(contractIdentity, chainCode); | |||
| PreparedTransaction ptx = txTpl.prepare(); | |||
| ptx.sign(ownerKey); | |||
| // 提交并等待共识返回; | |||
| TransactionResponse txResp = ptx.commit(); | |||
| // 验证结果; | |||
| contractAddress = contractIdentity.getAddress(); | |||
| this.setContractAddress(contractAddress); | |||
| System.out.println("contract's address="+contractAddress); | |||
| return txResp.isSuccess(); | |||
| } | |||
| public boolean deploy(String host, int port, HashDigest ledgerHash, BlockchainKeypair ownerKey, byte[] chainCode){ | |||
| register(); | |||
| BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity(); | |||
| initBcsrv(host,port); | |||
| return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||
| } | |||
| // 根据用户指定的公钥生成合约地址 | |||
| public boolean deploy(String host, int port, String ledger,String ownerPubPath, String ownerPrvPath, | |||
| String ownerPassword, String chainCodePath,String pubPath){ | |||
| PubKey pubKey = getPubKey(pubPath); | |||
| BlockchainIdentity contractIdentity = new BlockchainIdentityData(pubKey); | |||
| byte[] chainCode = getChainCode(chainCodePath); | |||
| BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||
| HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||
| initBcsrv(host,port); | |||
| return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||
| } | |||
| // 暂不支持从插件执行合约;此外,由于合约参数调用的格式发生变化,故此方法被废弃;by: huanghaiquan at 2019-04-30; | |||
| // public boolean exeContract(String ledger,String ownerPubPath, String ownerPrvPath, | |||
| // String ownerPassword,String event,String contractArgs){ | |||
| // BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||
| // HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||
| // | |||
| // // 定义交易,传输最简单的数字、字符串、提取合约中的地址; | |||
| // TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||
| // txTpl.contractEvents().send(getContractAddress(),event,contractArgs.getBytes()); | |||
| // | |||
| // // 签名; | |||
| // PreparedTransaction ptx = txTpl.prepare(); | |||
| // ptx.sign(ownerKey); | |||
| // | |||
| // // 提交并等待共识返回; | |||
| // TransactionResponse txResp = ptx.commit(); | |||
| // | |||
| // // 验证结果; | |||
| // return txResp.isSuccess(); | |||
| // } | |||
| public Bytes getContractAddress() { | |||
| return contractAddress; | |||
| } | |||
| public void setContractAddress(Bytes contractAddress) { | |||
| this.contractAddress = contractAddress; | |||
| } | |||
| } | |||