From 752c621ef6e84b3992e404b930a2fa52cfa33ce7 Mon Sep 17 00:00:00 2001 From: neodiX Date: Fri, 13 Sep 2024 16:53:16 +0400 Subject: [PATCH] use deterministic validator-engine-console and lite-server keys; upgrade TON binaries to 2024.09 release. --- .github/workflows/commit-macos-arm64.yml | 2 +- README.md | 34 ++++++++ pom.xml | 12 +-- .../generaterandomid/GenerateRandomId.java | 78 +++++++++++++++++++ .../validatorengine/ValidatorEngine.java | 10 +-- .../ton/ui/controllers/MainController.java | 4 + src/main/resources/org/ton/certs/client | 1 + src/main/resources/org/ton/certs/client.pub | 3 + src/main/resources/org/ton/certs/liteserver | 1 + .../resources/org/ton/certs/liteserver.pub | 1 + src/main/resources/org/ton/certs/server | 1 + src/main/resources/org/ton/certs/server.pub | 1 + 12 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/main/resources/org/ton/certs/client create mode 100644 src/main/resources/org/ton/certs/client.pub create mode 100644 src/main/resources/org/ton/certs/liteserver create mode 100644 src/main/resources/org/ton/certs/liteserver.pub create mode 100644 src/main/resources/org/ton/certs/server create mode 100644 src/main/resources/org/ton/certs/server.pub diff --git a/.github/workflows/commit-macos-arm64.yml b/.github/workflows/commit-macos-arm64.yml index 8c214ef..8ce4859 100644 --- a/.github/workflows/commit-macos-arm64.yml +++ b/.github/workflows/commit-macos-arm64.yml @@ -4,7 +4,7 @@ on: [ push,workflow_dispatch,workflow_call ] jobs: build: - runs-on: macos-13-xlarge + runs-on: macos-14 steps: - uses: actions/checkout@v3 diff --git a/README.md b/README.md index 3bbff0b..a0206cb 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,40 @@ for ARM64 architecture use: `java -jar MyLocalTon-arm64.jar` +### Parameters + +* `nogui` - used to run MyLocalTon without GUI interface. Can be used in Docker or server with headless Java. +* `ton-http-api` - enables ton-http-api service on start. Runs on port `8081`. +* `explorer` - enables native ton blockchain explorer on start. Runs on port `8000`. +* `ip.addr.xxx.xxx` - used to bind specific IP to MyLocalTon instead of 127.0.0.1. +* `with-validators-N` - used to start MyLocalTon with N additional validators. +* `debug` - used to start MyLocalTon in debug mode, that produces lots of useful log files. + +### Lite-client + +MyLocalTon uses deterministic (permanent) private and public keys for lite-server and validator-engine-console access. +These keys can be found [here](./src/main/resources/org/ton/certs). +Once MyLocalTon is ready, you can use lite-client with the base64 key: + +`lite-client -a 127.0.0.1:4443 -b E7XwFSQzNkcRepUC23J2nRpASXpnsEKmyyHYV4u/FZY= -c last` + +or validator-engine-console in this way: + +`validator-engine-console -a 127.0.0.1:4441 -k /myLocalTon/genesis/bin/certs/client -p /myLocalTon/genesis/bin/certs/server.pub` + +### Log files + +* **MyLocalTon** log files can be found under `./myLocalTon/MyLocalTon.log`. +* **validator-engine** log files can be found under `./myLocalTon/genesis/db/log`. + +### Reporting an issue + +* delete the current folder .`/myLocalTon` next to MyLocalTon*.jar +* execute `java -jar MyLocalTon*.jar debug`. (`*` replace with architecture and branch if needed) +* wait till the error appears and shutdown MyLocalTon. +* then send zipped above log files to Telegram @neodix or attach to issue at GitHub. +* Thanks for reporting. You are making MyLocalTon better. + ## Upgrade Today upgrade is not supported, that means once you have a new version of MyLocalTon just overwrite the existing diff --git a/pom.xml b/pom.xml index 8c525a2..5e007e5 100644 --- a/pom.xml +++ b/pom.xml @@ -33,27 +33,27 @@ 11.0.14 1.6.5 0.10.7 - 0.5.3 + 0.6.0 2.8.6 2.1.0 1.1 2.17.1 - https://cicd.neodix.io/view/pipelines/job/neodix-mylocalton-${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-linux-portable.zip + https://cicd.neodix.io/view/pipelines/job/${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-linux-portable.zip - https://cicd.neodix.io/view/pipelines/job/neodix-mylocalton-${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-macos-portable.zip + https://cicd.neodix.io/view/pipelines/job/${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-macos-portable.zip - https://cicd.neodix.io/view/pipelines/job/neodix-mylocalton-${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-windows.zip + https://cicd.neodix.io/view/pipelines/job/${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-x86-64-windows.zip - https://cicd.neodix.io/view/pipelines/job/neodix-mylocalton-${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-arm64-linux-portable.zip + https://cicd.neodix.io/view/pipelines/job/${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-arm64-linux-portable.zip - https://cicd.neodix.io/view/pipelines/job/neodix-mylocalton-${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-arm64-macos-portable.zip + https://cicd.neodix.io/view/pipelines/job/${ton_branch}-pipeline/lastSuccessfulBuild/artifact/artifacts/ton-arm64-macos-portable.zip diff --git a/src/main/java/org/ton/executors/generaterandomid/GenerateRandomId.java b/src/main/java/org/ton/executors/generaterandomid/GenerateRandomId.java index ece22ad..9829eeb 100644 --- a/src/main/java/org/ton/executors/generaterandomid/GenerateRandomId.java +++ b/src/main/java/org/ton/executors/generaterandomid/GenerateRandomId.java @@ -7,6 +7,7 @@ import org.ton.utils.Extractor; import java.io.File; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -47,6 +48,36 @@ public void generateClientCertificate(Node node, String serverIdHuman) throws Ex } } + public void getClientCertificate(Node node, String serverIdHuman) throws Exception { + // Generating server certificate + if (Files.exists(Paths.get(node.getTonBinDir() + "certs" + File.separator + "client"))) { + log.info("Found existing client certificate, skipping"); + } else { + log.debug("Getting client certificate for remote control"); + String clientIdHex = "C0E4A79C30225D8A9864AE03806A0FBF4BD1F988E889C191D1BD78D8681CB0F1"; + String clientIdBase64 = "wOSnnDAiXYqYZK4DgGoPv0vR+YjoicGR0b142GgcsPE="; + log.debug("Generated client private certificate for {}: {} {}", node.getNodeName(), clientIdHex, clientIdBase64); + + InputStream stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/client"); + Files.copy(stream, Paths.get(node.getTonBinDir() + "certs" + File.separator + "client"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/client.pub"); + Files.copy(stream, Paths.get(node.getTonBinDir() + "certs" + File.separator + "client.pub"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + //Adding client permissions + String content = Files.readString(Paths.get(Extractor.MY_LOCAL_TON_ROOT_DIR + "templates" + File.separator + "control.template"), StandardCharsets.UTF_8); + String replacedTemplate = StringUtils.replace(content, "CONSOLE-PORT", String.valueOf(node.getConsolePort())); + replacedTemplate = StringUtils.replace(replacedTemplate, "SERVER-ID", "\"" + serverIdHuman + "\""); + replacedTemplate = StringUtils.replace(replacedTemplate, "CLIENT-ID", "\"" + clientIdBase64 + "\""); + + String configFile = Files.readString(Paths.get(node.getTonDbDir() + "config.json"), StandardCharsets.UTF_8); + String configNew = StringUtils.replace(configFile, "\"control\" : [", replacedTemplate); + Files.writeString(Paths.get(node.getTonDbDir() + "config.json"), configNew, StandardOpenOption.CREATE); + } + } + /** * Creates server key in db and puts into directory db/keyring/hex. */ @@ -68,6 +99,33 @@ public String generateServerCertificate(Node node) throws Exception { } } + public String getServerCertificate(Node node) throws Exception { + // Generating server certificate + if (Files.exists(Paths.get(node.getTonBinDir() + "certs" + File.separator + "server"))) { + log.info("Found existing server certificate, skipping!"); + return null; + } else { + String serverIdHex = "40C90E768C026594EFABA6A190C89AC4DB0B5F08EFC72CA06FD7E7E949A068F1"; + String serverIdBase64 = "QMkOdowCZZTvq6ahkMiaxNsLXwjvxyygb9fn6UmgaPE="; + + log.debug("Server IDs for {}: {} {}", node.getNodeName(), serverIdHex, serverIdBase64); + + InputStream stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/server"); + Files.copy(stream, Paths.get(node.getTonDbKeyringDir() + serverIdHex), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/server"); + Files.copy(stream, Paths.get(node.getTonBinDir() + "certs" + File.separator + "server"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/server.pub"); + Files.copy(stream, Paths.get(node.getTonBinDir() + "certs" + File.separator + "server.pub"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + return serverIdBase64; + } + } + public Pair generateLiteServerKeys(Node node) throws Exception { String liteserverKeys = new RandomIdExecutor().execute(node, "-m", "keys", "-n", node.getTonDbKeyringDir() + "liteserver"); String[] liteServerHexBase64 = liteserverKeys.split(" "); @@ -78,4 +136,24 @@ public Pair generateLiteServerKeys(Node node) throws Exception { Files.copy(Paths.get(node.getTonDbKeyringDir() + "liteserver"), Paths.get(node.getTonDbKeyringDir() + liteServerIdHex), StandardCopyOption.REPLACE_EXISTING); return Pair.of(liteServerIdHex, liteServerIdBase64); } + + public Pair getLiteServerKeys(Node node) throws Exception { + String liteServerIdHex = "DA46DE8CCCED9AB6F29447B334636FBE07F7F4CAE6B6833D26AF1240A1BB34B1"; + String liteServerIdBase64 = "2kbejMztmrbylEezNGNvvgf39MrmtoM9Jq8SQKG7NLE="; + log.debug("liteServerIdHex {}, liteServerIdBase64 {} on {}", liteServerIdHex, liteServerIdBase64, node.getNodeName()); + + InputStream stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/liteserver"); + Files.copy(stream, Paths.get(node.getTonDbKeyringDir() + liteServerIdHex), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/liteserver"); + Files.copy(stream, Paths.get(node.getTonDbKeyringDir() + "liteserver"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + stream = Extractor.class.getClassLoader().getResourceAsStream("org/ton/certs/liteserver.pub"); + Files.copy(stream, Paths.get(node.getTonDbKeyringDir() + "liteserver.pub"), StandardCopyOption.REPLACE_EXISTING); + stream.close(); + + return Pair.of(liteServerIdHex, liteServerIdBase64); + } } diff --git a/src/main/java/org/ton/executors/validatorengine/ValidatorEngine.java b/src/main/java/org/ton/executors/validatorengine/ValidatorEngine.java index b4692e4..f2e3709 100644 --- a/src/main/java/org/ton/executors/validatorengine/ValidatorEngine.java +++ b/src/main/java/org/ton/executors/validatorengine/ValidatorEngine.java @@ -99,8 +99,8 @@ public void initFullnode(Node node, String sharedGlobalConfig) throws Exception //enable access to full node from validator-engine-console - required if you want to become validator later GenerateRandomId generateRandomId = new GenerateRandomId(); - String serverIdBase64 = generateRandomId.generateServerCertificate(node); - generateRandomId.generateClientCertificate(node, serverIdBase64); + String serverIdBase64 = generateRandomId.getServerCertificate(node); + generateRandomId.getClientCertificate(node, serverIdBase64); } } @@ -111,7 +111,7 @@ public void enableLiteServer(Node node, String myGlobalConfig, boolean reinstall } else { log.info("Enabling lite-server..."); - Pair liteServerKeys = new GenerateRandomId().generateLiteServerKeys(node); + Pair liteServerKeys = new GenerateRandomId().getLiteServerKeys(node); String liteServers = "\"liteservers\" : [{\"id\":\"" + liteServerKeys.getRight() + "\",\"port\":\"" + node.getLiteServerPort() + "\"}"; log.debug("liteservers: {} ", liteServers); @@ -135,9 +135,6 @@ public void enableLiteServer(Node node, String myGlobalConfig, boolean reinstall //add new lite-server to the global config String existingLiteserver = MyLocalTonUtils.sbb(myGlobalTonConfig, "\"liteservers\":["); liteServerConfigNew = "{\"id\":{\"key\":\"" + liteserverPubkeyBase64 + "\", \"@type\":\"pub.ed25519\"}, \"port\": " + node.getLiteServerPort() + ", \"ip\": " + publicIpNum + "}\n]"; - //liteServerConfigBoth = StringUtils.substring(existingLiteserver, 0, -1) + "," + liteServerConfigNew; - //myGlobalTonConfigNew = StringUtils.replace(myGlobalTonConfig, existingLiteserver, liteServerConfigBoth); - //FileUtils.writeStringToFile(new File(myGlobalConfig), myGlobalTonConfigNew, StandardCharsets.UTF_8); //replace and create new config myGlobalTonConfigNew = StringUtils.replace(myGlobalTonConfig, existingLiteserver, "[" + liteServerConfigNew); @@ -352,7 +349,6 @@ public void generateValidatorKeys(Node node, boolean updateGenZeroStateFif) thro // replace path to validator-key-1.pub in gen-zerostate.fif String genZeroStateFif = FileUtils.readFileToString(new File(node.getGenesisGenZeroStateFifLocation()), StandardCharsets.UTF_8); String genZeroStateFifNew = StringUtils.replace(genZeroStateFif, "// \"path_to_" + node.getNodeName() + "_pub_key\"", "\"" + node.getValidatorKeyPubLocation() + "\""); -// genZeroStateFifNew = StringUtils.replace(genZeroStateFifNew, "initial_stake_" + node.getNodeName(), node.getDefaultValidatorStake().min(BigDecimal.ONE).multiply(BigDecimal.valueOf(ONE_BLN)).toString()); genZeroStateFifNew = StringUtils.replace(genZeroStateFifNew, "initial_stake_" + node.getNodeName(), node.getDefaultValidatorStake().min(BigInteger.ONE).toString()); FileUtils.writeStringToFile(new File(node.getGenesisGenZeroStateFifLocation()), genZeroStateFifNew, StandardCharsets.UTF_8); } diff --git a/src/main/java/org/ton/ui/controllers/MainController.java b/src/main/java/org/ton/ui/controllers/MainController.java index 9cfd3e7..57eb466 100644 --- a/src/main/java/org/ton/ui/controllers/MainController.java +++ b/src/main/java/org/ton/ui/controllers/MainController.java @@ -2121,6 +2121,9 @@ public void updateValidationTabInfo() { String previous = "Previous validators (Public key, ADNL address, weight): " + System.lineSeparator() + config32.getValidators().getValidators().stream().map(i -> i.getPublicKey() + " " + i.getAdnlAddress() + " " + i.getWeight()).collect(Collectors.joining(System.lineSeparator())) + System.lineSeparator() + System.lineSeparator(); String current = "Current validators: " + System.lineSeparator() + config34.getValidators().getValidators().stream().map(i -> i.getPublicKey() + " " + i.getAdnlAddress() + " " + i.getWeight()).collect(Collectors.joining(System.lineSeparator())) + System.lineSeparator() + System.lineSeparator(); String next = "Next validators (available only within a Break time): " + System.lineSeparator() + config36.getValidators().getValidators().stream().map(i -> i.getPublicKey() + " " + i.getAdnlAddress() + " " + i.getWeight()).collect(Collectors.joining(System.lineSeparator())) + System.lineSeparator(); + log.debug("previous {}", previous); + log.debug("current {}", current); + log.debug("next {}", next); totalValidators.setTooltip(new Tooltip(previous + current + next)); if (nonNull(v.getBlockchainLaunchTime())) { @@ -2418,6 +2421,7 @@ private void updateValidator7TabPage(ValidationParam v) { private void colorValidationTiming(ValidationParam v) { long currentTime = System.currentTimeMillis() / 1000; + log.debug("colorValidationTiming: {}, {}", currentTime, MyLocalTonUtils.toUTC(currentTime)); if (v.getStartValidationCycle() > currentTime) { startCycle.setTextFill(Color.GREEN); diff --git a/src/main/resources/org/ton/certs/client b/src/main/resources/org/ton/certs/client new file mode 100644 index 0000000..fd9f638 --- /dev/null +++ b/src/main/resources/org/ton/certs/client @@ -0,0 +1 @@ +#hI N8&`钞w0g*+}, \ No newline at end of file diff --git a/src/main/resources/org/ton/certs/client.pub b/src/main/resources/org/ton/certs/client.pub new file mode 100644 index 0000000..42b0a5c --- /dev/null +++ b/src/main/resources/org/ton/certs/client.pub @@ -0,0 +1,3 @@ +ƴHg j + +Ohʆ#H=BpKV \ No newline at end of file diff --git a/src/main/resources/org/ton/certs/liteserver b/src/main/resources/org/ton/certs/liteserver new file mode 100644 index 0000000..d8fdc30 --- /dev/null +++ b/src/main/resources/org/ton/certs/liteserver @@ -0,0 +1 @@ +#hIa"fT 2#A*5:'={zV%0 \ No newline at end of file diff --git a/src/main/resources/org/ton/certs/liteserver.pub b/src/main/resources/org/ton/certs/liteserver.pub new file mode 100644 index 0000000..3341d6f --- /dev/null +++ b/src/main/resources/org/ton/certs/liteserver.pub @@ -0,0 +1 @@ +ƴH$36Gzrv@IzgB!W \ No newline at end of file diff --git a/src/main/resources/org/ton/certs/server b/src/main/resources/org/ton/certs/server new file mode 100644 index 0000000..3b75c62 --- /dev/null +++ b/src/main/resources/org/ton/certs/server @@ -0,0 +1 @@ +#hI'vYgI07AHo \ No newline at end of file diff --git a/src/main/resources/org/ton/certs/server.pub b/src/main/resources/org/ton/certs/server.pub new file mode 100644 index 0000000..01183ec --- /dev/null +++ b/src/main/resources/org/ton/certs/server.pub @@ -0,0 +1 @@ +ƴH \"(΋(y';~䎎yýZ \ No newline at end of file