From bbf938553fec7396e771f6f26025e7b5a8034d66 Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 8 Aug 2019 16:28:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96ump=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/manager/ump-booter/pom.xml | 60 ++ .../java/com/jd/blockchain/ump/UmpBooter.java | 138 +++ .../jd/blockchain/ump/UmpConfiguration.java | 12 + .../src/main/resources/application.properties | 5 + .../src/main/resources/assembly.xml | 27 + .../ump-booter/src/main/resources/banner.txt | 13 + .../src/main/resources/config.properties | 8 + .../src/main/resources/log4j2-jump.xml | 46 + .../src/main/resources/scripts/jump-start.sh | 9 + .../src/main/resources/scripts/jump-stop.sh | 16 + source/manager/ump-model/pom.xml | 81 ++ .../jd/blockchain/ump/dao/DBConnection.java | 16 + .../ump/dao/DBConnectionProvider.java | 58 ++ .../ump/dao/MemoryDBConnection.java | 47 + .../blockchain/ump/dao/RocksDBConnection.java | 145 +++ .../com/jd/blockchain/ump/dao/UmpDao.java | 4 + .../jd/blockchain/ump/dao/UmpDaoHandler.java | 115 +++ .../jd/blockchain/ump/model/MasterAddr.java | 47 + .../jd/blockchain/ump/model/PartiNode.java | 88 ++ .../ump/model/PeerSharedConfigs.java | 217 ++++ .../jd/blockchain/ump/model/UmpConstant.java | 104 ++ .../com/jd/blockchain/ump/model/UmpQueue.java | 50 + .../ump/model/config/ConsensusConfig.java | 24 + .../ump/model/config/LedgerConfig.java | 46 + .../model/config/LedgerIdentification.java | 92 ++ .../ump/model/config/LedgerInitConfig.java | 141 +++ .../ump/model/config/MasterConfig.java | 89 ++ .../ump/model/config/PeerLocalConfig.java | 160 +++ .../ump/model/config/PeerSharedConfig.java | 86 ++ .../ump/model/config/PeerSharedConfigVv.java | 180 ++++ .../ump/model/state/InstallProcess.java | 21 + .../ump/model/state/InstallSchedule.java | 54 + .../ump/model/state/LedgerBindingConf.java | 33 + .../ump/model/state/LedgerInited.java | 101 ++ .../ump/model/state/LedgerMasterInstall.java | 156 +++ .../ump/model/state/LedgerPeerInited.java | 42 + .../ump/model/state/LedgerPeerInstall.java | 117 +++ .../ump/model/state/PeerInstallSchedule.java | 32 + .../ump/model/state/PeerInstallSchedules.java | 61 ++ .../ump/model/state/PeerStartupSchedules.java | 40 + .../ump/model/state/ScheduleState.java | 43 + .../ump/model/state/StartupState.java | 48 + .../ump/model/user/UserKeyBuilder.java | 34 + .../blockchain/ump/model/user/UserKeys.java | 68 ++ .../blockchain/ump/model/user/UserKeysVv.java | 69 ++ .../blockchain/ump/model/web/ErrorCode.java | 20 + .../blockchain/ump/model/web/WebResponse.java | 97 ++ source/manager/ump-service/pom.xml | 114 +++ .../blockchain/ump/service/LedgerService.java | 31 + .../ump/service/LedgerServiceHandler.java | 310 ++++++ .../jd/blockchain/ump/service/UmpService.java | 36 + .../ump/service/UmpServiceHandler.java | 925 ++++++++++++++++++ .../ump/service/UmpSimulateService.java | 17 + .../service/UmpSimulateServiceHandler.java | 134 +++ .../ump/service/UmpStateService.java | 62 ++ .../ump/service/UmpStateServiceHandler.java | 880 +++++++++++++++++ .../blockchain/ump/service/UtilService.java | 15 + .../ump/service/UtilServiceHandler.java | 80 ++ .../service/consensus/ConsensusProvider.java | 21 + .../service/consensus/ConsensusService.java | 10 + .../consensus/ConsensusServiceHandler.java | 79 ++ .../providers/BftsmartConsensusProvider.java | 162 +++ .../consensus/providers/BftsmartConstant.java | 17 + .../providers/MsgQueueConsensusProvider.java | 41 + .../jd/blockchain/ump/util/Base58Utils.java | 153 +++ .../jd/blockchain/ump/util/CommandUtils.java | 133 +++ .../blockchain/ump/util/HttpClientPool.java | 289 ++++++ .../ump/util/HttpJsonClientUtils.java | 61 ++ source/manager/ump-web/pom.xml | 83 ++ .../ump/controller/UmpDBController.java | 22 + .../ump/controller/UmpKeyController.java | 69 ++ .../ump/controller/UmpMasterController.java | 68 ++ .../ump/controller/UmpPeerController.java | 147 +++ .../controller/UmpPeerSimulateController.java | 64 ++ .../ump/web/ControllerConfigurer.java | 29 + .../ump/web/ExceptionResponseAdvice.java | 38 + .../ump/web/JsonResponseAdvice.java | 51 + .../ump/web/LogPrintInterceptor.java | 32 + 78 files changed, 7333 insertions(+) create mode 100644 source/manager/ump-booter/pom.xml create mode 100644 source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java create mode 100644 source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java create mode 100644 source/manager/ump-booter/src/main/resources/application.properties create mode 100644 source/manager/ump-booter/src/main/resources/assembly.xml create mode 100644 source/manager/ump-booter/src/main/resources/banner.txt create mode 100644 source/manager/ump-booter/src/main/resources/config.properties create mode 100644 source/manager/ump-booter/src/main/resources/log4j2-jump.xml create mode 100644 source/manager/ump-booter/src/main/resources/scripts/jump-start.sh create mode 100644 source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh create mode 100644 source/manager/ump-model/pom.xml create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java create mode 100644 source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java create mode 100644 source/manager/ump-service/pom.xml create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java create mode 100644 source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java create mode 100644 source/manager/ump-web/pom.xml create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java create mode 100644 source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java diff --git a/source/manager/ump-booter/pom.xml b/source/manager/ump-booter/pom.xml new file mode 100644 index 00000000..63461b0f --- /dev/null +++ b/source/manager/ump-booter/pom.xml @@ -0,0 +1,60 @@ + + + + + manager + com.jd.blockchain + 1.1.0-SNAPSHOT + + 4.0.0 + + ump-booter + + ump-booter + + + UTF-8 + 1.8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-devtools + true + + + junit + junit + test + + + diff --git a/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java b/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java new file mode 100644 index 00000000..97656b03 --- /dev/null +++ b/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpBooter.java @@ -0,0 +1,138 @@ +package com.jd.blockchain.ump; + +import org.springframework.boot.SpringApplication; + +import java.io.File; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + + +public class UmpBooter { + + private static final String ARG_PORT = "-p"; + + private static final String ARG_HOST = "-h"; + + private static final String CONFIG = "BOOT-INF" + File.separator + "classes" + File.separator + "config.properties"; + + private static final String CONFIG_PROP_HOST = "server.host"; + + private static final String CONFIG_PROP_HOST_DEFAULT = "0.0.0.0"; + + private static final String CONFIG_PROP_PORT = "server.port"; + + private static final String CONFIG_PROP_PORT_DEFAULT = "8080"; + + private static final String CONFIG_PROP_DB_URL = "db.url"; + + private static final String CONFIG_PROP_DB_URL_DEFAULT = "rocksdb://#project#/jumpdb"; + + public static void main(String[] args) { + try { + startServer(server(args)); + System.out.println("Server Start SUCCESS !!!"); + } catch (Exception e) { + e.printStackTrace(); + System.err.printf("Server Start FAIL -> %s, Exit JVM !!!", e.toString()); + // 正常退出 + System.exit(0); + } + } + + private static void startServer(Server server) { + + System.out.printf("server.address = %s, server.port = %s, db.url = %s \r\n", + server.host, server.port, server.dbUrl); + + List argList = new ArrayList<>(); + argList.add(String.format("--server.address=%s", server.host)); + argList.add(String.format("--server.port=%s", server.port)); + argList.add(String.format("--db.url=%s", server.dbUrl)); + + String[] args = argList.toArray(new String[argList.size()]); + + // 启动服务器; + SpringApplication.run(UmpConfiguration.class, args); + } + + private static Server server(String[] args) { + Server defaultServer = serverFromConfig(); + if (args == null || args.length == 0) { + return defaultServer; + } + String host = null; + + int port = 0; + + // 读取参数列表 + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.equals(ARG_HOST)) { + host = args[i + 1]; + } else if (arg.equals(ARG_PORT)) { + port = Integer.parseInt(args[i + 1]); + } + } + + // 参数列表中的数据不完整,则剩余部分数据从配置文件中获取 + if (host == null) { + host = defaultServer.host; + } + if (port == 0) { + port = defaultServer.port; + } + + return new Server(host, port, defaultServer.dbUrl); + } + + private static Server serverFromConfig() { + try { + InputStream inputStream = UmpBooter.class.getResourceAsStream(File.separator + CONFIG); + if (inputStream == null) { + System.err.println("InputStream is NULL !!!"); + } + Properties props = new Properties(); + props.load(inputStream); + String host = props.getProperty(CONFIG_PROP_HOST, CONFIG_PROP_HOST_DEFAULT); + int port = Integer.parseInt( + props.getProperty(CONFIG_PROP_PORT, CONFIG_PROP_PORT_DEFAULT)); + String dbUrl = props.getProperty(CONFIG_PROP_DB_URL, CONFIG_PROP_DB_URL_DEFAULT); + return new Server(host, port, dbUrl); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private static class Server { + + private String host; + + private int port; + + private String dbUrl; + + public Server(String host, int port, String dbUrl) { + this.host = host; + this.port = port; + this.dbUrl = dbUrl; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + } +} diff --git a/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java b/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java new file mode 100644 index 00000000..f1e86f12 --- /dev/null +++ b/source/manager/ump-booter/src/main/java/com/jd/blockchain/ump/UmpConfiguration.java @@ -0,0 +1,12 @@ +package com.jd.blockchain.ump; + + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@EnableConfigurationProperties +@SpringBootApplication(exclude = { + org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class} + ) +public class UmpConfiguration { +} diff --git a/source/manager/ump-booter/src/main/resources/application.properties b/source/manager/ump-booter/src/main/resources/application.properties new file mode 100644 index 00000000..b5ef6943 --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/application.properties @@ -0,0 +1,5 @@ +server.tomcat.uri-encoding=utf-8 + +spring.mvc.favicon.enabled=false + +logging.config=classpath:log4j2-jump.xml \ No newline at end of file diff --git a/source/manager/ump-booter/src/main/resources/assembly.xml b/source/manager/ump-booter/src/main/resources/assembly.xml new file mode 100644 index 00000000..8fd114ba --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/assembly.xml @@ -0,0 +1,27 @@ + + + ${project.version} + + zip + + false + + + src/main/resources/scripts + bin + + + + + false + true + ext + + com.jd.blockchain:ump-booter + + + + \ No newline at end of file diff --git a/source/manager/ump-booter/src/main/resources/banner.txt b/source/manager/ump-booter/src/main/resources/banner.txt new file mode 100644 index 00000000..c39618bd --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/banner.txt @@ -0,0 +1,13 @@ + + ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄ ▄ +▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░▌ ▐░▌ + ▀▀▀▀▀█░█▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░█▀▀▀▀▀▀▀█░▌ ▀▀▀▀█░█▀▀▀▀ ▐░▌░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌░▌ ▐░▌ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ + ▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▄▄▄▄█░█▄▄▄▄ ▐░▌ ▐░▐░▌ +▐░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░▌ ▐░░▌ + ▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀ + diff --git a/source/manager/ump-booter/src/main/resources/config.properties b/source/manager/ump-booter/src/main/resources/config.properties new file mode 100644 index 00000000..deaf015e --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/config.properties @@ -0,0 +1,8 @@ +# Tomcat启动的HOST,默认为0.0.0.0 +server.host=0.0.0.0 + +# Tomcat启动监听端口号 +server.port=8080 + +# 本地数据库存储位置 +db.url=rocksdb://#project#/jumpdb \ No newline at end of file diff --git a/source/manager/ump-booter/src/main/resources/log4j2-jump.xml b/source/manager/ump-booter/src/main/resources/log4j2-jump.xml new file mode 100644 index 00000000..6b19f527 --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/log4j2-jump.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/manager/ump-booter/src/main/resources/scripts/jump-start.sh b/source/manager/ump-booter/src/main/resources/scripts/jump-start.sh new file mode 100644 index 00000000..a31a5b28 --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/scripts/jump-start.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +HOME=$(cd `dirname $0`;cd ../; pwd) +UMP=$(ls $HOME/ext | grep ump-booter-) +if [ ! -n "UMP" ]; then + echo "Unified Management Platform Is Null !!!" +else + nohup java -jar -server -Djump.log=$HOME $HOME/ext/$UMP $* >$HOME/bin/jump.out 2>&1 & +fi \ No newline at end of file diff --git a/source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh b/source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh new file mode 100644 index 00000000..b7155c88 --- /dev/null +++ b/source/manager/ump-booter/src/main/resources/scripts/jump-stop.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +#启动Home路径 +BOOT_HOME=$(cd `dirname $0`;cd ../; pwd) + +#获取进程PID +PID=`ps -ef | grep $BOOT_HOME/ext/ump-booter | grep -v grep | awk '{print $2}'` + +#通过Kill命令将进程杀死 +if [ -z "$PID" ]; then + echo "Unable to find UMP PID. stop aborted." +else + echo "Start to kill PID = $PID ..." + kill -9 $PID + echo "Unified Management Platform has been stopped ..." +fi \ No newline at end of file diff --git a/source/manager/ump-model/pom.xml b/source/manager/ump-model/pom.xml new file mode 100644 index 00000000..67436cc0 --- /dev/null +++ b/source/manager/ump-model/pom.xml @@ -0,0 +1,81 @@ + + + + + manager + com.jd.blockchain + 1.1.0-SNAPSHOT + + 4.0.0 + + ump-model + + ump-model + + + UTF-8 + 1.8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-devtools + true + + + + com.alibaba + fastjson + + + + org.reflections + reflections + + + + org.rocksdb + rocksdbjni + + + + commons-io + commons-io + + + + junit + junit + test + + + diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java new file mode 100644 index 00000000..eea65d3f --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnection.java @@ -0,0 +1,16 @@ +package com.jd.blockchain.ump.dao; + +public interface DBConnection { + + String dbSchema(); + + DBConnection initDbUrl(String dbUrl); + + void put(String key, String value); + + void put(String key, Object value, Class type); + + String get(String key); + + boolean exist(String dbUrl); +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java new file mode 100644 index 00000000..d029a411 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/DBConnectionProvider.java @@ -0,0 +1,58 @@ +package com.jd.blockchain.ump.dao; + +import org.reflections.Reflections; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +public class DBConnectionProvider { + + private static final Map dbConnections = new ConcurrentHashMap<>(); + + static { + init(); + } + + public static DBConnection dbConnection(String dbUrl) { + String dbSchema = dbSchema(dbUrl); + if (!dbConnections.containsKey(dbSchema)) { + throw new IllegalStateException( + String.format("Can not find DBConnection by {%s} !", dbUrl)); + } + + DBConnection dbConnection = dbConnections.get(dbSchema); + return dbConnection.initDbUrl(dbUrl); + } + + + private static String dbSchema(String dbUrl) { + // rocksdb:///home/xxx -> rocksdb + return dbUrl.split("://")[0]; + + } + + private static void init() { + // 初始化所有实现类 + Reflections reflections = new Reflections("com.jd.blockchain.ump.dao"); + + Set> dbConnectionSet = + reflections.getSubTypesOf(DBConnection.class); + + for (Class clazz : dbConnectionSet) { + + if (!clazz.isInterface() && !clazz.equals(UmpDaoHandler.class)) { + try { + // 根据class生成对象 + DBConnection dbConnection = clazz.newInstance(); + String dbSchema = dbConnection.dbSchema(); + if (dbSchema != null && dbSchema.length() > 0) { + dbConnections.put(dbSchema, dbConnection); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java new file mode 100644 index 00000000..ac9e5755 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/MemoryDBConnection.java @@ -0,0 +1,47 @@ +package com.jd.blockchain.ump.dao; + +import com.alibaba.fastjson.JSON; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class MemoryDBConnection implements DBConnection { + + private static final String MEMORY_SCHEMA = "memory"; + + private final Map memory = new ConcurrentHashMap<>(); + + @Override + public String dbSchema() { + return MEMORY_SCHEMA; + } + + @Override + public DBConnection initDbUrl(String dbUrl) { + return this; + } + + @Override + public void put(String key, String value) { + memory.put(key, value); + } + + @Override + public void put(String key, Object value, Class type) { + String json = JSON.toJSONString(value); + put(key, json); + } + + @Override + public String get(String key) { + return memory.get(key); + } + + @Override + public boolean exist(String dbUrl) { + if (dbUrl.startsWith(MEMORY_SCHEMA)) { + return true; + } + return false; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java new file mode 100644 index 00000000..ed32c519 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/RocksDBConnection.java @@ -0,0 +1,145 @@ +package com.jd.blockchain.ump.dao; + + +import com.alibaba.fastjson.JSON; +import org.apache.commons.io.FileUtils; +import org.rocksdb.*; +import org.rocksdb.util.SizeUnit; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class RocksDBConnection implements DBConnection { + + public static final String SCHEMA = "rocksdb"; + + public static final String PROTOCOL_SPLIT = "://"; + + public static final String ROCKSDB_PROTOCOL = SCHEMA + PROTOCOL_SPLIT; + + static { + RocksDB.loadLibrary(); + } + + private RocksDB rocksDB; + + @Override + public String dbSchema() { + return SCHEMA; + } + + @Override + public DBConnection initDbUrl(String dbUrl) { + if (!dbUrl.startsWith(dbSchema())) { + throw new IllegalStateException(String.format("Unsupport DBConnection by URL {%s} !!!", dbUrl)); + } + String dbSavePath = dbUrl.split(PROTOCOL_SPLIT)[1]; + initDBConnection(dbSavePath); + return this; + } + + @Override + public void put(String key, String value) { + if (this.rocksDB == null) { + throw new IllegalStateException("Rocksdb is NULL, Please initDbUrl first !!!"); + } + try { + this.rocksDB.put(key.getBytes(UTF_8), value.getBytes(UTF_8)); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public void put(String key, Object value, Class type) { + // 使用JSON序列化 + String json = JSON.toJSONString(value); + put(key, json); + } + + @Override + public String get(String key) { + try { + byte[] value = this.rocksDB.get(key.getBytes(UTF_8)); + if (value != null && value.length > 0) { + return new String(value, UTF_8); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + return null; + } + + @Override + public boolean exist(String dbUrl) { + // 首先该dbUrl是Rocksdb + if (dbUrl.startsWith(ROCKSDB_PROTOCOL)) { + // 判断File是否存在,并且是文件夹 + File dbPath = new File(dbUrl.substring(ROCKSDB_PROTOCOL.length())); + if (dbPath.exists() && dbPath.isDirectory()) { + return true; + } + } + return false; + } + + private void initDBConnection(String dbUrl) { + try { + File dbPath = new File(dbUrl); + File dbParentPath = dbPath.getParentFile(); + if (!dbParentPath.exists()) { + FileUtils.forceMkdir(dbParentPath); + } + this.rocksDB = RocksDB.open(initOptions(), dbUrl); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage(), e); + } + } + + private Options initOptions() { + final Filter bloomFilter = new BloomFilter(32); + final BlockBasedTableConfig tableOptions = new BlockBasedTableConfig() + .setFilter(bloomFilter) + .setBlockSize(4 * SizeUnit.KB) + .setBlockSizeDeviation(10) + .setBlockCacheSize(64 * SizeUnit.GB) + .setNoBlockCache(false) + .setCacheIndexAndFilterBlocks(true) + .setBlockRestartInterval(16) + ; + final List compressionLevels = new ArrayList<>(); + compressionLevels.add(CompressionType.NO_COMPRESSION); // 0-1 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 1-2 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 2-3 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 3-4 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 4-5 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 5-6 + compressionLevels.add(CompressionType.SNAPPY_COMPRESSION); // 6-7 + + Options options = new Options() + .setAllowConcurrentMemtableWrite(true) + .setEnableWriteThreadAdaptiveYield(true) + .setCreateIfMissing(true) + .setMaxWriteBufferNumber(3) + .setTableFormatConfig(tableOptions) + .setMaxBackgroundCompactions(10) + .setMaxBackgroundFlushes(4) + .setBloomLocality(10) + .setMinWriteBufferNumberToMerge(4) + .setCompressionPerLevel(compressionLevels) + .setNumLevels(7) + .setCompressionType(CompressionType.SNAPPY_COMPRESSION) + .setCompactionStyle(CompactionStyle.UNIVERSAL) + .setMemTableConfig(new SkipListMemTableConfig()) + ; + return options; + } + + public static void main(String[] args) { + String path = "rocksdb:///zhangsan/lisi"; + System.out.println(path.substring(ROCKSDB_PROTOCOL.length())); + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java new file mode 100644 index 00000000..1da5d48b --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDao.java @@ -0,0 +1,4 @@ +package com.jd.blockchain.ump.dao; + +public interface UmpDao { +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java new file mode 100644 index 00000000..62cce01d --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/dao/UmpDaoHandler.java @@ -0,0 +1,115 @@ +package com.jd.blockchain.ump.dao; + +import com.jd.blockchain.ump.model.UmpConstant; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Repository; + +import java.io.File; + +@Repository +public class UmpDaoHandler implements UmpDao, CommandLineRunner, DBConnection { + + public final String PROJECT_FLAG = "#project#"; + + private static final String PROTOCOL_FILE = "file:"; + + private static final String INNER_FILE_SEPARATOR = "!"; + + private static final String PROTOCOL_SEPARATOR = "://"; + + private DBConnection dbConnection; + + @Override + public void run(String... args) { + + String dbUrl = RocksDBConnection.SCHEMA + PROTOCOL_SEPARATOR + + PROJECT_FLAG + File.separator + UmpConstant.DB_NAME; + + if (args != null && args.length > 0) { + for (String arg : args) { + if (arg.startsWith("--db.url")) { + dbUrl = arg.split("=")[1]; + } + } + } + + dbConnection = DBConnectionProvider.dbConnection(realPath(dbUrl)); + + initProjectPath(); + } + + private void initProjectPath() { + UmpConstant.PROJECT_PATH = projectPath(); + System.out.printf("Init Project Path = %s \r\n", UmpConstant.PROJECT_PATH); + } + + @Override + public String dbSchema() { + return null; + } + + @Override + public DBConnection initDbUrl(String dbUrl) { + return dbConnection; + } + + @Override + public void put(String key, String value) { + dbConnection.put(key, value); + } + + @Override + public void put(String key, Object value, Class type) { + dbConnection.put(key, value, type); + } + + @Override + public String get(String key) { + return dbConnection.get(key); + } + + @Override + public boolean exist(String dbUrl) { + try { + return dbConnection.exist(dbUrl); + } catch (Exception e) { + // 不关心异常 + System.err.println(e); + return false; + } + } + + private String realPath(String dbUrl) { + if (dbUrl.contains(PROJECT_FLAG)) { + // 获取当前jar包路径 + try { + String projectPath = projectPath(); + return dbUrl.replaceAll(PROJECT_FLAG, projectPath); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + return dbUrl; + } + + private String projectPath() { + File jarDirectory = new File(jarRootPath()); + return jarDirectory.getParentFile().getParentFile().getPath(); + } + + private String jarRootPath() { + // 获取Jar包所在路径 + String jarRootPath = UmpDaoHandler.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + + // 处理打包到SpringBoot后路径问题:file: + if (jarRootPath.startsWith(PROTOCOL_FILE)) { + jarRootPath = jarRootPath.substring(PROTOCOL_FILE.length()); + } + // 处理打包到SpringBoot后内部分隔符问题:! + if (jarRootPath.contains(INNER_FILE_SEPARATOR)) { + jarRootPath = jarRootPath.substring(0, jarRootPath.indexOf(INNER_FILE_SEPARATOR)); + } + + return jarRootPath; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java new file mode 100644 index 00000000..700cef0b --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/MasterAddr.java @@ -0,0 +1,47 @@ +package com.jd.blockchain.ump.model; + +public class MasterAddr { + + private String ipAddr; + + private int port; + + public MasterAddr() { + } + + public MasterAddr(String ipAddr, int port) { + this.ipAddr = ipAddr; + this.port = port; + } + + public String getIpAddr() { + return ipAddr; + } + + public void setIpAddr(String ipAddr) { + this.ipAddr = ipAddr; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public static MasterAddr newInstance(String ipAddr, int port) { + return new MasterAddr(ipAddr, port); + } + + public String toHttpUrl() { + return "http://" + ipAddr + ":" + port; + } + + public boolean legal() { + if (this.ipAddr == null || this.ipAddr.length() == 0 || this.port == 0) { + return false; + } + return true; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java new file mode 100644 index 00000000..9281d408 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PartiNode.java @@ -0,0 +1,88 @@ +package com.jd.blockchain.ump.model; + +import java.util.ArrayList; +import java.util.List; + +public class PartiNode { + + private int id; + + private String name; + + private String pubKey; + + private String initHost; + + private int initPort; + + private boolean isSecure; + + public List toConfigChars() { + + List configCharList = new ArrayList<>(); + + configCharList.add(formatConfig(UmpConstant.PARTINODE_NAME_FORMAT, name)); + + configCharList.add(formatConfig(UmpConstant.PARTINODE_PUBKEY_FORMAT, pubKey)); + + configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_HOST_FORMAT, initHost)); + + configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_PORT_FORMAT, initPort)); + + configCharList.add(formatConfig(UmpConstant.PARTINODE_INIT_SECURE_FORMAT, isSecure)); + + return configCharList; + } + + private String formatConfig(String formatter, Object value) { + return String.format(formatter, id) + "=" + value; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + public String getInitHost() { + return initHost; + } + + public void setInitHost(String initHost) { + this.initHost = initHost; + } + + public int getInitPort() { + return initPort; + } + + public void setInitPort(int initPort) { + this.initPort = initPort; + } + + public boolean isSecure() { + return isSecure; + } + + public void setSecure(boolean secure) { + isSecure = secure; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java new file mode 100644 index 00000000..63251967 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/PeerSharedConfigs.java @@ -0,0 +1,217 @@ +package com.jd.blockchain.ump.model; + +import com.jd.blockchain.ump.model.config.LedgerInitConfig; +import com.jd.blockchain.ump.model.config.MasterConfig; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.config.PeerSharedConfig; +import com.jd.blockchain.ump.model.state.LedgerMasterInstall; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class PeerSharedConfigs { + + /** + * 默认的一次邀请码最长等待时间,单位分钟,默认30分钟 + */ + private static final int MAX_WAIT_MINUTE = 30; + + private CountDownLatch latch = null; + + private Lock lock = new ReentrantLock(); + + private Lock waitLock = new ReentrantLock(); + + private Condition sizeCondition = waitLock.newCondition(); + + private List sharedConfigs = new ArrayList<>(); + + private int waitNodeSize; + + private String consensusProvider; + + private String sharedKey; + + private String ledgerName; + + private LedgerInitConfig ledgerInitConfig; + + public synchronized PeerSharedConfigs addConfig(PeerLocalConfig sharedConfig) { + + // 判断内容是否存在重复 + for (PeerSharedConfig innerSharedConfig : sharedConfigs) { + if (innerSharedConfig.getName().equals(sharedConfig.getName()) + || innerSharedConfig.getPubKey().equals(sharedConfig.getPubKey())) { + return null; + } + } + + if (sharedConfig.getMasterConfig().isMaster()) { + initDataByMaster(sharedConfig); + } + + sharedConfigs.add(sharedConfig); + + if (latch != null) { + // 不管是Master还是普通用户都需要-1 + latch.countDown(); + } + return this; + } + + /** + * 由Master节点传入的信息对数据进行初始化 + * + * @param sharedConfig + */ + private void initDataByMaster(PeerLocalConfig sharedConfig) { + + MasterConfig masterConfig = sharedConfig.getMasterConfig(); + + // master需要对数据进行组织 + if (latch == null) { + latch = new CountDownLatch(masterConfig.getNodeSize() - sharedConfigs.size()); + } + if (consensusProvider == null) { + consensusProvider = sharedConfig.getConsensusProvider(); + } + if (sharedKey == null) { + sharedKey = sharedConfig.getSharedKey(); + } + if (ledgerName == null) { + ledgerName = masterConfig.getLedgerName(); + } + waitNodeSize = masterConfig.getNodeSize(); + } + + /** + * 线程等待 + * 一直处于等待状态(30分钟),直到有线程调用single方法 + * + */ + public void await() { + waitLock.lock(); + try { + sizeCondition.await(MAX_WAIT_MINUTE, TimeUnit.MINUTES); + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + waitLock.unlock(); + } + } + + /** + * 通知其他线程等待状态结束 + * + */ + public void single() { + waitLock.lock(); + try { + sizeCondition.signalAll(); + } catch (Exception e) { + throw new IllegalStateException(e); + } finally { + waitLock.unlock(); + } + } + + /** + * Master线程调用,等待数据满足后通知其他线程 + * + */ + public void waitAndNotify() { + if (this.latch == null) { + throw new IllegalStateException("Please init MasterConfig first !!!"); + } + try { + latch.await(MAX_WAIT_MINUTE, TimeUnit.MINUTES); + single(); // 通知其他线程释放 + } catch (Exception e) { + if (sharedConfigs.size() >= waitNodeSize) { + // 成功 + single(); + } + } + } + + public synchronized LedgerInitConfig ledgerInitConfig(String seed, String createTime) { + if (ledgerInitConfig != null) { + return ledgerInitConfig; + } + + // 处理该ledgerInitConfig + ledgerInitConfig = new LedgerInitConfig(seed, ledgerName, createTime, consensusProvider, waitNodeSize); + + // 添加参与方 + for (int i = 0; i < sharedConfigs.size(); i++) { + PeerLocalConfig sharedConfig = sharedConfigs.get(i); + ledgerInitConfig.addPartiNode(sharedConfig.toPartiNode(i)); + } + + return ledgerInitConfig; + } + + public String getConsensusProvider() { + return consensusProvider; + } + + public void setConsensusProvider(String consensusProvider) { + this.consensusProvider = consensusProvider; + } + + public String getSharedKey() { + return sharedKey; + } + + public void setSharedKey(String sharedKey) { + this.sharedKey = sharedKey; + } + + public Lock getLock() { + return lock; + } + + public String getLedgerName() { + return ledgerName; + } + + public void setLedgerName(String ledgerName) { + this.ledgerName = ledgerName; + } + + public List getSharedConfigs() { + return sharedConfigs; + } + + public void setSharedConfigs(List sharedConfigs) { + this.sharedConfigs = sharedConfigs; + } + + public LedgerInitConfig getLedgerInitConfig() { + return ledgerInitConfig; + } + + public void setLedgerInitConfig(LedgerInitConfig ledgerInitConfig) { + this.ledgerInitConfig = ledgerInitConfig; + } + + public LedgerMasterInstall toLedgerMasterInstall() { + + // String ledgerKey, String sharedKey, int totalNodeSize + LedgerMasterInstall masterInstall = new LedgerMasterInstall( + ledgerInitConfig.ledgerKey(), sharedConfigs.size()) + .initCreateTime(ledgerInitConfig.getCreateTime()); + + for (PeerLocalConfig sharedConfig : sharedConfigs) { + + masterInstall.add(sharedConfig.toPeerInstall()); + } + + return masterInstall; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java new file mode 100644 index 00000000..5f383e02 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpConstant.java @@ -0,0 +1,104 @@ +package com.jd.blockchain.ump.model; + +import java.io.File; + +public class UmpConstant { + + public static String PROJECT_PATH = ""; + + public static final String DB_NAME = "jumpdb"; + + public static final String URL_SEPARATOR = "/"; + + public static final String URL_MASTER = "/master"; + + public static final String URL_PEER = "/peer"; + + public static final String PRIVATE_KEY_SUFFIX = ".priv"; + + public static final String PUBLIC_KEY_SUFFIX = ".priv"; + + public static final String PWD_SUFFIX = ".pwd"; + + public static final String REQUEST_SHARED_URL = URL_MASTER + URL_SEPARATOR + "share"; + + public static final String REQUEST_STATE_URL = URL_MASTER + URL_SEPARATOR + "receive"; + + public static final String PARTINODE_COUNT = "cons_parti.count"; + + public static final String PARTINODE_FORMAT = "cons_parti.%s"; + + public static final String PARTINODE_NAME_FORMAT = PARTINODE_FORMAT + ".name"; + + public static final String PARTINODE_PUBKEY_FORMAT = PARTINODE_FORMAT + ".pubkey"; + + public static final String PARTINODE_INIT_FORMAT = PARTINODE_FORMAT + ".initializer"; + + public static final String PARTINODE_INIT_HOST_FORMAT = PARTINODE_INIT_FORMAT + ".host"; + + public static final String PARTINODE_INIT_PORT_FORMAT = PARTINODE_INIT_FORMAT + ".port"; + + public static final String PARTINODE_INIT_SECURE_FORMAT = PARTINODE_INIT_FORMAT + ".secure"; + + public static final String LEDGER_PREFIX = "ledger"; + + public static final String LEDGER_SEED_PREFIX = LEDGER_PREFIX + ".seed"; + + public static final String LEDGER_NAME_PREFIX = LEDGER_PREFIX + ".name"; + + public static final String CREATE_TIME_PREFIX = "created-time"; + + public static final String CONSENSUS_PREFIX = "consensus"; + + public static final String CONSENSUS_PROVIDER_PREFIX = CONSENSUS_PREFIX + ".service-provider"; + + public static final String CONSENSUS_CONF_PREFIX = CONSENSUS_PREFIX + ".conf"; + + public static final String CRYPTO_PREFIX = "crypto"; + + public static final String CRYPTO_PROVIDERS_PREFIX = CRYPTO_PREFIX + ".service-providers"; + + public static final String LOCAL_PREFIX = "local"; + + public static final String LOCAL_PARTI_PREFIX = LOCAL_PREFIX + ".parti"; + + public static final String LOCAL_PARTI_ID_PREFIX = LOCAL_PARTI_PREFIX + ".id"; + + public static final String LOCAL_PARTI_PUBKEY_PREFIX = LOCAL_PARTI_PREFIX + ".pubkey"; + + public static final String LOCAL_PARTI_PRIVKEY_PREFIX = LOCAL_PARTI_PREFIX + ".privkey"; + + public static final String LOCAL_PARTI_PWD_PREFIX = LOCAL_PARTI_PREFIX + ".pwd"; + + public static final String LEDGER_BINDING_OUT_PREFIX = LEDGER_PREFIX + ".binding.out"; + + public static final String LEDGER_DB_URI_PREFIX = LEDGER_PREFIX + ".db.uri"; + + public static final String LEDGER_DB_PWD_PREFIX = LEDGER_PREFIX + ".db.pwd"; + + public static final String CMD_LEDGER_INIT = "/bin/bash %s -monitor"; + + public static final String CMD_START_UP_FORMAT = "/bin/bash %s"; + + public static final String PATH_BIN = File.separator + "bin"; + + public static final String PATH_LEDGER_INIT_BIN = PATH_BIN + File.separator + "ledger-init.sh"; + + public static final String PATH_STARTUP_BIN = PATH_BIN + File.separator + "startup.sh"; + + public static final String PATH_LIBS = File.separator + "libs"; + + public static final String PATH_SYSTEM = File.separator + "system"; + + public static final String PATH_CONFIG = File.separator + "config"; + + public static final String PATH_CONFIG_KEYS = PATH_CONFIG + File.separator + "keys"; + + public static final String PATH_LEDGER_BINDING_CONFIG = PATH_CONFIG + File.separator + "ledger-binding.conf"; + + public static final String PATH_CONFIG_INIT = PATH_CONFIG + File.separator + "init"; + + public static final String PATH_LOCAL_CONFIG = PATH_CONFIG_INIT + File.separator + "local.conf"; + + public static final String PATH_LEDGER_INIT_CONFIG = PATH_CONFIG_INIT + File.separator + "ledger.init"; +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java new file mode 100644 index 00000000..509fb4a5 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/UmpQueue.java @@ -0,0 +1,50 @@ +package com.jd.blockchain.ump.model; + +import com.jd.blockchain.ump.model.state.InstallSchedule; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class UmpQueue { + + private final BlockingQueue QUEUE_INSTALL_SCHEDULE = new LinkedBlockingQueue<>(); + + public void put(InstallSchedule installSchedule, MasterAddr masterAddr) throws InterruptedException { + QUEUE_INSTALL_SCHEDULE.put(new InstallScheduleRequest(installSchedule, masterAddr)); + } + + public InstallScheduleRequest take() throws InterruptedException { + return QUEUE_INSTALL_SCHEDULE.take(); + } + + public static class InstallScheduleRequest { + + private InstallSchedule installSchedule; + + private MasterAddr masterAddr; + + public InstallScheduleRequest() { + } + + public InstallScheduleRequest(InstallSchedule installSchedule, MasterAddr masterAddr) { + this.installSchedule = installSchedule; + this.masterAddr = masterAddr; + } + + public InstallSchedule getInstallSchedule() { + return installSchedule; + } + + public void setInstallSchedule(InstallSchedule installSchedule) { + this.installSchedule = installSchedule; + } + + public MasterAddr getMasterAddr() { + return masterAddr; + } + + public void setMasterAddr(MasterAddr masterAddr) { + this.masterAddr = masterAddr; + } + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java new file mode 100644 index 00000000..e6963c2f --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/ConsensusConfig.java @@ -0,0 +1,24 @@ +package com.jd.blockchain.ump.model.config; + +public class ConsensusConfig { + + private String confPath; + + private byte[] content; + + public String getConfPath() { + return confPath; + } + + public void setConfPath(String confPath) { + this.confPath = confPath; + } + + public byte[] getContent() { + return content; + } + + public void setContent(byte[] content) { + this.content = content; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java new file mode 100644 index 00000000..2b435f93 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerConfig.java @@ -0,0 +1,46 @@ +package com.jd.blockchain.ump.model.config; + +public class LedgerConfig { + + private LedgerInitConfig initConfig; + + /** + * 共识文件配置信息,Base58格式 + */ + private String consensusConfig; + + + public LedgerConfig() { + } + + /** + * 包装一下,使用JSON处理过程 + * + * @param ledgerConfig + */ + public LedgerConfig(LedgerConfig ledgerConfig) { + this.consensusConfig = ledgerConfig.getConsensusConfig(); + + } + + public LedgerConfig(LedgerInitConfig initConfig, String consensusConfig) { + this.initConfig = initConfig; + this.consensusConfig = consensusConfig; + } + + public LedgerInitConfig getInitConfig() { + return initConfig; + } + + public void setInitConfig(LedgerInitConfig initConfig) { + this.initConfig = initConfig; + } + + public String getConsensusConfig() { + return consensusConfig; + } + + public void setConsensusConfig(String consensusConfig) { + this.consensusConfig = consensusConfig; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java new file mode 100644 index 00000000..1b724dc7 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerIdentification.java @@ -0,0 +1,92 @@ +package com.jd.blockchain.ump.model.config; + +import com.jd.blockchain.ump.model.MasterAddr; + +public class LedgerIdentification { + + private String ledgerKey; + + private String ledgerAndNodeKey; + + private MasterAddr masterAddr; + + private int nodeId; + + private PeerLocalConfig localConfig; + + private LedgerInitConfig initConfig; + + public LedgerIdentification() { + } + + public LedgerIdentification(int nodeId, PeerLocalConfig localConfig, MasterAddr masterAddr, String ledgerAndNodeKey, LedgerInitConfig initConfig) { + this.nodeId = nodeId; + this.localConfig = localConfig; + this.masterAddr = masterAddr; + this.ledgerKey = initConfig.ledgerKey(); + this.ledgerAndNodeKey = ledgerAndNodeKey; + this.initConfig = initConfig; + init(); + } + + private void init() { + // 初始化部分配置信息 + MasterConfig masterConfig = localConfig.getMasterConfig(); + // 设置账本名称 + if (masterConfig.getLedgerName() == null || masterConfig.getLedgerName().length() == 0) { + masterConfig.setLedgerName(initConfig.getName()); + } + // 设置NodeSize + if (masterConfig.getNodeSize() == 0) { + masterConfig.setNodeSize(initConfig.getNodeSize()); + } + } + + public String getLedgerKey() { + return ledgerKey; + } + + public void setLedgerKey(String ledgerKey) { + this.ledgerKey = ledgerKey; + } + + public String getLedgerAndNodeKey() { + return ledgerAndNodeKey; + } + + public void setLedgerAndNodeKey(String ledgerAndNodeKey) { + this.ledgerAndNodeKey = ledgerAndNodeKey; + } + + public MasterAddr getMasterAddr() { + return masterAddr; + } + + public void setMasterAddr(MasterAddr masterAddr) { + this.masterAddr = masterAddr; + } + + public int getNodeId() { + return nodeId; + } + + public void setNodeId(int nodeId) { + this.nodeId = nodeId; + } + + public PeerLocalConfig getLocalConfig() { + return localConfig; + } + + public void setLocalConfig(PeerLocalConfig localConfig) { + this.localConfig = localConfig; + } + + public LedgerInitConfig getInitConfig() { + return initConfig; + } + + public void setInitConfig(LedgerInitConfig initConfig) { + this.initConfig = initConfig; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java new file mode 100644 index 00000000..f31d84fe --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/LedgerInitConfig.java @@ -0,0 +1,141 @@ +package com.jd.blockchain.ump.model.config; + +import com.jd.blockchain.ump.model.PartiNode; +import com.jd.blockchain.ump.model.UmpConstant; + +import java.util.ArrayList; +import java.util.List; + +public class LedgerInitConfig { + + private String seed; + + private String name; + + private String createTime; + + private String consensusProvider; + + private int nodeSize; + + private String cryptoProviders = + "com.jd.blockchain.crypto.service.classic.ClassicCryptoService, " + + "com.jd.blockchain.crypto.service.sm.SMCryptoService"; + + + private List partiNodes = new ArrayList<>(); + + public LedgerInitConfig() { + } + + public LedgerInitConfig(String seed, String name, String createTime, String consensusProvider, int nodeSize) { + this.seed = seed; + this.name = name; + this.createTime = createTime; + this.consensusProvider = consensusProvider; + this.nodeSize = nodeSize; + } + + public List toConfigChars(String consensusConf) { + + List configChars = new ArrayList<>(); + + configChars.add(toConfigChars(UmpConstant.LEDGER_SEED_PREFIX, seed)); + + configChars.add(toConfigChars(UmpConstant.LEDGER_NAME_PREFIX, name)); + + configChars.add(toConfigChars(UmpConstant.CREATE_TIME_PREFIX, createTime)); + + configChars.add(toConfigChars(UmpConstant.CONSENSUS_PROVIDER_PREFIX, consensusProvider)); + + configChars.add(toConfigChars(UmpConstant.CONSENSUS_CONF_PREFIX, consensusConf)); + + configChars.add(toConfigChars(UmpConstant.CRYPTO_PROVIDERS_PREFIX, cryptoProviders)); + + configChars.add(toConfigChars(UmpConstant.PARTINODE_COUNT, partiNodes.size())); + + for (PartiNode partiNode : partiNodes) { + configChars.addAll(partiNode.toConfigChars()); + } + + return configChars; + } + + public String ledgerKey() { + return seed + "-" + name; + } + + public int nodeId(String pubKey) { + for (int i = 0; i < partiNodes.size(); i++) { + PartiNode partiNode = partiNodes.get(i); + if (partiNode.getPubKey().equals(pubKey)) { + return i; + } + } + throw new IllegalStateException(String.format("Can not find PubKey = %s !", pubKey)); + } + + private String toConfigChars(String prefix, Object value) { + return prefix + "=" + value; + } + + public String getSeed() { + return seed; + } + + public void setSeed(String seed) { + this.seed = seed; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getConsensusProvider() { + return consensusProvider; + } + + public void setConsensusProvider(String consensusProvider) { + this.consensusProvider = consensusProvider; + } + + public int getNodeSize() { + return nodeSize; + } + + public void setNodeSize(int nodeSize) { + this.nodeSize = nodeSize; + } + + public String getCryptoProviders() { + return cryptoProviders; + } + + public void setCryptoProviders(String cryptoProviders) { + this.cryptoProviders = cryptoProviders; + } + + public List getPartiNodes() { + return partiNodes; + } + + public void setPartiNodes(List partiNodes) { + this.partiNodes = partiNodes; + } + + public void addPartiNode(PartiNode partiNode) { + this.partiNodes.add(partiNode); + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java new file mode 100644 index 00000000..f3807773 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/MasterConfig.java @@ -0,0 +1,89 @@ +package com.jd.blockchain.ump.model.config; + +import com.jd.blockchain.ump.model.MasterAddr; + +public class MasterConfig { + + private String masterAddr; + + private int masterPort; + + private String ledgerName; + + private int nodeSize; + + private boolean isMaster = false; + + public MasterConfig() { + } + + public String getMasterAddr() { + return masterAddr; + } + + public void setMasterAddr(String masterAddr) { + this.masterAddr = masterAddr; + } + + public int getMasterPort() { + return masterPort; + } + + public void setMasterPort(int masterPort) { + this.masterPort = masterPort; + } + + public String getLedgerName() { + return ledgerName; + } + + public void setLedgerName(String ledgerName) { + this.ledgerName = ledgerName; + } + + public int getNodeSize() { + return nodeSize; + } + + public void setNodeSize(int nodeSize) { + this.nodeSize = nodeSize; + } + + public boolean isMaster() { + return isMaster; + } + + public void setMaster(boolean master) { + isMaster = master; + } + + public MasterConfig buildIsMaster(boolean isMaster) { + setMaster(isMaster); + return this; + } + + public MasterConfig buildNodeSize(int nodeSize) { + setNodeSize(nodeSize); + return this; + } + + public MasterConfig buildLedgerName(String ledgerName) { + setLedgerName(ledgerName); + return this; + } + + public MasterConfig buildMasterAddr(String masterAddr) { + setMasterAddr(masterAddr); + return this; + } + + public MasterConfig buildMasterPort(int masterPort) { + setMasterPort(masterPort); + return this; + } + + + public MasterAddr toMasterAddr() { + return MasterAddr.newInstance(masterAddr, masterPort); + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java new file mode 100644 index 00000000..21ba3220 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerLocalConfig.java @@ -0,0 +1,160 @@ +package com.jd.blockchain.ump.model.config; + + +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.PartiNode; +import com.jd.blockchain.ump.model.UmpConstant; +import com.jd.blockchain.ump.model.state.LedgerMasterInstall; +import com.jd.blockchain.ump.model.state.LedgerPeerInstall; + +import java.io.File; + +/** + * Peer本地配置信息 + */ +public class PeerLocalConfig extends PeerSharedConfig { + + private String peerPath; + + private String consensusConf = "bftsmart.config"; // 默认为bftsmart配置 + + private String privKey; + + private String encodePwd; + + private String dbName; + + private MasterConfig masterConfig; + + public String bindingOutPath() { + return peerPath + UmpConstant.PATH_CONFIG; + } + + public String localConfPath() { + return peerPath + UmpConstant.PATH_LOCAL_CONFIG; + } + + public String ledgerInitConfPath() { + return peerPath + UmpConstant.PATH_LEDGER_INIT_CONFIG; + } + + public String consensusConfPath() { + return peerPath + UmpConstant.PATH_CONFIG_INIT + File.separator + consensusConf; + } + + public String libsDirectory() { + return peerPath + UmpConstant.PATH_LIBS; + } + + public String getPeerPath() { + return peerPath; + } + + public void setPeerPath(String peerPath) { + this.peerPath = peerPath; + } + + public String getConsensusConf() { + return consensusConf; + } + + public void setConsensusConf(String consensusConf) { + this.consensusConf = consensusConf; + } + + public String getPrivKey() { + return privKey; + } + + public void setPrivKey(String privKey) { + this.privKey = privKey; + } + + public String getEncodePwd() { + return encodePwd; + } + + public void setEncodePwd(String encodePwd) { + this.encodePwd = encodePwd; + } + + public String getDbName() { + return dbName; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + + public MasterConfig getMasterConfig() { + return masterConfig; + } + + public void setMasterConfig(MasterConfig masterConfig) { + this.masterConfig = masterConfig; + } + + public synchronized PartiNode toPartiNode(int nodeId) { + if (this.partiNode != null) { + return partiNode; + } + partiNode = new PartiNode(); + partiNode.setId(nodeId); + partiNode.setName(name); + partiNode.setInitHost(initAddr); + partiNode.setInitPort(initPort); + partiNode.setPubKey(pubKey); + partiNode.setSecure(false); + return partiNode; + } + + public LedgerPeerInstall toLedgerPeerInstall(int totalNodeSize) { + return new LedgerPeerInstall(name, sharedKey, peerPath, totalNodeSize); + } + + public LedgerMasterInstall.PeerInstall toPeerInstall() { + return new LedgerMasterInstall.PeerInstall(name, pubKey, initAddr, initPort, consensusNode, consensusProvider); + } + + public void verify() { + + // 主要校验dbName地址是否存在 + String dbPath = peerPath + File.separator + dbName; + File dbDir = new File(dbPath); + if (dbDir.exists()) { + throw new IllegalStateException(String.format("DB name = %s, path = %s is exist !!!", dbName, dbPath)); + } + + // 其他配置信息是否正确 + if (masterConfig == null) { + // Master不能为空 + throw new IllegalStateException("Master Config can not be NULL !!!"); + } + if (masterConfig.isMaster()) { + // 账本名字及NodeSize不能为空 + if (masterConfig.getLedgerName() == null || masterConfig.getLedgerName().length() == 0) { + throw new IllegalStateException("Master 's LedgerName can not be empty !!!"); + } + if (masterConfig.getNodeSize() == 0) { + throw new IllegalStateException("Master 's NodeSize can not be Zero !!!"); + } + } else { + // 普通Peer需要检查Master的IP地址及端口 + if (masterConfig.getMasterAddr() == null || masterConfig.getMasterAddr().length() == 0) { + throw new IllegalStateException("Master 's IP Address can not be empty !!!"); + } + + if (masterConfig.getMasterPort() == 0) { + throw new IllegalStateException("Master 's Port must be Set !!!"); + } + } + } + + public boolean master() { + return masterConfig.isMaster(); + } + + public MasterAddr masterAddr() { + return masterConfig.toMasterAddr(); + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java new file mode 100644 index 00000000..cf5d71ef --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfig.java @@ -0,0 +1,86 @@ +package com.jd.blockchain.ump.model.config; + +import com.jd.blockchain.ump.model.PartiNode; + +public class PeerSharedConfig { + + public static final String DB_ROCKSDB_SUFFIX = "rocksdb_"; + + protected String sharedKey; + + protected String name; + + protected String initAddr; + + protected String pubKey; + + protected int initPort; + + protected String consensusNode; + + protected String consensusProvider = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"; + + protected PartiNode partiNode; + + public String getSharedKey() { + return sharedKey; + } + + public void setSharedKey(String sharedKey) { + this.sharedKey = sharedKey; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getInitAddr() { + return initAddr; + } + + public void setInitAddr(String initAddr) { + this.initAddr = initAddr; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + public int getInitPort() { + return initPort; + } + + public void setInitPort(int initPort) { + this.initPort = initPort; + } + + public String addr() { + return initAddr + "-" + initPort; + } + + public String getConsensusNode() { + return consensusNode; + } + + public void setConsensusNode(String consensusNode) { + this.consensusNode = consensusNode; + } + + public String getConsensusProvider() { + return consensusProvider; + } + + public void setConsensusProvider(String consensusProvider) { + this.consensusProvider = consensusProvider; + } + + +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java new file mode 100644 index 00000000..6e536b32 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/config/PeerSharedConfigVv.java @@ -0,0 +1,180 @@ +package com.jd.blockchain.ump.model.config; + + +import com.jd.blockchain.ump.model.UmpConstant; +import com.jd.blockchain.ump.model.user.UserKeys; + +/** + * + */ +public class PeerSharedConfigVv { + + private String sharedKey; + + private String name; + + private int userId; + + private String pubKey; + + private String initAddr; + + private int initPort; + + private String consensusNode; + + private String peerPath = UmpConstant.PROJECT_PATH; + + private String dbName; + + private int nodeSize; + + private String masterAddr; + + private int masterPort; + + private String ledgerName; + + public String getSharedKey() { + return sharedKey; + } + + public void setSharedKey(String sharedKey) { + this.sharedKey = sharedKey; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getUserId() { + return userId; + } + + public void setUserId(int userId) { + this.userId = userId; + } + + public String getInitAddr() { + return initAddr; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + public void setInitAddr(String initAddr) { + this.initAddr = initAddr; + } + + public int getInitPort() { + return initPort; + } + + public void setInitPort(int initPort) { + this.initPort = initPort; + } + + public String getConsensusNode() { + return consensusNode; + } + + public void setConsensusNode(String consensusNode) { + this.consensusNode = consensusNode; + } + + public String getPeerPath() { + return peerPath; + } + + public void setPeerPath(String peerPath) { + this.peerPath = peerPath; + } + + public String getDbName() { + return dbName; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + + public int getNodeSize() { + return nodeSize; + } + + public void setNodeSize(Integer nodeSize) { + this.nodeSize = nodeSize; + } + + public String getMasterAddr() { + return masterAddr; + } + + public void setMasterAddr(String masterAddr) { + this.masterAddr = masterAddr; + } + + public int getMasterPort() { + return masterPort; + } + + public void setMasterPort(Integer masterPort) { + this.masterPort = masterPort; + } + + public String getLedgerName() { + return ledgerName; + } + + public void setLedgerName(String ledgerName) { + this.ledgerName = ledgerName; + } + + public PeerLocalConfig toPeerLocalConfig(UserKeys userKeys) { + + PeerLocalConfig localConfig = new PeerLocalConfig(); + + localConfig.setSharedKey(sharedKey); + localConfig.setName(name); + localConfig.setInitAddr(initAddr); + localConfig.setInitPort(initPort); + localConfig.setConsensusNode(consensusNode); + localConfig.setPubKey(userKeys.getPubKey()); + localConfig.setPrivKey(userKeys.getPrivKey()); + localConfig.setEncodePwd(userKeys.getEncodePwd()); + localConfig.setPeerPath(peerPath); + localConfig.setDbName(dbName); + + MasterConfig masterConfig = new MasterConfig(); + + if (master()) { + masterConfig.buildIsMaster(true) + .buildLedgerName(ledgerName) + .buildNodeSize(nodeSize); + } else { + masterConfig.buildIsMaster(false) + .buildMasterAddr(masterAddr) + .buildMasterPort(masterPort); + } + + localConfig.setMasterConfig(masterConfig); + + return localConfig; + } + + private boolean master() { + if (masterAddr == null || masterAddr.length() == 0) { + return true; + } + return false; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java new file mode 100644 index 00000000..a373f5be --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallProcess.java @@ -0,0 +1,21 @@ +package com.jd.blockchain.ump.model.state; + +public class InstallProcess { + + private String content; + + public InstallProcess() { + } + + public InstallProcess(String content) { + this.content = content; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java new file mode 100644 index 00000000..66f26ebb --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/InstallSchedule.java @@ -0,0 +1,54 @@ +package com.jd.blockchain.ump.model.state; + +public class InstallSchedule { + + private String ledgerKey; + + private String ledgerAndNodeKey; + + private InstallProcess process; + + private ScheduleState state; + + public InstallSchedule() { + } + + public InstallSchedule(String ledgerKey, String ledgerAndNodeKey, InstallProcess process, ScheduleState state) { + this.ledgerKey = ledgerKey; + this.ledgerAndNodeKey = ledgerAndNodeKey; + this.process = process; + this.state = state; + } + + public String getLedgerKey() { + return ledgerKey; + } + + public void setLedgerKey(String ledgerKey) { + this.ledgerKey = ledgerKey; + } + + public String getLedgerAndNodeKey() { + return ledgerAndNodeKey; + } + + public void setLedgerAndNodeKey(String ledgerAndNodeKey) { + this.ledgerAndNodeKey = ledgerAndNodeKey; + } + + public InstallProcess getProcess() { + return process; + } + + public void setProcess(InstallProcess process) { + this.process = process; + } + + public ScheduleState getState() { + return state; + } + + public void setState(ScheduleState state) { + this.state = state; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java new file mode 100644 index 00000000..7843dade --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerBindingConf.java @@ -0,0 +1,33 @@ +package com.jd.blockchain.ump.model.state; + +import java.util.Set; + +public class LedgerBindingConf { + + private Set ledgerHashs; + + private long lastTime; + + public LedgerBindingConf() { + } + + public LedgerBindingConf(long lastTime) { + this.lastTime = lastTime; + } + + public Set getLedgerHashs() { + return ledgerHashs; + } + + public void setLedgerHashs(Set ledgerHashs) { + this.ledgerHashs = ledgerHashs; + } + + public long getLastTime() { + return lastTime; + } + + public void setLastTime(long lastTime) { + this.lastTime = lastTime; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java new file mode 100644 index 00000000..64445781 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerInited.java @@ -0,0 +1,101 @@ +package com.jd.blockchain.ump.model.state; + +public class LedgerInited { + + private String ledgerHash; + + private String ledgerName; + + private String partiName; + + private String partiAddress; + + private String dbUri; + + private StartupState startupState = StartupState.UNKNOWN; + + public LedgerInited() { + } + + public LedgerInited(String ledgerHash) { + this.ledgerHash = ledgerHash; + } + + public String getLedgerHash() { + return ledgerHash; + } + + public void setLedgerHash(String ledgerHash) { + this.ledgerHash = ledgerHash; + } + + public String getLedgerName() { + return ledgerName; + } + + public void setLedgerName(String ledgerName) { + this.ledgerName = ledgerName; + } + + public String getPartiName() { + return partiName; + } + + public void setPartiName(String partiName) { + this.partiName = partiName; + } + + public String getPartiAddress() { + return partiAddress; + } + + public void setPartiAddress(String partiAddress) { + this.partiAddress = partiAddress; + } + + public String getDbUri() { + return dbUri; + } + + public void setDbUri(String dbUri) { + this.dbUri = dbUri; + } + + public StartupState getStartupState() { + return startupState; + } + + public void setStartupState(StartupState startupState) { + this.startupState = startupState; + } + + public LedgerInited buildLedgerHash(String ledgerHash) { + setLedgerHash(ledgerHash); + return this; + } + + public LedgerInited buildLedgerName(String ledgerName) { + setLedgerName(ledgerName); + return this; + } + + public LedgerInited buildPartiName(String partiName) { + setPartiName(partiName); + return this; + } + + public LedgerInited buildPartiAddress(String partiAddress) { + setPartiAddress(partiAddress); + return this; + } + + public LedgerInited buildDbUri(String dbUri) { + setDbUri(dbUri); + return this; + } + + public LedgerInited buildStartupState(StartupState startupState) { + setStartupState(startupState); + return this; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java new file mode 100644 index 00000000..76ca3d41 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerMasterInstall.java @@ -0,0 +1,156 @@ +package com.jd.blockchain.ump.model.state; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class LedgerMasterInstall { + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + private String ledgerKey; + + private int totalNodeSize; + + private String createTime; + + private List peerInstalls = new ArrayList<>(); + + public LedgerMasterInstall() { + } + + public LedgerMasterInstall(String ledgerKey, int totalNodeSize) { + this.ledgerKey = ledgerKey; + this.totalNodeSize = totalNodeSize; + } + + public LedgerMasterInstall initCreateTime(String createTime) { + this.createTime = createTime; + return this; + } + + public LedgerMasterInstall initCreateTime(Date date) { + this.createTime = SDF.format(date); + return this; + } + + public LedgerMasterInstall add(PeerInstall peerInstall) { + peerInstalls.add(peerInstall); + return this; + } + + public LedgerMasterInstall add(String name, String pubKey, String ipAddr, int initPort, + String consensusNode, String consensusProvider) { + PeerInstall peerInstall = new PeerInstall( + name, pubKey, ipAddr, initPort, consensusNode, consensusProvider); + return add(peerInstall); + } + + public String getLedgerKey() { + return ledgerKey; + } + + public void setLedgerKey(String ledgerKey) { + this.ledgerKey = ledgerKey; + } + + public int getTotalNodeSize() { + return totalNodeSize; + } + + public void setTotalNodeSize(int totalNodeSize) { + this.totalNodeSize = totalNodeSize; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public List getPeerInstalls() { + return peerInstalls; + } + + public void setPeerInstalls(List peerInstalls) { + this.peerInstalls = peerInstalls; + } + + public static class PeerInstall { + + private String name; + + private String pubKey; + + private String ipAddr; + + private int initPort; + + private String consensusNode; + + private String consensusProvider; + + public PeerInstall() { + } + + public PeerInstall(String name, String pubKey, String ipAddr, int initPort, String consensusNode, String consensusProvider) { + this.name = name; + this.pubKey = pubKey; + this.ipAddr = ipAddr; + this.initPort = initPort; + this.consensusNode = consensusNode; + this.consensusProvider = consensusProvider; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + public String getIpAddr() { + return ipAddr; + } + + public void setIpAddr(String ipAddr) { + this.ipAddr = ipAddr; + } + + public int getInitPort() { + return initPort; + } + + public void setInitPort(int initPort) { + this.initPort = initPort; + } + + public String getConsensusNode() { + return consensusNode; + } + + public void setConsensusNode(String consensusNode) { + this.consensusNode = consensusNode; + } + + public String getConsensusProvider() { + return consensusProvider; + } + + public void setConsensusProvider(String consensusProvider) { + this.consensusProvider = consensusProvider; + } + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java new file mode 100644 index 00000000..7026aa57 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInited.java @@ -0,0 +1,42 @@ +package com.jd.blockchain.ump.model.state; + +public class LedgerPeerInited { + + private String ledgerHash; + + private LedgerPeerInstall peerInstall; + + private StartupState startupState; + + public LedgerPeerInited() { + } + + public LedgerPeerInited(String ledgerHash, LedgerPeerInstall peerInstall) { + this.ledgerHash = ledgerHash; + this.peerInstall = peerInstall; + } + + public String getLedgerHash() { + return ledgerHash; + } + + public void setLedgerHash(String ledgerHash) { + this.ledgerHash = ledgerHash; + } + + public LedgerPeerInstall getPeerInstall() { + return peerInstall; + } + + public void setPeerInstall(LedgerPeerInstall peerInstall) { + this.peerInstall = peerInstall; + } + + public StartupState getStartupState() { + return startupState; + } + + public void setStartupState(StartupState startupState) { + this.startupState = startupState; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java new file mode 100644 index 00000000..932d621c --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/LedgerPeerInstall.java @@ -0,0 +1,117 @@ +package com.jd.blockchain.ump.model.state; + +import com.jd.blockchain.ump.model.MasterAddr; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class LedgerPeerInstall { + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + private String ledgerKey; + + private String ledgerAndNodeKey; + + private String nodeName; + + private String sharedKey; + + private String peerPath; + + private int totalNodeSize; + + private MasterAddr masterAddr; + + private String createTime; + + public LedgerPeerInstall() { + } + + public LedgerPeerInstall(String nodeName, String sharedKey, String peerPath, int totalNodeSize) { + this.nodeName = nodeName; + this.sharedKey = sharedKey; + this.peerPath = peerPath; + this.totalNodeSize = totalNodeSize; + } + + public LedgerPeerInstall initKey(String ledgerKey, String ledgerAndNodeKey) { + this.ledgerKey = ledgerKey; + this.ledgerAndNodeKey = ledgerAndNodeKey; + return this; + } + + public LedgerPeerInstall initMasterAddr(MasterAddr masterAddr) { + this.masterAddr = masterAddr; + return this; + } + + public LedgerPeerInstall initCreateTime(Date date) { + createTime = SDF.format(date); + return this; + } + + public String getLedgerKey() { + return ledgerKey; + } + + public void setLedgerKey(String ledgerKey) { + this.ledgerKey = ledgerKey; + } + + public String getLedgerAndNodeKey() { + return ledgerAndNodeKey; + } + + public void setLedgerAndNodeKey(String ledgerAndNodeKey) { + this.ledgerAndNodeKey = ledgerAndNodeKey; + } + + public String getNodeName() { + return nodeName; + } + + public void setNodeName(String nodeName) { + this.nodeName = nodeName; + } + + public String getSharedKey() { + return sharedKey; + } + + public void setSharedKey(String sharedKey) { + this.sharedKey = sharedKey; + } + + public String getPeerPath() { + return peerPath; + } + + public void setPeerPath(String peerPath) { + this.peerPath = peerPath; + } + + public int getTotalNodeSize() { + return totalNodeSize; + } + + public void setTotalNodeSize(int totalNodeSize) { + this.totalNodeSize = totalNodeSize; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public MasterAddr getMasterAddr() { + return masterAddr; + } + + public void setMasterAddr(MasterAddr masterAddr) { + this.masterAddr = masterAddr; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java new file mode 100644 index 00000000..dc85343a --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedule.java @@ -0,0 +1,32 @@ +package com.jd.blockchain.ump.model.state; + +public class PeerInstallSchedule { + + private InstallProcess process; + + private ScheduleState state; + + public PeerInstallSchedule() { + } + + public PeerInstallSchedule(InstallProcess process, ScheduleState state) { + this.process = process; + this.state = state; + } + + public InstallProcess getProcess() { + return process; + } + + public void setProcess(InstallProcess process) { + this.process = process; + } + + public ScheduleState getState() { + return state; + } + + public void setState(ScheduleState state) { + this.state = state; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java new file mode 100644 index 00000000..d6aaa7b1 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerInstallSchedules.java @@ -0,0 +1,61 @@ +package com.jd.blockchain.ump.model.state; + +import com.jd.blockchain.ump.model.config.LedgerIdentification; + +import java.util.ArrayList; +import java.util.List; + +public class PeerInstallSchedules { + + private String ledgerHash; + + private LedgerIdentification identification; + + private List installSchedules = new ArrayList<>(); + + public PeerInstallSchedules() { + } + + public PeerInstallSchedules(LedgerIdentification identification) { + this.identification = identification; + } + + public PeerInstallSchedules(LedgerIdentification identification, String ledgerHash) { + this.identification = identification; + this.ledgerHash = ledgerHash; + } + + public PeerInstallSchedules addInstallSchedule(PeerInstallSchedule installSchedule) { + this.installSchedules.add(installSchedule); + return this; + } + + public PeerInstallSchedules initLedgerHash(String ledgerHash) { + setLedgerHash(ledgerHash); + return this; + } + + public String getLedgerHash() { + return ledgerHash; + } + + public void setLedgerHash(String ledgerHash) { + this.ledgerHash = ledgerHash; + } + + public LedgerIdentification getIdentification() { + return identification; + } + + public void setIdentification(LedgerIdentification identification) { + this.identification = identification; + } + + public List getInstallSchedules() { + return installSchedules; + } + + public void setInstallSchedules(List installSchedules) { + this.installSchedules = installSchedules; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java new file mode 100644 index 00000000..ba9ac9da --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/PeerStartupSchedules.java @@ -0,0 +1,40 @@ +package com.jd.blockchain.ump.model.state; + +import java.util.ArrayList; +import java.util.List; + +public class PeerStartupSchedules { + + private String peerPath; + + private List installSchedules = new ArrayList<>(); + + public PeerStartupSchedules() { + } + + public PeerStartupSchedules(String peerPath) { + this.peerPath = peerPath; + } + + + public PeerStartupSchedules addInstallSchedule(PeerInstallSchedule installSchedule) { + this.installSchedules.add(installSchedule); + return this; + } + + public List getInstallSchedules() { + return installSchedules; + } + + public void setInstallSchedules(List installSchedules) { + this.installSchedules = installSchedules; + } + + public String getPeerPath() { + return peerPath; + } + + public void setPeerPath(String peerPath) { + this.peerPath = peerPath; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java new file mode 100644 index 00000000..6307e498 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/ScheduleState.java @@ -0,0 +1,43 @@ +package com.jd.blockchain.ump.model.state; + +public enum ScheduleState { + + /** + * 加载内容,包括获取各种数据列表 + */ + LOAD, + LOAD_SUCCESS, // 加载成功 + LOAD_FAIL, // 加载失败 + + /** + * 将获取的数据写入文件 + * + */ + WRITE, + WRITE_SUCCESS, // 写入文件成功 + WRITE_FAIL, // 写入文件失败 + + /** + * Ledger_INIT:账本初始化过程 + * 主要是调用SHELL + * + */ + INIT, + INIT_SUCCESS, // 账本初始化成功 + INIT_FAIL, // 账本初始化失败 + + /** + * 无须启动PEER,等待PEER自动更新账本信息 + */ + NO_STARTUP, + + /** + * 启动Peer节点 + */ + STARTUP_START, + STARTUP_OVER, + STARTUP_SUCCESS, // Peer节点启动成功 + STARTUP_FAIL, // Peer节点启动失败 + ; + +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java new file mode 100644 index 00000000..d605ccd8 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/state/StartupState.java @@ -0,0 +1,48 @@ +package com.jd.blockchain.ump.model.state; + +public enum StartupState { + + /** + * UNEXIST + * 不存在,描述该账本Hash曾经创建,但目前在LedgerBinding.conf文件中不存在 + * 此状态不支持任何其他操作 + */ + UNEXIST, + + /** + * UNLOAD + * 账本存在,但未加载 + * 此状态可以启动,不能停止 + */ + UNLOAD, + + /** + * LOADING + * 账本加载中,说明程序已经启动,但尚未加载该程序 + * 此状态不可以启动,不建议停止 + */ + LOADING, + + /** + * LOADED + * 账本已加载 + * 此状态不可以启动,后续可以支持停止操作 + */ + LOADED, + + /** + * UNKNOWN + * 未知,常见于命令检测执行错误或程序启动,但账本尚未加载完成 + * 此状态不支持任何其他操作 + */ + UNKNOWN, + + /** + * DB_UNEXIST + * 该账本对应的数据库不存在 + * 此状态不支持任何其他操作 + */ + DB_UNEXIST, + + ; +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java new file mode 100644 index 00000000..e3967c01 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeyBuilder.java @@ -0,0 +1,34 @@ +package com.jd.blockchain.ump.model.user; + +public class UserKeyBuilder { + + private String name; + + private String seed; + + private String pwd; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSeed() { + return seed; + } + + public void setSeed(String seed) { + this.seed = seed; + } + + public String getPwd() { + return pwd; + } + + public void setPwd(String pwd) { + this.pwd = pwd; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java new file mode 100644 index 00000000..121d3ed7 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeys.java @@ -0,0 +1,68 @@ +package com.jd.blockchain.ump.model.user; + +public class UserKeys { + + private int id; + + private String name; + + private String privKey; + + private String pubKey; + + private String encodePwd; + + public UserKeys() { + } + + public UserKeys(String name, String privKey, String pubKey, String encodePwd) { + this.name = name; + this.privKey = privKey; + this.pubKey = pubKey; + this.encodePwd = encodePwd; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrivKey() { + return privKey; + } + + public void setPrivKey(String privKey) { + this.privKey = privKey; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + public String getEncodePwd() { + return encodePwd; + } + + public void setEncodePwd(String encodePwd) { + this.encodePwd = encodePwd; + } + + public UserKeysVv toUserKeysVv() { + return new UserKeysVv(id, name, privKey, pubKey); + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java new file mode 100644 index 00000000..90eaae9c --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/user/UserKeysVv.java @@ -0,0 +1,69 @@ +package com.jd.blockchain.ump.model.user; + +public class UserKeysVv { + + public static final int PRIVKEY_HEADER_LENGTH = 4; + + public static final int PRIVKEY_TAIL_LENGTH = 8; + + public static final String PRIVKEY_HIDE_CONTENT = "******"; + + private int id; + + private String name; + + private String privKey; + + private String pubKey; + + public UserKeysVv() { + } + + public UserKeysVv(int id, String name, String privKey, String pubKey) { + this.id = id; + this.name = name; + this.privKey = encodePrivKey(privKey); + this.pubKey = pubKey; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPrivKey() { + return privKey; + } + + public void setPrivKey(String privKey) { + this.privKey = privKey; + } + + public String getPubKey() { + return pubKey; + } + + public void setPubKey(String pubKey) { + this.pubKey = pubKey; + } + + private String encodePrivKey(final String privKey) { + if (privKey != null && privKey.length() > (PRIVKEY_HEADER_LENGTH + PRIVKEY_TAIL_LENGTH)) { + return privKey.substring(0, PRIVKEY_HEADER_LENGTH) + + PRIVKEY_HIDE_CONTENT + + privKey.substring(privKey.length() - PRIVKEY_TAIL_LENGTH); + } + return privKey; + } +} diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java new file mode 100644 index 00000000..ca023e05 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/ErrorCode.java @@ -0,0 +1,20 @@ +package com.jd.blockchain.ump.model.web; + +/** + * 错误代码; + */ +public enum ErrorCode { + + UNEXPECTED(5000), + ; + + private int value; + + ErrorCode(int value) { + this.value = value; + } + + public int getValue() { + return value; + } +} \ No newline at end of file diff --git a/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java new file mode 100644 index 00000000..29890518 --- /dev/null +++ b/source/manager/ump-model/src/main/java/com/jd/blockchain/ump/model/web/WebResponse.java @@ -0,0 +1,97 @@ +package com.jd.blockchain.ump.model.web; + +public class WebResponse { + + private boolean success; + + private T data; + + private ErrorMessage error; + + private WebResponse(){ + + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public ErrorMessage getError() { + return error; + } + + public void setError(ErrorMessage error) { + this.error = error; + } + + public static WebResponse createSuccessResult(Object data){ + WebResponse responseResult = new WebResponse(); + responseResult.setSuccess(true); + responseResult.setData(data); + return responseResult; + } + + public static WebResponse createFailureResult(int code, String message){ + ErrorMessage errorMessage = new ErrorMessage(code, message); + return createFailureResult(errorMessage); + } + + public static WebResponse createFailureResult(ErrorMessage errorMessage){ + WebResponse responseResult = new WebResponse(); + responseResult.setSuccess(false); + responseResult.setError(errorMessage); + return responseResult; + } + + + + /** + * 错误消息实体 + * + * @author liuxrb + * + */ + public static class ErrorMessage { + + private int errorCode; + + private String errorMessage; + + public ErrorMessage() { + + } + + public ErrorMessage(int errorCode, String errorMessage) { + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } + + public int getErrorCode() { + return errorCode; + } + + public void setErrorCode(int errorCode) { + this.errorCode = errorCode; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + } +} diff --git a/source/manager/ump-service/pom.xml b/source/manager/ump-service/pom.xml new file mode 100644 index 00000000..99b5f2c4 --- /dev/null +++ b/source/manager/ump-service/pom.xml @@ -0,0 +1,114 @@ + + + + + manager + com.jd.blockchain + 1.1.0-SNAPSHOT + + 4.0.0 + + ump-service + + ump-service + + + UTF-8 + 1.8 + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-devtools + true + + + + com.jd.blockchain + crypto-classic + ${project.version} + + + + com.jd.blockchain + crypto-sm + ${project.version} + + + + com.jd.blockchain + tools-keygen + ${project.version} + + + + com.alibaba + fastjson + + + + commons-io + commons-io + + + + commons-codec + commons-codec + + + + com.jd.blockchain + ump-model + ${project.version} + + + + org.reflections + reflections + + + + org.apache.httpcomponents + httpclient + + + + com.sun + tools + 1.8 + system + ${project.basedir}/../ump-booter/libs/tools.jar + + + + junit + junit + test + + + diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java new file mode 100644 index 00000000..77c11016 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerService.java @@ -0,0 +1,31 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.state.LedgerBindingConf; +import com.jd.blockchain.ump.model.state.LedgerInited; + +import java.util.List; + +public interface LedgerService { + + String randomSeed(); + + String currentCreateTime(); + + String ledgerInitCommand(String peerPath); + + String peerStartCommand(String peerPath); + + LedgerBindingConf allLedgerHashs(String peerPath); + + LedgerBindingConf allLedgerHashs(long lastTime, String peerPath); + + List allLedgerIniteds(String peerPath); + + boolean dbExist(String peerPath, String ledgerHash); + + String peerVerifyKey(String peerPath); + + void save(String ledgerAndNodeKey, String ledgerHash); + + String readLedgerHash(String ledgerAndNodeKey); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java new file mode 100644 index 00000000..f78aef42 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/LedgerServiceHandler.java @@ -0,0 +1,310 @@ +package com.jd.blockchain.ump.service; + + +import com.jd.blockchain.ump.dao.DBConnection; +import com.jd.blockchain.ump.model.UmpConstant; +import com.jd.blockchain.ump.model.state.LedgerBindingConf; +import com.jd.blockchain.ump.model.state.LedgerInited; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.io.FileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.util.*; + +@Service +public class LedgerServiceHandler implements LedgerService { + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ"); + + private static final String LEDGER_HASHS_FLAG = "ledger.bindings"; + + private static final String LEDGER_NAME_FORMAT = "binding.%s.name"; + + private static final String LEDGER_PARTI_ADDRESS_FORMAT = "binding.%s.parti.address"; + + private static final String LEDGER_PARTI_NAME_FORMAT = "binding.%s.parti.name"; + + private static final String LEDGER_DB_FORMAT = "binding.%s.db.uri"; + + private static final String FILE_PEER_FLAG = "deployment-peer"; + + private static final String JAR_SUFFIX = "jar"; + + private static final int SEED_BYTES_LENGTH = 32; + + private static final int NAME_BYTES_LENGTH = 8; + + private static final int SEED_PART_LENGTH = 8; + + private static final Random LEDGER_RANDOM = new Random(); + + @Autowired + private UmpStateService umpStateService; + + @Autowired + private DBConnection dbConnection; + + @Override + public String randomSeed() { + byte[] seedBytes = new byte[SEED_BYTES_LENGTH]; + + LEDGER_RANDOM.nextBytes(seedBytes); + + char[] seedChars = Hex.encodeHex(seedBytes); + + StringBuilder sBuilder = new StringBuilder(); + + for (int i = 0; i < seedChars.length; i++) { + if (i != 0 && i % SEED_PART_LENGTH == 0) { + sBuilder.append("-"); + } + sBuilder.append(seedChars[i]); + } + + return sBuilder.toString(); + } + + @Override + public String currentCreateTime() { + return SDF.format(new Date()); + } + + @Override + public String ledgerInitCommand(String peerPath) { + + return String.format(UmpConstant.CMD_LEDGER_INIT, + peerPath + UmpConstant.PATH_LEDGER_INIT_BIN); + } + + @Override + public String peerStartCommand(String peerPath) { + return String.format(UmpConstant.CMD_START_UP_FORMAT, + peerPath + UmpConstant.PATH_STARTUP_BIN); + } + + @Override + public LedgerBindingConf allLedgerHashs(String peerPath) { + + return allLedgerHashs(0L, peerPath); + } + + @Override + public LedgerBindingConf allLedgerHashs(long lastTime, String peerPath) { + + // 读取LedgerBingConf文件,假设该文件不存在则返回空值 + Set allLedgerHashs = new HashSet<>(); + + PropAndTime propAndTime = loadLedgerBindingConf(lastTime, peerPath); + + Properties props = propAndTime.getProp(); + + if (props != null) { + + String ledgerHashChars = props.getProperty(LEDGER_HASHS_FLAG); + + if (ledgerHashChars != null && ledgerHashChars.length() > 0) { + String[] ledgerHashArray = ledgerHashChars.split(","); + if (ledgerHashArray.length > 0) { + for (String ledgerHash : ledgerHashArray) { + allLedgerHashs.add(ledgerHash.trim()); + } + } + } + } + + LedgerBindingConf ledgerBindingConf = new LedgerBindingConf(propAndTime.getLastTime()); + + ledgerBindingConf.setLedgerHashs(allLedgerHashs); + + return ledgerBindingConf; + } + + @Override + public List allLedgerIniteds(String peerPath) { + + List ledgerIniteds = new ArrayList<>(); + + PropAndTime propAndTime = loadLedgerBindingConf(0L, peerPath); + + Properties props = propAndTime.getProp(); + + if (props != null) { + + String ledgerHashChars = props.getProperty(LEDGER_HASHS_FLAG); + + Set ledgerHashSet = new HashSet<>(); + + if (ledgerHashChars != null && ledgerHashChars.length() > 0) { + String[] ledgerHashArray = ledgerHashChars.split(","); + if (ledgerHashArray.length > 0) { + for (String ledgerHash : ledgerHashArray) { + ledgerHashSet.add(ledgerHash.trim()); + } + } + } + + // 根据Hash值,遍历Prop + for (String hash : ledgerHashSet) { + + LedgerInited ledgerInited = new LedgerInited(hash); + + String ledgerName = props.getProperty(String.format(LEDGER_NAME_FORMAT, hash)); + + String partiAddress = props.getProperty(String.format(LEDGER_PARTI_ADDRESS_FORMAT, hash)); + + String partiName = props.getProperty(String.format(LEDGER_PARTI_NAME_FORMAT, hash)); + + String dbUri = props.getProperty(String.format(LEDGER_DB_FORMAT, hash)); + + ledgerIniteds.add( + ledgerInited + .buildLedgerName(ledgerName) + .buildPartiAddress(partiAddress) + .buildPartiName(partiName) + .buildDbUri(dbUri)); + } + } + return ledgerIniteds; + } + + @Override + public synchronized boolean dbExist(String peerPath, String ledgerHash) { + // 检查该账本对应的数据库是否存在 + + PropAndTime propAndTime = loadLedgerBindingConf(0L, peerPath); + + // binding.j5faRYSqSqSRmSVgdmPsgq7Hzd1yP7yAGPWkTihekWms94.db.uri=rocksdb:///Users/shaozhuguang/Documents/ideaProjects/jdchain-patch/source/test/test-integration/rocks.db/rocksdb4.db + Properties props = propAndTime.getProp(); + + if (props != null) { + String dbKey = String.format(LEDGER_DB_FORMAT, ledgerHash); + + String dbUri = props.getProperty(dbKey); + + if (dbUri != null && dbUri.length() > 0) { + + return dbConnection.exist(dbUri); + } + } + + return false; + } + + @Override + public String peerVerifyKey(String peerPath) { + // 从libs中读取对应的Peer.jar的文件名称,配合全路径 + File libsDirectory = new File(peerPath + UmpConstant.PATH_SYSTEM); + + Collection jars = FileUtils.listFiles(libsDirectory, new String[]{JAR_SUFFIX}, false); + + String peerVerifyKey = null; + + if (!jars.isEmpty()) { + for (File jar : jars) { + String jarName = jar.getName(); + if (jarName.startsWith(FILE_PEER_FLAG)) { + peerVerifyKey = jar.getPath(); + break; + } + } + } + + return peerVerifyKey; + } + + @Override + public void save(String ledgerAndNodeKey, String ledgerHash) { + // 保存LedgerAndNodeKey与账本关系 + umpStateService.saveLedgerHash(ledgerAndNodeKey, ledgerHash); + } + + @Override + public String readLedgerHash(String ledgerAndNodeKey) { + + return umpStateService.readLedgerHash(ledgerAndNodeKey); + } + + private PropAndTime loadLedgerBindingConf(long lastTime, String peerPath) { + + File ledgerBindingConf = new File(peerPath + UmpConstant.PATH_LEDGER_BINDING_CONFIG); + + PropAndTime propAndTime = new PropAndTime(lastTime); + + // 说明被修改过 + if (ledgerBindingConf.exists() && ledgerBindingConf.lastModified() > lastTime) { + + propAndTime.lastTime = ledgerBindingConf.lastModified(); + + try (InputStream inputStream = new FileInputStream(ledgerBindingConf)) { + + Properties props = new Properties(); + + props.load(inputStream); + + propAndTime.prop = props; + + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + return propAndTime; + } + + private static class PropAndTime { + + private Properties prop; + + private long lastTime; + + public PropAndTime() { + } + + public PropAndTime(long lastTime) { + this.lastTime = lastTime; + } + + public Properties getProp() { + return prop; + } + + public void setProp(Properties prop) { + this.prop = prop; + } + + public long getLastTime() { + return lastTime; + } + + public void setLastTime(long lastTime) { + this.lastTime = lastTime; + } + } + +// private Properties loadLedgerBindingConf(String peerPath) { +// +// File ledgerBindingConf = new File(peerPath + UmpConstant.PATH_LEDGER_BINDING_CONFIG); +// +// if (ledgerBindingConf.exists()) { +// +// try (InputStream inputStream = new FileInputStream(ledgerBindingConf)) { +// +// Properties props = new Properties(); +// +// props.load(inputStream); +// +// return props; +// +// } catch (Exception e) { +// throw new IllegalStateException(e); +// } +// } +// +// return null; +// } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java new file mode 100644 index 00000000..08e1ee4a --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpService.java @@ -0,0 +1,36 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.PeerSharedConfigs; +import com.jd.blockchain.ump.model.config.*; +import com.jd.blockchain.ump.model.state.PeerInstallSchedules; +import com.jd.blockchain.ump.model.state.PeerStartupSchedules; + + +public interface UmpService { + + PeerSharedConfigs loadPeerSharedConfigs(PeerLocalConfig sharedConfig); + + LedgerConfig response(PeerSharedConfigs peerSharedConfigs, PeerLocalConfig localConfig); + + String save(MasterAddr masterAddr, LedgerConfig ledgerConfig, PeerLocalConfig localConfig); + + String ledgerAndNodeKey(LedgerConfig ledgerConfig, PeerSharedConfig sharedConfig); + + PeerInstallSchedules install(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey); + + PeerInstallSchedules install(String ledgerAndNodeKey); + + PeerInstallSchedules init(String ledgerAndNodeKey); + + PeerInstallSchedules init(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey); + +// PeerInstallSchedules startup(String ledgerAndNodeKey); + + PeerStartupSchedules startup(); + + boolean stop(String ledgerAndNodeKey); + + boolean stop(); + +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java new file mode 100644 index 00000000..c17cc309 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpServiceHandler.java @@ -0,0 +1,925 @@ +package com.jd.blockchain.ump.service; + + +import com.jd.blockchain.ump.dao.DBConnection; +import com.jd.blockchain.ump.dao.RocksDBConnection; +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.PeerSharedConfigs; +import com.jd.blockchain.ump.model.UmpConstant; +import com.jd.blockchain.ump.model.config.*; +import com.jd.blockchain.ump.model.state.*; +import com.jd.blockchain.ump.service.consensus.ConsensusService; +import com.jd.blockchain.ump.util.Base58Utils; +import com.jd.blockchain.ump.util.CommandUtils; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; + +@Service +public class UmpServiceHandler implements UmpService { + + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + private static final String SUCCESS = "SUCCESS"; + + private static final String ROCKSDB_PROTOCOL = RocksDBConnection.ROCKSDB_PROTOCOL; + + private static final int DB_SUFFIX_LENGTH = 4; + + private static final Random DB_RANDOM = new Random(); + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMMddHHmmssSSS");//yyyy-MM-dd HH:mm:ss为目标的样式 + + private final Map ledgerConfigs = new ConcurrentHashMap<>(); + + private final Map masterConfigs = new ConcurrentHashMap<>(); + + private final Map peerShareds = new ConcurrentHashMap<>(); + + private final Map ledgerConfigMemory = new ConcurrentHashMap<>(); + + @Autowired + private ConsensusService consensusService; + + @Autowired + private LedgerService ledgerService; + + @Autowired + private DBConnection dbConnection; + + @Autowired + private UmpStateService umpStateService; + + @Override + public synchronized PeerSharedConfigs loadPeerSharedConfigs(PeerLocalConfig sharedConfig) { + + String sharedKey = sharedConfig.getSharedKey(); + + PeerSharedConfigs peerSharedConfigs = peerShareds.get(sharedKey); + + if (peerSharedConfigs == null) { + peerSharedConfigs = new PeerSharedConfigs(); + peerShareds.put(sharedKey, peerSharedConfigs); + } + + return peerSharedConfigs.addConfig(sharedConfig); + } + + @Override + public LedgerConfig response(PeerSharedConfigs sharedConfigs, PeerLocalConfig localConfig) { + try { + // 对于Master和Peer处理方式不同 + if (localConfig.getMasterConfig().isMaster()) { + + // Master节点需要等待完成后通知其他线程 + sharedConfigs.waitAndNotify(); + } else { + + // 等待Master节点通知 + sharedConfigs.await(); + } + + // 此处需要防止并发 + final String sharedKey = sharedConfigs.getSharedKey(); + + LedgerConfig savedLedgerConfig = ledgerConfigMemory.get(sharedKey); + + if (savedLedgerConfig != null) { + return savedLedgerConfig; + } + + // 获取当前对象锁(所有节点请求使用同一个对象) + final Lock lock = sharedConfigs.getLock(); + + lock.lock(); + + try { + // 执行到此表示获取到锁,此时需要判断是否有数据 + // Double Check !!! + savedLedgerConfig = ledgerConfigMemory.get(sharedKey); + + if (savedLedgerConfig != null) { + return savedLedgerConfig; + } + + // 校验 + verify(sharedConfigs); + + // 所有数据到达之后生成返回的应答 + LedgerInitConfig initConfig = sharedConfigs.ledgerInitConfig( + ledgerService.randomSeed(), ledgerService.currentCreateTime()); + + // 生成共识文件 + String consensusConfig = consensusService.initConsensusConf( + sharedConfigs.getConsensusProvider(), sharedConfigs.getSharedConfigs()); + + LedgerConfig ledgerConfig = new LedgerConfig(initConfig, consensusConfig); + + // 将本次LedgerKey信息写入数据库 + String ledgerKey = initConfig.ledgerKey(); + + dbConnection.put(ledgerKey, ledgerConfig, LedgerConfig.class); + + // 将节点的Key信息写入数据库 + umpStateService.save(ledgerKey, sharedConfigKeys(ledgerKey, sharedConfigs)); + + // 将本地生成数据的信息写入数据库 + LedgerMasterInstall masterInstall = sharedConfigs.toLedgerMasterInstall(); + + umpStateService.save(masterInstall); + + // 将数据放入内存 + ledgerConfigMemory.put(sharedKey, ledgerConfig); + + return ledgerConfig; + } finally { + lock.unlock(); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public String save(MasterAddr masterAddr, LedgerConfig ledgerConfig, PeerLocalConfig localConfig) { + + String ledgerAndNodeKey = ledgerAndNodeKey(ledgerConfig, localConfig); + + ledgerConfigs.put(ledgerAndNodeKey, ledgerConfig); + + // 保存本次需要发送的Master地址 + masterConfigs.put(ledgerAndNodeKey, localConfig.getMasterConfig()); + + // 保存所有的信息至本地 + umpStateService.save(ledgerAndNodeKey, localConfig); + + // 保存当前同步信息至数据库 + LedgerPeerInstall peerInstall = localConfig.toLedgerPeerInstall(ledgerConfig.getInitConfig().getNodeSize()); + + // init相关配置信息 + peerInstall + .initKey(ledgerConfig.getInitConfig().ledgerKey(), ledgerAndNodeKey) + .initCreateTime(new Date()) + .initMasterAddr(masterAddr); + + // 写入数据库 + umpStateService.save(peerInstall); + + return ledgerAndNodeKey; + } + + @Override + public String ledgerAndNodeKey(LedgerConfig ledgerConfig, PeerSharedConfig sharedConfig) { + + return ledgerAndNodeKey(ledgerConfig.getInitConfig().ledgerKey(), sharedConfig); + } + + @Override + public PeerInstallSchedules install(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey) { + + // 初始化Peer节点数据 + PeerInstallSchedules installSchedules = init(identification, localConfig, ledgerAndNodeKey); + + // Peer节点启动 + peerStart(localConfig.getPeerPath(), installSchedules); + + return installSchedules; + } + + @Override + public PeerInstallSchedules install(String ledgerAndNodeKey) { + + PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey); + + if (localConfig != null) { + + // 获取LedgerIdentification + LedgerIdentification identification = umpStateService.readIdentification(ledgerAndNodeKey); + + return install(identification, localConfig, ledgerAndNodeKey); + } + throw new IllegalStateException("Can not find LocalConfig from DataBase !!!"); + } + + @Override + public PeerInstallSchedules init(LedgerIdentification identification, PeerLocalConfig localConfig, String ledgerAndNodeKey) { + + PeerInstallSchedules installSchedules = new PeerInstallSchedules(identification); + + MasterAddr masterAddr = loadMaster(localConfig); + + LedgerConfig ledgerConfig = ledgerConfigs.get(ledgerAndNodeKey); + + if (ledgerConfig == null || ledgerConfig.getInitConfig() == null) { + saveInstallSchedule(installSchedules, masterAddr, "", ledgerAndNodeKey, + String.format("Ledger Key = [%s] can not find Ledger-Config !!!", ledgerAndNodeKey), + ScheduleState.LOAD_FAIL); + throw new IllegalStateException(String.format("Ledger Key = [%s] can not find Ledger-Config !!!", ledgerAndNodeKey)); + } + + LedgerInitConfig initConfig = ledgerConfig.getInitConfig(); + + String ledgerKey = initConfig.ledgerKey(); + + List localConfContents, ledgerInitContents; + + try { + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Find LedgerConfig from Memory for Key [%s] -> %s", ledgerAndNodeKey, SUCCESS), + ScheduleState.LOAD); + + // 首先获取当前节点的ID + int nodeId = initConfig.nodeId(localConfig.getPubKey()); + + // 生成local.conf文件内容 + localConfContents = localConfContents(localConfig, nodeId); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Init Local.Conf's Content -> %s", SUCCESS), + ScheduleState.LOAD); + + // 生成LedgerInit内容 + ledgerInitContents = initConfig.toConfigChars(localConfig.consensusConfPath()); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Init Ledger.Init's Content -> %s", SUCCESS), + ScheduleState.LOAD); + } catch (Exception e) { + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Load Config's Content !!!", + ScheduleState.LOAD_FAIL); + throw new IllegalStateException(e); + } + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Load Config's Content !!!", + ScheduleState.LOAD_SUCCESS); + + try { + // 将该文件内容写入Local.Conf + forceWrite(localConfContents, new File(localConfig.localConfPath())); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Write And Backup File local.conf -> %s", SUCCESS), + ScheduleState.WRITE); + + // 将文件内容写入Ledger-Init + forceWrite(ledgerInitContents, new File(localConfig.ledgerInitConfPath())); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Write And Backup File ledger.init -> %s", SUCCESS), + ScheduleState.WRITE); + + // 将共识内容写入文件,例如bftsmart.conf + String consensusFileName = writeConsensusContent(ledgerConfig.getConsensusConfig(), + new File(localConfig.consensusConfPath())); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Write And Backup Consensus File %s -> %s", consensusFileName, SUCCESS), + ScheduleState.WRITE); + + } catch (Exception e) { + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Write Config's Content to Config File !!!", + ScheduleState.WRITE_FAIL); + throw new IllegalStateException(e); + } + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Write Config's Content to Config File !!!", + ScheduleState.WRITE_SUCCESS); + + // 账本初始化 + String ledgerHash = ledgerInit(localConfig.getPeerPath(), installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey); + + // 设置账本Hash + installSchedules.setLedgerHash(ledgerHash); + + return installSchedules; + } + + @Override + public PeerInstallSchedules init(String ledgerAndNodeKey) { + + PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey); + + if (localConfig != null) { + + // 获取LedgerIdentification + LedgerIdentification identification = umpStateService.readIdentification(ledgerAndNodeKey); + + return init(identification, localConfig, ledgerAndNodeKey); + } + throw new IllegalStateException("Can not find LocalConfig from DataBase !!!"); + } + + +// @Override +// public PeerInstallSchedules startup(String ledgerAndNodeKey) { +// +// PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey); +// +// if (localConfig != null) { +// +// PeerInstallSchedules installSchedules = umpStateService.loadState(ledgerAndNodeKey); +// +// // Peer节点启动 +// return peerStart(localConfig.getPeerPath(), installSchedules); +// +// } +// throw new IllegalStateException("Can not find LocalConfig from DataBase !!!"); +// } + + @Override + public PeerStartupSchedules startup() { + + PeerStartupSchedules startupSchedules = new PeerStartupSchedules(UmpConstant.PROJECT_PATH); + + return peerStart(startupSchedules); + } + + @Override + public boolean stop(String ledgerAndNodeKey) { + PeerLocalConfig localConfig = umpStateService.readConfig(ledgerAndNodeKey); + + if (localConfig != null) { + + // Peer节点停止 + return peerStop(localConfig.getPeerPath()); + } + throw new IllegalStateException("Can not find LocalConfig from DataBase !!!"); + } + + @Override + public boolean stop() { + + return peerStop(UmpConstant.PROJECT_PATH); + } + + private MasterAddr loadMaster(PeerLocalConfig localConfig) { + + // 开始安装之后则可以将内存中的数据释放 + String sharedKey = localConfig.getSharedKey(); + + if (sharedKey != null) { + ledgerConfigMemory.remove(sharedKey); + } + + if (localConfig.master()) { + return null; + } + + return localConfig.masterAddr(); + } + + private List sharedConfigKeys(String ledgerKey, PeerSharedConfigs sharedConfigs) { + + List sharedConfigKeys = new ArrayList<>(); + + List pscs = sharedConfigs.getSharedConfigs(); + + for(PeerSharedConfig psc : pscs) { + sharedConfigKeys.add(ledgerAndNodeKey(ledgerKey, psc)); + } + + return sharedConfigKeys; + } + + private String ledgerAndNodeKey(String ledgerKey, PeerSharedConfig sharedConfig) { + + return ledgerKey + "-" + sharedConfig.getName(); + } + + private String ledgerInit(String peerPath, PeerInstallSchedules installSchedules, MasterAddr masterAddr, String ledgerKey, String ledgerAndNodeKey) { + + String newLedgerHash = ""; + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Steps to start processing LedgerInit !!!", + ScheduleState.INIT); + + // 获取当前已经存在的Ledger列表 + LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(peerPath); + + Set currentLedgerHashs = ledgerBindingConf.getLedgerHashs(); + + long lastTime = ledgerBindingConf.getLastTime(); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Find History Ledger's Size = %s", currentLedgerHashs.size()), + ScheduleState.INIT); + + String ledgerInitCommand = ledgerService.ledgerInitCommand(peerPath); + + try { + + LOGGER.info("Execute Ledger-Init's Shell {}", ledgerInitCommand); + + Process ledgerInitProcess; + + try { + // 调用ledgerInit初始化脚本 + ledgerInitProcess = CommandUtils.execute(CommandUtils.toCommandList(ledgerInitCommand)); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Execute LedgerInit's Command -> %s", SUCCESS), + ScheduleState.INIT); + } catch (Exception e) { + LOGGER.error("Execute Ledger-Init's Shell !!!", e); + throw new IllegalStateException(e); + } + + int maxSize = 512; + + boolean isInitSuccess = false; + + int checkIndex = 1; + + while (maxSize > 0) { + // 时延 + Thread.sleep(6000); + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("%s Check LedgerInit's Status ...... ", checkIndex++), + ScheduleState.INIT); + + // 检查账本是否增加 + CurrentLedger currentLedger = checkNewLedger(lastTime, peerPath, currentLedgerHashs); + + lastTime = currentLedger.getLastTime(); + + newLedgerHash = currentLedger.getLedgerHash(); + + if (newLedgerHash != null && newLedgerHash.length() > 0) { + isInitSuccess = true; + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Find New Ledger = %s", newLedgerHash), + ScheduleState.INIT); + break; + } + maxSize --; + } + + // 完成后,不管是否处理完,都将命令停止 + // 为防止其他应用仍在访问,延时6秒停止 + try { + Thread.sleep(6000); + ledgerInitProcess = ledgerInitProcess.destroyForcibly(); + if (ledgerInitProcess.isAlive()) { + // 再尝试一次 + ledgerInitProcess.destroyForcibly(); + } + } catch (Exception e) { + // 暂时打印日志 + LOGGER.error("Stop Ledger Init Command !!!", e); + } + + // 再次判断是否初始化账本成功 + if (newLedgerHash == null) { + + CurrentLedger currentLedger = checkNewLedger(lastTime, peerPath, currentLedgerHashs); + + newLedgerHash = currentLedger.getLedgerHash(); + + if (newLedgerHash != null && newLedgerHash.length() > 0) { + isInitSuccess = true; + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Final Find New Ledger = %s", newLedgerHash), + ScheduleState.INIT); + } + } + + if (!isInitSuccess) { + // 失败则抛出异常 + throw new IllegalStateException("Can Not Find New Ledger !!!"); + } + } catch (Exception e) { + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + "Execute Ledger-Init Command Fail !!!", + ScheduleState.INIT_FAIL); + LOGGER.error("Execute Ledger-Init Command Fail !!!", e); + throw new IllegalStateException(e); + } + + saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, + String.format("Steps to processing LedgerInit -> %s", SUCCESS), + ScheduleState.INIT_SUCCESS); + + // 将账本Hash写入数据库 + ledgerService.save(ledgerAndNodeKey, newLedgerHash); + + return newLedgerHash; + } + + private CurrentLedger checkNewLedger(long lastTime, String peerPath, Set currentLedgerHashs) { + // 再次判断是否初始化账本成功 + LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(lastTime, peerPath); + + Set newLedgerHashs = ledgerBindingConf.getLedgerHashs(); + + CurrentLedger currentLedger = new CurrentLedger(ledgerBindingConf.getLastTime()); + + if (newLedgerHashs.size() > currentLedgerHashs.size()) { + // 获取其新安装的LedgerHash + for (String ledgerHash : newLedgerHashs) { + if (!currentLedgerHashs.contains(ledgerHash)) { + // 新获取的LedgerHash为当前值 + currentLedger.ledgerHash = ledgerHash; + break; + } + } + } + return currentLedger; + } + + + private PeerInstallSchedules peerStart(String peerPath, PeerInstallSchedules installSchedules) { + + saveInstallSchedule(installSchedules, + "Steps to start processing PeerNodeStart !!!", + ScheduleState.STARTUP_START); + // 启动Peer + // 说明初始化成功 + // 判断是否需要启动Peer + String peerVerify = ledgerService.peerVerifyKey(peerPath); + + try { + if (!CommandUtils.isActive(peerVerify)) { + // 不存在,则需要再启动 + String peerStartCmd = ledgerService.peerStartCommand(peerPath); + + LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd); + + if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) { + // Peer节点启动失败 + throw new IllegalStateException("Peer Node Start UP Fail !!!"); + } + saveInstallSchedule(installSchedules, + String.format("Peer's process %s start -> %s", peerVerify, SUCCESS), + ScheduleState.STARTUP_SUCCESS); + } else { + // 命令已经存在 + saveInstallSchedule(installSchedules, + String.format("Peer's process is exist -> %s", peerVerify), + ScheduleState.NO_STARTUP); + } + } catch (Exception e) { + saveInstallSchedule(installSchedules, + e.getMessage(), + ScheduleState.STARTUP_FAIL); + throw new IllegalStateException(e); + } + + saveInstallSchedule(installSchedules, + "Steps to start processing PeerNodeStart over !!!", + ScheduleState.STARTUP_OVER); + + return installSchedules; + } + + private PeerStartupSchedules peerStart(PeerStartupSchedules startupSchedules) { + + String peerPath = startupSchedules.getPeerPath(); + + saveStartupSchedules(startupSchedules, + "Steps to start processing PeerNodeStart !!!", + ScheduleState.STARTUP_START); + // 启动Peer + // 说明初始化成功 + // 判断是否需要启动Peer + String peerVerify = ledgerService.peerVerifyKey(peerPath); + + try { + if (!CommandUtils.isActive(peerVerify)) { + // 不存在,则需要再启动 + String peerStartCmd = ledgerService.peerStartCommand(peerPath); + + LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd); + + if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) { + // Peer节点启动失败 + throw new IllegalStateException("Peer Node Start UP Fail !!!"); + } + saveStartupSchedules(startupSchedules, + String.format("Peer's process %s start -> %s", peerVerify, SUCCESS), + ScheduleState.STARTUP_SUCCESS); + } else { + // 命令已经存在 + saveStartupSchedules(startupSchedules, + String.format("Peer's process is exist -> %s", peerVerify), + ScheduleState.NO_STARTUP); + } + } catch (Exception e) { + saveStartupSchedules(startupSchedules, + e.getMessage(), + ScheduleState.STARTUP_FAIL); + throw new IllegalStateException(e); + } + + saveStartupSchedules(startupSchedules, + "Steps to start processing PeerNodeStart over !!!", + ScheduleState.STARTUP_OVER); + + return startupSchedules; + } + +// private PeerInstallSchedules peerStart(String peerPath, PeerInstallSchedules installSchedules) { +// +// MasterAddr masterAddr = installSchedules.getIdentification().getMasterAddr(); +// +// String ledgerKey = installSchedules.getIdentification().getLedgerKey(); +// +// String ledgerAndNodeKey = installSchedules.getIdentification().getLedgerAndNodeKey(); +// +// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, +// "Steps to start processing PeerNodeStart !!!", +// ScheduleState.STARTUP_START); +// // 启动Peer +// // 说明初始化成功 +// // 判断是否需要启动Peer +// String peerVerify = ledgerService.peerVerifyKey(peerPath); +// +// try { +// if (!CommandUtils.isActive(peerVerify)) { +// // 不存在,则需要再启动 +// String peerStartCmd = ledgerService.peerStartCommand(peerPath); +// +// LOGGER.info("Execute Peer-Startup's Shell {}", peerStartCmd); +// +// if (!CommandUtils.executeAndVerify(CommandUtils.toCommandList(peerStartCmd), peerVerify)) { +// // Peer节点启动失败 +// throw new IllegalStateException("Peer Node Start UP Fail !!!"); +// } +// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, +// String.format("Peer's process %s start -> %s", peerVerify, SUCCESS), +// ScheduleState.STARTUP_SUCCESS); +// } else { +// // 命令已经存在 +// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, +// String.format("Peer's process is exist -> %s", peerVerify), +// ScheduleState.NO_STARTUP); +// } +// } catch (Exception e) { +// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, +// e.getMessage(), +// ScheduleState.STARTUP_FAIL); +// throw new IllegalStateException(e); +// } +// +// saveInstallSchedule(installSchedules, masterAddr, ledgerKey, ledgerAndNodeKey, +// "Steps to start processing PeerNodeStart over !!!", +// ScheduleState.STARTUP_OVER); +// +// return installSchedules; +// } + + private boolean peerStop(String peerPath) { + + // 判断是否需要停止Peer + String peerVerify = ledgerService.peerVerifyKey(peerPath); + + try { + if (CommandUtils.isActive(peerVerify)) { + + LOGGER.info("We need stop peer {}", peerVerify); + // 需要停止Peer节点 + CommandUtils.killVm(peerVerify); + + // 最多循环5次进行判断 + int maxSize = 5; + + while (maxSize > 0) { + try { + Thread.sleep(3000); + if (!CommandUtils.isActive(peerVerify)) { + return true; + } + } catch (Exception e) { + LOGGER.error("Check Peer Stop State !!!", e); + } finally { + maxSize--; + } + } + } else { + LOGGER.info("We do not need stop peer {}", peerVerify); + return false; + } + } catch (Exception e) { + LOGGER.error("Stop Peer Node", e); + throw new IllegalStateException(e); + } + return false; + } + + private String writeConsensusContent(String consensusContent, File consensusFile) throws IOException { + // 将字符串转换为字节数组 + byte[] consensusBytes = Base58Utils.decode(consensusContent); + forceWrite(consensusBytes, consensusFile); + return consensusFile.getName(); + } + + private void forceWrite(List lines, File file) throws IOException { + if (file.exists()) { + FileUtils.moveFile(file, new File(file.getPath() + "_bak_" + currentDate())); + } + + FileUtils.writeLines(file, StandardCharsets.UTF_8.toString(), lines); + } + + private void forceWrite(byte[] content, File file) throws IOException { + if (file.exists()) { + FileUtils.moveFile(file, new File(file.getPath() + "_bak_" + currentDate())); + } + + FileUtils.writeByteArrayToFile(file, content); + } + + private void verify(PeerSharedConfigs peerSharedConfigs) { + // 校验其中内容 + List sharedConfigs = peerSharedConfigs.getSharedConfigs(); + + // 首先保证其中的数据一致性 + // 1、name不能重复; + // 2、pubKey不能重复; + // 3、ipAddr + initPort不能重复; + + Set nameSet = new HashSet<>(), + pubKeySet = new HashSet<>(), + addrSet = new HashSet<>(); + + for (PeerSharedConfig sharedConfig : sharedConfigs) { + String name = sharedConfig.getName(), + pubKey = sharedConfig.getPubKey(), + addr = sharedConfig.addr(); + if (nameSet.contains(name)) { + throw new IllegalStateException(String.format("Name [%s] is Conflict !!!", name)); + } else { + nameSet.add(name); + } + + if (pubKeySet.contains(pubKey)) { + throw new IllegalStateException(String.format("PubKey [%s] is Conflict !!!", pubKey)); + } else { + pubKeySet.add(pubKey); + } + + if (addrSet.contains(addr)) { + throw new IllegalStateException(String.format("Address [%s] is Conflict !!!", addr)); + } else { + addrSet.add(addr); + } + } + } + + private void saveInstallSchedule(PeerInstallSchedules installSchedules, MasterAddr masterAddr, String ledgerKey, String ledgerAndNodeKey, String content, ScheduleState state) { + + // 日志打印相关内容 + LOGGER.info(content); + + // 生成InstallSchedule对象 + InstallSchedule schedule = installSchedule(ledgerKey, ledgerAndNodeKey, content, state); + + // 加入反馈列表 + installSchedules.addInstallSchedule( + new PeerInstallSchedule(new InstallProcess(content), state)); + + // 将InstallSchedule写入数据库 + umpStateService.save(schedule, masterAddr); + } + + private void saveInstallSchedule(PeerInstallSchedules installSchedules, String content, ScheduleState state) { + + // 日志打印相关内容 + LOGGER.info(content); + + // 加入反馈列表 + installSchedules.addInstallSchedule( + new PeerInstallSchedule(new InstallProcess(content), state)); + } + + private void saveStartupSchedules(PeerStartupSchedules startupSchedules, String content, ScheduleState state) { + + // 日志打印相关内容 + LOGGER.info(content); + + // 加入反馈列表 + startupSchedules.addInstallSchedule( + new PeerInstallSchedule(new InstallProcess(content), state)); + } + + private InstallSchedule installSchedule(String ledgerKey, String ledgerAndNodeKey, String content, ScheduleState state) { + + InstallProcess process = new InstallProcess(content); + + return new InstallSchedule(ledgerKey, ledgerAndNodeKey, process, state); + + } + + private List localConfContents(PeerLocalConfig localConfig, int nodeId) { + /** + * #当前参与方的 id,与ledger.init文件中cons_parti.id一致,默认从0开始 + * local.parti.id=0 + * + * #当前参与方的公钥 + * local.parti.pubkey= + * + * #当前参与方的私钥(密文编码) + * local.parti.privkey= + * + * #当前参与方的私钥解密密钥(原始口令的一次哈希,Base58格式),如果不设置,则启动过程中需要从控制台输入 + * local.parti.pwd= + * + * #账本初始化完成后生成的"账本绑定配置文件"的输出目录 + * #推荐使用绝对路径,相对路径以当前文件(local.conf)所在目录为基准 + * ledger.binding.out=../ + * + * #账本数据库的连接字符 + * #rocksdb数据库连接格式:rocksdb://{path},例如:rocksdb:///export/App08/peer/rocks.db/rocksdb0.db + * #redis数据库连接格式:redis://{ip}:{prot}/{db},例如:redis://127.0.0.1:6379/0 + * ledger.db.uri= + * + * #账本数据库的连接口令 + * ledger.db.pwd= + */ + + List localContents = new ArrayList<>(); + + localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_ID_PREFIX, nodeId)); + + localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PUBKEY_PREFIX, localConfig.getPubKey())); + + localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PRIVKEY_PREFIX, localConfig.getPrivKey())); + + localContents.add(valueToConfig(UmpConstant.LOCAL_PARTI_PWD_PREFIX, localConfig.getEncodePwd())); + + localContents.add(valueToConfig(UmpConstant.LEDGER_BINDING_OUT_PREFIX, localConfig.bindingOutPath())); + + localContents.add(valueToConfig(UmpConstant.LEDGER_DB_URI_PREFIX, dbUri(localConfig.getDbName(), localConfig.getPeerPath()))); + + localContents.add(valueToConfig(UmpConstant.LEDGER_DB_PWD_PREFIX, "")); + + return localContents; + } + + private String valueToConfig(String prefix, Object value) { + return prefix + "=" + value; + } + + private String currentDate() { + return SDF.format(new Date()); + } + + private String dbUri(final String dbName, final String peerPath) { + + String dbDirectoryPath = peerPath + File.separator + dbName; + + String dbUri = ROCKSDB_PROTOCOL + dbDirectoryPath; + + File dbDirectory = new File(dbDirectoryPath); + + if (!dbDirectory.exists()) { + return dbUri; + } + throw new IllegalStateException(String.format("DB name = %s, path = %s is Exist !!!", dbName, dbDirectoryPath)); + } + + private static class CurrentLedger { + + private String ledgerHash; + + private long lastTime; + + public CurrentLedger() { + } + + public CurrentLedger(long lastTime) { + this.lastTime = lastTime; + } + + public String getLedgerHash() { + return ledgerHash; + } + + public void setLedgerHash(String ledgerHash) { + this.ledgerHash = ledgerHash; + } + + public long getLastTime() { + return lastTime; + } + + public void setLastTime(long lastTime) { + this.lastTime = lastTime; + } + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java new file mode 100644 index 00000000..c6c8ea82 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateService.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.config.PeerSharedConfigVv; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.model.user.UserKeysVv; + +public interface UmpSimulateService { + + UserKeysVv userKeysVv(int nodeId); + + UserKeys userKeys(int nodeId); + + PeerLocalConfig nodePeerLocalConfig(int nodeId, boolean isMaster); + + PeerSharedConfigVv peerSharedConfigVv(int nodeId, boolean isMaster); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java new file mode 100644 index 00000000..3bfb20bf --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpSimulateServiceHandler.java @@ -0,0 +1,134 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.config.PeerSharedConfigVv; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.model.user.UserKeysVv; +import com.jd.blockchain.ump.service.consensus.providers.BftsmartConsensusProvider; +import org.apache.commons.codec.binary.Hex; +import org.springframework.stereotype.Service; + +import java.util.Random; + +@Service +public class UmpSimulateServiceHandler implements UmpSimulateService { + + private static final Random RANDOM_ROCKSDB = new Random(); + + private static final String SHARED_KEY = "JDChain"; + + private static final int TOTAL_SIZE = 4; + + private static final String LOCALHOST = "127.0.0.1"; + + private static final String CONSENSUS_PROVIDER = BftsmartConsensusProvider.BFTSMART_PROVIDER; + + private static final String CONSENSUS_CONF = BftsmartConsensusProvider.BFTSMART_CONFIG_FILE; + + private static final int INIT_PORT_START = 9000; + + private static final String[] PUBKEYS = new String[]{ + "3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9", + "3snPdw7i7PajLB35tEau1kmixc6ZrjLXgxwKbkv5bHhP7nT5dhD9eX", + "3snPdw7i7PZi6TStiyc6mzjprnNhgs2atSGNS8wPYzhbKaUWGFJt7x", + "3snPdw7i7PifPuRX7fu3jBjsb3rJRfDe9GtbDfvFJaJ4V4hHXQfhwk"}; + + private static final String[] PRIVKEYS = new String[]{ + "177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x", + "177gju9p5zrNdHJVEQnEEKF4ZjDDYmAXyfG84V5RPGVc5xFfmtwnHA7j51nyNLUFffzz5UT", + "177gjtwLgmSx5v1hFb46ijh7L9kdbKUpJYqdKVf9afiEmAuLgo8Rck9yu5UuUcHknWJuWaF", + "177gk1pudweTq5zgJTh8y3ENCTwtSFsKyX7YnpuKPo7rKgCkCBXVXh5z2syaTCPEMbuWRns"}; + + private static final String ENCODE_PWD = "DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY"; + + private static final String BINDING_OUT = "../"; + + private static final String[] DB_URIS = new String[]{ + "rocksdb:///Users/shaozhuguang/Documents/simulate/peer0/rocksdb", + "rocksdb:///Users/shaozhuguang/Documents/simulate/peer1/rocksdb", + "rocksdb:///Users/shaozhuguang/Documents/simulate/peer2/rocksdb", + "rocksdb:///Users/shaozhuguang/Documents/simulate/peer3/rocksdb"}; + + private static final String DB_PWD = ""; + + private static final String DB_NAME = "rocksdb_"; + + private static final String[] PEER_PATHS = new String[]{ + "/Users/shaozhuguang/Documents/simulate/peer0", + "/Users/shaozhuguang/Documents/simulate/peer1", + "/Users/shaozhuguang/Documents/simulate/peer2", + "/Users/shaozhuguang/Documents/simulate/peer3"}; + + private static final String[] CONSENSUS_NODES = new String[]{ + "127.0.0.1:6000", + "127.0.0.1:6010", + "127.0.0.1:6020", + "127.0.0.1:6030"}; + + + @Override + public UserKeysVv userKeysVv(int nodeId) { + + UserKeys userKeys = userKeys(nodeId); + + return userKeys.toUserKeysVv(); + } + + @Override + public UserKeys userKeys(int nodeId) { + + return new UserKeys("Peer-" + nodeId, PRIVKEYS[nodeId], PUBKEYS[nodeId], ENCODE_PWD); + } + + @Override + public PeerLocalConfig nodePeerLocalConfig(int nodeId, boolean isMaster) { + + UserKeys userKeys = userKeys(nodeId); + + return peerSharedConfigVv(nodeId, isMaster).toPeerLocalConfig(userKeys); + } + + @Override + public PeerSharedConfigVv peerSharedConfigVv(int nodeId, boolean isMaster) { + + PeerSharedConfigVv sharedConfigVv = new PeerSharedConfigVv(); + + sharedConfigVv.setSharedKey(SHARED_KEY); + sharedConfigVv.setName(SHARED_KEY + "-" + nodeId); + sharedConfigVv.setInitAddr(LOCALHOST); + sharedConfigVv.setInitPort(INIT_PORT_START + nodeId * 10); + sharedConfigVv.setConsensusNode(CONSENSUS_NODES[nodeId]); + sharedConfigVv.setPubKey(PUBKEYS[nodeId]); + sharedConfigVv.setUserId(nodeId); + sharedConfigVv.setPeerPath(PEER_PATHS[nodeId]); + sharedConfigVv.setDbName(dbName()); + + if (isMaster) { + sharedConfigVv.setLedgerName(ledgerName()); + sharedConfigVv.setNodeSize(TOTAL_SIZE); + } else { + sharedConfigVv.setMasterAddr(LOCALHOST); + sharedConfigVv.setMasterPort(8080); + } + + return sharedConfigVv; + } + + private String ledgerName() { + + byte[] nameBytes = new byte[4]; + + RANDOM_ROCKSDB.nextBytes(nameBytes); + + return Hex.encodeHexString(nameBytes); + } + + private String dbName() { + + byte[] nameBytes = new byte[4]; + + RANDOM_ROCKSDB.nextBytes(nameBytes); + + return DB_NAME + Hex.encodeHexString(nameBytes); + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java new file mode 100644 index 00000000..161ed867 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateService.java @@ -0,0 +1,62 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.config.LedgerIdentification; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.state.*; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.model.user.UserKeysVv; + +import java.util.List; +import java.util.Map; + +public interface UmpStateService { + + void save(String ledgerAndNodeKey, PeerLocalConfig localConfig); + + void save(String ledgerKey, List sharedConfigKeys); + + void save(InstallSchedule installSchedule, MasterAddr masterAddr); + + void save(UserKeys userKeys); + + void save(LedgerPeerInstall peerInstall); + + void save(LedgerMasterInstall masterInstall); + + void save(LedgerIdentification identification); + + void saveLedgerHash(String ledgerAndNodeKey, String ledgerHash); + + List readUserKeysList(); + + List readUserKeysVvList(); + + UserKeys readUserKeys(int id); + + PeerLocalConfig readConfig(String ledgerAndNodeKey); + + PeerInstallSchedules loadState(String ledgerAndNodeKey); + + PeerInstallSchedules loadInitState(String ledgerAndNodeKey); + + PeerInstallSchedules readState(String ledgerAndNodeKey); + + PeerInstallSchedules readInitState(String ledgerAndNodeKey); + + Map> readStates(String ledgerKey); + + LedgerIdentification readIdentification(String ledgerAndNodeKey); + + List readLedgerPeerInstalls(); + + List readLedgerMasterInstalls(); + + List readLedgerPeerIniteds(); + + List readLedgerPeerIniteds(String search); + + List readLedgerIniteds(String search); + + String readLedgerHash(String ledgerAndNodeKey); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java new file mode 100644 index 00000000..5ed51aca --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UmpStateServiceHandler.java @@ -0,0 +1,880 @@ +package com.jd.blockchain.ump.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.jd.blockchain.ump.dao.DBConnection; +import com.jd.blockchain.ump.model.*; +import com.jd.blockchain.ump.model.config.LedgerIdentification; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.state.*; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.model.user.UserKeysVv; +import com.jd.blockchain.ump.util.CommandUtils; +import com.jd.blockchain.ump.util.HttpJsonClientUtils; +import org.apache.commons.io.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Service +public class UmpStateServiceHandler implements UmpStateService, Closeable { + + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyyMM-ddHHmmss"); + + private static final String PEER_IDENTIFICATION_FORMAT = "PEER_IDENTIFICATION_INDEX_%s"; + + private static final String PEER_INSTALL_MAX_KEY = "PEER_INSTALL_MAX_INDEX"; + + private static final String PEER_INSTALL_KEY_FORMAT = "PEER_INSTALL_INDEX_%s"; + + private static final String MASTER_INSTALL_MAX_KEY = "MASTER_INSTALL_MAX_INDEX"; + + private static final String MASTER_INSTALL_KEY_FORMAT = "MASTER_INSTALL_INDEX_%s"; + + private static final String USERS_KEY_MAX_KEY = "USERS_KEY_MAX_INDEX"; + + private static final String USERS_KEY_FORMAT = "USERS_%s_REGISTER"; + + private static final String MAX_SIZE_KEY_SUFFIX = "_MAX_SIZE_KEY"; + + private static final String LEDGER_HASH_KEY_SUFFIX = "_LEDGER_HASH_KEY"; + + private static final String LEDGER_NODE_KEY_CONFIG_SUFFIX = "_LEDGER_NODE_CONFIG_KEY"; + + private static final String LEDGER_NODE_KEY_SUFFIX = "_LEDGER_NODE_KEY"; + + private static final String CURRENT_INDEX_KEY_SUFFIX_FORMAT = "_%s_INDEX_KEY"; + + private static final String PORT_ARG = "-p"; + + private static final String LOCALHOST = "127.0.0.1"; + + private ExecutorService singleHttpThread = Executors.newSingleThreadExecutor(); + + @Autowired + private DBConnection dbConnection; + + @Autowired + private LedgerService ledgerService; + + @Override + public synchronized void save(String ledgerAndNodeKey, PeerLocalConfig localConfig) { + + String ledgerAndNodeConfigKey = ledgerAndNodeConfigKey(ledgerAndNodeKey); + + dbConnection.put(ledgerAndNodeConfigKey, JSON.toJSONString(localConfig)); + } + + @Override + public synchronized void save(String ledgerKey, List sharedConfigKeys) { + + String ledgerAllNodeKey = ledgerAllNodeKey(ledgerKey); + + StringBuilder sBuilder = new StringBuilder(); + + for (String sharedConfigKey : sharedConfigKeys) { + if (sBuilder.length() > 0) { + sBuilder.append(";"); + } + sBuilder.append(sharedConfigKey); + } + + dbConnection.put(ledgerAllNodeKey, sBuilder.toString()); + } + + @Override + public synchronized void save(InstallSchedule installSchedule, MasterAddr masterAddr) { + try { + String ledgerAndNodeKey = installSchedule.getLedgerAndNodeKey(); + // 不使用队列,直接将其写入数据库 + // 需要查询目前该Key对应的最大值是多少 + String maxKey = ledgerAndNodeMaxKey(ledgerAndNodeKey); + String maxIdChars = dbConnection.get(maxKey); + int maxId = 0; + if (maxIdChars != null && maxIdChars.length() > 0) { + maxId = Integer.parseInt(maxIdChars) + 1; + } + + String newKey = ledgerAndNodeCurrentNewKey(ledgerAndNodeKey, maxId); + + // 内容写入数据库 + dbConnection.put(newKey, installSchedule, InstallSchedule.class); + + // 更新最大值 + dbConnection.put(maxKey, String.valueOf(maxId)); + + if (masterAddr != null && masterAddr.legal()) { + singleHttpThread.execute(() -> { + + try { + // 发送HTTP请求 + HttpJsonClientUtils.httpPost(masterAddr, UmpConstant.REQUEST_STATE_URL, installSchedule, String.class, false); + } catch (Exception e) { + // 暂不关注是否发送成功 + LOGGER.error(e.toString()); + } + + }); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public synchronized void save(UserKeys userKeys) { + + int maxIndex = maxIndex(USERS_KEY_MAX_KEY); + + String userKey = usersKey(maxIndex); + + // 重置userId + userKeys.setId(maxIndex); + + // 将用户信息写入数据库 + dbConnection.put(userKey, JSON.toJSONString(userKeys)); + + // 更新最大值 + dbConnection.put(USERS_KEY_MAX_KEY, String.valueOf(maxIndex)); + + try { + // 将其放入文件中 + String keysDirPath = UmpConstant.PROJECT_PATH + UmpConstant.PATH_CONFIG_KEYS; + + File keysDir = new File(keysDirPath); + + if (!keysDir.exists()) { + // 创建文件夹 + keysDir.mkdir(); + } + saveKeys2Files(keysDirPath, userKeys); + } catch (Exception e) { + LOGGER.error("Save Keys To File !", e); + } + } + + @Override + public synchronized void save(LedgerPeerInstall peerInstall) { + + int maxIndex = maxIndex(PEER_INSTALL_MAX_KEY); + + // 将用户信息写入数据库 + dbConnection.put(peerInstallKey(maxIndex), JSON.toJSONString(peerInstall)); + + // 更新最大值 + dbConnection.put(PEER_INSTALL_MAX_KEY, String.valueOf(maxIndex)); + + } + + @Override + public synchronized void save(LedgerMasterInstall masterInstall) { + + int maxIndex = maxIndex(MASTER_INSTALL_MAX_KEY); + + // 将用户信息写入数据库 + dbConnection.put(masterInstallKey(maxIndex), JSON.toJSONString(masterInstall)); + + // 更新最大值 + dbConnection.put(MASTER_INSTALL_MAX_KEY, String.valueOf(maxIndex)); + } + + @Override + public synchronized void save(LedgerIdentification identification) { + + String ledgerAndNodeKey = identification.getLedgerAndNodeKey(); + + String idKey = String.format(PEER_IDENTIFICATION_FORMAT, ledgerAndNodeKey); + + dbConnection.put(idKey, JSON.toJSONString(identification)); + } + + @Override + public void saveLedgerHash(String ledgerAndNodeKey, String ledgerHash) { + + String ledgerHashKey = ledgerAndNodeHashKey(ledgerAndNodeKey); + + dbConnection.put(ledgerHashKey, ledgerHash); + } + + @Override + public List readUserKeysList() { + + List userKeysList = new ArrayList<>(); + + String maxIndexChars = dbConnection.get(USERS_KEY_MAX_KEY); + + if (maxIndexChars != null && maxIndexChars.length() > 0) { + + int maxIndex = Integer.parseInt(maxIndexChars); + + for (int i = 0; i <= maxIndex; i++) { + try { + + String json = dbConnection.get(usersKey(i)); + + if (json != null && json.length() > 0) { + userKeysList.add(JSON.parseObject(json, UserKeys.class)); + } + } catch (Exception e) { + LOGGER.error(e.toString()); + } + } + } + + return userKeysList; + } + + @Override + public List readUserKeysVvList() { + + List userKeysVvList = new ArrayList<>(); + + List userKeysList = readUserKeysList(); + + if (!userKeysList.isEmpty()) { + for (UserKeys userKeys : userKeysList) { + + userKeysVvList.add(userKeys.toUserKeysVv()); + } + } + + return userKeysVvList; + } + + @Override + public UserKeys readUserKeys(int id) { + + String userKey = usersKey(id); + + String userKeysJson = dbConnection.get(userKey); + + if (userKeysJson != null && userKeysJson.length() > 0) { + return JSON.parseObject(userKeysJson, UserKeys.class); + } + + return null; + } + + @Override + public PeerLocalConfig readConfig(String ledgerAndNodeKey) { + + String json = dbConnection.get(ledgerAndNodeConfigKey(ledgerAndNodeKey)); + + if (json != null && json.length() > 0) { + + return JSON.parseObject(json, PeerLocalConfig.class); + } + + return null; + } + + @Override + public PeerInstallSchedules loadState(String ledgerAndNodeKey) { + + PeerInstallSchedules installSchedules = loadInitState(ledgerAndNodeKey); + + String ledgerHash = ledgerService.readLedgerHash(ledgerAndNodeKey); + + if (ledgerHash == null || ledgerHash.length() == 0) { + throw new IllegalStateException("Can not find LedgerHash from DataBase !!!"); + } + + return installSchedules.initLedgerHash(ledgerHash); + + } + + @Override + public PeerInstallSchedules loadInitState(String ledgerAndNodeKey) { + // 获取LedgerIdentification + LedgerIdentification identification = readIdentification(ledgerAndNodeKey); + + if (identification == null) { + throw new IllegalStateException("Can not find LedgerIdentification from DataBase !!!"); + } + + return new PeerInstallSchedules(identification); + } + + @Override + public PeerInstallSchedules readState(final String ledgerAndNodeKey) { + + PeerInstallSchedules installSchedules = loadState(ledgerAndNodeKey); + + loadInstallSchedules(installSchedules, ledgerAndNodeKey); + + return installSchedules; + } + + @Override + public PeerInstallSchedules readInitState(String ledgerAndNodeKey) { + + PeerInstallSchedules installSchedules = loadInitState(ledgerAndNodeKey); + + loadInstallSchedules(installSchedules, ledgerAndNodeKey); + + return installSchedules; + } + + @Override + public Map> readStates(String ledgerKey) { + + String ledgerAllNodeKey = ledgerAllNodeKey(ledgerKey); + + String ledgerAllNodeValues = dbConnection.get(ledgerAllNodeKey); + + String[] ledgerAndNodeKeys = ledgerAllNodeValues.split(";"); + + Map> allInstallSchedules = new HashMap<>(); + + // 不存在就返回空值 + if (ledgerAndNodeKeys.length > 0) { + + for (String ledgerAndNodeKey : ledgerAndNodeKeys) { + // 获取每个LedgerAndNodeKey数据 + List installSchedules = readInstallSchedules(ledgerAndNodeKey); + + if (installSchedules != null) { + + allInstallSchedules.put(ledgerAndNodeKey, installSchedules); + } + } + } + + return allInstallSchedules; + } + + @Override + public LedgerIdentification readIdentification(String ledgerAndNodeKey) { + + String idKey = String.format(PEER_IDENTIFICATION_FORMAT, ledgerAndNodeKey); + + String identificationJson = dbConnection.get(idKey); + + if (identificationJson != null && identificationJson.length() > 0) { + + return JSON.parseObject(identificationJson, LedgerIdentification.class); + } + + return null; + } + + @Override + public List readLedgerPeerInstalls() { + + List peerInstallList = new ArrayList<>(); + + String maxIndexChars = dbConnection.get(PEER_INSTALL_MAX_KEY); + + if (maxIndexChars != null && maxIndexChars.length() > 0) { + + int maxIndex = Integer.parseInt(maxIndexChars); + + for (int i = 1; i <= maxIndex; i++) { + try { + String json = dbConnection.get(peerInstallKey(i)); + + if (json != null && json.length() > 0) { + peerInstallList.add(JSON.parseObject(json, LedgerPeerInstall.class)); + } + } catch (Exception e) { + LOGGER.error(e.toString()); + } + } + } + + return peerInstallList; + } + + @Override + public List readLedgerMasterInstalls() { + + List masterInstalls = new ArrayList<>(); + + String maxIndexChars = dbConnection.get(PEER_INSTALL_MAX_KEY); + + if (maxIndexChars != null && maxIndexChars.length() > 0) { + + int maxIndex = Integer.parseInt(maxIndexChars); + + for (int i = 1; i <= maxIndex; i++) { + try { + String json = dbConnection.get(masterInstallKey(i)); + + if (json != null && json.length() > 0) { + masterInstalls.add(JSON.parseObject(json, LedgerMasterInstall.class)); + } + } catch (Exception e) { + LOGGER.error(e.toString()); + } + } + } + + return masterInstalls; + } + + @Override + public List readLedgerPeerIniteds() { + + List peerIniteds = new ArrayList<>(); + + List peerInstalls = readLedgerPeerInstalls(); + + if (!peerInstalls.isEmpty()) { + + LOGGER.info("Read LedgerPeerInstalls, Size = {}", peerInstalls.size()); + for (LedgerPeerInstall peerInstall : peerInstalls) { + + String ledgerAndNodeKey = peerInstall.getLedgerAndNodeKey(); + + // 数据库中读取存放的LedgerHash + String ledgerHash = readLedgerHash(ledgerAndNodeKey); + + if (ledgerHash == null || ledgerHash.length() == 0) { + continue; + } + + LedgerPeerInited peerInited = new LedgerPeerInited(ledgerHash, peerInstall); + + // 检测账本中的Hash是否真正存在 + StartupState startupState = StartupState.UNKNOWN; + try { + startupState = startupState(ledgerHash, peerInstall); + } catch (Exception e) { + LOGGER.error("Check Ledger Hash Exist !!!", e); + } + + // 设置账本状态 + peerInited.setStartupState(startupState); + + // 添加到集合 + peerIniteds.add(peerInited); + } + } else { + LOGGER.error("Read LedgerPeerInstalls is Empty !!!"); + } + return peerIniteds; + } + + @Override + public List readLedgerPeerIniteds(String search) { + + List initedList = readLedgerPeerIniteds(); + + if (search != null && search.length() > 0 && !initedList.isEmpty()) { + + List filterInitedList = new ArrayList<>(); + + for (LedgerPeerInited peerInited : initedList) { + if (isMatch(peerInited, search)) { + filterInitedList.add(peerInited); + } + } + + return filterInitedList; + } + + return initedList; + } + + @Override + public List readLedgerIniteds(String search) { + + List ledgerInitedsFromConf = loadAllLedgerIniteds(UmpConstant.PROJECT_PATH); + + if (!ledgerInitedsFromConf.isEmpty()) { + + List ledgerIniteds = new ArrayList<>(); + + for (LedgerInited ledgerInited : ledgerInitedsFromConf) { + + if (isMatch(ledgerInited, search)) { + ledgerIniteds.add(ledgerInited); + } + } + + return ledgerIniteds; + } + + return ledgerInitedsFromConf; + } + + @Override + public String readLedgerHash(String ledgerAndNodeKey) { + + String ledgerHashKey = ledgerAndNodeHashKey(ledgerAndNodeKey); + + return dbConnection.get(ledgerHashKey); + } + + @Override + public void close() throws IOException { +// writeRunner.close(); + } + + private boolean isMatch(LedgerInited ledgerInited, String search) { + + if (search == null || search.length() == 0) { + return true; + } + + String ledgerHash = ledgerInited.getLedgerHash(); + String ledgerName = ledgerInited.getLedgerName(); + String partiName = ledgerInited.getPartiName(); + String partiAddress = ledgerInited.getPartiAddress(); + String dbUri = ledgerInited.getDbUri(); + StartupState startupState = ledgerInited.getStartupState(); + + if ( + ledgerHash.contains(search) || + startupState.toString().equals(search) || + ledgerName.contains(search) || + partiName.contains(search) || + partiAddress.contains(search) || + dbUri.contains(search) + ) { + return true; + } + return false; + } + + private boolean isMatch(LedgerPeerInited peerInited, String search) { + + if (search == null || search.length() == 0) { + return true; + } + + String ledgerHash = peerInited.getLedgerHash(); + StartupState startupState = peerInited.getStartupState(); + LedgerPeerInstall peerInstall = peerInited.getPeerInstall(); + + if (ledgerHash.contains(search) || + startupState.toString().equals(search) || + peerInstall.getNodeName().contains(search) || + peerInstall.getCreateTime().contains(search) + ) { + return true; + } + return false; + } + + private void loadInstallSchedules(PeerInstallSchedules installSchedules, String ledgerAndNodeKey) { + List schedules = readInstallSchedules(ledgerAndNodeKey); + + for (InstallSchedule installSchedule : schedules) { + installSchedules.addInstallSchedule( + new PeerInstallSchedule(installSchedule.getProcess(), installSchedule.getState())); + } + } + + private List readInstallSchedules(String ledgerAndNodeKey) { + String maxKey = ledgerAndNodeMaxKey(ledgerAndNodeKey); + String maxIdChars = dbConnection.get(maxKey); + if (maxIdChars == null || maxIdChars.length() == 0) { + return null; + } + int maxId = Integer.parseInt(maxIdChars); + + List schedules = new ArrayList<>(); + + for (int i = 0; i <= maxId; i++) { + + try { + String currentKey = ledgerAndNodeCurrentNewKey(ledgerAndNodeKey, i); + + String jsonChars = dbConnection.get(currentKey); + + if (jsonChars != null && jsonChars.length() > 0) { + schedules.add(JSON.parseObject(jsonChars, InstallSchedule.class)); + } + } catch (Exception e) { + // 打印错误,暂不处理其他 + LOGGER.error(e.toString()); + } + } + + return schedules; + } + + private List loadAllLedgerIniteds(String peerPath) { + + List ledgerInitedsFromConf = ledgerService.allLedgerIniteds(peerPath); + + if (!ledgerInitedsFromConf.isEmpty()) { + + // 逐个检查其状态 + for (LedgerInited ledgerInited : ledgerInitedsFromConf) { + // 判断该账本对应的数据库是否存在 + if (!dbConnection.exist(ledgerInited.getDbUri())) { + ledgerInited.setStartupState(StartupState.DB_UNEXIST); + continue; + } + + String peerVerify = ledgerService.peerVerifyKey(peerPath); + + try { + if (!CommandUtils.isActive(peerVerify)) { + // 进程不存在 + LOGGER.info("Can not find Peer Process {} !!!", peerVerify); + ledgerInited.setStartupState(StartupState.UNLOAD); + continue; + } + } catch (Exception e) { + // 进程处理错误打印日志即可 + LOGGER.error(String.format("Command Check %s !!!", peerVerify), e); + } + // 查看该进程对应的监听端口 + try { + int listenPort = listenPort(peerVerify); + + LOGGER.info("Find Listen Port = {} !", listenPort); + + if (listenPort > 0) { + + int maxSize = 5, checkIndex = 1; + + boolean isRead = false; + + while (maxSize > 0) { + + try { + // 发送请求到对应地址 + JSONArray ledgerHashs = HttpJsonClientUtils.httpGet(ledgersUrl(listenPort), JSONArray.class, true); + + if (ledgerHashs != null && !ledgerHashs.isEmpty()) { + for(Object hashObj : ledgerHashs) { + if (hashObj instanceof JSONObject) { + if (ledgerInited.getLedgerHash().equals(((JSONObject) hashObj).getString("value"))) { + // 说明该账本已经被加载 + ledgerInited.setStartupState(StartupState.LOADED); + isRead = true; + break; + } + } + } + if (isRead) { + break; + } + } + + // 6秒休眠 + Thread.sleep(6000); + } catch (Exception e) { + LOGGER.error(String.format("Request LedgerHashs from PeerNode [%s]", checkIndex++), e); + } + + maxSize --; + } + + if (!isRead) { + // 表明等待加载,无须再启动 + ledgerInited.setStartupState(StartupState.LOADING); + } + } + } catch (Exception e) { + LOGGER.error(String.format("Command [%s] 'Listen Port Check !!!", peerVerify), e); + } + } + } + + return ledgerInitedsFromConf; + } + + private StartupState startupState(String ledgerHash, LedgerPeerInstall peerInstall) { + + String peerPath = peerInstall.getPeerPath(); + + // 首先检查文件中是否存在该Hash值 + LedgerBindingConf ledgerBindingConf = ledgerService.allLedgerHashs(peerPath); + + Set allLedgerHashs = ledgerBindingConf.getLedgerHashs(); + + if (!allLedgerHashs.contains(ledgerHash)) { + + // 文件中不存在 + return StartupState.UNEXIST; + } + + // 判断该账本对应的数据库是否存在 + if (!ledgerService.dbExist(peerPath, ledgerHash)) { + + // 该账本对应数据库不存在 + return StartupState.DB_UNEXIST; + } + + // 文件中存在则检查进程是否存在 + // 进程存在标识为LOADED,否则标识为LOADING,暂时用不到LOADING + String peerVerify = ledgerService.peerVerifyKey(peerPath); + + try { + if (!CommandUtils.isActive(peerVerify)) { + // 进程不存在 + return StartupState.UNLOAD; + } + + } catch (Exception e) { + // 进程处理错误打印日志即可 + LOGGER.error(String.format("Command Check %s !!!", peerVerify), e); + } + + // 查看该进程对应的监听端口 + try { + int listenPort = listenPort(peerVerify); + + LOGGER.info("Find Listen Port = {} !", listenPort); + + if (listenPort > 0) { + // 发送请求到对应地址 + JSONArray ledgerHashs = HttpJsonClientUtils.httpGet(ledgersUrl(listenPort), JSONArray.class, true); + + if (ledgerHashs != null && !ledgerHashs.isEmpty()) { + for(Object hashObj : ledgerHashs) { + if (hashObj instanceof JSONObject) { + if (ledgerHash.equals(((JSONObject) hashObj).getString("value"))) { + // 说明该账本已经被加载 + return StartupState.LOADED; + } + } + } + // 表明等待加载,无须再启动 + return StartupState.LOADING; + } + } + } catch (Exception e) { + LOGGER.error(String.format("Command [%s] 'Listen Port Check !!!", peerVerify), e); + } + + return StartupState.UNKNOWN; + } + + private String ledgersUrl(int listenPort) { + return "http://" + LOCALHOST + ":" + listenPort + "/ledgers"; + } + + private int listenPort(String peerVerify) throws Exception { + + String portArg = mainArg(peerVerify, PORT_ARG); + + if (portArg != null && portArg.length() > 0) { + return Integer.parseInt(portArg); + } + + return 0; + } + + private String mainArg(String processName, String argKey) throws Exception { + + String[] cmdLineArray = mainArgs(processName); + + if (cmdLineArray != null && cmdLineArray.length > 0) { + for (int i = 0; i < cmdLineArray.length; i++) { + String currArg = cmdLineArray[i].trim(); + if (currArg.equals(argKey) && (i + 1) < cmdLineArray.length) { + return cmdLineArray[i+1].trim(); + } + } + } + return null; + } + + private String[] mainArgs(String processName) throws Exception { + + String mainArgs = CommandUtils.mainArgs(processName); + + if (mainArgs != null && mainArgs.length() > 0) { + ///Users/shaozhuguang/Documents/newenv/peer4/system/deployment-peer-1.1.0-SNAPSHOT.jar -home=/Users/shaozhuguang/Documents/newenv/peer4 -c /Users/shaozhuguang/Documents/newenv/peer4/config/ledger-binding.conf -p 7080 + return mainArgs.split(" "); + } + + return null; + } + + private synchronized int maxIndex(String key) { + int maxIndex = 1; + String maxIndexChars = dbConnection.get(key); + if (maxIndexChars != null && maxIndexChars.length() > 0) { + maxIndex = Integer.parseInt(maxIndexChars) + 1; + } + return maxIndex; + } + + private String usersKey(int userId) { + return String.format(USERS_KEY_FORMAT, userId); + } + + private String peerInstallKey(int index) { + return String.format(PEER_INSTALL_KEY_FORMAT, index); + } + + private String masterInstallKey(int index) { + return String.format(MASTER_INSTALL_KEY_FORMAT, index); + } + + private String ledgerAndNodeConfigKey(String ledgerAndNodeKey) { + + return ledgerAndNodeKey + LEDGER_NODE_KEY_CONFIG_SUFFIX; + } + + private String ledgerAllNodeKey(String ledgerKey) { + + return ledgerKey + LEDGER_NODE_KEY_SUFFIX; + } + + private String ledgerAndNodeMaxKey(String ledgerAndNodeKey) { + + return ledgerAndNodeKey + MAX_SIZE_KEY_SUFFIX; + } + + private String ledgerAndNodeHashKey(String ledgerAndNodeKey) { + + return ledgerAndNodeKey + LEDGER_HASH_KEY_SUFFIX; + } + + private String ledgerAndNodeCurrentNewKey(String ledgerAndNodeKey, int currentId) { + + return String.format( + ledgerAndNodeKey + CURRENT_INDEX_KEY_SUFFIX_FORMAT, + currentId); + } + + private void saveKeys2Files(String keysDirPath, UserKeys userKeys) throws IOException { + + // 写入私钥 + write(keysDirPath, userKeys.getName(), UmpConstant.PRIVATE_KEY_SUFFIX, userKeys.getPrivKey()); + // 写入公钥 + write(keysDirPath, userKeys.getName(), UmpConstant.PUBLIC_KEY_SUFFIX, userKeys.getPubKey()); + // 写入密钥 + write(keysDirPath, userKeys.getName(), UmpConstant.PWD_SUFFIX, userKeys.getEncodePwd()); + } + + private void write(String keysDirPath, String name, String suffix, String writeContent) throws IOException { + + String keyeFilePath = keysDirPath + File.separator + name + suffix; + + File keysFile = new File(keyeFilePath); + + if (keysFile.exists()) { + // 文件存在,备份文件 + FileUtils.copyFile(keysFile, new File(keyeFilePath + "_bak_" + currentTime())); + } + + // 将Priv文件内容写入 + FileUtils.writeStringToFile(keysFile, writeContent, StandardCharsets.UTF_8); + } + + private String currentTime() { + return SDF.format(new Date()); + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java new file mode 100644 index 00000000..a2083d88 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilService.java @@ -0,0 +1,15 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.ump.model.user.UserKeyBuilder; +import com.jd.blockchain.ump.model.user.UserKeys; + +public interface UtilService { + + UserKeys create(UserKeyBuilder builder); + + UserKeys create(String name, String seed, String pwd); + + UserKeys read(int id); + + boolean verify(UserKeys userKeys, String pwd); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java new file mode 100644 index 00000000..3abf5bb4 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/UtilServiceHandler.java @@ -0,0 +1,80 @@ +package com.jd.blockchain.ump.service; + +import com.jd.blockchain.crypto.PrivKey; +import com.jd.blockchain.crypto.PubKey; +import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; +import com.jd.blockchain.crypto.utils.classic.ED25519Utils; +import com.jd.blockchain.ump.model.user.UserKeyBuilder; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.utils.codec.Base58Utils; +import com.jd.blockchain.utils.security.ShaUtils; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import org.bouncycastle.crypto.prng.FixedSecureRandom; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.nio.charset.Charset; + +import static com.jd.blockchain.tools.keygen.KeyGenCommand.encodePrivKey; +import static com.jd.blockchain.tools.keygen.KeyGenCommand.encodePubKey; + +@Service +public class UtilServiceHandler implements UtilService { + + private static final String UTF_8 = "UTF-8"; + + @Autowired + private UmpStateService umpStateService; + + @Override + public UserKeys create(UserKeyBuilder builder) { + + return create(builder.getName(), builder.getSeed(), builder.getPwd()); + } + + @Override + public UserKeys create(String name, String seed, String pwd) { + + AsymmetricCipherKeyPair keyPair = ED25519Utils.generateKeyPair( + new FixedSecureRandom(seed.getBytes(Charset.forName(UTF_8)))); + + PubKey pubKey = new PubKey(ClassicAlgorithm.ED25519, + ((Ed25519PublicKeyParameters) keyPair.getPublic()).getEncoded()); + + PrivKey privKey = new PrivKey(ClassicAlgorithm.ED25519, + ((Ed25519PrivateKeyParameters) keyPair.getPrivate()).getEncoded()); + + return create(name, pubKey, privKey, pwd); + } + + @Override + public UserKeys read(int userId) { + + return umpStateService.readUserKeys(userId); + } + + @Override + public boolean verify(UserKeys userKeys, String pwd) { + + String encodePwd = Base58Utils.encode((ShaUtils.hash_256(pwd.getBytes(Charset.forName(UTF_8))))); + + if (encodePwd.equals(userKeys.getEncodePwd())) { + return true; + } + return false; + } + + private UserKeys create(String name, PubKey pubKey, PrivKey privKey, String pwd) { + + byte[] pwdBytes = ShaUtils.hash_256(pwd.getBytes(Charset.forName(UTF_8))); + + return new UserKeys( + name, + encodePrivKey(privKey, pwdBytes), + encodePubKey(pubKey), +// pwd, // 密码不保存到数据库,防止泄露 + Base58Utils.encode(pwdBytes)); + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java new file mode 100644 index 00000000..124b6d10 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusProvider.java @@ -0,0 +1,21 @@ +package com.jd.blockchain.ump.service.consensus; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; + +import java.util.List; +import java.util.Properties; + +public interface ConsensusProvider { + + String NEXT_LINE = "\r\n"; + + String provider(); + + String configFilePath(); + + void setConfig(Properties properties); + + Properties getConfig(); + + byte[] handleSharedConfigs(List sharedConfigs); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java new file mode 100644 index 00000000..aeb5fcba --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusService.java @@ -0,0 +1,10 @@ +package com.jd.blockchain.ump.service.consensus; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; + +import java.util.List; + +public interface ConsensusService { + + String initConsensusConf(String consensusProvider, List sharedConfigs); +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java new file mode 100644 index 00000000..50cdb00f --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/ConsensusServiceHandler.java @@ -0,0 +1,79 @@ +package com.jd.blockchain.ump.service.consensus; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.util.Base58Utils; +import org.reflections.Reflections; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +@Service +public class ConsensusServiceHandler implements ConsensusService { + + private static final Map CONSENSUS_PROVIDERS = new ConcurrentHashMap<>(); + + static { + try { + initProviders(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @Override + public String initConsensusConf(String consensusProvider, List sharedConfigs) { + // 首先根据provider获取对应的配置信息 + ConsensusProvider provider = CONSENSUS_PROVIDERS.get(consensusProvider); + + if (provider == null) { + throw new IllegalStateException( + String.format("ConsensusProvider[%s] can not find Manage-Class !!!", consensusProvider)); + } + + byte[] result = provider.handleSharedConfigs(sharedConfigs); + + return Base58Utils.encode(result); + } + + private static void initProviders() { + // 初始化所有实现类 + Reflections reflections = new Reflections("com.jd.blockchain.ump.service.consensus"); + + Set> providerSet = + reflections.getSubTypesOf(ConsensusProvider.class); + + for (Class clazz : providerSet) { + + if (!clazz.isInterface()) { + try { + // 根据class生成对象 + ConsensusProvider provider = clazz.newInstance(); + String providerKey = provider.provider(); + if (providerKey != null && providerKey.length() > 0 && + !CONSENSUS_PROVIDERS.containsKey(providerKey)) { + + // 根据value读取配置文件中的内容 + InputStream currentFileInputStream = ConsensusServiceHandler.class.getResourceAsStream( + File.separator + provider.configFilePath()); + + Properties currentProps = new Properties(); + + currentProps.load(currentFileInputStream); + + provider.setConfig(currentProps); + + CONSENSUS_PROVIDERS.put(providerKey, provider); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + } + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java new file mode 100644 index 00000000..acb89a84 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConsensusProvider.java @@ -0,0 +1,162 @@ +package com.jd.blockchain.ump.service.consensus.providers; + + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.config.PeerSharedConfig; +import com.jd.blockchain.ump.service.consensus.ConsensusProvider; + +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class BftsmartConsensusProvider implements ConsensusProvider { + + public static final String BFTSMART_PROVIDER = "com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider"; + + public static final String BFTSMART_CONFIG_FILE = "bftsmart.config"; + + private static final int MIN_PARTI_SIZE = 4; + + private Properties bftsmartProps; + + @Override + public String provider() { + return BFTSMART_PROVIDER; + } + + @Override + public String configFilePath() { + return BFTSMART_CONFIG_FILE; + } + + @Override + public void setConfig(Properties properties) { + bftsmartProps = properties; + } + + @Override + public Properties getConfig() { + return bftsmartProps; + } + + @Override + public byte[] handleSharedConfigs(List sharedConfigs) { + + // 首先校验其中的ConsensusNode是否完全一致,若完全一致则不可以 + verify(sharedConfigs); + + StringBuilder sBuilder = new StringBuilder(); + + // 先加入当前节点信息 + List nodeConfigs = nodeConfigs(sharedConfigs); + + for (String nodeConfig : nodeConfigs) { + sBuilder.append(nodeConfig).append(NEXT_LINE); + } + + int nodeNum = sharedConfigs.size(); + + // 写入之前配置文件中的内容 + for (Map.Entry entry : bftsmartProps.entrySet()) { + + // 获取Key-Value + String key = (String) entry.getKey(), value = (String) entry.getValue(); + + // 对特殊的Key和Value单独处理 + /** + * system.servers.num = 4 + * + * system.servers.f = 1 + * + * system.initial.view = 0,1,2,3 + */ + if (key.startsWith(BftsmartConstant.SERVERS_NUM_PREFIX)) { + + sBuilder.append(BftsmartConstant.SERVERS_NUM_PREFIX + " = " + nodeNum).append(NEXT_LINE); + } else if (key.startsWith(BftsmartConstant.SERVERS_F_PREFIX)) { + + sBuilder.append(BftsmartConstant.SERVERS_F_PREFIX + " = " + nodeFNum(nodeNum)).append(NEXT_LINE); + } else if (key.startsWith(BftsmartConstant.INIT_VIEW_PREFIX)) { + + sBuilder.append(BftsmartConstant.INIT_VIEW_PREFIX + " = " + initView(nodeNum)).append(NEXT_LINE); + } else { + + sBuilder.append(key + " = " + value).append(NEXT_LINE); + } + } + + return sBuilder.toString().getBytes(StandardCharsets.UTF_8); + } + + private String initView(int nodeNum) { + + StringBuilder views = new StringBuilder(); + + for (int i = 0; i < nodeNum; i++) { + if (views.length() > 0) { + views.append(","); + } + views.append(i); + } + return views.toString(); + } + + private void verify(List sharedConfigs) { + + Set consensusInfos = new HashSet<>(); + + if (sharedConfigs == null) { + throw new IllegalStateException("Shared Configs is NULL !!!"); + } + + if (sharedConfigs.size() < MIN_PARTI_SIZE) { + throw new IllegalStateException( + String.format("Shared Configs's size = %s, can not meet minimum %s !!!", + sharedConfigs.size(), MIN_PARTI_SIZE)); + } + + for (PeerLocalConfig sharedConfig : sharedConfigs) { + String consensusInfo = sharedConfig.getConsensusNode(); + if (consensusInfos.contains(consensusInfo)) { + throw new IllegalStateException("Shared Configs's Consensus may be conflict !!!"); + } + consensusInfos.add(consensusInfo); + } + } + + private List nodeConfigs(List sharedConfigs) { + + List nodeConfigs = new ArrayList<>(); + + if (sharedConfigs != null && !sharedConfigs.isEmpty()) { + for (int i = 0; i < sharedConfigs.size(); i++) { + + PeerSharedConfig sharedConfig = sharedConfigs.get(i); + + String consensusNode = sharedConfig.getConsensusNode(); + + String[] hostAndPort = consensusNode.split(":"); + + nodeConfigs.add(String.format(BftsmartConstant.HOST_FORMAT, i, hostAndPort[0])); + + nodeConfigs.add(String.format(BftsmartConstant.PORT_FORMAT, i, hostAndPort[1])); + + nodeConfigs.add(String.format(BftsmartConstant.SECURE_FORMAT, i, false)); + + } + } + + return nodeConfigs; + } + + private int nodeFNum(int nodeNum) { + /** + * 3F+1 + * + * 假设有4个节点,则可有一个,若有N个,则N-1/3 + */ + if (nodeNum < 4) { + return 0; + } + return (nodeNum - 1) / 3; + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java new file mode 100644 index 00000000..78afdbe4 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/BftsmartConstant.java @@ -0,0 +1,17 @@ +package com.jd.blockchain.ump.service.consensus.providers; + +public class BftsmartConstant { + + public static final String HOST_FORMAT = "system.server.%s.network.host=%s"; + + public static final String PORT_FORMAT = "system.server.%s.network.port=%s"; + + public static final String SECURE_FORMAT = "system.server.%s.network.secure=%s"; + + public static final String SERVERS_NUM_PREFIX = "system.servers.num"; + + public static final String SERVERS_F_PREFIX = "system.servers.f"; + + public static final String INIT_VIEW_PREFIX = "system.initial.view"; + +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java new file mode 100644 index 00000000..d4b197e7 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/service/consensus/providers/MsgQueueConsensusProvider.java @@ -0,0 +1,41 @@ +package com.jd.blockchain.ump.service.consensus.providers; + +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.service.consensus.ConsensusProvider; + +import java.util.List; +import java.util.Properties; + +public class MsgQueueConsensusProvider implements ConsensusProvider { + + private static final String MSGQUEUE_PROVIDER = "com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider"; + + private static final String MSGQUEUE_CONFIG_FILE = "mq.config"; + + private Properties msgQueueProps; + + @Override + public String provider() { + return MSGQUEUE_PROVIDER; + } + + @Override + public String configFilePath() { + return MSGQUEUE_CONFIG_FILE; + } + + @Override + public void setConfig(Properties properties) { + this.msgQueueProps = properties; + } + + @Override + public Properties getConfig() { + return msgQueueProps; + } + + @Override + public byte[] handleSharedConfigs(List sharedConfigs) { + return new byte[0]; + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java new file mode 100644 index 00000000..ff74ba9b --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/Base58Utils.java @@ -0,0 +1,153 @@ +package com.jd.blockchain.ump.util; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; + +public class Base58Utils { + + public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray(); + + private static final int[] INDEXES = new int[128]; + + static { + for (int i = 0; i < INDEXES.length; i++) { + INDEXES[i] = -1; + } + for (int i = 0; i < ALPHABET.length; i++) { + INDEXES[ALPHABET[i]] = i; + } + } + + /** + * Encodes the given bytes in base58. No checksum is appended. + */ + public static String encode(byte[] input) { + if (input.length == 0) { + return ""; + } + input = copyOfRange(input, 0, input.length); + // Count leading zeroes. + int zeroCount = 0; + while (zeroCount < input.length && input[zeroCount] == 0) { + ++zeroCount; + } + // The actual encoding. + byte[] temp = new byte[input.length * 2]; + int j = temp.length; + + int startAt = zeroCount; + while (startAt < input.length) { + byte mod = divmod58(input, startAt); + if (input[startAt] == 0) { + ++startAt; + } + temp[--j] = (byte) ALPHABET[mod]; + } + + // Strip extra '1' if there are some after decoding. + while (j < temp.length && temp[j] == ALPHABET[0]) { + ++j; + } + // Add as many leading '1' as there were leading zeros. + while (--zeroCount >= 0) { + temp[--j] = (byte) ALPHABET[0]; + } + + byte[] output = copyOfRange(temp, j, temp.length); + try { + return new String(output, "US-ASCII"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); // Cannot happen. + } + } + + public static byte[] decode(String input) throws IllegalArgumentException { + if (input.length() == 0) { + return new byte[0]; + } + byte[] input58 = new byte[input.length()]; + // Transform the String to a base58 byte sequence + for (int i = 0; i < input.length(); ++i) { + char c = input.charAt(i); + + int digit58 = -1; + if (c >= 0 && c < 128) { + digit58 = INDEXES[c]; + } + if (digit58 < 0) { + throw new IllegalArgumentException("Illegal character " + c + " at " + i); + } + + input58[i] = (byte) digit58; + } + // Count leading zeroes + int zeroCount = 0; + while (zeroCount < input58.length && input58[zeroCount] == 0) { + ++zeroCount; + } + // The encoding + byte[] temp = new byte[input.length()]; + int j = temp.length; + + int startAt = zeroCount; + while (startAt < input58.length) { + byte mod = divmod256(input58, startAt); + if (input58[startAt] == 0) { + ++startAt; + } + + temp[--j] = mod; + } + // Do no add extra leading zeroes, move j to first non null byte. + while (j < temp.length && temp[j] == 0) { + ++j; + } + + return copyOfRange(temp, j - zeroCount, temp.length); + } + + public static BigInteger decodeToBigInteger(String input) throws IllegalArgumentException { + return new BigInteger(1, decode(input)); + } + + // + // number -> number / 58, returns number % 58 + // + private static byte divmod58(byte[] number, int startAt) { + int remainder = 0; + for (int i = startAt; i < number.length; i++) { + int digit256 = (int) number[i] & 0xFF; + int temp = remainder * 256 + digit256; + + number[i] = (byte) (temp / 58); + + remainder = temp % 58; + } + + return (byte) remainder; + } + + // + // number -> number / 256, returns number % 256 + // + private static byte divmod256(byte[] number58, int startAt) { + int remainder = 0; + for (int i = startAt; i < number58.length; i++) { + int digit58 = (int) number58[i] & 0xFF; + int temp = remainder * 58 + digit58; + + number58[i] = (byte) (temp / 256); + + remainder = temp % 256; + } + + return (byte) remainder; + } + + private static byte[] copyOfRange(byte[] source, int from, int to) { + byte[] range = new byte[to - from]; + System.arraycopy(source, from, range, 0, range.length); + + return range; + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java new file mode 100644 index 00000000..3290d2ce --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/CommandUtils.java @@ -0,0 +1,133 @@ +package com.jd.blockchain.ump.util; + +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.MonitoredVmUtil; +import sun.jvmstat.monitor.VmIdentifier; + +import java.util.*; + +public class CommandUtils { + + public static void killVm(String processName) throws Exception { + + MonitoredVm activeVm = activeVm(processName); + + if (activeVm != null) { + killVm(activeVm); + } + } + + public static void killVm(MonitoredVm vm) throws Exception { + if (vm != null) { + int vmId = vm.getVmIdentifier().getLocalVmId(); + List killCmd = killCommand(vmId); + execute(killCmd); + } + } + + public static List toCommandList(String cmd) { + // 要求使用空格 + String[] cmdArray = cmd.split(" "); + + if (cmdArray.length > 0) { + return Arrays.asList(cmdArray); + } + + return null; + + } + + public static Process execute(List cmds) throws Exception { + + if (cmds == null || cmds.isEmpty()) { + throw new IllegalStateException("Command's List is NULL !!!"); + } + + ProcessBuilder pBuilder = new ProcessBuilder(cmds); + + Process process = pBuilder.start(); + + return process; + + } + + public static boolean executeAndVerify(List cmds, String verify) throws Exception { + + if (cmds == null || cmds.isEmpty()) { + throw new IllegalStateException("Command's List is NULL !!!"); + } + + ProcessBuilder pBuilder = new ProcessBuilder(cmds); + + pBuilder.start(); + + // 时延5s,再进行判断 + Thread.sleep(5000); + + return isActive(verify); + + } + + public static MonitoredVm activeVm(String processName) throws Exception { + + MonitoredHost localMonitored = MonitoredHost.getMonitoredHost("localhost"); + + Set activeVms = new HashSet<>(localMonitored.activeVms()); + + for (Integer vmId : activeVms) { + + try { + MonitoredVm vm = localMonitored.getMonitoredVm(new VmIdentifier("//" + vmId)); + + String vmProcessName = MonitoredVmUtil.mainClass(vm, true); + + if (vmProcessName.contains(processName)) { + return vm; + } + } catch (Exception e) { + // 此处异常打印即可,不需要处理 + System.err.println(e); + } + } + + return null; + } + + public static boolean isActive(String processName) throws Exception { + + MonitoredVm activeVm = activeVm(processName); + + return activeVm != null; + } + + public static String mainArgs(MonitoredVm vm) { + if (vm != null) { + try { + return MonitoredVmUtil.mainArgs(vm); + } catch (Exception e) { + // 打印日志即可 + System.err.println(e); + } + } + return null; + } + + public static String mainArgs(String processName) throws Exception { + + return mainArgs(activeVm(processName)); + } + + public static List killCommand(int vmId) { + if (vmId > 1) { + List killCmd = new ArrayList<>(); + killCmd.add("kill"); + killCmd.add("-9"); + killCmd.add(String.valueOf(vmId)); + + return killCmd; + } + + throw new IllegalStateException(String.format("Can not kill Process ID = [%s]", vmId)); + } +} diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java new file mode 100644 index 00000000..dd575d0d --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpClientPool.java @@ -0,0 +1,289 @@ +/** + * Copyright: Copyright 2016-2020 JD.COM All Right Reserved + * FileName: com.jd.blockchain.utils.http.agent.HttpClientPool + * Author: shaozhuguang + * Department: 区块链研发部 + * Date: 2019/1/14 下午3:20 + * Description: + */ +package com.jd.blockchain.ump.util; + +import org.apache.http.*; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.LayeredConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLHandshakeException; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; +import java.net.UnknownHostException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * + * @author shaozhuguang + * @create 2019/1/14 + * @since 1.0.0 + */ + +public class HttpClientPool { + + private static final int TEN_MINUTE = 600 * 1000; + + private static final int TIME_OUT = TEN_MINUTE; + + private static final int CONNECT_TIME_OUT = TEN_MINUTE; + + private static final int SOCKET_TIME_OUT = TEN_MINUTE; + + private static final int MAX_TOTAL = 200; + + private static final int MAX_PER_ROUTE = 40; + + private static final int MAX_ROUTE = 100; + + private static final int RETRY_COUNT = 5; + + private static final String DEFAULT_CHARSET = "UTF-8"; + + private static final Map httpClients = new ConcurrentHashMap<>(); + + private final static Lock lock = new ReentrantLock(); + + private static void config(HttpRequestBase httpRequestBase) { + // 配置请求的超时设置 + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(TIME_OUT) + .setConnectTimeout(CONNECT_TIME_OUT) + .setSocketTimeout(SOCKET_TIME_OUT) + .build(); + httpRequestBase.setConfig(requestConfig); + } + + /** + * 获取HttpClient对象 + * + * @param url + * @return + */ + public static CloseableHttpClient getHttpClient(String url) { + String hostName = url.split("/")[2]; + int port = 80; + if (hostName.contains(":")) { + String[] arr = hostName.split(":"); + hostName = arr[0]; + port = Integer.parseInt(arr[1]); + } + return getHttpClient(hostName, port); + } + + /** + * 获取HttpClient对象 + * + * @param hostName + * @param port + * @return + */ + public static CloseableHttpClient getHttpClient(String hostName, int port) { + String key = hostName + ":" + port; + CloseableHttpClient httpClient = httpClients.get(key); + if (httpClient == null) { + try { + lock.lock(); + if (httpClient == null) { + httpClient = createHttpClient(MAX_TOTAL, MAX_PER_ROUTE, MAX_ROUTE, hostName, port); + httpClients.put(key, httpClient); + } + } finally { + lock.unlock(); + } + } + return httpClient; + } + + /** + * 创建HttpClient + * + * @param maxTotal + * @param maxPerRoute + * @param maxRoute + * @param hostname + * @param port + * @return + */ + public static CloseableHttpClient createHttpClient(int maxTotal, + int maxPerRoute, int maxRoute, String hostname, int port) { + ConnectionSocketFactory plainsf = PlainConnectionSocketFactory + .getSocketFactory(); + LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory + .getSocketFactory(); + Registry registry = RegistryBuilder + . create().register("http", plainsf) + .register("https", sslsf).build(); + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager( + registry); + cm.setMaxTotal(maxTotal); + cm.setDefaultMaxPerRoute(maxPerRoute); + HttpHost httpHost = new HttpHost(hostname, port); + cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute); + HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> { + if (executionCount >= RETRY_COUNT) {// 最多重试5次 + return false; + }else if (exception instanceof NoHttpResponseException) { + return true; + }else if (exception instanceof SSLException) { + return false; + }else if (exception instanceof InterruptedIOException) { + return false; + }else if (exception instanceof SSLHandshakeException) { + return false; + }else if (exception instanceof UnknownHostException) { + return false; + }else if (exception instanceof ConnectTimeoutException) { + return false; + } + + HttpClientContext clientContext = HttpClientContext + .adapt(context); + HttpRequest request = clientContext.getRequest(); + if (!(request instanceof HttpEntityEnclosingRequest)) { + return true; + } + return false; + }; + + CloseableHttpClient httpClient = HttpClients.custom() + .setConnectionManager(cm) + .setRetryHandler(httpRequestRetryHandler).build(); + + return httpClient; + } + + private static void setPostParams(HttpPost httpPost, + Map params) { + List nameValuePairs = new ArrayList<>(); + Set keySet = params.keySet(); + for (String key : keySet) { + nameValuePairs.add(new BasicNameValuePair(key, params.get(key).toString())); + } + try { + httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEFAULT_CHARSET)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + private static void setJsonPostParams(HttpPost httpPost, String json) { + httpPost.addHeader("Content-type","application/json; charset=utf-8"); + httpPost.setHeader("Accept", "application/json"); + httpPost.setEntity(new StringEntity(json, Charset.forName("UTF-8"))); + } + + /** + * POST请求 + * + * @param url + * @param params + * @return String + * @throws IOException + */ + public static String post(String url, Map params) throws IOException { + HttpPost httpPost = new HttpPost(url); + config(httpPost); + setPostParams(httpPost, params); + try (CloseableHttpResponse response = httpPost(url, httpPost)) { + return parseResponse(response); + } + } + + public static String jsonPost(String url, String json) throws IOException { + HttpPost httpPost = new HttpPost(url); + config(httpPost); + setJsonPostParams(httpPost, json); + try (CloseableHttpResponse response = httpPost(url, httpPost)) { + return parseResponse(response); + } + } + + /** + * GET请求 + * + * @param url + * @return String + */ + public static String get(String url) throws IOException { + HttpGet httpGet = new HttpGet(url); + config(httpGet); + try (CloseableHttpResponse response = httpGet(url, httpGet)) { + return parseResponse(response); + } + } + + /** + * Get请求的真实执行 + * + * @param url + * @param httpGet + * @return + * @throws IOException + */ + private static CloseableHttpResponse httpGet(String url, HttpGet httpGet) throws IOException { + return getHttpClient(url) + .execute(httpGet, HttpClientContext.create()); + } + + /** + * POST请求的真实执行 + * + * @param url + * @param httpPost + * @return + * @throws IOException + */ + private static CloseableHttpResponse httpPost(String url, HttpPost httpPost) throws IOException { + return getHttpClient(url) + .execute(httpPost, HttpClientContext.create()); + } + + /** + * 解析response + * + * @param response + * @return + * @throws IOException + */ + private static String parseResponse(CloseableHttpResponse response) throws IOException { + HttpEntity entity = response.getEntity(); + String result = EntityUtils.toString(entity, DEFAULT_CHARSET); + EntityUtils.consume(entity); + return result; + } +} \ No newline at end of file diff --git a/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java new file mode 100644 index 00000000..04c8c927 --- /dev/null +++ b/source/manager/ump-service/src/main/java/com/jd/blockchain/ump/util/HttpJsonClientUtils.java @@ -0,0 +1,61 @@ +package com.jd.blockchain.ump.util; + +import com.alibaba.fastjson.JSON; +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.web.WebResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HttpJsonClientUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpJsonClientUtils.class); + + public static T httpPost(MasterAddr masterAddr, String url, Object body, Class returnType, boolean isWrapper) { + + try { + String responseJson = HttpClientPool.jsonPost(masterAddr.toHttpUrl() + url, JSON.toJSONString(body)); + + LOGGER.info("Http Post Receive info =[ {} ] from {} ", responseJson, masterAddr.toHttpUrl() + url); + + return response(responseJson, returnType, isWrapper); + } catch (Exception e) { + + LOGGER.error("HttpPostRequestException {}", e.getMessage()); + + throw new IllegalStateException(e); + } + } + + public static T httpGet(String url, Class returnType, boolean isWrapper) { + try { + String responseJson = HttpClientPool.get(url); + + LOGGER.info("Http Get Receive info =[ {} ] from {} ", responseJson, url); + + return response(responseJson, returnType, isWrapper); + + } catch (Exception e) { + + LOGGER.error("HttpGetRequestException {}", e.toString()); + + throw new IllegalStateException(e); + } + } + + private static T response(String responseJson, Class returnType, boolean isWrapper) { + if (isWrapper) { + // 封装类型的情况下使用的是WebResponse + WebResponse webResponse = JSON.parseObject(responseJson, WebResponse.class); + LOGGER.info("Wrapper JSON Data = {}", JSON.toJSONString(webResponse)); + return webResponse.getData(); + } + + if (!JSON.isValid(responseJson)) { + return (T)responseJson; + } + // 对responseJson进行转换 + T data = JSON.parseObject(responseJson, returnType); + LOGGER.info("UnWrapper JSON Data = {}", JSON.toJSONString(data)); + return data; + } +} diff --git a/source/manager/ump-web/pom.xml b/source/manager/ump-web/pom.xml new file mode 100644 index 00000000..658f3205 --- /dev/null +++ b/source/manager/ump-web/pom.xml @@ -0,0 +1,83 @@ + + + + + manager + com.jd.blockchain + 1.1.0-SNAPSHOT + + 4.0.0 + + ump-web + + ump-web + + + UTF-8 + 1.8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-devtools + true + + + + com.jd.blockchain + ump-service + ${project.version} + + + + com.jd.blockchain + ump-model + ${project.version} + + + + com.jd.blockchain + utils-common + ${project.version} + + + + com.jd.blockchain + ump-explorer + + + + junit + junit + test + + + diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java new file mode 100644 index 00000000..be55fa34 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpDBController.java @@ -0,0 +1,22 @@ +package com.jd.blockchain.ump.controller; + +import com.jd.blockchain.ump.dao.DBConnection; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping(path = "/db/") +public class UmpDBController { + + @Autowired + private DBConnection dbConnection; + + @RequestMapping(method = RequestMethod.GET, path = "read/{key}") + public String read(@PathVariable(name = "key") String key) { + + return dbConnection.get(key); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java new file mode 100644 index 00000000..3b274530 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpKeyController.java @@ -0,0 +1,69 @@ +package com.jd.blockchain.ump.controller; + +import com.jd.blockchain.ump.model.user.UserKeyBuilder; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.model.user.UserKeysVv; +import com.jd.blockchain.ump.service.UmpStateService; +import com.jd.blockchain.ump.service.UtilService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping(path = "/keys/") +public class UmpKeyController { + + @Autowired + private UtilService utilService; + + @Autowired + private UmpStateService umpStateService; + + @RequestMapping(method = RequestMethod.POST, path = "create") + public UserKeysVv create(@RequestBody final UserKeyBuilder builder) { + + // 使用种子生成公私钥 + UserKeys userKeys = utilService.create(builder); + + // 将userKeys保存至数据库 + umpStateService.save(userKeys); + + return userKeys.toUserKeysVv(); + } + + @RequestMapping(method = RequestMethod.GET, path = "list") + public List list() { + + // 从数据库中读取,返回 + return umpStateService.readUserKeysVvList(); + } + + @RequestMapping(method = RequestMethod.GET, path = "read/{user}/{pubKey}") + public UserKeysVv read(@PathVariable(name = "user") int userId, + @PathVariable(name = "pubKey") String pubKey) { + + UserKeys userKeys = utilService.read(userId); + + if (userKeys != null) { + if (userKeys.getPubKey().equals(pubKey)) { + + return userKeys.toUserKeysVv(); + } + } + throw new IllegalStateException(String.format("Can not find UserKeys by %s", pubKey)); + } + + @RequestMapping(method = RequestMethod.GET, path = "resolve/{user}/{pwd}") + public UserKeys resolve(@PathVariable(name = "user") int userId, + @PathVariable(name = "pwd") String pwd) { + + UserKeys userKeys = utilService.read(userId); + + if (utilService.verify(userKeys, pwd)) { + + return userKeys; + } + throw new IllegalStateException(String.format("Can not resolve UserKeys by %s", pwd)); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java new file mode 100644 index 00000000..753ab3c0 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpMasterController.java @@ -0,0 +1,68 @@ +package com.jd.blockchain.ump.controller; + +import com.jd.blockchain.ump.model.PeerSharedConfigs; +import com.jd.blockchain.ump.model.config.LedgerConfig; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.state.InstallSchedule; +import com.jd.blockchain.ump.model.state.LedgerMasterInstall; +import com.jd.blockchain.ump.service.UmpService; +import com.jd.blockchain.ump.service.UmpStateService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping(path = "/master/") +public class UmpMasterController { + + @Autowired + private UmpService umpService; + + @Autowired + private UmpStateService umpStateService; + + /** + * 需要支持的接口 + * 1、接收节点Share的信息 + * 2、接收节点发送来的状态信息 + * 3、接收前端查看某些节点状态的请求 + */ + @RequestMapping(method = RequestMethod.POST, path = "share") + public LedgerConfig share(@RequestBody final PeerLocalConfig sharedConfig) { + + PeerSharedConfigs sharedConfigs = umpService.loadPeerSharedConfigs(sharedConfig); + + if (sharedConfigs == null) { + throw new IllegalStateException("PeerSharedConfig may be exits Conflict !!!"); + } + + return umpService.response(sharedConfigs, sharedConfig); + } + + @RequestMapping(method = RequestMethod.POST, path = "receive") + public String receive(@RequestBody final InstallSchedule installSchedule) { + + try { + umpStateService.save(installSchedule, null); + } catch (Exception e) { + return "FAIL"; + } + + return "SUCCESS"; + } + + @RequestMapping(method = RequestMethod.GET, path = "read/{ledgerKey}") + public Map> readState(@PathVariable(name = "ledgerKey") String ledgerKey) { + + return umpStateService.readStates(ledgerKey); + } + + @RequestMapping(method = RequestMethod.GET, path = "list") + public List ledgerInstallList() { + + // 返回当前Master收到的所有节点所有的安装信息 + return umpStateService.readLedgerMasterInstalls(); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java new file mode 100644 index 00000000..9222b14c --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerController.java @@ -0,0 +1,147 @@ +package com.jd.blockchain.ump.controller; + +import com.jd.blockchain.ump.model.MasterAddr; +import com.jd.blockchain.ump.model.UmpConstant; +import com.jd.blockchain.ump.model.config.LedgerConfig; +import com.jd.blockchain.ump.model.config.LedgerIdentification; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.config.PeerSharedConfigVv; +import com.jd.blockchain.ump.model.state.*; +import com.jd.blockchain.ump.model.user.UserKeys; +import com.jd.blockchain.ump.service.UmpService; +import com.jd.blockchain.ump.service.UmpStateService; +import com.jd.blockchain.ump.service.UtilService; +import com.jd.blockchain.ump.util.HttpJsonClientUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping(path = "/peer/") +public class UmpPeerController { + + @Autowired + private UmpService umpService; + + @Autowired + private UmpStateService umpStateService; + + @Autowired + private UmpMasterController masterController; + + @Autowired + private UtilService utilService; + +// @RequestMapping(method = RequestMethod.POST, path = "share") + public LedgerIdentification share(@RequestBody PeerLocalConfig localConfig) { + + //首先校验配置信息 + localConfig.verify(); + + MasterAddr masterAddr = localConfig.masterAddr(); + + LedgerConfig ledgerConfig; + + if (localConfig.master()) { + // 当前节点本身是master,直接调用Controller方法 + ledgerConfig = masterController.share(localConfig); + } else { + ledgerConfig = HttpJsonClientUtils.httpPost(masterAddr, UmpConstant.REQUEST_SHARED_URL, localConfig, LedgerConfig.class, false); + } + + if (ledgerConfig == null) { + // 未加载成功 + throw new IllegalStateException("Can not load Ledger-Config's Data from Master Node !!!"); + } + + String ledgerAndNodeKey = umpService.save(masterAddr, ledgerConfig, localConfig); + + int nodeId = ledgerConfig.getInitConfig().nodeId(localConfig.getPubKey()); + + LedgerIdentification identification = new LedgerIdentification(nodeId, localConfig, + masterAddr, ledgerAndNodeKey, ledgerConfig.getInitConfig()); + + // 将数据写入数据库 + umpStateService.save(identification); + + return identification; + } + + @RequestMapping(method = RequestMethod.POST, path = "share") + public LedgerIdentification share(@RequestBody PeerSharedConfigVv sharedConfigVv) { + + String pubKey = sharedConfigVv.getPubKey(); + + if (pubKey == null || pubKey.length() == 0) { + throw new IllegalStateException("Public Key can not be empty !!!"); + } + + // 获取对应的UsersKey,转换为LocalConfig + UserKeys userKeys = utilService.read(sharedConfigVv.getUserId()); + + if (userKeys == null || !pubKey.equals(userKeys.getPubKey())) { + throw new IllegalStateException(String.format("Can not find UserKeys by %s", pubKey)); + } + + PeerLocalConfig localConfig = sharedConfigVv.toPeerLocalConfig(userKeys); + + return share(localConfig); + } + + @RequestMapping(method = RequestMethod.POST, path = "install/{ledgerAndNodeKey}") + public PeerInstallSchedules install(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) { + + return umpService.install(ledgerAndNodeKey); + } + + @RequestMapping(method = RequestMethod.POST, path = "init/{ledgerAndNodeKey}") + public PeerInstallSchedules init(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) { + + return umpService.init(ledgerAndNodeKey); + } + + @RequestMapping(method = RequestMethod.POST, path = "startup") + public PeerStartupSchedules startup() { + + return umpService.startup(); + } + +// @RequestMapping(method = RequestMethod.POST, path = "stop/{ledgerAndNodeKey}") + public boolean stop(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) { + + return umpService.stop(ledgerAndNodeKey); + } + + @RequestMapping(method = RequestMethod.POST, path = "stop") + public boolean stop() { + + return umpService.stop(); + } + + @RequestMapping(method = RequestMethod.GET, path = "init/read/{ledgerAndNodeKey}") + public PeerInstallSchedules readInitState(@PathVariable(name = "ledgerAndNodeKey") String ledgerAndNodeKey) { + + return umpStateService.readInitState(ledgerAndNodeKey); + } + + @RequestMapping(method = RequestMethod.GET, path = "list") + public List ledgerInstallList() { + + // 返回当前Peer节点所有的安装信息 + return umpStateService.readLedgerPeerInstalls(); + } + + public List ledgerInitedList(@RequestParam(name = "search", required = false) String search) { + + // 返回当前Peer节点所有的初始化后信息 + return umpStateService.readLedgerPeerIniteds(search); + } + + @RequestMapping(method = RequestMethod.GET, path = "initeds") + public List ledgerIniteds(@RequestParam(name = "search", required = false) String search) { + + // 返回当前Peer节点所有的初始化后信息 + return umpStateService.readLedgerIniteds(search); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java new file mode 100644 index 00000000..35f0e8af --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/controller/UmpPeerSimulateController.java @@ -0,0 +1,64 @@ +package com.jd.blockchain.ump.controller; + +import com.jd.blockchain.ump.model.config.LedgerIdentification; +import com.jd.blockchain.ump.model.config.PeerLocalConfig; +import com.jd.blockchain.ump.model.state.PeerInstallSchedules; +import com.jd.blockchain.ump.service.UmpService; +import com.jd.blockchain.ump.service.UmpSimulateService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@RestController +@RequestMapping(path = "/peer/") +public class UmpPeerSimulateController { + + private final Map ledgerAndNodeKeys = new ConcurrentHashMap<>(); + + @Autowired + private UmpService umpService; + + @Autowired + private UmpSimulateService simulateService; + + @Autowired + private UmpPeerController peerController; + + @RequestMapping(method = RequestMethod.GET, path = "share/simulate/{node}") + public LedgerIdentification share(@PathVariable(name = "node") int nodeId) { + + boolean isMaster = false; + if (nodeId == 0) { + isMaster = true; + } + + PeerLocalConfig localConfig = simulateService.nodePeerLocalConfig(nodeId, isMaster); + + LedgerIdentification identification = peerController.share(localConfig); + + // 作为缓存使用 + ledgerAndNodeKeys.put(nodeId, identification.getLedgerAndNodeKey()); + + return identification; + } + + + @RequestMapping(method = RequestMethod.GET, path = "install/simulate/{node}") + public PeerInstallSchedules install(@PathVariable(name = "node") int nodeId) { + + String ledgerAndNodeKey = ledgerAndNodeKeys.get(nodeId); + + return umpService.install(ledgerAndNodeKey); + } + + @RequestMapping(method = RequestMethod.GET, path = "init/simulate/{node}") + public PeerInstallSchedules init(@PathVariable(name = "node") int nodeId) { + + return umpService.init(ledgerAndNodeKeys.get(nodeId)); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java new file mode 100644 index 00000000..6c5be2f3 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ControllerConfigurer.java @@ -0,0 +1,29 @@ +package com.jd.blockchain.ump.web; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class ControllerConfigurer implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + + // 添加打印日志的拦截器 + registry.addInterceptor(new LogPrintInterceptor()).addPathPatterns("/**"); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/webjars/**") + .addResourceLocations("classpath:/META-INF/resources"); + } + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("web/index.html"); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java new file mode 100644 index 00000000..c079fccc --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/ExceptionResponseAdvice.java @@ -0,0 +1,38 @@ +package com.jd.blockchain.ump.web; + +import com.jd.blockchain.ump.model.web.ErrorCode; +import com.jd.blockchain.ump.model.web.WebResponse; +import com.jd.blockchain.utils.BusinessException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; + +@RestControllerAdvice +public class ExceptionResponseAdvice { + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public WebResponse json(HttpServletRequest req, Exception ex) { + + WebResponse.ErrorMessage message; + + String reqURL = "[" + req.getMethod() + "] " + req.getRequestURL().toString(); + + if (ex instanceof BusinessException) { + BusinessException businessException = (BusinessException) ex; + message = new WebResponse.ErrorMessage(businessException.getErrorCode(), businessException.getMessage()); + } else { + logger.error("Exception occurred! --[RequestURL=" + reqURL + "][" + ex.getClass().toString() + + "]" + ex.getMessage(), ex); + + message = new WebResponse.ErrorMessage(ErrorCode.UNEXPECTED.getValue(), ex.toString()); + } + return WebResponse.createFailureResult(message); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java new file mode 100644 index 00000000..822aee64 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/JsonResponseAdvice.java @@ -0,0 +1,51 @@ +package com.jd.blockchain.ump.web; + +import com.jd.blockchain.ump.model.config.LedgerConfig; +import com.jd.blockchain.ump.model.web.WebResponse; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +@RestControllerAdvice +public class JsonResponseAdvice implements ResponseBodyAdvice { + + @Override + public boolean supports(MethodParameter returnType, Class> converterType) { + if (MappingJackson2HttpMessageConverter.class == converterType + && (returnType.getContainingClass().getName().startsWith("com.jd.blockchain.ump") + || returnType.getDeclaringClass().getName().startsWith("com.jd.blockchain.ump"))) { + return true; + } + return false; + } + + @Override + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, + Class> selectedConverterType, ServerHttpRequest request, + ServerHttpResponse response) { + if (body == null) { + return WebResponse.createSuccessResult(null); + } + + if (body instanceof ResponseEntity) { + return body; + } + + // LedgerConfig单独处理 + if (body instanceof LedgerConfig) { + return body; + } + + // 把返回结果自动转换为 WebResponse; + if (body instanceof WebResponse) { + return body; + } + return WebResponse.createSuccessResult(body); + } +} diff --git a/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java new file mode 100644 index 00000000..c68ef5e8 --- /dev/null +++ b/source/manager/ump-web/src/main/java/com/jd/blockchain/ump/web/LogPrintInterceptor.java @@ -0,0 +1,32 @@ +package com.jd.blockchain.ump.web; + +import com.alibaba.fastjson.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +public class LogPrintInterceptor implements HandlerInterceptor { + + private final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + // 记录日志 + // 请求的参数: + String parameters = ""; + Map requestParameters = request.getParameterMap(); + if (requestParameters != null && !requestParameters.isEmpty()) { + parameters = JSON.toJSONString(requestParameters); + } + LOGGER.info("Request[{}][{}], parameters=[{}]", + request.getRequestURL().toString(), // 请求URL + request.getMethod(), // 请求的方法 + parameters); // 请求的参数 + + return true; + } +}