From 9742c7565542727dff4666187458fdc511e91510 Mon Sep 17 00:00:00 2001 From: Rob Kaandorp Date: Mon, 30 Mar 2020 10:43:27 +0200 Subject: [PATCH 1/4] Add onion address for @robkaandorp's btcnode Network proposal https://github.com/bisq-network/proposals/issues/189 --- core/src/main/java/bisq/core/btc/nodes/BtcNodes.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java b/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java index 4f998500542..a14b10e4daf 100644 --- a/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java +++ b/core/src/main/java/bisq/core/btc/nodes/BtcNodes.java @@ -77,7 +77,10 @@ public List getProvidedBtcNodes() { new BtcNode("node100.wiz.network", "m3yqzythryowgedc.onion", "103.99.168.100", BtcNode.DEFAULT_PORT, "@wiz"), new BtcNode("node130.wiz.network", "22tg6ufbwz6o3l2u.onion", "103.99.168.130", BtcNode.DEFAULT_PORT, "@wiz"), new BtcNode("node140.wiz.network", "jiuuuislm7ooesic.onion", "103.99.168.140", BtcNode.DEFAULT_PORT, "@wiz"), - new BtcNode("node150.wiz.network", "zyhtr2ffbzn5yeg3.onion", "103.99.168.150", BtcNode.DEFAULT_PORT, "@wiz") + new BtcNode("node150.wiz.network", "zyhtr2ffbzn5yeg3.onion", "103.99.168.150", BtcNode.DEFAULT_PORT, "@wiz"), + + // Rob Kaandorp + new BtcNode(null, "2pj2o2mrawj7yotg.onion", null, BtcNode.DEFAULT_PORT, "@robkaandorp") // cannot provide IP because no static IP ) : new ArrayList<>(); } From 0a2be9564647860e42c671d89a0fa8e78f7845e8 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Thu, 26 Mar 2020 20:17:18 -0300 Subject: [PATCH 2/4] Remove read stdin loop Replaced the Scanner input read loop with upgraded joptsimple dependency. Cli now takes a single, non-option program argument, runs it and exits. Also removed the "stop client" command because there is no input loop, but shutdown() is called for orderly channel shudown before the jvm terminates. Also changed cmd syntax from camel case to lowercase, mimicking bitcoin-cli. Configured logback to supress all debug & info level netty output, and bypassed logback to print results to System.out. --- build.gradle | 3 +- .../main/java/bisq/cli/app/BisqCliMain.java | 106 +++++++++--------- .../main/java/bisq/cli/app/CommandParser.java | 27 +++++ cli/src/main/resources/logback.xml | 4 +- gradle/witness/gradle-witness.gradle | 2 +- 5 files changed, 86 insertions(+), 56 deletions(-) create mode 100644 cli/src/main/java/bisq/cli/app/CommandParser.java diff --git a/build.gradle b/build.gradle index 19c2d56679b..f8c8682b805 100644 --- a/build.gradle +++ b/build.gradle @@ -51,7 +51,7 @@ configure(subprojects) { jcsvVersion = '1.4.0' jetbrainsAnnotationsVersion = '13.0' jfoenixVersion = '9.0.6' - joptVersion = '5.0.3' + joptVersion = '5.0.4' jsonsimpleVersion = '1.1.1' junitVersion = '4.12' jupiterVersion = '5.3.2' @@ -337,6 +337,7 @@ configure(project(':cli')) { dependencies { compile project(':proto') + implementation "net.sf.jopt-simple:jopt-simple:$joptVersion" implementation "com.google.guava:guava:$guavaVersion" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation("io.grpc:grpc-core:$grpcVersion") { diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index 5f1dec323e3..b0ac0c34cc9 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -20,18 +20,22 @@ import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; -import java.util.ArrayList; -import java.util.Arrays; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import joptsimple.OptionSpec; + import java.util.List; -import java.util.Scanner; import java.util.concurrent.TimeUnit; import lombok.extern.slf4j.Slf4j; +import static bisq.cli.app.CommandParser.GETBALANCE; +import static bisq.cli.app.CommandParser.GETVERSION; +import static bisq.cli.app.CommandParser.STOPSERVER; import static java.lang.String.format; import static java.lang.System.currentTimeMillis; import static java.lang.System.exit; -import static java.lang.System.in; +import static java.lang.System.out; /** * gRPC client. @@ -41,60 +45,28 @@ public class BisqCliMain { private final ManagedChannel channel; private final CliCommand cmd; + private final OptionParser cmdParser; public static void main(String[] args) { - new BisqCliMain("localhost", 8888); + new BisqCliMain("localhost", 8888, args); } - private BisqCliMain(String host, int port) { + private BisqCliMain(String host, int port, String[] params) { // Channels are secure by default (via SSL/TLS); for the example disable TLS to avoid needing certificates. this(ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()); - // Simple input scanner - // TODO use some more sophisticated input processing with validation.... - try (Scanner scanner = new Scanner(in)) { - while (true) { - long startTs = currentTimeMillis(); - - String[] tokens = scanner.nextLine().split(" "); - if (tokens.length == 0) { - return; - } - String command = tokens[0]; - if (tokens.length > 1) { - List params = new ArrayList<>(Arrays.asList(tokens)); - params.remove(0); - } - String result; - - switch (command) { - case "getBalance": - long satoshis = cmd.getBalance(); - // TODO mimic bitcoin-cli? Depends on an error code: Loading block index... Verifying blocks... - result = satoshis == -1 ? "Server initializing..." : cmd.prettyBalance.apply(satoshis); - break; - case "getVersion": - result = cmd.getVersion(); - break; - case "stop": - result = "Shut down client"; - try { - shutdown(); - } catch (InterruptedException e) { - log.error(e.toString(), e); - } - break; - case "stopServer": - cmd.stopServer(); - result = "Server stopped"; - break; - default: - result = format("Unknown command '%s'", command); - } - - // First response is rather slow (300 ms) but following responses are fast (3-5 ms). - log.info("{}\t{}", result, cmd.responseTime.apply(startTs)); - } + long startTs = currentTimeMillis(); + + String command = parseCommand(params); + String result = runCommand(command); + + // First response is rather slow (300 ms) but following responses are fast (3-5 ms). + // log.info("{}\t{}", result, cmd.responseTime.apply(startTs)); + out.println(result + "\t" + cmd.responseTime.apply(startTs)); + + try { + shutdown(); // Orderly channel shutdown + } catch (InterruptedException ignored) { } } @@ -104,6 +76,38 @@ private BisqCliMain(String host, int port) { private BisqCliMain(ManagedChannel channel) { this.channel = channel; this.cmd = new CliCommand(channel); + this.cmdParser = new CommandParser().configure(); + } + + private String runCommand(String command) { + final String result; + switch (command) { + case GETBALANCE: + long satoshis = cmd.getBalance(); + result = satoshis == -1 ? "Server initializing..." : cmd.prettyBalance.apply(satoshis); + break; + case GETVERSION: + result = cmd.getVersion(); + break; + case STOPSERVER: + cmd.stopServer(); + result = "Server stopped"; + break; + default: + result = format("Unknown command '%s'", command); + } + return result; + } + + private String parseCommand(String[] params) { + OptionSpec nonOptions = cmdParser.nonOptions().ofType(String.class); + OptionSet options = cmdParser.parse(params); + List detectedOptions = nonOptions.values(options); + if (detectedOptions.isEmpty()) { + CommandParser.printUsage(); + exit(0); + } + return detectedOptions.get(0); } private void shutdown() throws InterruptedException { diff --git a/cli/src/main/java/bisq/cli/app/CommandParser.java b/cli/src/main/java/bisq/cli/app/CommandParser.java new file mode 100644 index 00000000000..1c5c8b1157d --- /dev/null +++ b/cli/src/main/java/bisq/cli/app/CommandParser.java @@ -0,0 +1,27 @@ +package bisq.cli.app; + +import joptsimple.OptionParser; + +import static java.lang.System.err; + +final class CommandParser { + + // Option name constants + static final String HELP = "help"; + static final String GETBALANCE = "getbalance"; + static final String GETVERSION = "getversion"; + static final String STOPSERVER = "stopserver"; + + OptionParser configure() { + OptionParser parser = new OptionParser(); + parser.allowsUnrecognizedOptions(); + parser.nonOptions(GETBALANCE).ofType(String.class).describedAs("get btc balance"); + parser.nonOptions(GETVERSION).ofType(String.class).describedAs("get bisq version"); + return parser; + } + + static void printUsage() { + err.println("Usage: bisq-cli getbalance | getversion"); + } + +} diff --git a/cli/src/main/resources/logback.xml b/cli/src/main/resources/logback.xml index c5b1fcf9aa3..bc8edf02211 100644 --- a/cli/src/main/resources/logback.xml +++ b/cli/src/main/resources/logback.xml @@ -10,8 +10,6 @@ - - - + diff --git a/gradle/witness/gradle-witness.gradle b/gradle/witness/gradle-witness.gradle index bce96457fc8..82d9b023060 100644 --- a/gradle/witness/gradle-witness.gradle +++ b/gradle/witness/gradle-witness.gradle @@ -68,7 +68,7 @@ dependencyVerification { 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'net.glxn:qrgen:c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882', 'net.jcip:jcip-annotations:be5805392060c71474bf6c9a67a099471274d30b83eef84bfc4e0889a4f1dcc0', - 'net.sf.jopt-simple:jopt-simple:6f45c00908265947c39221035250024f2caec9a15c1c8cf553ebeecee289f342', + 'net.sf.jopt-simple:jopt-simple:df26cc58f235f477db07f753ba5a3ab243ebe5789d9f89ecf68dd62ea9a66c28', 'network.bisq.btcd-cli4j:btcd-cli4j-core:203156fc63dc1202774de9818e4f21149549f79b25d356b08bb0c784be40c0e8', 'network.bisq.btcd-cli4j:btcd-cli4j-daemon:0a2783a851add6e3d8ae899ade48c041b250bfac64b6a4c5f6380ebcdbbe6848', 'org.apache.commons:commons-compress:5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0', From ca9353080fc6429039eca312a70b4eaa1c855206 Mon Sep 17 00:00:00 2001 From: ghubstan <36207203+ghubstan@users.noreply.github.com> Date: Mon, 30 Mar 2020 11:20:19 -0300 Subject: [PATCH 3/4] Implement requested changes in PR #4097 Change member name OptionParser cmdParser -> parser. Change server listening port to 9998, client port to 9998. Change constructor argument from String[] param -> args. Print the result only, w/out exec time. Handle help command & print that to stdout; print help triggered by user error to stderr. Use explicit system SUCCESS/FAIL codes in System.exit(0 || 1). --- .../main/java/bisq/cli/app/BisqCliMain.java | 37 +++++++++---------- .../main/java/bisq/cli/app/CliCommand.java | 4 -- .../main/java/bisq/cli/app/CommandParser.java | 6 +-- .../java/bisq/core/grpc/BisqGrpcServer.java | 2 +- 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/cli/src/main/java/bisq/cli/app/BisqCliMain.java b/cli/src/main/java/bisq/cli/app/BisqCliMain.java index b0ac0c34cc9..015051bdc32 100644 --- a/cli/src/main/java/bisq/cli/app/BisqCliMain.java +++ b/cli/src/main/java/bisq/cli/app/BisqCliMain.java @@ -31,9 +31,9 @@ import static bisq.cli.app.CommandParser.GETBALANCE; import static bisq.cli.app.CommandParser.GETVERSION; +import static bisq.cli.app.CommandParser.HELP; import static bisq.cli.app.CommandParser.STOPSERVER; import static java.lang.String.format; -import static java.lang.System.currentTimeMillis; import static java.lang.System.exit; import static java.lang.System.out; @@ -43,27 +43,23 @@ @Slf4j public class BisqCliMain { + private static final int EXIT_SUCCESS = 0; + private static final int EXIT_FAILURE = 1; + private final ManagedChannel channel; private final CliCommand cmd; - private final OptionParser cmdParser; + private final OptionParser parser; public static void main(String[] args) { - new BisqCliMain("localhost", 8888, args); + new BisqCliMain("localhost", 9998, args); } - private BisqCliMain(String host, int port, String[] params) { + private BisqCliMain(String host, int port, String[] args) { // Channels are secure by default (via SSL/TLS); for the example disable TLS to avoid needing certificates. this(ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()); - - long startTs = currentTimeMillis(); - - String command = parseCommand(params); + String command = parseCommand(args); String result = runCommand(command); - - // First response is rather slow (300 ms) but following responses are fast (3-5 ms). - // log.info("{}\t{}", result, cmd.responseTime.apply(startTs)); - out.println(result + "\t" + cmd.responseTime.apply(startTs)); - + out.println(result); try { shutdown(); // Orderly channel shutdown } catch (InterruptedException ignored) { @@ -76,12 +72,15 @@ private BisqCliMain(String host, int port, String[] params) { private BisqCliMain(ManagedChannel channel) { this.channel = channel; this.cmd = new CliCommand(channel); - this.cmdParser = new CommandParser().configure(); + this.parser = new CommandParser().configure(); } private String runCommand(String command) { final String result; switch (command) { + case HELP: + CommandParser.printHelp(); + exit(EXIT_SUCCESS); case GETBALANCE: long satoshis = cmd.getBalance(); result = satoshis == -1 ? "Server initializing..." : cmd.prettyBalance.apply(satoshis); @@ -100,18 +99,18 @@ private String runCommand(String command) { } private String parseCommand(String[] params) { - OptionSpec nonOptions = cmdParser.nonOptions().ofType(String.class); - OptionSet options = cmdParser.parse(params); + OptionSpec nonOptions = parser.nonOptions().ofType(String.class); + OptionSet options = parser.parse(params); List detectedOptions = nonOptions.values(options); if (detectedOptions.isEmpty()) { - CommandParser.printUsage(); - exit(0); + CommandParser.printHelp(); + exit(EXIT_FAILURE); } return detectedOptions.get(0); } private void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(1, TimeUnit.SECONDS); - exit(0); + exit(EXIT_SUCCESS); } } diff --git a/cli/src/main/java/bisq/cli/app/CliCommand.java b/cli/src/main/java/bisq/cli/app/CliCommand.java index f40a39c673c..e3b0bc813fe 100644 --- a/cli/src/main/java/bisq/cli/app/CliCommand.java +++ b/cli/src/main/java/bisq/cli/app/CliCommand.java @@ -18,8 +18,6 @@ import lombok.extern.slf4j.Slf4j; -import static java.lang.System.currentTimeMillis; - @Slf4j final class CliCommand { @@ -32,8 +30,6 @@ final class CliCommand { @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled") final Function prettyBalance = (sats) -> btcFormat.format(BigDecimal.valueOf(sats).divide(satoshiDivisor)); - final Function responseTime = (t0) -> "(response time: " + (currentTimeMillis() - t0) + " ms)"; - CliCommand(ManagedChannel channel) { getBalanceStub = GetBalanceGrpc.newBlockingStub(channel); getVersionStub = GetVersionGrpc.newBlockingStub(channel); diff --git a/cli/src/main/java/bisq/cli/app/CommandParser.java b/cli/src/main/java/bisq/cli/app/CommandParser.java index 1c5c8b1157d..b1615d81165 100644 --- a/cli/src/main/java/bisq/cli/app/CommandParser.java +++ b/cli/src/main/java/bisq/cli/app/CommandParser.java @@ -2,7 +2,7 @@ import joptsimple.OptionParser; -import static java.lang.System.err; +import static java.lang.System.out; final class CommandParser { @@ -20,8 +20,8 @@ OptionParser configure() { return parser; } - static void printUsage() { - err.println("Usage: bisq-cli getbalance | getversion"); + static void printHelp() { + out.println("Usage: bisq-cli getbalance | getversion"); } } diff --git a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java index fc6a09726a7..ef6631462f9 100644 --- a/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java +++ b/core/src/main/java/bisq/core/grpc/BisqGrpcServer.java @@ -200,7 +200,7 @@ public void stop() { private void start() throws IOException { // TODO add to options - int port = 8888; + int port = 9998; // Config services server = ServerBuilder.forPort(port) From 736419820a8ddfcd112e4f75536b3f21a009afb5 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Tue, 31 Mar 2020 10:36:00 +0200 Subject: [PATCH 4/4] Avoid startup failure when bannedSeedNodes arg is empty This commit fixes #4103, where it was demonstrated that a bisq.properties file containing the following entries would cause Bisq to fail at startup: baseCurrencyNetwork=BTC_MAINNET bannedSeedNodes= bannedBtcNodes= bannedPriceRelayNodes=5bmpx76qllutpcyp The source of the problem was that the jOptSimple argument parsing library converts the empty value of bannedSeedNodes to a List of size 1 where the 0th element of the list is an empty string. This empty string was then attempted to be converted into a new NodeAddress, causing a validation error. This conversion happened during Guice wiring, and manifested as a blank white screen appearing as wiring errors often do in Bisq. The fix is simple and surgical. We now filter out any empty string elements before attempting to convert the banned seed node value to a new node address. I have reviewed the other related options, such as bannedPriceRelayNodes and bannedBtcNodes, and they do not cause the problem described above, so no filtering or other changes have been made to the way they work. --- .../core/network/p2p/seed/DefaultSeedNodeRepository.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java index f526cd0d5e8..ec4f70ef59a 100644 --- a/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java +++ b/core/src/main/java/bisq/core/network/p2p/seed/DefaultSeedNodeRepository.java @@ -81,7 +81,11 @@ private void reload() { }); // filter - cache.removeAll(config.bannedSeedNodes.stream().map(NodeAddress::new).collect(Collectors.toSet())); + cache.removeAll( + config.bannedSeedNodes.stream() + .filter(n -> !n.isEmpty()) + .map(NodeAddress::new) + .collect(Collectors.toSet())); log.info("Seed nodes: {}", cache); } catch (Throwable t) {